
Creating a Python package is an essential step for organizing reusable code, promoting modular design, and enabling distribution across projects or teams. A well-structured package also facilitates collaboration, testing, documentation, and deployment—whether you aim to release it publicly on PyPI or use it internally in enterprise environments.
This comprehensive guide will walk you through the entire process of building a Python package—from directory layout and metadata configuration to testing, building, and publishing.
Why Build a Python Package?
Packaging code offers a wide range of benefits:
- Encapsulation: Group related code logically into modules
- Code Reusability: Avoid duplication across multiple projects
- Version Control: Track changes using Git and version tags
- Ease of Distribution: Install via
pip
like any third-party library - Team Collaboration: Share consistent interfaces and behaviors
- Production Deployment: Publish to internal or public registries for use across environments
1. Create Your Project Directory
Begin by creating the top-level project structure:
my_package/
├── my_package/
│ ├── __init__.py
│ └── core.py
├── tests/
│ └── test_core.py
├── README.md
├── LICENSE
├── setup.py
├── pyproject.toml
├── requirements.txt
├── .gitignore
Component Breakdown:
my_package/
: The main package directory containing your actual implementation__init__.py
: Declares this as a Python package; used for exportstests/
: Contains unit tests and test suitesREADME.md
: Project documentation for usersLICENSE
: Your chosen open-source license (e.g., MIT, Apache 2.0)setup.py
: Package configuration for setuptoolspyproject.toml
: Specifies build system requirementsrequirements.txt
: Development dependencies.gitignore
: Files and directories to exclude from Git
2. Write Your Package Code
Example content for my_package/core.py
:
def add(a, b):
return a + b
def subtract(a, b):
return a - b
In my_package/__init__.py
, expose the functions:
from .core import add, subtract
__all__ = ["add", "subtract"]
This allows consumers to import like so:
from my_package import add
3. Add a README and License
README.md example:
# my_package
A simple Python package for performing basic arithmetic operations.
## Installation
```bash
pip install my_package
Usage
from my_package import add, subtract
print(add(5, 3)) # 8
print(subtract(10, 2)) # 8
**LICENSE**: Choose a license appropriate for your use case, such as:
- MIT (Permissive and widely used)
- Apache 2.0 (Permissive with patent rights)
- GPL (Strong copyleft)
---
## 4. Add Unit Tests
Inside `tests/test_core.py`:
```python
import unittest
from my_package import add, subtract
class TestCoreFunctions(unittest.TestCase):
def test_add(self):
self.assertEqual(add(3, 4), 7)
def test_subtract(self):
self.assertEqual(subtract(10, 3), 7)
if __name__ == "__main__":
unittest.main()
Run the tests using:
python -m unittest discover tests
You may also use pytest
for more advanced testing workflows.
5. Create setup.py
This file defines the package metadata and installation behavior.
from setuptools import setup, find_packages
setup(
name='my_package',
version='0.1.0',
description='A simple arithmetic Python package',
long_description=open('README.md', encoding='utf-8').read(),
long_description_content_type='text/markdown',
author='Your Name',
author_email='your.email@example.com',
url='https://github.com/yourusername/my_package',
license='MIT',
packages=find_packages(),
install_requires=[],
classifiers=[
'Programming Language :: Python :: 3',
'Operating System :: OS Independent',
'License :: OSI Approved :: MIT License',
],
python_requires='>=3.6',
)
6. Add pyproject.toml
Defines the build backend and dependencies for the build process.
[build-system]
requires = ["setuptools>=42", "wheel"]
build-backend = "setuptools.build_meta"
7. Build the Package
Install the necessary tools:
pip install build
Then build your package:
python -m build
This will generate the following files in the dist/
folder:
my_package-0.1.0.tar.gz
(source distribution)my_package-0.1.0-py3-none-any.whl
(wheel binary)
8. Publish to PyPI
Step 1: Register on PyPI
Create an account at: https://pypi.org/account/register/
Step 2: Install Twine
pip install twine
Step 3: Upload the Package
twine upload dist/*
You will be prompted for your PyPI username and password. After a successful upload, your package becomes publicly installable via:
pip install my_package
To test in a staging environment, use TestPyPI:
twine upload --repository-url https://test.pypi.org/legacy/ dist/*
9. Best Practices
- Use semantic versioning:
MAJOR.MINOR.PATCH
- Keep dependencies minimal and list them explicitly
- Provide unit tests and ideally coverage reports
- Automate builds using CI/CD tools like GitHub Actions
- Maintain a CHANGELOG.md for tracking changes
- Include
.gitignore
to keep the repo clean - Use
requirements.txt
orrequirements-dev.txt
for development dependencies
10. Optional Enhancements
- Add a
__version__
string insidemy_package/__init__.py
: pythonCopyEdit__version__ = "0.1.0"
- Add a
setup.cfg
for declarative configurations: iniCopyEdit[metadata] name = my_package version = 0.1.0 description = A simple arithmetic package [options] packages = find: python_requires = >=3.6
- Include
MANIFEST.in
to include non-code files like README, LICENSE: makefileCopyEditinclude README.md include LICENSE
- Use static analysis tools:
black
for code formattingflake8
for lintingmypy
for static type checkingruff
for combined linting and style enforcement
Final Thoughts
Building a Python package is more than just bundling files—it’s about defining a clean, documented, and reusable interface that others (or your future self) can install and use with minimal friction. Whether you’re contributing to open source or building internal tools, following these best practices will make your packages more maintainable, easier to test, and simpler to distribute.

I’m Shreyash Mhashilkar, an IT professional who loves building user-friendly, scalable digital solutions. Outside of coding, I enjoy researching new places, learning about different cultures, and exploring how technology shapes the way we live and travel. I share my experiences and discoveries to help others explore new places, cultures, and ideas with curiosity and enthusiasm.