Structuring Your Python Project
While there is no one correct way to structure a python project, it is better to consider how to leverage pythons feature set to create clean, DRY and effective codebase, with clear logic and dependancies in the planning stages of your development rather that having to worry about restructuring at a later date.
Consider the structure first and plan up front for a more streamlined and targeted approach to your coding sessions.
A Basic Sample Repository
Repository structure is critical to your project architecture.
README.rst LICENSE setup.py requirements.txt sample/__init__.py sample/core.py sample/helpers.py docs/conf.py docs/index.rst tests/test_basic.py tests/test_advanced.py
- Your library does not belong in an ambiguous
- Likewise, documentation should be in the main repo. There is no reason for it to be hidden away.
Test modules must import your packaged module to test it. Use a simple (but explicit) path modification to resolve the package properly. Requiring a developer to run setup.py develop to test an actively changing codebase also requires them to have an isolated environment setup for each instance of the codebase.
To give the individual tests import context, create a
- See also Structuring A Django Project
Signs of a poorly structured project include:
Multiple and messy circular dependencies: if your classes
furn.py need to import Carpenter from
workers.py to answer a question such as
table.isdoneby(), and if conversely the class
Carpenter needs to import
Chair to answer the question
carpenter.whatdo(), then you have a circular dependency. In this case you will have to resort to fragile hacks such as using import statements inside methods or functions.
Hidden coupling: each and every change in
Table’s implementation breaks 20 tests in unrelated test cases because it breaks
Carpenter’s code, which requires very careful surgery to adapt the change. This means you have too many assumptions about
Carpenter’s code or the reverse.
Heavy usage of global state or context: instead of explicitly passing (
wood) to each other,
Carpenter rely on global variables that can be modified and are modified on the fly by different agents. You need to scrutinize all access to these global variables to understand why a rectangular
table became a
square, and discover that remote template code is also modifying this context, messing with table dimensions.
Spaghetti code: multiple pages of nested if clauses and for loops with a lot of copy-pasted procedural code and no proper segmentation are known as spaghetti code. Python’s meaningful indentation make it very hard to maintain this kind of code. So the good news is that you might not see too much of it.
Ravioli code is more likely in Python: it consists of hundreds of similar little pieces of logic, often classes or objects, without proper structure. If you never can remember if you have to use
Table, or even
TableNew for your task at hand, you might be swimming in ravioli code.