Skip to main content

Parse IBM z/OS JCL and serialize to JSON, YAML, CSV, or roundtrip JCL.

Project description

fromjcl

PyPI Python License CI

Parse IBM z/OS JCL into a typed Python model, then serialize it to JSON, YAML, CSV, or back to byte-exact JCL.

demo

fromjcl job.jcl --to json
fromjcl job.jcl --to yaml
fromjcl job.jcl --to csv          # one row per (step, DD, dataset)
fromjcl job.jcl --to jcl          # byte-exact roundtrip
fromjcl job.jcl --to raw          # parse-tree dump

The parser is a pure-Python port of Mike Fulton's JCLParser (Apache 2.0). Byte-exact roundtrip is enforced on every commit against an 83-sample corpus pulled from github.com/IBM/*, github.com/zowe/*, and hand-authored paraphrases (see tests/jcl_samples/).

Install

pip install fromjcl

Python 3.12+. Runtime deps are pyyaml and typer. Pure Python, so the same wheel installs under IBM Open Enterprise Python on z/OS as well as Linux, macOS, and Windows.

Optional [zoau] extra (experimental)

pip install 'fromjcl[zoau]'

Enables --to zoau and --to mvscmd, which translate each step into its closest ZOAU shell equivalent (or an mvscmd/mvscmdauth invocation when no opinionated mapping exists). Pulls in bashlex to structurally check every flag in the emitted script against a frozen ZOAU 1.x manpage table.

The output is best-effort. Every generated script starts with an EXPERIMENTAL banner, and bashlex catches flag typos but does not verify semantic equivalence to the source JCL. Review before running against real datasets.

Quick start

Given test.jcl:

//TESTJOB  JOB (ACCT),'TEST',CLASS=A
//STEP01   EXEC PGM=IDCAMS
//SYSPRINT DD SYSOUT=*
//SYSIN    DD *
 /* HELLO */
/*

fromjcl test.jcl --to yaml:

name: TESTJOB
account: (ACCT)
programmer: TEST
class_: A
steps:
- name: STEP01
  program: IDCAMS
  dds:
  - name: SYSPRINT
    sysout: '*'
  - name: SYSIN
    instream: ' /* HELLO */'

Querying with jq

# every dataset referenced
fromjcl job.jcl --to json | jq -r '.steps[].dds[].datasets[]?.dsn'

# datasets being created
fromjcl job.jcl --to json | jq -r '.steps[].dds[].datasets[]? | select(.disposition.status=="NEW") | .dsn'

# steps that run a specific program
fromjcl job.jcl --to json | jq -r '.steps[] | select(.program=="IDCAMS") | .name'

Python API

The public surface is what fromjcl/__init__.py re-exports. Anything under fromjcl._* or fromjcl.converters.* is internal.

from fromjcl import parse, Job, to_yaml, to_jcl, from_dump

# Parse + walk the model.
job = Job.from_parsed(parse("test.jcl"))
for step in job.steps:
    print(step.name, step.program, [dd.name for dd in step.dds])

# Forward: serialize the Job to a human-readable format.
print(to_yaml(job))           # YAML
# to_json(job), to_csv(job) also available

# Byte-exact roundtrip preserves comments, column layout, blank lines.
# Pass the parse tree, not the Job (the Job IR is lossy by design).
print(to_jcl(parse("test.jcl")))

# Reverse: take a JSON/YAML/CSV dump and emit JCL (functionally
# equivalent, not byte-exact).
print(from_dump(open("job.yaml").read(), "yaml"))

Available names:

Symbol What it is
parse(path), parse_bytes(data) Parser. Returns a dict with full byte-level metadata.
Job, Step, DD, Dataset, Disposition, Space, DCB Dataclasses. Standard equality, asdict(), structural pattern matching.
Job.from_parsed(tree) Build the Job model from a parse tree.
to_json(job), to_yaml(job), to_csv(job) Serialize a Job.
to_jcl(tree), to_raw(tree) Serialize a parse tree (byte-exact / raw dump).
from_dump(text, fmt) Reverse path: text dump back to JCL.

[zoau] extra adds two private modules accessible via the CLI's --to zoau / --to mvscmd paths. They are not part of the stable Python API.

Reverse: re-emit JCL from JSON, YAML, or CSV

fromjcl job.json --rejcl              # auto-detects input format
fromjcl job.yaml --rejcl --from yaml
fromjcl job.csv  --rejcl --from csv

The reverse path produces functionally equivalent JCL, not byte-exact. Comments, blank lines, and column layout are lost on the forward pass through the IR and cannot be reconstructed. The combinatoric matrix in tests/test_rejcl_matrix.py asserts that Job → format → JCL → Job is a fixed point under dataclass equality across the entire IBM/community/ZOAU corpus.

z/OS notes

fromjcl reads EBCDIC-encoded JCL natively. Binary-transferred JCL files (not auto-converted by the z/OS UNIX shell) are detected by their // byte signature (EBCDIC 0x61 0x61) and decoded as cp037 by default. All characters that appear in JCL syntax have identical byte values in cp037, cp500, and cp1047, so the choice of code page rarely matters for parsing.

If auto-detection picks the wrong code page, pass --encoding explicitly:

fromjcl job.jcl --encoding cp037   # EBCDIC US/Canada (default)
fromjcl job.jcl --encoding cp500   # EBCDIC International
fromjcl job.jcl --encoding cp1047  # z/OS Open Systems (remapped to cp037)
fromjcl job.jcl --encoding ebcdic  # alias for cp037

If pip install itself trips over EBCDIC tagging, set _BPXK_AUTOCVT=ON in the install shell.

Development

uv sync --all-groups
tests/check.sh        # ruff format + check, mypy, vulture, pytest

The test group is z/OS-installable (pytest + bashlex, both pure Python). The dev group adds workstation-only tooling (ruff, mypy, vulture, radon, interrogate); ruff and uv are Rust binaries with no z/OS build.

CI runs the same tests/check.sh pipeline on every push and pull request (see .github/workflows/ci.yml).

Docs

License

Apache-2.0. See LICENSE and NOTICE.

Trademarks

IBM, the IBM logo, z/OS, MVS, and Z Open Automation Utilities (ZOAU) are trademarks or registered trademarks of International Business Machines Corporation, registered in many jurisdictions worldwide. Other product and service names might be trademarks of IBM or other companies. A current list of IBM trademarks is available at https://www.ibm.com/legal/copytrade.

This project is an independent community effort. It is not affiliated with, endorsed by, or sponsored by IBM.

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

fromjcl-0.5.0.tar.gz (63.8 kB view details)

Uploaded Source

Built Distribution

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

fromjcl-0.5.0-py3-none-any.whl (55.9 kB view details)

Uploaded Python 3

File details

Details for the file fromjcl-0.5.0.tar.gz.

File metadata

  • Download URL: fromjcl-0.5.0.tar.gz
  • Upload date:
  • Size: 63.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for fromjcl-0.5.0.tar.gz
Algorithm Hash digest
SHA256 5d6fde87503804680b73b15b42c27d295404fdc3ca16bf861e843beca83ffc2c
MD5 74bec9546a600e0260da362c4600392f
BLAKE2b-256 87c7f821976997494d0a85905ce0246adb53568a46ffbb096170ac632f9da773

See more details on using hashes here.

File details

Details for the file fromjcl-0.5.0-py3-none-any.whl.

File metadata

  • Download URL: fromjcl-0.5.0-py3-none-any.whl
  • Upload date:
  • Size: 55.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for fromjcl-0.5.0-py3-none-any.whl
Algorithm Hash digest
SHA256 fd57ad600284858095bcb2626e45c7006b7c78ecab6b5531215eb3020902a368
MD5 fc84d2064c124aac16bc2598a0fe840e
BLAKE2b-256 21f654232246e863858d555af8b33728a4038451ebe2d6b721dc1f3c6e42fd22

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