Command-Line Interface

portalocker ships a small command-line interface, invoked as python -m portalocker. Its only subcommand, combine, bundles the package into a single vendorable portalocker.py file for projects that cannot add portalocker as a dependency – a vendoring or single-file-deployment constraint, for example – and instead copy one generated file with the same public API into their own tree.

Running combine

$ python -m portalocker combine

This writes the combined file to dist/portalocker.py by default. Pick a different destination with --output-file/-o:

$ python -m portalocker combine --output-file vendor/portalocker.py
$ python -m portalocker combine -o vendor/portalocker.py

If the ruff command is available, the output is formatted and lint-fixed in place; if not, that step is skipped with a warning. Either way, the generated file is then executed once as a smoke test, so a broken combine surfaces immediately rather than only when a downstream project imports the file.

What the transform does

Starting from portalocker/__init__.py, combine walks the package’s modules and inlines every relative import it finds – from .foo import bar and its parenthesised multi-line form – with the source of the referenced module, recursively, so the result has no relative imports left. A module referenced from more than one place is only inlined once.

if TYPE_CHECKING: blocks are the one exception: they are copied verbatim rather than inlined, preserving the runtime guard their else-branch relies on. That includes the optional try: from .redis import RedisLock guard in __init__.py: redis.py is inlined like any other sibling module, re-indented to stay inside the try, so the combined file binds RedisLock the same way the package does – to None if importing redis fails.

Qualified references left behind by inlining (constants.LockFlags becoming just LockFlags, for instance) are cleaned up, and useless self-assignments the cleanup can produce (spam = spam) are stripped entirely.

README.rst and LICENSE are also copied near the top of the output, each wrapped in a triple-quoted string, for reference.

Limitations

The combined file still needs the redis package installed for RedisLock to work: combining inlines the code that binds to redis, not redis itself.

Every file combine reads – the package’s own modules, plus README.rst and LICENSE – is opened with encoding='ascii'. That means the entire portalocker source tree, along with README.rst and LICENSE, must stay ASCII-only: an em dash, curly quote, box-drawing character, or any other non-ASCII byte anywhere in those files makes combine raise UnicodeDecodeError instead of silently mis-encoding the result. portalocker_tests/test_combined.py asserts the combined output can still be produced, which is how a stray non-ASCII character elsewhere in the package gets caught by the test suite. Keep contributions to those files ASCII-only for this reason.