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.pyMANIFEST.in
To package the project as a source distribution:
python3 setup.py sdistThis 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.inrequirements.txtdev-requirements.indev-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/activateOn 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 pipThis 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.inAfter generating or updating the requirements files, sync them:
(venv)$ pip-sync requirements.txt dev-requirements.txtAfter 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 toxRun all environments:
tox #To run a specific environment, specify it like: -e pep8Unit 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: Callingpythonin 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 packagecryptosteganographyis in the project root, it shadows thecryptosteganographypackage installed in the tox environment. - Namespace Collisions: Calling
pytestdirectly anywhere that it can find the tests will also add the project root tosys.pathif thetestsfolder is a Python package (that is, it contains an__init__.pyfile). pytest adds all folders containing packages tosys.pathbecause 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__.pyfile fromtestsand runpytestdirectly as a tox command. - Remove the
__init__.pyfile fromtestsand change the working directory ofpython -m pytesttotests. - Move the Source Packages to a Dedicated
srcFolder.
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
mainbranch.
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
mainanddevelopbranches - On pull request to
mainanddevelopbranches
- 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.