Skip to main content

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 .env with BASE_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 with erpclasp 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).

  1. Configure credentials — in your project directory, create a .env file (you can copy .env.example; keep .env secret — 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 names ERPCLASP_BASE_URL, ERPCLASP_API_KEY, and ERPCLASP_API_SECRET still work if you already use them.

  2. Log in — verifies the server, updates .env with BASE_URL, API_KEY, and API_SECRET (your single source of truth), and writes a small .erpclasp.json marker (no secrets in that file):

    erpclasp login
    

    No prompts if all three variables are set. You can override any value with --base-url, --api-key, or --api-secret.

    pull / push / diff / status / watch read credentials from .env first. Older projects may still have keys only in .erpclasp.json; that still works until you run login again (which migrates toward .env-only).

    • erpclasp login --skip-ping — if frappe.ping is 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 on API_SECRET in .env (recommended).
  3. Initialize project files (optional but convenient):

    erpclasp init
    

    Creates scripts/ and an empty .erpclasp-map.json if missing.

  4. Pull all Server Scripts from the site:

    erpclasp pull
    

    By default you get a summary plus each filename under scripts/. Use erpclasp pull --files (-f) to print ERP script name → file while downloading. erpclasp pull --backup logs backup paths when overwriting.

    • Fetches /api/resource/Server Script (paginated)
    • Writes one .py file per script under scripts/
    • Maintains .erpclasp-map.json: local filename → ERPNext script name
  5. 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.pyscripts/my_script.py) and Server Script name in ERPNext are two different things (names can include spaces). erpclasp pull fills the map automatically for scripts that already exist on the site—you only need add when linking a new local file to an existing ERP name. Use --create if the .py file should be created empty.

  6. Diff local vs server:

    erpclasp diff
    erpclasp diff my_script.py
    

    Exits with status 1 if there are differences or errors (useful in CI).

  7. 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 .py files (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).

  8. 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 Script with pagination (limit_page_length, limit_start)
  • Read: GET /api/resource/Server Script/{name}
  • Update: PUT with {"script": "..."}; if the server rejects a partial body, the client retries with a full document merged from GET + updated script field

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).

  1. Install build tools (once):

    pip install build twine
    

    Or: pip install -e ".[dev]" — dev extras include build and twine.

  2. Bump the version in pyproject.toml ([project] version = "0.1.0") and in erpclasp/__init__.py (__version__) so each upload is unique.

  3. Build the wheel and sdist from the repo root:

    python -m build
    

    This creates dist/erpclasp-0.1.0-py3-none-any.whl and dist/erpclasp-0.1.0.tar.gz.

  4. Check the artifacts:

    twine check dist/*
    
  5. 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 the pypi- prefix) as the password, or configure ~/.pypirc.

  6. Update [project.urls] in pyproject.toml to 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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

erpclasp-0.1.0.tar.gz (25.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

erpclasp-0.1.0-py3-none-any.whl (24.3 kB view details)

Uploaded Python 3

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

Hashes for erpclasp-0.1.0.tar.gz
Algorithm Hash digest
SHA256 c1216b0a8821095e18751b798a965133ad8ec8f3f6b193e45da046a9d498d9f6
MD5 8d972fd522a9403da7c8a3becd62a1e1
BLAKE2b-256 38d1ee9a19895ae11b908a99bceb7619e008f5571c3bacdf1e332a1ae31a1483

See more details on using hashes here.

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

Hashes for erpclasp-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 897840c0d733fb67b176c38ed37c8aba67f1721b0e81ef49ba4039d4cde3df3b
MD5 0b05d377b948b0086b7fd692b0f5b9af
BLAKE2b-256 35f5a153335b3b08c064d996da8681b24edb475a87fa59deac29d47ffbaba254

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page