A Visual Studio Code extension with support for Python manifest
templates, e.g. MANIFEST.in
.
The Python manifest template has always been tricky to deal with. First you
have to get the right configuration between all of the involved bits, such as
setup.py
, setup.cfg
, and MANIFEST.in
. Then you then need to play
whack-a-mole testing your distribution or — actually probably and —
take a very deep dive into distutils
and setuptools
code to figure out
the nuance of the six template commands for including and excluding files.
Hopefully between the syntax, snippets, and documentation (below) your pain will lessen.
That is a good question! More and more the answer is, “Possibly not.” There
are various setuptools
extensions like setuptools_scm
that can
leverage your version control for tracking files to include and exclude.
There are also complete build system replacements, such as flit
.
However, you may still need a MANIFEST.in
.
- You may be unable or unwilling to use a build system other than
setuptools
. - Your project may be so simple that you don’t want to bother with another dependency for version control integration.
- Your project may be so complex that version control integration does not fully meet your needs. You may be generating untracked files that need to be included, or need to exclude tracked files.
If you do need a MANIFEST.in
we are going to try to make it hurt less. They
can be tough because first you have to get the right configuration between
all of the involved bits, such as setup.py
, setup.cfg
, and MANIFEST.in
.
Then you then need to play whack-a-mole testing your distribution or —
actually probably and — take a very deep dive into distutils
and
setuptools
code to figure out the nuance of the six template commands for
including and excluding files.
Look at the included example
directory to see an documented example of a
Python package with a MANIFEST.in
.
There are eight commands that take one, two, or more shell-style patterns.
Add | Remove | Arguments | Anchored |
---|---|---|---|
include |
exclude |
file-pattern1 [file-patternN] | ✔ |
global-include |
global-exclude |
file-pattern1 [file-patternN] | ✘ |
recursive-include |
recursive-exclude |
dir-pattern file-pattern1 [file-patternN] | ✔ dir pattern ✘ file patterns |
graft |
prune |
dir-pattern | ✔ |
The order of the commands in your template file matters. I recommend doing includes first, then excludes, going from most specific to most general.
include
sglobal-include
srecursive-include
sgraft
sexclude
sglobal-exclude
srecursive-exclude
sprune
s
Remember: You only need to exclude files get added to the list by default or
*with your include commands -- *you do not need to fully mirror your
*.gitignore
with exclude commands.
If a pattern is anchored that means it must match the root of the project precisely. For example, given these files:
.
├── LICENSE.txt
└── things
└── LICENSE.txt
- The command
include LICENSE.txt
would addLICENSE.txt
but missthings/LICENSE.txt
. - The command
global-include LICENSE.txt
would add anyLICENSE.txt
found in the tree.
Thus you want to be certain to use a global-exclude
to keep out unwanted
files that get strewn about everywhere:
global-exclude *.py[cod]
global-exclude .DS_Store
Glob | Becomes regex | Matches | Example |
---|---|---|---|
* |
[^/]* |
Match 0 or more anything but a path seperator, e.g. / |
*.txt |
? |
[^/] |
Match 1 of anything but a path seperator, e.g. / |
|
** |
.* |
Match anything, including path seperators. | src/**/templates |
[seq] |
[seq] |
Match any character within; ranges are valid. | step-[0-9].png |
[!seq] |
[^seq] |
Match anything except a character within; ranges are valid. | [!0-9] |
Note: Older versions of Python did not support the globstar (
**
). While it is a wonderful addition in newer version of Python andsetuptools
, it can still take some playing with to get the result you want, particularly withgraft
andprune
.
- Leading and trailing whitespace are irrelevant.
- Comments are an
#
not escaped with a\
, i.e.,\#
would not start a comment. - Lines can be continued using a
\
.
An example of some syntax is useful:
include LICENSE.txt
# If you need a literal special glob character, put it in a sequence.
include myfile[?].txt
# To match a literal hash, escape it.
include my\#file.txt
graft docs
global-exclude \
*.py[cod] \ # Comments after line continuations are valid.
# And between line continuations as well!
.DS_Store \ # Last item can have a line continuation as well, as long as the next line is blank.
prune docs/build
For a real-world example, have a look at the included example/MANIFEST.in
.