jcl-parser 2.2.2__tar.gz → 2.2.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/PKG-INFO +1 -1
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jcl_parser.egg-info/PKG-INFO +1 -1
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/__init__.py +1 -1
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/lint/rules.py +15 -10
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/model.py +23 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/validators.py +14 -5
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/pyproject.toml +1 -1
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/LICENSE +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/README.md +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jcl_parser.egg-info/SOURCES.txt +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jcl_parser.egg-info/dependency_links.txt +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jcl_parser.egg-info/entry_points.txt +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jcl_parser.egg-info/requires.txt +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jcl_parser.egg-info/top_level.txt +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/__main__.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/_include_origins.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/_job_builder.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/_model_factories.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/_post_parse.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/_source_scanner.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/_statement_parser.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/builtin_procs.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/checks.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/cli.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/condition_parser.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/continuation_handler.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/dataset_lifecycle.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/errors.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/explosion.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/include_loader.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/jcl_file_type.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/jes_statements.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/lineage.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/lint/__init__.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/lint/base.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/lint/config.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/lint/runner.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/lint/suppress.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/metrics.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/parameter_ast.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/parameter_validators.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/parser.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/plugins/__init__.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/plugins/base.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/proc_loader.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/profiling.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/program_profiles/__init__.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/program_profiles/_control.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/program_profiles/_invoked.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/program_profiles/adrdssu.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/program_profiles/base.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/program_profiles/binder.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/program_profiles/bpxbatch.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/program_profiles/compilers.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/program_profiles/db2_batch.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/program_profiles/dfsrrc00.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/program_profiles/dsnutilb.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/program_profiles/ftp.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/program_profiles/icetool.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/program_profiles/idcams.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/program_profiles/iebcompr.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/program_profiles/iebdg.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/program_profiles/iebgener.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/program_profiles/iebptpch.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/program_profiles/iebupdte.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/program_profiles/iefbr14.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/program_profiles/iehinitt.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/program_profiles/iehlist.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/program_profiles/iehprogm.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/program_profiles/ikjeft01.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/program_profiles/irxjcl.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/program_profiles/registry.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/program_profiles/sort.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/py.typed +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/rc_analysis.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/serialization.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/sql_detector.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/system_symbols.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/jclparser/utils.py +0 -0
- {jcl_parser-2.2.2 → jcl_parser-2.2.3}/setup.cfg +0 -0
|
@@ -20,7 +20,7 @@ application, for example::
|
|
|
20
20
|
import logging as _logging
|
|
21
21
|
|
|
22
22
|
# Package metadata
|
|
23
|
-
__version__ = "2.2.
|
|
23
|
+
__version__ = "2.2.3" # x-release-please-version
|
|
24
24
|
__author__ = "JCL Parser Team"
|
|
25
25
|
__description__ = "Parse IBM JCL scripts into Python objects"
|
|
26
26
|
|
|
@@ -12,7 +12,7 @@ from collections.abc import Iterable
|
|
|
12
12
|
from typing import TYPE_CHECKING
|
|
13
13
|
|
|
14
14
|
from ..errors import ErrorSeverity, ValidationError
|
|
15
|
-
from ..model import ConditionalBlock, _dataset_dds, iter_execution_steps
|
|
15
|
+
from ..model import ConditionalBlock, _dataset_dds, dd_label, iter_execution_steps
|
|
16
16
|
from .base import LintRule
|
|
17
17
|
|
|
18
18
|
if TYPE_CHECKING:
|
|
@@ -29,7 +29,8 @@ class HardcodedHLQRule(LintRule):
|
|
|
29
29
|
defer = config.should_run(LiteralSetValueHlqRule.code)
|
|
30
30
|
set_values = _qualifier_symbols(job)
|
|
31
31
|
for step in iter_execution_steps(job.steps):
|
|
32
|
-
|
|
32
|
+
dds = _dataset_dds(step)
|
|
33
|
+
for dd in dds:
|
|
33
34
|
dsn = dd.dataset_name
|
|
34
35
|
if not dsn or dsn.startswith("&&"):
|
|
35
36
|
continue
|
|
@@ -49,7 +50,7 @@ class HardcodedHLQRule(LintRule):
|
|
|
49
50
|
if defer and dsn.split(".", 1)[0].upper() in set_values:
|
|
50
51
|
continue
|
|
51
52
|
yield self._err(
|
|
52
|
-
f"DD '{dd
|
|
53
|
+
f"DD '{dd_label(dds, dd)}' in step '{step.name}' uses literal HLQ "
|
|
53
54
|
f"in dataset '{dsn}' — consider &HLQ",
|
|
54
55
|
line_number=dd.line_number,
|
|
55
56
|
config=config,
|
|
@@ -63,7 +64,8 @@ class LiteralSysdaUnitRule(LintRule):
|
|
|
63
64
|
|
|
64
65
|
def check(self, job: Job, config: LintConfig) -> Iterable[ValidationError]:
|
|
65
66
|
for step in iter_execution_steps(job.steps):
|
|
66
|
-
|
|
67
|
+
dds = _dataset_dds(step)
|
|
68
|
+
for dd in dds:
|
|
67
69
|
unit = dd.parameters.get("UNIT")
|
|
68
70
|
if not unit:
|
|
69
71
|
continue
|
|
@@ -72,7 +74,7 @@ class LiteralSysdaUnitRule(LintRule):
|
|
|
72
74
|
unit_val = unit if isinstance(unit, str) else str(unit[0])
|
|
73
75
|
if unit_val.strip("()").split(",")[0].strip().upper() == "SYSDA":
|
|
74
76
|
yield self._err(
|
|
75
|
-
f"DD '{dd
|
|
77
|
+
f"DD '{dd_label(dds, dd)}' in step '{step.name}' uses UNIT=SYSDA",
|
|
76
78
|
line_number=dd.line_number,
|
|
77
79
|
config=config,
|
|
78
80
|
)
|
|
@@ -97,7 +99,8 @@ class CriticalDatasetDeleteRule(LintRule):
|
|
|
97
99
|
if not patterns:
|
|
98
100
|
return
|
|
99
101
|
for step in iter_execution_steps(job.steps):
|
|
100
|
-
|
|
102
|
+
dds = _dataset_dds(step)
|
|
103
|
+
for dd in dds:
|
|
101
104
|
if not dd.dataset_name:
|
|
102
105
|
continue
|
|
103
106
|
upper = dd.dataset_name.upper()
|
|
@@ -156,7 +159,8 @@ class NewDatasetWithoutRlseRule(LintRule):
|
|
|
156
159
|
|
|
157
160
|
def check(self, job: Job, config: LintConfig) -> Iterable[ValidationError]:
|
|
158
161
|
for step in iter_execution_steps(job.steps):
|
|
159
|
-
|
|
162
|
+
dds = _dataset_dds(step)
|
|
163
|
+
for dd in dds:
|
|
160
164
|
dsn = dd.dataset_name
|
|
161
165
|
# A temporary dataset is deleted at the end of the job anyway.
|
|
162
166
|
if not dsn or dsn.startswith("&&"):
|
|
@@ -169,7 +173,7 @@ class NewDatasetWithoutRlseRule(LintRule):
|
|
|
169
173
|
if space is None or space.rlse:
|
|
170
174
|
continue
|
|
171
175
|
yield self._err(
|
|
172
|
-
f"DD '{dd
|
|
176
|
+
f"DD '{dd_label(dds, dd)}' in step '{step.name}' allocates new dataset "
|
|
173
177
|
f"'{dsn}' with SPACE but no RLSE",
|
|
174
178
|
line_number=dd.line_number,
|
|
175
179
|
config=config,
|
|
@@ -259,7 +263,8 @@ class LiteralSetValueHlqRule(LintRule):
|
|
|
259
263
|
if not symbols:
|
|
260
264
|
return
|
|
261
265
|
for step in iter_execution_steps(job.steps):
|
|
262
|
-
|
|
266
|
+
dds = _dataset_dds(step)
|
|
267
|
+
for dd in dds:
|
|
263
268
|
dsn = dd.dataset_name
|
|
264
269
|
# coded_dataset_name is set only when the name used symbols.
|
|
265
270
|
if not dsn or dd.coded_dataset_name is not None or "&" in dsn:
|
|
@@ -270,7 +275,7 @@ class LiteralSetValueHlqRule(LintRule):
|
|
|
270
275
|
if symbol is None:
|
|
271
276
|
continue
|
|
272
277
|
yield self._err(
|
|
273
|
-
f"DD '{dd
|
|
278
|
+
f"DD '{dd_label(dds, dd)}' in step '{step.name}' codes HLQ "
|
|
274
279
|
f"'{dsn.split('.', 1)[0]}' in '{dsn}' literally; "
|
|
275
280
|
f"SET symbol &{symbol} has that value",
|
|
276
281
|
line_number=dd.line_number,
|
|
@@ -1082,6 +1082,29 @@ def iter_execution_steps(steps: list[Step | ConditionalBlock]) -> Iterator[Step]
|
|
|
1082
1082
|
yield from iter_execution_steps(s.else_steps)
|
|
1083
1083
|
|
|
1084
1084
|
|
|
1085
|
+
def dd_label(dds: list[DDStatement], dd: DDStatement) -> str:
|
|
1086
|
+
"""*dd* as messages name it: ``IN``, or ``IN, concatenation member 2``
|
|
1087
|
+
for an unnamed concatenation member coded after ``//IN DD`` in *dds*
|
|
1088
|
+
(the named DD is member 1). The same label ``DatasetEvent.dd_label``
|
|
1089
|
+
gives. An unnamed DD with no named DD before it is ``(unnamed)``.
|
|
1090
|
+
"""
|
|
1091
|
+
if dd.name:
|
|
1092
|
+
return dd.name
|
|
1093
|
+
owner, member = "", 0
|
|
1094
|
+
for other in dds:
|
|
1095
|
+
if other.name:
|
|
1096
|
+
owner, member = other.name, 0
|
|
1097
|
+
elif owner:
|
|
1098
|
+
member = member + 1 if member else 2
|
|
1099
|
+
if other is dd:
|
|
1100
|
+
break
|
|
1101
|
+
else:
|
|
1102
|
+
return "(unnamed)"
|
|
1103
|
+
if not owner:
|
|
1104
|
+
return "(unnamed)"
|
|
1105
|
+
return f"{owner}, concatenation member {member}"
|
|
1106
|
+
|
|
1107
|
+
|
|
1085
1108
|
def _dataset_dds(step: Step) -> list[DDStatement]:
|
|
1086
1109
|
"""The DDs of *step* that can name a dataset, in source order.
|
|
1087
1110
|
|
|
@@ -15,6 +15,7 @@ from .model import (
|
|
|
15
15
|
Job,
|
|
16
16
|
Step,
|
|
17
17
|
_dataset_dds,
|
|
18
|
+
dd_label,
|
|
18
19
|
iter_execution_steps,
|
|
19
20
|
)
|
|
20
21
|
from .parameter_validators import DatasetNameValidator, DISPValidator
|
|
@@ -408,7 +409,7 @@ def validate_step_structure(step: Step) -> list[ValidationError]:
|
|
|
408
409
|
|
|
409
410
|
# Validate each DD statement
|
|
410
411
|
for dd in step.dd_statements:
|
|
411
|
-
errors.extend(validate_dd_statement(dd))
|
|
412
|
+
errors.extend(validate_dd_statement(dd, label=dd_label(step.dd_statements, dd)))
|
|
412
413
|
|
|
413
414
|
return errors
|
|
414
415
|
|
|
@@ -430,17 +431,25 @@ _TEMP_ALLOCATION_KEYS = (
|
|
|
430
431
|
)
|
|
431
432
|
|
|
432
433
|
|
|
433
|
-
def validate_dd_statement(
|
|
434
|
+
def validate_dd_statement(
|
|
435
|
+
dd: DDStatement, label: str | None = None
|
|
436
|
+
) -> list[ValidationError]:
|
|
434
437
|
"""
|
|
435
438
|
Validate DD statement structure and parameters.
|
|
436
439
|
|
|
437
440
|
Args:
|
|
438
441
|
dd: DDStatement object to validate
|
|
442
|
+
label: How messages name the DD (default ``dd.name``); the step
|
|
443
|
+
check passes ``model.dd_label`` so an unnamed concatenation
|
|
444
|
+
member reads ``IN, concatenation member 2``.
|
|
439
445
|
|
|
440
446
|
Returns:
|
|
441
447
|
List of validation errors
|
|
442
448
|
"""
|
|
443
449
|
errors = []
|
|
450
|
+
# How messages name the DD: *label* when the caller knows the DD's place
|
|
451
|
+
# in its step (``IN, concatenation member 2``, see ``model.dd_label``).
|
|
452
|
+
name = label if label is not None else dd.name
|
|
444
453
|
|
|
445
454
|
# DD name validation — empty names are valid for DD concatenation statements
|
|
446
455
|
if dd.name and not validate_jcl_identifier(dd.name):
|
|
@@ -470,7 +479,7 @@ def validate_dd_statement(dd: DDStatement) -> list[ValidationError]:
|
|
|
470
479
|
if dd.disposition and not validate_disposition(dd.disposition):
|
|
471
480
|
errors.append(
|
|
472
481
|
ValidationError(
|
|
473
|
-
f"Invalid DISP parameter '{dd.disposition}' on DD {
|
|
482
|
+
f"Invalid DISP parameter '{dd.disposition}' on DD {name}",
|
|
474
483
|
ErrorType.VALIDATION_ERROR,
|
|
475
484
|
line_number=dd.line_number,
|
|
476
485
|
)
|
|
@@ -500,7 +509,7 @@ def validate_dd_statement(dd: DDStatement) -> list[ValidationError]:
|
|
|
500
509
|
if conflict_count > 1:
|
|
501
510
|
errors.append(
|
|
502
511
|
ValidationError(
|
|
503
|
-
f"DD {
|
|
512
|
+
f"DD {name} has conflicting data source specifications",
|
|
504
513
|
ErrorType.VALIDATION_ERROR,
|
|
505
514
|
line_number=dd.line_number,
|
|
506
515
|
)
|
|
@@ -508,7 +517,7 @@ def validate_dd_statement(dd: DDStatement) -> list[ValidationError]:
|
|
|
508
517
|
elif source_count == 0:
|
|
509
518
|
errors.append(
|
|
510
519
|
ValidationError(
|
|
511
|
-
f"DD {
|
|
520
|
+
f"DD {name} must specify a data source (DSN, SYSOUT, DUMMY, or inline data)",
|
|
512
521
|
ErrorType.VALIDATION_ERROR,
|
|
513
522
|
line_number=dd.line_number,
|
|
514
523
|
)
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "jcl-parser"
|
|
7
|
-
version = "2.2.
|
|
7
|
+
version = "2.2.3"
|
|
8
8
|
description = "Parse IBM JCL (Job Control Language) scripts into Python objects"
|
|
9
9
|
authors = [
|
|
10
10
|
{name = "Samuel Dion", email = "sam94dion@gmail.com"}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|