When it comes to software development, the choices we make in the beginning can really impact how our projects turn out. One important choice is how we structure our project. Today I’m going to show you how I structure my projects to make the most of Poetry, and how to structure your projects in preparation for publishing.
The anatomy of a well-structured project
A fairly typical way to structure your project is as follows:
my_project/
│
├── src/ # Main package source directory
│ ├── sub_modules/
│ │ ├── __init__.py # Initializes the sub module
│ │ └── nested_module.py # another nested module
│ └── module.py # Your module(s)
│
├── tests/ # Test directory
│ ├── __init__.py # Initialize the test package
│ └── test_module.py # Test cases for your modules
│
├── docs/
│ ├── README.md # Project description and instructions
| └── WIKI.MD # Project documentation
|
├── .gitignore # Specifies intentionally untracked files to ignore
├── pyproject.toml # Project specification, including dependencies
└── LICENSE.MD # License information
The src/
directory
The src
directory is often used by convention to contain all of your modules and submodules, as well as the entry point to your application.
By separating our code into into its own directory, we get the following benefits:
- Isolation: It ensures that your source code is neatly separated from other project elements, such as tests and documentation. This separation is crucial for avoiding the accidental inclusion of non-essential files in your package’s distribution.
- Simplicity: By clearly separating your package’s internal code in the
src
directory, it makes importing statements in your tests and scripts easier, which helps make the development process run more smoothly. - Flexibility: It allows for easier refactoring of your project’s internal structure without impacting external users, providing a foundation for scalable and maintainable code.
The tests/
directory
Testing is a vital component of software development to ensure that code functions as intended. It’s advisable to store tests in a designated folder, such as the tests folder. Testing suites can be set up to execute tests from this designated folder, which can help automate the testing process.
- Organization: Keeping tests separate from the source code maintains your project’s cleanliness and organization.
- Efficiency: By excluding tests from your package’s distribution, you reduce its size, thereby accelerating the installation process for end users.
- Integration: A separate
tests
directory seamlessly integrates with continuous integration (CI) systems, facilitating running automated testing in isolated environments.
The docs/
directory
The README.md
file is often the first point of contact between your project and potential users or contributors. It serves as an essential guide, detailing your project’s purpose, setup instructions, and usage examples. A well-crafted README enhances accessibility, clarity, and engagement with your project’s audience.
A good readme generally includes:
- Short description: It’s good to give a clear, concise idea of the purpose and goals of your application.
- Installation instructions: Does your application have external dependencies that are not provided on PyPI? Do you have optional dependencies? Let the user know.
- Overview of features: What are your application capabilities? Does it have compatibility or interoperability with other libraries?
- Example usage: Show the user how your application works in practice. Depending on the size and complexity of your application, you may wish to provide only basic examples, and link to a wiki.
Include a .gitignore
file
The .gitignore
file plays a crucial role in maintaining the integrity of your Git repository. It specifies which files and directories should be ignored, preventing the accidental inclusion of sensitive information or unnecessary files in your repository. It’s highly unlikely that you will need to include IDE configurations, venvs, and other files specific to your particular environment, and as such, you should also add these to your .gitignore
file.
Understanding pyproject.toml
The pyproject.toml
file is a standard for defining Python project metadata and dependencies. It allows us to define many aspects of our application configuration, from build systems, such as Poetry, to our dependencies and other metadata.
- Standardization: The
pyproject.toml
file is recommended by PEP and is widely used as an industry standard. - Ease of use: Simplifies the setup process for developers, fostering a more accessible and user-friendly development environment.
- Compatibility: Ensures compatibility with the broader Python packaging ecosystem, streamlining package creation and dependency management.
- Configurability: Enables the definition of dependencies, including those for development and optional use.
Why include a LICENSE
file?
For open-source projects, the LICENSE
file is non-negotiable. It outlines how others can use, modify, and distribute your project, providing legal protection and defining the scope of permitted use. A clear license supports the open-source community by encouraging participation and contribution under defined terms. When one isn’t included, it’s generally presumed that the project has an all rights reserved license, but I would recommend including one to avoid any ambiguity.
Note, it’s best practice to use an existing licence like MIT or GPL instead of writing your own, as they have been thoroughly reviewed by the open source community.