[Zope3-dev] __init__.py interfaces.py guidelines?

Martijn Faassen faassen at infrae.com
Mon Nov 21 06:15:22 EST 2005


Hi there,

Jean-Marc Orliaguet wrote:
  > are there any guidelines / best practises for setting the contents of
> __init__.py, interfaces.py, and the packages that they import or that 
> they expose? there are too many alternatives and too many ways of ending 
> up doing circular imports and I'd like to have a consistent pattern for 
> reducing that risk.
> 
> but there doesn't seem to be a 100% clear pattern to follow when looking 
> at the zope3 code base:
> 
> some packages in have all the implementation code in __init__.py, others 
> have it in a file and the imports are done in __init__.py, others import 
> files starting with an underscore (to make them private I suppose).

I personally very much prefer __init__.py to be as empty as possible. I 
like namespace packages. For me it's always a doubletake when I realize 
most of the implementation of some Zope 3 package I'm trying to 
understand is actually hiding out in __init__.py, so I don't like this 
practice.

> some packages have an interfaces.py file others have a "interfaces" 
> folder, others have the interface definitions in the implementation code 
> itself ...

The pattern changed over time during Zope 3 development. In my current 
opinion, interfaces.py should usually be able to accomodate all the 
interfaces of a package. If interface definitions are to be 'private' 
then they can be in the implementation code, but such privacy is very, 
very rare in practice.

> Jim mentioned to me that only public and official interface definitions 
> should be listed in 'interfaces', the others should be defined inline 
> with the implementation - are there guidelines to follow?

Don't know. I think the best rule would be to make the interface public 
unless you have a very good reason not to do so, not the other way around.

> I like the inline option because it reduces the amount of imports and 
> the risk for import cycles. Does it mean that interfaces should be 
> defined inline with the code and those that are "official" be imported 
> from intertaces.py? It sounds like a good pattern.

With this pattern, the chances are increased people will point to the 
interface through two different paths, and the chances are increased 
that people forget to import things to interfaces.py even though they 
should. It's also an extra indirection; people looking for the interface 
referenced in some ZCML file discover that in fact they need to go to 
another module yet again when they look it up.

I tend to stick all my interfaces in interfaces.py. I believe keeping 
interfaces at least somewhat separate from implementation is valuable. 
It also makes for an easy place to go to to actually find out what 
interfaces are defined by a package -- I don't have to go read all the 
source code to see what interfaces exist. You can posit documentation 
tools that create such a list of all interfaces, but I like my code 
being inviting to all comers, whether or not they have particular tools.

If you really like the other pattern of sticking interfaces together 
with implementation code, then perhaps don't import them into 
interfaces.py and don't add an interfaces.py at all. This way things 
will at least be clearly defined in one place only.

I don't really think the public/private divide between interfaces is 
strong enough to worry too much about hiding certain interfaces.

My recommendations for any guidelines would be:

* use namespace packages, so nothing (or very minimal stuff only, like a 
few imports) in __init__.py. I think this is recommended practice 
outside of Zope 3 as well, so we should stick with this. Twisted seems 
to have small or empty __init__.py packages for instance, and so does 
PEAK, to compare with some other large frameworks in Python.

* use interfaces.py and put interfaces there unless there's a very good 
reason it should be private (which is rare).

Regards,

Martijn


More information about the Zope3-dev mailing list