Including non-Python files with setup.py
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.
Introduction
Python packages often need to ship more than .py files. Templates, static assets, schemas, configuration defaults, and example data all need packaging rules of their own. When you are using setup.py, the important question is whether the files live inside a package directory or outside it, because that determines whether package_data, include_package_data, or MANIFEST.in is the right tool.
Understand the Two Packaging Questions
There are really two different concerns here.
- Should the non-Python files be included in the source distribution and wheel.
- Will your code be able to access those files correctly at runtime.
The first concern is solved by packaging configuration. The second is solved by loading the files through package-aware APIs instead of assuming a working-directory path.
Use package_data for Files Inside a Package
If the files live inside an importable package directory, package_data is the most direct setup.py option.
Suppose your project looks like this:
Then setup.py can include those files like this:
That tells setuptools to include matching files that live under mypkg.
Use include_package_data and MANIFEST.in When Needed
If you want setuptools to honor file-inclusion rules from MANIFEST.in, enable include_package_data=True.
Then create a MANIFEST.in file:
This is especially useful when you want broader declarative file rules or already maintain MANIFEST.in for source distributions.
A simple mental model is:
- '
package_datais explicit insetup.py' - '
MANIFEST.inis a file-list language that setuptools can apply wheninclude_package_data=True'
Files Outside the Package Need Extra Thought
If a file sits outside the actual package directory, including it in a source distribution is not the same thing as making it accessible as package data at runtime. This is where many setups go wrong.
For example, a top-level README.md can be included in the source package, but your installed code should not assume it lives next to the importable package.
That is why runtime assets are usually best placed inside the package tree itself. If the code needs the file later, keep it under the package rather than beside setup.py.
Access the Files Correctly at Runtime
After including the files, read them through package-aware APIs. In modern Python, importlib.resources is the cleanest approach.
This is much safer than using relative paths from the current working directory, which often fail once the package is installed.
Verify What Actually Got Packaged
Do not assume the packaging rules worked. Build the distributions and inspect them.
Then check the contents under dist/. If the file is missing there, the problem is in packaging configuration. If it is present there but missing at runtime, the problem is probably how the file is being accessed.
That distinction saves time during debugging.
A Good Practical Rule
If your application code needs the file at runtime, place it inside the package, declare it in package_data or via MANIFEST.in, and load it with importlib.resources. That combination is much more reliable than scattering resource files around the repository and hoping installation paths line up later.
Common Pitfalls
- Putting runtime resource files outside the package directory and then assuming they will behave like package data after installation.
- Using
MANIFEST.inwithout enablinginclude_package_data=Truewhen that integration is required. - Including files in the distribution but still loading them at runtime with fragile working-directory-relative paths.
- Forgetting to inspect the built
sdistor wheel and therefore debugging the wrong part of the packaging flow. - Treating source-distribution inclusion and runtime resource access as though they were the same problem.
Summary
- Non-Python files can be included from
setup.py, but the correct mechanism depends on where the files live. - Use
package_datafor files inside the package. - Use
include_package_data=Truetogether withMANIFEST.inwhen you want declarative inclusion rules. - Keep runtime assets inside the package tree whenever possible.
- Load packaged resources with
importlib.resources, not fragile relative file paths.
Related reading
- Incremental Nearest Neighbor Algorithm in Python
- IndentationError unindent does not match any outer indentation level, although the indentation looks correct
- Index all except one item in python
- Index of a maximum element in TensorFlow tensor
- Inference with TensorRT .engine file on python
- Information Gain calculation with Scikit-learn
- Initialise a list to a specific length in Python
- Initialising an array of fixed size in Python
.png&w=3840&q=75)
Tackling System Design Interview Problems
A short course that equips you with the skills to approach system design interviews methodically.
Start the free courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.