manageprojects - Manage Python / Django projects
Mix the idea of Ansible with CookieCutter Templates and Django Migrations to manage and update your Python Packages and Django Projects...
The main idea it to transfer changes of a CookieCutter template back to the created project. Manageprojects used git to create a patch of the template changes and applies it to the created project.
Besides this, manageprojects also includes other generic helper for Python packages:
publish_package()- Build and upload a new release to PyPi, but with many pre-checks.format-file- Format/Check a Python source file with Darker & Co., useful as IDE action.install_python.py- One file and no dependencies to install Python, if needed, from official Python FTP server, verified.setup_python.py- One file and no dependencies to download and setup redistributable Python, if needed.
Read below the Helper section.
Documentation: docs/ (WIP)
GitHub suspended me!
Important notice:
GitHub suspended my account sometime in late August 2026 ! There was no warning beforehand, nor any explanation of the reasons afterwards. Since then, I have had no access or control over my data on GitHub.
All my projects and everything about me have completely disappeared. Everything just results in a 404 "Not Found" error page.
A support request still hasn't been answered, even after several weeks (apart from a confirmation that the request was received).
For that reason, I have been looking for a new home for all my OpenSource projects. (Or rather, I am in the process of republishing all my projects elsewhere.)
Now you can find my on these places:
- Codeberg.org/jedie
- OpenCommit.eu/jedie
- GitLab.com/users/jedie
- Radicle: did:key:z6MkfvNUuBCwRtNZwANEAGd4vaTzyuZXMKfiSyjoBALga934 | jedie.radicle.garden
That is why there will probably be a lot of broken links pointing to my GitHub account for quite some time!
install
You can use pipx to install and use PyHardLinkBackup, e.g.:
sudo apt install pipx
pipx install manageprojects
After this you can call the CLI via manageprojects command.
To upgrade an existing installation, use:
pipx upgrade PyHardLinkBackup
see: https://pipx.pypa.io/stable/docs/#pipx-upgrade
The output of manageprojects --help looks like:
usage: manageprojects [-h] {clone-project,format-file,reverse,shell-completion,start-project,update-project,version,wiggle}
╭─ options ──────────────────────────────────────────────────────────────────────────────╮
│ -h, --help show this help message and exit │
╰────────────────────────────────────────────────────────────────────────────────────────╯
╭─ subcommands ──────────────────────────────────────────────────────────────────────────╮
│ (required) │
│ • clone-project Clone existing project by replay the cookiecutter template in a │
│ new directory. │
│ │
│ e.g.: │
│ │
│ manageprojects clone-project ~/foo/bar ~/cloned/ │
│ • format-file Format and check the given python source code file with ruff, │
│ codespell and mypy. │
│ │
│ If the given file is a directory, all python files that are │
│ tracked as changed by git will be formatted. │
│ │
│ The optional fallback values will be only used, if we can't get │
│ them from the project meta files like ".editorconfig" and │
│ "pyproject.toml" │
│ • reverse Create a cookiecutter template from a managed project. │
│ │
│ e.g.: │
│ │
│ manageprojects reverse ~/my_managed_project/ │
│ ~/my_new_cookiecutter_template/ │
│ • shell-completion Setup shell completion for this CLI (Currently only for bash │
│ shell) │
│ • start-project Start a new "managed" project via a CookieCutter Template. Note: │
│ The CookieCutter Template *must* be use git! │
│ │
│ e.g.: │
│ │
│ manageprojects start-project │
│ git+https://codeberg.org/jedie/cookiecutter_templates/ │
│ --directory uv-python ~/foobar/ │
│ • update-project Update a existing project. │
│ │
│ e.g. update by overwrite (and merge changes manually via git): │
│ │
│ manageprojects update-project ~/foo/bar/ │
│ • version Print version and exit │
│ • wiggle Run wiggle to merge *.rej in given directory. │
│ https://github.com/neilbrown/wiggle │
│ │
│ e.g.: │
│ │
│ manageprojects wiggle ~/my_managed_project/ │
╰────────────────────────────────────────────────────────────────────────────────────────╯
most important commands
start-project
Help from manageprojects start-project --help Looks like:
usage: manageprojects start-project [-h] [START-PROJECT OPTIONS] STR PATH
Start a new "managed" project via a CookieCutter Template. Note: The CookieCutter Template *must* be use git!
e.g.:
manageprojects start-project git+https://codeberg.org/jedie/cookiecutter_templates/ --directory uv-python ~/foobar/
╭─ positional arguments ─────────────────────────────────────────────────────────────────╮
│ STR The name of the CookieCutter Template. (required) │
│ PATH Target path for the new project. Must not exist yet! (required) │
╰────────────────────────────────────────────────────────────────────────────────────────╯
╭─ options ──────────────────────────────────────────────────────────────────────────────╮
│ -h, --help show this help message and exit │
│ -v, --verbosity Verbosity level; e.g.: -v, -vv, -vvv, etc. (repeatable) │
│ --directory {None}|STR │
│ Cookiecutter Option: Directory within repo that holds │
│ cookiecutter.json file for advanced repositories with multi templates │
│ in it (default: None) │
│ --replay, --no-replay │
│ Cookiecutter Option: Do not prompt for parameters and only use │
│ information entered previously (default: False) │
│ --input, --no-input │
│ Cookiecutter Option: Do not prompt for parameters and only use │
│ cookiecutter.json file content (default: False) │
│ --checkout {None}|STR │
│ Cookiecutter Option: Optional branch, tag or commit ID to checkout │
│ after clone (default: None) │
│ --password {None}|STR │
│ Cookiecutter Option: Password to use when extracting the repository │
│ (default: None) │
│ --config-file {None}|PATH │
│ Cookiecutter Option: Optional path to "cookiecutter_config.yaml" │
│ (default: None) │
╰────────────────────────────────────────────────────────────────────────────────────────╯
update-project
Help from manageprojects update-project --help Looks like:
usage: manageprojects update-project [-h] [UPDATE-PROJECT OPTIONS] PATH
Update a existing project.
e.g. update by overwrite (and merge changes manually via git):
manageprojects update-project ~/foo/bar/
╭─ positional arguments ─────────────────────────────────────────────────────────────────╮
│ PATH project-path (required) │
╰────────────────────────────────────────────────────────────────────────────────────────╯
╭─ options ──────────────────────────────────────────────────────────────────────────────╮
│ -h, --help show this help message and exit │
│ -v, --verbosity Verbosity level; e.g.: -v, -vv, -vvv, etc. (repeatable) │
│ --overwrite, --no-overwrite │
│ Overwrite all Cookiecutter template files to the last template state │
│ and do not apply the changes via git patches. The developer is │
│ supposed to apply the differences manually via git. Will be aborted │
│ if the project git repro is not in a clean state. (default: True) │
│ --cleanup, --no-cleanup │
│ Cleanup created temporary files (default: True) │
│ --input, --no-input │
│ Cookiecutter Option: Do not prompt for parameters and only use │
│ cookiecutter.json file content (default: False) │
│ --password {None}|STR │
│ Cookiecutter Option: Password to use when extracting the repository │
│ (default: None) │
│ --config-file {None}|PATH │
│ Cookiecutter Option: Optional path to "cookiecutter_config.yaml" │
│ (default: None) │
╰────────────────────────────────────────────────────────────────────────────────────────╯
workflow
1. Create a new project
Use start-project command and a github url as Cookiecutter template, e.g.:
~/manageprojects$ manageprojects start-project https://codeberg.org/jedie/cookiecutter_templates/ --directory piptools-python ~/my_new_project/
~/manageprojects$ cd ~/my_new_project/your_cool_package/
~/my_new_project/your_cool_package/$ git init
~/my_new_project/your_cool_package/$ git add .
~/my_new_project/your_cool_package/$ git commit --message "my cool new project"
Note: https://codeberg.org/jedie/cookiecutter_templates is a multi template repository, the piptools-python template is here: https://codeberg.org/jedie/cookiecutter_templates/tree/main/piptools-python
After running the start-project command, look into the created files.
Manage projects stores all needed meta information about the used Cookiecutter template into pyproject.toml, e.g.:
~/manageprojects$ cat ~/my_new_project/your_cool_package/pyproject.toml
...
[manageprojects] # https://codeberg.org/jedie/manageprojects
initial_revision = "6e4c875"
initial_date = 2022-11-10T12:37:20+01:00
cookiecutter_template = "https://codeberg.org/jedie/cookiecutter_templates/"
cookiecutter_directory = "piptools-python"
[manageprojects.cookiecutter_context.cookiecutter]
...
2. Update existing project
If the source Cookiecutter changed, then you can apply these changes to your created project, e.g.:
~/manageprojects$ manageprojects update-project ~/my_new_project/your_cool_package/
After this, manageproject will update the own meta information in pyproject.toml by add applied_migrations with the information about the current Cookiecutter version, e.g.:
~/manageprojects$ cat ~/my_new_project/your_cool_package/pyproject.toml
...
[manageprojects] # https://codeberg.org/jedie/manageprojects
initial_revision = "6e4c875"
initial_date = 2022-11-10T12:37:20+01:00
cookiecutter_template = "https://codeberg.org/jedie/cookiecutter_templates/"
cookiecutter_directory = "piptools-python"
applied_migrations = [
"dd69dcf", # 2022-11-22T19:48:28+01:00
]
...
How?
Everything is based on git ;)
- manageprojects knows the git hash of the used Cookiecutter Template at creation time and the current git hash.
- It builds a git patch between these two commits.
- This patch will be applied to the created project sources.
So theoretically the changes in the template are applied to the project.
However, this does not work in every case, because git can't match the changes.
See below:
drawbacks
One problem is that git can't apply all changes.
But git apply is used with --reject.
It applies the parts of the patch that are applicable,
and leave the rejected hunks in corresponding *.rej files.
There is a cool tool, called wiggle: https://github.com/neilbrown/wiggle
It tries to apply rejected patches by perform word-wise diffs.
Just run wiggle via manageproject CLI, e.g.:
~/manageprojects$ manageprojects wiggle ~/my_new_project/your_cool_package/
Update by overwrite
A alternative way to update a project:
- Just overwrite all files with the current Cookiecutter template output
- Merge changes manually via
git
So you doesn't have trouble with not applicable git patches ;)
Just add --overwrite, e.g.:
~/manageprojects$ manageprojects update-project --overwrite ~/my_new_project/your_cool_package/
Helper
Below are some generic tools helpful for Python packages.
install_python.py
A script to download, build and install a Python interpreter, but only if the system Python is not the required major version. It's a standalone script with no dependencies. Works with Python 3.9+.
More information: docs/install_python.md
"reverse" - Reverse a project into a Cookiecutter template
A existing managed project can be converted back to a Cookiecutter template, e.g.:
~/manageprojects$ manageprojects reverse ~/my_new_project/ ~/cookiecutter_template/
"format-file" - Format and check the given python source code file
You can use format-file as "Action on save" or manual action in your IDE to fix code style ;)
usage: manageprojects format-file [-h] PATH [-v] [--py-version STR] [--max-line-length INT] [--max-distance INT]
Format and check the given python source code file with ruff, codespell and mypy.
If the given file is a directory, all python files that are tracked as changed by git will be formatted.
The optional fallback values will be only used, if we can't get them from the project meta files like ".editorconfig" and "pyproject.toml"
╭─ positional arguments ─────────────────────────────────────────────────────────────────╮
│ PATH file-path (required) │
╰────────────────────────────────────────────────────────────────────────────────────────╯
╭─ options ──────────────────────────────────────────────────────────────────────────────╮
│ -h, --help show this help message and exit │
│ -v, --verbosity Verbosity level; e.g.: -v, -vv, -vvv, etc. (repeatable) │
│ --py-version STR Fallback Python version for darker/pyupgrade, if version is not │
│ defined in pyproject.toml (default: 3.10) │
│ --max-line-length INT Fallback max. line length for darker/isort etc., if not defined │
│ in .editorconfig (default: 119) │
│ --max-distance INT If we only format the changed lines: The maximum number of │
│ lines between two chunks that can be merged. (default: 1) │
╰────────────────────────────────────────────────────────────────────────────────────────╯
publish
The manageprojects.utilities.publish.publish_package() is designed for external packages, too.
Build and upload (with twine) a project to PyPi with many pre-checks:
- Has correct version number?
- Is on main branch and up-to-date with origin?
- Check if current version already published
- Build a git tag based on current package version
- Adds change messages since last release to git tag message
Some checks result in a hard exit, but some can be manually confirmed from the user to continue publishing.
start development
At least uv is needed. Install e.g.: via pipx:
apt-get install pipx
pipx install uv
Clone the project and just start the CLI help commands. A virtual environment will be created/updated automatically.
~$ git clone https://codeberg.org/jedie/manageprojects.git
~$ cd manageprojects
~/manageprojects$ manageprojects --help
For developing manageprojects, there is the dev-cli.py with all development related commands.
The output of ./dev-cli.py --help looks like:
usage: ./dev-cli.py [-h] {coverage,git-hooks,install,lint,mypy,nox,pip-audit,publish,run-git-hooks,shell-completion,test,update,update-readme-history,update-test-snapshot-files,version}
╭─ options ──────────────────────────────────────────────────────────────────────────────╮
│ -h, --help show this help message and exit │
╰────────────────────────────────────────────────────────────────────────────────────────╯
╭─ subcommands ──────────────────────────────────────────────────────────────────────────╮
│ (required) │
│ • coverage Run tests and show coverage report. │
│ • git-hooks Setup our "pre-commit" git hooks │
│ • install Install requirements and 'manageprojects' via pip as editable. │
│ • lint Check/fix code style by run: "ruff check --fix" │
│ • mypy Run Mypy (configured in pyproject.toml) │
│ • nox Run nox │
│ • pip-audit Run pip-audit check against current requirements files │
│ • publish Build and upload this project to PyPi │
│ • run-git-hooks │
│ Run the installed "pre-commit" git hooks │
│ • shell-completion │
│ Setup shell completion for this CLI (Currently only for bash shell) │
│ • test Run unittests │
│ • update Update dependencies (uv.lock) and git pre-commit hooks │
│ • update-readme-history │
│ Update project history base on git commits/tags in README.md │
│ │
│ Will be exited with 1 if the README.md was updated otherwise with 0. │
│ │
│ Also, callable via e.g.: │
│ python -m cli_base update-readme-history -v │
│ • update-test-snapshot-files │
│ Update all test snapshot files (by remove and recreate all snapshot │
│ files) │
│ • version Print version and exit │
╰────────────────────────────────────────────────────────────────────────────────────────╯
development git hooks
To install the git hooks, run:
~/manageprojects$ ./dev-cli.py git-hooks
History
See also git tags: https://codeberg.org/jedie/manageprojects/tags
Links
- Own Cookiecutter Templates: https://codeberg.org/jedie/cookiecutter_templates
- https://github.com/cookiecutter/cookiecutter
- Available Cookiecutters template on GitHub: https://github.com/search?q=cookiecutter&type=Repositories
- Packaging Python Projects: https://packaging.python.org/en/latest/tutorials/packaging-projects/
Metadata
Release files for manageprojects 0.29.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| manageprojects-0.29.0.tar.gz | 157.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| manageprojects-0.29.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 254.8 kB
Release files / manageprojects-0.29.0.tar.gz
| Download URL | manageprojects-0.29.0.tar.gz |
|---|---|
| Size | 157.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e2cabd1aa87d58a29da2a2b439ab7ff5c8b786dc1c7e4087fbd60418e34ce9f0
|
|
BLAKE2b-256 checksum How to use checksums |
d78bcf86657ad65ae982ee6f0d61e3eae3c8b6e88a0dfe56e519dbfef783e44f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.4
|
Release files / manageprojects-0.29.0-py3-none-any.whl
| Download URL | manageprojects-0.29.0-py3-none-any.whl |
|---|---|
| Size | 97.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
d4728f37bf1e925662a38eda2eb091d3e2546275c45e8523769a351dec504954
|
|
BLAKE2b-256 checksum How to use checksums |
31813cc22f3c280bd0b59d80c0906d969533fd00fb55ab18da16ce7e7bdffab2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.4
|