Skip to content

Instantly share code, notes, and snippets.

Last active March 4, 2024 18:08
Show Gist options
  • Save althonos/6914b896789d3f2078d1e6237642c35c to your computer and use it in GitHub Desktop.
Save althonos/6914b896789d3f2078d1e6237642c35c to your computer and use it in GitHub Desktop.
A `setup.cfg` template for my Python projects
name = {name}
version = file: {name}/_version.txt
author = Martin Larralde
author_email =
url ={name}
description = {description}
long_description = file:
long_description_content_type = text/markdown
license = MIT
license_file = COPYING
platform = any
keywords = {keywords}
classifiers =
Development Status :: 3 - Alpha
Intended Audience :: Developers
License :: OSI Approved :: MIT License
Operating System :: OS Independent
Programming Language :: Python
Programming Language :: Python :: 3.4
Programming Language :: Python :: 3.5
Programming Language :: Python :: 3.6
Programming Language :: Python :: 3.7
Programming Language :: Python :: 3.8
Topic :: Software Development :: Libraries :: Python Modules
project_urls =
Bug Tracker ={name}/issues
Changelog ={name}/blob/master/
zip_safe = false
include_package_data = true
python_requires = >= 2.7, != 3.0.*, != 3.1.*, != 3.2.*
packages = {name}
test_suite = tests
setup_requires =
# setuptools >=30.3.0 # minimal version for `setup.cfg`
# setuptools >=38.3.0 # version with most `setup.cfg` bugfixes
# setuptools >=46.4.0 # let's you use attr: to extract version from a module
install_requires =
tests_require =
{name} = py.typed, _version.txt, *.pyi
universal = true
formats = zip, gztar
show_missing = true
exclude_lines =
pragma: no cover
if False
# @abc.abstractmethod
# @abc.abstractproperty
# raise NotImplementedError
# return NotImplemented
# except ImportError
# raise MemoryError
# if __name__ == .__main__.:
# if typing.TYPE_CHECKING:
file-pattern = test_*.py
verbose = 2
no-skip-report = true
quiet-stdout = true
run-coverage = true
match-dir = (?!tests)(?!resources)(?!docs)[^\.].*
match = (?!test)(?!setup)[^\._].*\.py
inherit = false
ignore = D200, D203, D213, D406, D407 # Google conventions
max-line-length = 99
doctests = True
exclude = .git, .eggs, __pycache__, tests/, docs/, build/, dist/
disallow_any_decorated = true
disallow_any_generics = true
disallow_any_unimported = false
disallow_subclassing_any = false
disallow_untyped_calls = true
disallow_untyped_defs = true
ignore_missing_imports = true
warn_unused_ignores = true
warn_return_any = true
Copy link

aureylz commented Mar 1, 2022

Hi, about the py.typed in [options.package_data], does it mean you place it at the same level than the setup.cfg ? I thought it was supposed to be inside the /src package. I'm tying to figure out how I can generate my package and make supported by MyPy.

Copy link

althonos commented Mar 1, 2022

Hi @kyweez ,

the py.typed file goes inside your package, so if you are developing myawesomepackage you should have the following structure:

├── myawesomepackage
│   ├──
│   ├──
│   └── py.typed
├── setup.cfg

Copy link

aureylz commented Mar 1, 2022

Ok, thanks a lot, that's what I thought.
So I guess my problem comes from my setup.cfg. I wrote ./myawesomepackage/py.typed instead of a simple py.typed in the [options.package_data].
Happy to find your template, thanks for this.

Copy link

althonos commented Mar 1, 2022

Yes, it should be:

myawesomepackage = py.typed

filenames are given as relative to the Python package, not full paths.

Also, you may or may not need a file as well to make sure py.typed gets in your source distribution and not just the wheel distribution.

Happy to find your template, thanks for this.

Happy that it's useful!

Copy link

borgeser commented Jun 1, 2022

Thank you @althonos, I was wondering where to put the py.typed in my setup.cfg. You saved my day!

Copy link


{name}, is an auto-format ? no need to specify anyware ?
Like response to kyweez, if package strcuture is the same, {name} call directlly myawesomepackage ?

Copy link

@jeremybep : no, it's not autoformat, you need to replace every {name} occurence with the name of your package, same for every variable in the template 👍

Copy link

Okay, that's what I thought.
however, I would like to know how you use the var {name}. Is from CI/CD, or another package, or ?
I would like to understand the logic of your setup.cfg;

thank you,

Copy link

Oh, I wrote it that way because you could use Python formatting to fill in the blanks:

import urllib.request

with urllib.request.urlopen("") as gist:
    template =

with open("setup.cfg", "w") as dst:
        description="My Awesome Package", 
        keywords="awesome, package", 

But it's not like there is a magic formula that's going to fill them for you, at some point you'll have to edit the file yourself when you're creating a new project, it's not a cookiecutter template or anything. I just have it here because i copy that file and then edit it to add what i need every time i create a new package.

Copy link

Ha, ok i see.
Thank you for sharing

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment