-
Notifications
You must be signed in to change notification settings - Fork 2
Coding Conventions
The styling of our source is derived from PEP8 and the flake8
tool. There are, however, issues relating to patterns of usage which are not covered by that. Eventually this page will become our settled guidelines on these issues but for the moment it is a place to record discussions.
There are two basic ways to use a module, they can be imported: whole or in parts. Which you choose effects how you refer to the included objects.
If the whole module is imported then any part thereof must be specified by a full path.
import some.old.toot
...
if some.old.toot.gubbins():
variable = some.old.toot.Thing()
On the other hand importing only parts of a module allow them to be referred to directly.
from some.old.toot import gubbins, Thing
...
if gubbins():
variable = Thing()
The great advantage of the second approach is that it shortens the references which helps keep a lid on line length. The major down side is that it is not uncommon for modules to provide convenience functions such as open
which share names with built-in objects. These references then become ambiguous. It is also slightly less clear where a thing comes from at first glance.
Conversesly the first approach is very clear on the origin of things and there is no chance of collisions with built-in objects. However it can lead to the source being messy and lines get long very fast.
Matthew says:
I tend to use the full import for module level functions but like the partial import for classes. The problem with this is when you want to do both.
Steve says:
I like the suggestion of using the partial import for class names and the full import for functions; I guess in the case of needing both there's nothing stopping us from having 2 import lines? Perhaps with the added convention that where we have imports from the same module they must be adjacent to each other:
import some.module
from some.module import AClass
When an argument list, either in function definition or call, gets too long for a line it must be broken across lines. There are many different ways to achieve this but it would probably be best to agree on just one.
There are so many alternative approaches that instead of trying to list all or even some of them it's probably best just to present the ones we like and then have a discussion about those.
Matthew says:
I like to include the first argument on the first line and line up remaining arguments below it:
def foo(first,
second,
third):
I find the aligned argument start to be easy to track down whithout adding any more lines than necessary. It does lead to diff churn when adding arguments at the beginning and end but I don't consider that a problem as code is read far more often than it is written or reviewed.
Steve says:
I do like the above approach (of keeping first argument inlined and subsequent arguments lined up with the first) but it gets awkward when you have this situation:
def quite_long_function_name(and_first_argument_is_also_quite_long, # maybe over 80
or_first_arg_is_short_but_later_arg_is_long,
It's quite possible (probably, even) that the above situation arises from a design failure and the arguments shouldn't ever be statement or appear long enough for this to happen... but when it does I tend to switch to the argument style of having the first argument on the next line (indented to 4 characters):
def quite_long_function_name(
and_first_argument_is_also_quite_long,
or_first_arg_is_short_but_later_arg_is_long,
Python is happy to continue to the next line with no newline escape provided it is enclosed by a structure of some sort:
setting_a_variable = [
this_is_fine,
]
But where there isn't an enclosing structure one has to use either an escaped newline or an enclosing tuple, our most common case of doing this would be:
from fab.some.module import \
thingA, \
thingB
versus:
from fab.some.module import (
thingA,
thingB,
)
Steve says:
I think the latter (i.e. not using escapes) is more common
- Future Release
- vn1.0 Release, March 2023
- 0.11 Beta Release, Jan 2023
- 0.10 Beta Release, Oct 2022
- 0.9 Alpha Release, June 2022
- Phase 2
- Phase 3
- Phase 4
- Repository Management
- Development Process
- Development Environment
- Releasing Fab
- Coding Conventions
- Glossary
- Concerning the Database
- Unit Test Coverage
- Issues With the System Testing Framework