Skip to content

Instantly share code, notes, and snippets.

@thehappycheese
Last active September 14, 2022 01:52
Show Gist options
  • Save thehappycheese/845fd17fef65ba67126554c91652ce7a to your computer and use it in GitHub Desktop.
Save thehappycheese/845fd17fef65ba67126554c91652ce7a to your computer and use it in GitHub Desktop.
Python Package Boilerplate

I like to use the following folder structure

NicksPythonPackage/
├─ src/
│  ├─ examplepythonpackage/
│  │  ├─ __init__.py
│  │  ├─ some_module.py
│  │  ├─ some_sub_package/
│  │  │  ├─ __init__.py
│  │  │  ├─ some_sub_module.py
├─ tests/
│  ├─ __init__.py
│  ├─ test_some_function.py
├─ pyproject.toml
├─ setup.cfg
├─ readme.md
├─ .gitignore

Note:

  1. setup.cfg will not be needed in the future. All config will go in pyproject.toml.
  2. I have included a dependancy on pandas in setup.cfg just for demonstration
  3. I have included basic setup for pytest
  4. Although __init__.py may sometimes be unnessisary in newer python versions, it is still required by setuptools to recognise modules AND submodules.
  5. __init__.py files are blank
  6. the __init__.py file in the tests/ folder is required for pytest-cov to work

Tests

To run tests, the package will need to be installed using

pip install -e .

Where . indicates that the current working directory is the package source.

Notes about testing:

  • performing imports inside each the test function will prevent pytest from erroring out before providing feedback about what went wrong this is important if working in vscode; if you import at the top of the module, and the import failes, vscode provides poor error messaging in its UI
  • by default, pytest will only search fot tests in:
    • the directory specified in pyproject.toml
    • all files containing tests must start with test_....py
    • all test functions names must begin with def test_...
*.pyc
__pycache__/
.vscode
.idea
.ipynb_checkpoints
dist/
*.egg-info/
Thumbs.db
.pytest_cache/
[build-system]
requires = [
"setuptools >= 40.9.0",
"wheel",
]
build-backend = "setuptools.build_meta"
[tool.pytest.ini_options]
minversion = "6.0"
addopts = "-ra -q --tb=short"
testpaths = [
"tests"
]
[metadata]
name = examplepythonpackage
version = 0.2.3
author = thehappycheese
url=https://gist.github.com/thehappycheese/845fd17fef65ba67126554c91652ce7a
long_description = file: readme.md
long_description_content_type = text/markdown
[options]
package_dir =
= src
packages = find:
install_requires =
pandas
python_requires = >=3.9
[options.packages.find]
where = src
[options.extras_require]
dev=
pytest
# src/examplepythonpackage/some_module.py
from .some_sub_package.some_sub_module import some_sub_function
def some_function(x):
return 2*x
def call_some_sub_function(x, y):
return some_sub_function(x, y)
# src/examplepythonpackage/some_sub_package/some_sub_module.py
def some_sub_function(x,y):
return x+y
# tests/test_some_function.py
# Note: put your imports inside each test function. This is optional but avoids cryptic pytest errors in vscode.
def test_something():
from examplepythonpackage.mymodule import some_function
result = some_function(5)
expected_result = 10
assert result == expected_result
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment