Recursively chmod directories, files, and executables with sensible defaults.
Project description
OpenChmod
Recursively fix file permissions across a project tree in one command.
pychmod walks a directory and applies sensible defaults — 0755 for directories, 0644 for regular files, 0755 for scripts and executables — so you don't have to chain find ... -exec chmod ... invocations or remember which mode goes where. Scripts are detected by extension or by #! shebang, even when there is no extension at all.
Features
- One pass, three modes: separate permissions for directories, files, and executables.
- Smart script detection: known extensions (
.sh,.py,.pl,.rb, ...) plus shebang sniffing for extensionless files. --dry-runto preview changes and--checkto fail CI when permissions drift.- Glob-based
--include/--excludefilters, repeatable. - Optional symlink following, off by default.
- Zero runtime dependencies. Pure Python, 3.10+.
Why not just find -exec chmod?
The classic recipe needs three passes and assumes you know which files are scripts:
find . -type d -exec chmod 0755 {} +
find . -type f -exec chmod 0644 {} +
find . -type f \( -name "*.sh" -o -name "*.py" \) -exec chmod 0755 {} +
pychmod does the same in one walk, classifies scripts by shebang as well as extension (so an extensionless ./build with #!/usr/bin/env bash gets the right mode), and adds --dry-run plus --check so you can preview changes or fail CI on drift — none of which find gives you for free.
Installation
pip install pychmod
Quick start
Apply defaults (dirs=0755, files=0644, exec=0755) to a project tree:
pychmod /path/to/project
Preview without writing:
pychmod /path/to/project --dry-run
Verify in CI — exits non-zero if anything drifts:
pychmod /path/to/project --check
Usage
pychmod [-h] [-p DIR] [--dirperms DIRPERMS] [-f FILEPERMS] [-x EXECPERMS]
[-e PATTERN] [-i PATTERN] [--files-only] [-s] [-v] [-n] [--check]
[DIR]
| Option | Description | Default |
|---|---|---|
DIR / -p DIR |
Directory to traverse (positional or flag). | — |
--dirperms |
Octal mode for directories. | 0755 |
-f, --fileperms |
Octal mode for regular files. | 0644 |
-x, --execperms |
Octal mode for scripts/executables. | 0755 |
-e, --exclude |
Glob pattern to exclude (repeatable). | — |
-i, --include |
Glob pattern to include, files only (repeatable). | — |
--files-only |
Skip directory permissions; only chmod files. | false |
-s, --symlinks |
Follow symlinks. | false |
-v, --verbose |
Print every entry processed. | false |
-n, --dry-run |
Show changes without applying them. | false |
--check |
Exit non-zero if any permissions are wrong. No changes made. | false |
[!TIP] Files without an extension are inspected for a
#!shebang line to decide whether they should be executable.
Examples
Tighten down a webroot:
pychmod /var/www --dirperms 0750 --fileperms 0640 --execperms 0750
Skip VCS and cache directories:
pychmod /path/to/project -e .git -e __pycache__ --verbose
Only retouch Python and shell scripts:
pychmod /path/to/project -i "*.py" -i "*.sh"
Only fix C/C++ source files, leave directories untouched:
pychmod /path/to/project -i "*.c" -i "*.h" -i "*.cpp" --files-only
Follow symlinks (use with care):
pychmod /path/to/project --symlinks
Use as a pre-commit / CI gate
Add a --check step to your pipeline so a stray chmod 777 never lands on main:
- name: Verify file permissions
run: pychmod . --check -e .git
Development
git clone https://github.com/Junbo-Zheng/OpenChmod.git
cd OpenChmod
pip install -e ".[dev]"
pytest
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pychmod-0.0.2.tar.gz.
File metadata
- Download URL: pychmod-0.0.2.tar.gz
- Upload date:
- Size: 11.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4d941d6e0ad8935b6064063e72114efa23f9ddd9b1aec7061fe911ebb69d3de5
|
|
| MD5 |
c6a00a4bbecbf98847f1e6af9f3a6d19
|
|
| BLAKE2b-256 |
9b4dab174e5fd4fc6f8e4722b078d613d8f92431d7121ae191541d56f370ba71
|
File details
Details for the file pychmod-0.0.2-py3-none-any.whl.
File metadata
- Download URL: pychmod-0.0.2-py3-none-any.whl
- Upload date:
- Size: 10.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3d4752305c600a8dff13428fcbaf0ef07d0c870407bacdb92bef3f543444f685
|
|
| MD5 |
3c341893abf04904895c56d388a38a72
|
|
| BLAKE2b-256 |
0be6059ac8c819c3ce2bb48f7f371dfdb30ac23ee903b85e72c971abb04dd772
|