CLI to pull, push, diff, and watch ERPNext Server Scripts via Frappe REST API
Project description
erpclasp
Python library and CLI to pull, push, diff, status, and watch ERPNext Server Scripts on Frappe Cloud (or any Frappe site) using the REST API—similar in spirit to clasp for Apps Script.
Requirements
- Python 3.11+
- A Frappe user with a valid API Key and API Secret (User → API Access → Generate Keys)
- Permission to read/update the Server Script DocType
Install
From the repository root:
pip install -e .
Or with requirements.txt:
pip install -r requirements.txt
pip install -e .
The erpclasp command is installed on your PATH.
Python library
Use the same logic from code (automation, tests, notebooks). Import from the top-level package; public names are listed in erpclasp.__all__.
from pathlib import Path
from erpclasp import FrappeClient, load_app_config, pull_scripts, push_scripts
project = Path("/path/to/your/project") # contains .env and/or .erpclasp.json
cfg = load_app_config(project)
client = FrappeClient(cfg)
result = pull_scripts(client, project)
print("pulled:", result.pulled, "errors:", result.errors)
# push_scripts(client, project, only_filenames={"my_script.py"})
You can still import submodules directly (e.g. from erpclasp.api import FrappeClient) if you prefer; the package root re-exports the stable surface.
Sharing the tool with others
Anyone with Python 3.11+ can use the same CLI:
| How | Command / notes |
|---|---|
| From a cloned repo | git clone … && cd erpclasp && python -m venv .venv then activate venv and run pip install -e . |
| Install from Git without cloning first | pip install "git+https://github.com/YOUR_ORG/erpclasp.git#egg=erpclasp" (adjust URL and branch/tag) |
| Isolated global CLI (recommended for “just the command”) | pipx: pipx install . from the repo root, or after you publish: pipx install erpclasp |
| Publish to PyPI (optional) | Build with python -m build and upload; then others run pip install erpclasp from any machine |
What each developer needs
- Their own
.envwithBASE_URL,API_KEY,API_SECRET(or keys for a bot user your team agrees on). Never commit.env. - A project folder for scripts: either clone your team repo that contains
scripts/and.erpclasp-map.json, or start fresh witherpclasp init+erpclasp login+erpclasp pull.
What you can commit to Git (for the team): scripts/*.py, .erpclasp-map.json, .env.example, and this tool’s source. Do not commit .env or .erpclasp.json if they contain secrets (your .gitignore already ignores typical cases).
Quick start
Run these from the directory you want to use as the project root (where .env and project files live).
-
Configure credentials — in your project directory, create a
.envfile (you can copy.env.example; keep.envsecret — it is gitignored if you use the provided.gitignore):BASE_URL=https://your-site.frappe.cloud API_KEY=your_api_key_here API_SECRET=your_api_secret_here
The site URL should include
https://and no trailing slash. Legacy namesERPCLASP_BASE_URL,ERPCLASP_API_KEY, andERPCLASP_API_SECRETstill work if you already use them. -
Log in — verifies the server, updates
.envwithBASE_URL,API_KEY, andAPI_SECRET(your single source of truth), and writes a small.erpclasp.jsonmarker (no secrets in that file):erpclasp loginNo prompts if all three variables are set. You can override any value with
--base-url,--api-key, or--api-secret.pull/push/diff/status/watchread credentials from.envfirst. Older projects may still have keys only in.erpclasp.json; that still works until you runloginagain (which migrates toward.env-only).erpclasp login --skip-ping— iffrappe.pingis blocked but credentials are valid.- Windows / interactive only: hidden secret prompts often block paste — use
--plain-secret-prompt,--api-secret-file path.txt, or rely onAPI_SECRETin.env(recommended).
-
Initialize project files (optional but convenient):
erpclasp initCreates
scripts/and an empty.erpclasp-map.jsonif missing. -
Pull all Server Scripts from the site:
erpclasp pullBy default you get a summary plus each filename under
scripts/. Useerpclasp pull --files(-f) to print ERP script name → file while downloading.erpclasp pull --backuplogs backup paths when overwriting.- Fetches
/api/resource/Server Script(paginated) - Writes one
.pyfile per script underscripts/ - Maintains
.erpclasp-map.json: local filename → ERPNext script name
- Fetches
-
Edit files under
scripts/, then push to ERPNext:erpclasp push # all mapped .py files erpclasp push test.py # only scripts/test.py (basename) erpclasp push --dry-run # show what would be pushed
New file (the Server Script must already exist on ERPNext, or create it there first):
erpclasp add my_script.py "Exact Server Script Name" # path + ERP name in one go erpclasp add my_script.py # terminal prompts for the ERP name erpclasp add my_script.py --name "Exact Server Script Name" # non-interactive (CI/scripts) erpclasp push my_script.py
The file path (
my_script.py→scripts/my_script.py) and Server Script name in ERPNext are two different things (names can include spaces).erpclasp pullfills the map automatically for scripts that already exist on the site—you only needaddwhen linking a new local file to an existing ERP name. Use--createif the.pyfile should be created empty. -
Diff local vs server:
erpclasp diff erpclasp diff my_script.py
Exits with status 1 if there are differences or errors (useful in CI).
-
Status — what needs a push (or fix): by default only modified (local ≠ server) and error rows; if everything matches, prints a short “nothing to push” line. Unmapped
.pyfiles (not in.erpclasp-map.json) are listed separately when present.erpclasp status erpclasp status --all # every mapped file, including clean (full audit)
Exits 1 if any mapped script is modified or errored; 0 when all mapped files are clean (unmapped files alone do not fail the exit code).
-
Watch for saves and auto-push (debounced):
erpclasp watch
List what’s in scripts/ (files + mapped ERP names):
erpclasp list
Project layout
your-project/
├── .env # BASE_URL, API_KEY, API_SECRET — single source of truth (do not commit)
├── .erpclasp.json # small marker from `login` (no secrets; do not commit)
├── .erpclasp-map.json # "filename.py" -> "ERPNext Server Script Name"
├── scripts/ # local Python files
│ └── .backups/ # optional; created when using pull --backup
└── ...
Mapping file
ERPNext script names can contain spaces and arbitrary casing; local filenames must be portable. The map ties them together, for example:
{
"sales_order_validate.py": "Sales Order Validate Script"
}
The map is updated automatically on pull. You can edit it by hand if you rename files—keep keys aligned with files in scripts/.
Pull backups
To copy existing files to scripts/.backups/ before overwriting:
erpclasp pull --backup
Authentication
Requests use the standard Frappe header:
Authorization: token <api_key>:<api_secret>
Content-Type: application/json
On each run, erpclasp loads project/.env (project root is detected from .erpclasp.json, .erpclasp-map.json, or your working tree). Secrets live only in .env. erpclasp login checks the server, writes those three variables into .env, and writes .erpclasp.json as a marker without API keys. Change keys by editing .env (or re-run login); other commands pick up changes on the next invocation.
API behavior
- List:
GET /api/resource/Server Scriptwith pagination (limit_page_length,limit_start) - Read:
GET /api/resource/Server Script/{name} - Update:
PUTwith{"script": "..."}; if the server rejects a partial body, the client retries with a full document merged from GET + updatedscriptfield
Troubleshooting
| Issue | What to try |
|---|---|
| No project found / missing credentials | Run erpclasp init and erpclasp login from the project root. Parent directories are searched for .erpclasp.json or .erpclasp-map.json. Ensure .env contains BASE_URL, API_KEY, and API_SECRET. |
| Login / ping fails | Check URL (https), firewall, and API keys. Try erpclasp login --skip-ping. |
401 / 403 |
Invalid key/secret or user lacks permission on Server Script. |
404 on push |
Script was deleted on server or mapping name is wrong—run pull again or fix .erpclasp-map.json. |
No mapping for foo.py |
Add a line in .erpclasp-map.json or run pull so filenames are registered. |
| Network timeouts | Default timeouts are set on every request; unstable links may need retries (built-in) or a stable connection. |
Use erpclasp -v / --verbose for debug logs.
Publishing to PyPI (pip install erpclasp)
After you create a PyPI account and (recommended) enable 2FA, create an API token at pypi.org → Account settings → API tokens with scope “Entire account” (or per-project once the name exists).
-
Install build tools (once):
pip install build twine
Or:
pip install -e ".[dev]"— dev extras includebuildandtwine. -
Bump the version in
pyproject.toml([project] version = "0.1.0") and inerpclasp/__init__.py(__version__) so each upload is unique. -
Build the wheel and sdist from the repo root:
python -m build
This creates
dist/erpclasp-0.1.0-py3-none-any.whlanddist/erpclasp-0.1.0.tar.gz. -
Check the artifacts:
twine check dist/*
-
Upload (use a test run first against TestPyPI):
twine upload --repository testpypi dist/* pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ "erpclasp==0.1.0"
Then upload to the real index:
twine upload dist/*
Twine will ask for credentials: use
__token__as the username and your API token (including thepypi-prefix) as the password, or configure~/.pypirc. -
Update
[project.urls]inpyproject.tomlto your real GitHub (or other) URLs before publishing.
Note: The project name erpclasp must be available on PyPI. If it is taken, change name = "erpclasp" in pyproject.toml to something unique (e.g. erpnext-server-scripts-cli).
Development
pip install -e ".[dev]"
License
MIT — see LICENSE.
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 erpclasp-0.1.0.tar.gz.
File metadata
- Download URL: erpclasp-0.1.0.tar.gz
- Upload date:
- Size: 25.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c1216b0a8821095e18751b798a965133ad8ec8f3f6b193e45da046a9d498d9f6
|
|
| MD5 |
8d972fd522a9403da7c8a3becd62a1e1
|
|
| BLAKE2b-256 |
38d1ee9a19895ae11b908a99bceb7619e008f5571c3bacdf1e332a1ae31a1483
|
File details
Details for the file erpclasp-0.1.0-py3-none-any.whl.
File metadata
- Download URL: erpclasp-0.1.0-py3-none-any.whl
- Upload date:
- Size: 24.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
897840c0d733fb67b176c38ed37c8aba67f1721b0e81ef49ba4039d4cde3df3b
|
|
| MD5 |
0b05d377b948b0086b7fd692b0f5b9af
|
|
| BLAKE2b-256 |
35f5a153335b3b08c064d996da8681b24edb475a87fa59deac29d47ffbaba254
|