CKAN Developer Discovers C Headers
At some point at university I borrowed, read a tiny amount of and got fined for the late return of Large Scale C++ software design. I think somewhere at the beginning there was a section on using headers to avoid circular imports. ckan is a large enough project that we can learn a thing or two here.
So we have a ckan python style guide, where we used to recommend avoiding
from blah import banana
style imports and instead recommended
import blah.banana as banana
Eventually we decided to allow from imports, because the above is ugly, but the docs were updated to include some additional rules about what you can and cannot import to avoid circular imports.
ckan.model often gets imported all over the shop and I believe it was the cause of many circular import problems. Stuff like get_action
ended up creating stuff to get around it. A simple example of ckan.model ending up everywhere would be importing
from ckan.logic import schema
schema would contain all the action functions (schema.default_show_package_schema
, etc), but it also has schema.model
(really ckan.model
), schema.maintain
(ckan.lib.maintain
). These are all implementation details of the schema functions default_show_package_schema
etc.
What if we changed ckan/logic/schema.py so that it imports only the action function into it?
This way when user of the code import the schema functions
from ckan.logic import schema
schema will have a list of functions without dirtying up their namespace with implementation details of ckan.model/maintain/whatever. We already do this for the models, as I think this is more standard for code that uses sqlalchemy, but we should really do this everywhere.
Seeing as many people write extensions for ckan we really should be doing this to define a good interface for people to use without exposing internal details to them when they import a module.
I see this as similar-ish to having a .h header and a .c file in C. We're hiding the implementation details from ckan.logic.schema by only allowing imports from elsewhere. Will this solve the circular import issues ckan had before? I don't know, but it feels better than
import ckan.model as model
import ckan.helpers as helpers
# ...
everywhere.