This guide explains how to set up the development environment, understand the project architecture, and follow the code style.
- Requirements
- Windows Support
- Installation
- Packaging
- Dependencies
- Testing
- Project Structure
- Contribution Process
-
Python 3.9+
Note:
Support for Python 2.7 in this project has been discontinued because Python 2.7 support ended on January 1, 2020.
On Windows, use py
instead of python3
for many of the examples in this documentation.
This package fully supports Windows, along with Linux and macOS, but Python is typically installed differently on Windows. Windows users typically access Python through the py launcher rather than a python3
link in their PATH
. Within a virtual environment, all platforms operate the same and use a python
link to access the Python version used in that virtual environment.
To install and run the program without a development environment, follow these instructions:
-
Create and start the virtual environment (refer to the Virtual Environments section for more details):
python3 -m venv venv source venv/bin/activate
-
Install the required dependencies:
pip install -r requirements.txt
This project is designed as a Python package, meaning it can be bundled and redistributed as a single compressed file.
Packaging is configured by:
setup.py
MANIFEST.in
To package the project as a source distribution:
python3 setup.py sdist
This will generate dist/cryptosteganography-0.0.1.tar.gz
.
(Note: The exact filename will vary based on the version number specified in setup.py
.)
Dependencies are defined in:
requirements.in
requirements.txt
dev-requirements.in
dev-requirements.txt
It is best practice during development to create an isolated Python virtual environment using the venv
standard library module. This will keep dependent Python packages from interfering with other Python projects on your system.
On Linux/macOS:
python3 -m venv venv
source venv/bin/activate
On Windows cmd
:
py -m venv venv # Activate the virtual environment
venv\Scripts\activate.bat # On newer systems, you might only need to run 'venv\Scripts\activate' (without .bat)
Check if the terminal prompt changes to indicate the virtual environment is active (e.g., (venv) will appear in the terminal prompt)
Once activated, it is good practice to update pip
to the latest version:
(venv)$ pip install --upgrade pip
This project uses pip-tools to lock project dependencies and create reproducible virtual environments.
Note: Library projects should not lock their requirements.txt
. Since cryptosteganography
also has a CLI application, this end-user application example demonstrates how to lock application dependencies.
To update dependencies:
(venv)$ pip install pip-tools
(venv)$ pip-compile --output-file requirements.txt requirements.in
(venv)$ pip-compile --output-file dev-requirements.txt dev-requirements.in
After generating or updating the requirements files, sync them:
(venv)$ pip-sync requirements.txt dev-requirements.txt
After that run the unit tests as described in the Unit Testing section to ensure that the updates do not cause incompatibilities in the project.
Automated testing is performed using tox. Tox will automatically create virtual environments based on tox.ini
for unit testing, PEP8 style guide checking, and documentation generation.
Install tox (only needed once):
python3 -m pip install tox
Run all environments:
tox #To run a specific environment, specify it like: -e pep8
Unit testing is performed with pytest, a de facto standard Python unit testing framework. Some key advantages over the built-in unittest module are:
- Significantly less boilerplate needed for tests.
- PEP8 compliant names (e.g.
pytest.raises()
instead ofself.assertRaises()
). - Vibrant ecosystem of plugins.
pytest will automatically discover and run tests by recursively searching for folders and .py
files prefixed with test
, as well as any functions prefixed by test
.
The tests
folder is created as a Python package (i.e., there is an __init__.py
file within it) because this helps pytest
uniquely namespace the test files. Without this, two test files cannot be named the same, even if they are in different sub-directories.
Code coverage is provided by the pytest-cov plugin.
When running a unit test tox environment (e.g., tox
, tox -e py37
, etc.), a data file (e.g., .coverage.py37
) containing the coverage data is generated. This file is not readable on its own, but when the coverage
tox environment is run (e.g., tox
or tox -e coverage
), coverage from all unit test environments is combined into a single data file. An HTML report is generated in the htmlcov
folder, showing each source file and indicating which lines were executed during unit testing. Open htmlcov/index.html
in a web browser to view the report. Code coverage reports help identify areas of the project that are not currently tested.
Code coverage is configured in the .coveragerc
file.
PEP8 is the universally accepted style guide for Python code. PEP8 code compliance is verified using flake8. flake8 is configured in the [flake8]
section of tox.ini
. Three extra flake8 plugins are also included:
pep8-naming
: Ensure functions, classes, and variables are named with correct casing.flake8-quotes
: Ensure that' '
style string quoting is used consistently.flake8-import-order
: Ensure consistency in the way imports are grouped and sorted.
Traditionally, Python projects place the source for their packages in the root of the project structure:
root_folder
├── cryptosteganography
│ ├── __init__.py
│ ├── cli.py
│ └── lib.py
├── tests
│ ├── __init__.py
│ └── test_generate.py
├── tox.ini
└── setup.py
However, this structure is known to have bad interactions with pytest
and tox
, which are standard tools for maintaining Python projects. The fundamental issue is that tox creates an isolated virtual environment for testing. By installing the distribution into the virtual environment, tox
ensures that the tests pass even after the distribution has been packaged and installed, thereby catching any errors in packaging and installation scripts, which are common.
Having the Python packages in the project root subverts this isolation for two reasons:
- Sys.path Issues with
pytest
: Callingpython
in the project root (for example,python -m pytest tests/
) causes Python to add the current working directory (the project root) tosys.path
, which Python uses to find modules. Because the source packagecryptosteganography
is in the project root, it shadows thecryptosteganography
package installed in the tox environment. - Namespace Collisions: Calling
pytest
directly anywhere that it can find the tests will also add the project root tosys.path
if thetests
folder is a Python package (that is, it contains an__init__.py
file). pytest adds all folders containing packages tosys.path
because it imports the tests like regular Python modules.
To properly test the project, the source packages must not be on the Python path. To prevent this, there are three possible solutions:
- Remove the
__init__.py
file fromtests
and runpytest
directly as a tox command. - Remove the
__init__.py
file fromtests
and change the working directory ofpython -m pytest
totests
. - Move the Source Packages to a Dedicated
src
Folder.
The dedicated src
directory is the recommended solution by pytest
when using tox. This solution is promoted because it is the least brittle, even though it deviates from the traditional Python project structure. It results in a directory structure like:
root_folder
├── src
│ └── cryptosteganography
│ ├── __init__.py
│ ├── cli.py
│ └── lib.py
├── tests
│ ├── __init__.py
│ ├── test_cli.py
│ └── test_lib.py
├── tox.ini
└── setup.py
- Isolation: Ensures that the source code is not accidentally imported from the project root, preserving the isolation of the virtual environment.
- Packaging Accuracy: Catches any errors in packaging and installation scripts early by installing the distribution into a controlled environment before testing.
- Namespace Management: Minimizes the risk of namespace collisions, making it easier to manage and discover tests.
Adopting the src
layout is considered best practice for maintaining a clean and manageable project structure.
To contribute to cryptosteganography, follow these steps:
- Open an issue: If you find a bug or have a request, open an issue first to discuss what you would like to change.
- Fork the repository: Create your fork of the repository on GitHub.
- Create a feature branch: Make your changes in a feature branch (
git checkout -b feature/FeatureName
). - Testing and linting: Run tests and ensure code style checks pass.
- Commit your changes: Write clear and concise commit messages.
- Sync your branch: Before pushing, make sure to pull the latest changes from the main branch and resolve any potential conflicts.
- Push the branch: Push your branch to your forked repository (
git push origin feature/FeatureName
). - Create a pull request: Submit a pull request to merge your changes into the
main
branch.
We will review your pull request and provide feedback. Once approved, your changes will be merged. Thank you for your contributions!
We have set up templates to streamline the process of reporting issues and submitting pull requests. These templates ensure that you provide all the necessary information, making it easier for maintainers and contributors to collaborate effectively.
Our issue templates are located in the .github/ISSUE_TEMPLATE
directory. When opening a new issue, you can choose from the following templates:
-
Bug Report: Use this template to report bugs. It helps you provide all necessary information to reproduce and fix the bug. The template includes sections for describing the bug, steps to reproduce, expected behavior, screenshots, and environment details.
- Template File:
.github/ISSUE_TEMPLATE/bug_report.md
- Template File:
-
Feature Request: Use this template to suggest new features or enhancements. It guides you in describing the problem, proposed solution, and any alternatives considered.
- Template File:
.github/ISSUE_TEMPLATE/feature_request.md
- Template File:
When submitting a pull request, please use the provided template. This ensures that you include all relevant information about the changes you are proposing, the testing done, and the impact on the project. The template includes checkboxes for you to confirm that you have followed the contribution guidelines.
- Template File:
.github/PULL_REQUEST_TEMPLATE.md
Our project uses GitHub Actions for continuous integration. The workflow is defined in the .github/workflows/python-package.yml
file. This workflow runs on every push and pull request to the main
and develop
branches. It ensures that our codebase remains stable and meets quality standards across different Python versions (3.9, 3.10, 3.11, 3.12).
Workflow File: .github/workflows/python-package.yml
Workflow Details:
-
Name: Python Package CI
-
Triggers:
- On push to
main
anddevelop
branches - On pull request to
main
anddevelop
branches
- On push to
-
Jobs:
- Build: Runs on
ubuntu-latest
- Matrix strategy to test multiple Python versions
- Steps:
- Checkout the repository
- Set up Python
- Install dependencies
- Run tests using
pytest
,mypy
, andflake8
- Generate documentation using
sphinx
- Upload coverage to Codecov (for Python 3.9)
- Build: Runs on
This setup ensures that all code changes are thoroughly tested and meet the project's standards before being merged.