setuptools has three different ways to specify data files that should be packages together with your project, Manifest.in, data_files, and package_data. For config files that are under your source tree, package_data is usually the easiest to use.
Given a very small sample project that looks like this:
.
├───setup.py
└───tmp
├───__init__.py
└───keys.json
You'd need a setup.py file with at least this configuration to package all code and .json files under tmp :
from setuptools import setup
setup(
name="tmp",
version="0.1.0",
packages=["tmp"],
package_data={"tmp": ["*.json"]},
)
The keys.json file only contains {"key": "foo"}.
The safest way to parse packaged config files from within your package is to use importlib.resources to access it, in particular its path function (if you are stuck on python 3.7 or older, importlib_resources is an equivalent pip-installable backport):
tmp/__init__.py
from importlib import resources
import json
def print_keys():
with resources.path("tmp", "keys.json") as foo_path:
print(json.load(foo_path.open()))
Once I install this package with pip install -e ., I can run:
>>> import tmp
>>> tmp.print_keys()
{'key': 'foo'}
If you plan to work with python packaging for a while, consider using a more modern build-backend than setuptools, such as poetry or flit. They make the experience a lot more bearable.