j2py-converter 0.1.0a1__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.
Files changed (134) hide show
  1. j2py_converter-0.1.0a1/.gitignore +17 -0
  2. j2py_converter-0.1.0a1/CHANGELOG.md +132 -0
  3. j2py_converter-0.1.0a1/CONTRIBUTING.md +121 -0
  4. j2py_converter-0.1.0a1/LICENSE +21 -0
  5. j2py_converter-0.1.0a1/Makefile +81 -0
  6. j2py_converter-0.1.0a1/PKG-INFO +199 -0
  7. j2py_converter-0.1.0a1/README.md +158 -0
  8. j2py_converter-0.1.0a1/SECURITY.md +21 -0
  9. j2py_converter-0.1.0a1/docs/ARCHITECTURE.md +150 -0
  10. j2py_converter-0.1.0a1/docs/CORPUS_SCOREBOARD.md +147 -0
  11. j2py_converter-0.1.0a1/docs/PRD.md +81 -0
  12. j2py_converter-0.1.0a1/docs/RELEASING.md +42 -0
  13. j2py_converter-0.1.0a1/docs/TRANSLATION_TARGETS.md +68 -0
  14. j2py_converter-0.1.0a1/docs/decisions/0001-record-architecture-decisions.md +58 -0
  15. j2py_converter-0.1.0a1/docs/decisions/0002-tree-sitter-for-java-parsing.md +47 -0
  16. j2py_converter-0.1.0a1/docs/decisions/0003-layered-translation-pipeline.md +69 -0
  17. j2py_converter-0.1.0a1/docs/decisions/0004-claude-as-llm-backend.md +49 -0
  18. j2py_converter-0.1.0a1/docs/decisions/0005-python-311-target-with-type-hints.md +52 -0
  19. j2py_converter-0.1.0a1/docs/decisions/0006-overload-translation-policy.md +52 -0
  20. j2py_converter-0.1.0a1/docs/decisions/0007-type-declaration-translation.md +42 -0
  21. j2py_converter-0.1.0a1/docs/decisions/0008-expression-narrowing-and-bitwise-translation.md +66 -0
  22. j2py_converter-0.1.0a1/docs/decisions/0009-two-tier-overload-translation.md +107 -0
  23. j2py_converter-0.1.0a1/docs/decisions/0010-post-llm-structural-verification.md +47 -0
  24. j2py_converter-0.1.0a1/docs/decisions/0010-synchronized-this-translation.md +37 -0
  25. j2py_converter-0.1.0a1/j2py/__init__.py +3 -0
  26. j2py_converter-0.1.0a1/j2py/analyze/__init__.py +1 -0
  27. j2py_converter-0.1.0a1/j2py/analyze/graph.py +130 -0
  28. j2py_converter-0.1.0a1/j2py/analyze/symbols.py +264 -0
  29. j2py_converter-0.1.0a1/j2py/cli/__init__.py +1 -0
  30. j2py_converter-0.1.0a1/j2py/cli/main.py +437 -0
  31. j2py_converter-0.1.0a1/j2py/config/__init__.py +1 -0
  32. j2py_converter-0.1.0a1/j2py/config/default.py +159 -0
  33. j2py_converter-0.1.0a1/j2py/config/loader.py +88 -0
  34. j2py_converter-0.1.0a1/j2py/llm/__init__.py +1 -0
  35. j2py_converter-0.1.0a1/j2py/llm/client.py +141 -0
  36. j2py_converter-0.1.0a1/j2py/llm/prompts.py +84 -0
  37. j2py_converter-0.1.0a1/j2py/parse/__init__.py +1 -0
  38. j2py_converter-0.1.0a1/j2py/parse/java_ast.py +111 -0
  39. j2py_converter-0.1.0a1/j2py/pipeline.py +255 -0
  40. j2py_converter-0.1.0a1/j2py/translate/__init__.py +1 -0
  41. j2py_converter-0.1.0a1/j2py/translate/classes.py +1645 -0
  42. j2py_converter-0.1.0a1/j2py/translate/comments.py +41 -0
  43. j2py_converter-0.1.0a1/j2py/translate/diagnostics.py +127 -0
  44. j2py_converter-0.1.0a1/j2py/translate/expressions.py +1753 -0
  45. j2py_converter-0.1.0a1/j2py/translate/node_utils.py +23 -0
  46. j2py_converter-0.1.0a1/j2py/translate/rules/__init__.py +1 -0
  47. j2py_converter-0.1.0a1/j2py/translate/rules/literals.py +151 -0
  48. j2py_converter-0.1.0a1/j2py/translate/rules/naming.py +71 -0
  49. j2py_converter-0.1.0a1/j2py/translate/rules/types.py +138 -0
  50. j2py_converter-0.1.0a1/j2py/translate/runtime/__init__.py +21 -0
  51. j2py_converter-0.1.0a1/j2py/translate/runtime/j2py_runtime.py +221 -0
  52. j2py_converter-0.1.0a1/j2py/translate/skeleton.py +114 -0
  53. j2py_converter-0.1.0a1/j2py/translate/statements.py +920 -0
  54. j2py_converter-0.1.0a1/j2py/validate/__init__.py +1 -0
  55. j2py_converter-0.1.0a1/j2py/validate/checks.py +84 -0
  56. j2py_converter-0.1.0a1/j2py/verify/__init__.py +2 -0
  57. j2py_converter-0.1.0a1/j2py/verify/structure.py +114 -0
  58. j2py_converter-0.1.0a1/pyproject.toml +97 -0
  59. j2py_converter-0.1.0a1/tests/__init__.py +0 -0
  60. j2py_converter-0.1.0a1/tests/analyze/__init__.py +0 -0
  61. j2py_converter-0.1.0a1/tests/analyze/test_graph.py +128 -0
  62. j2py_converter-0.1.0a1/tests/analyze/test_symbols.py +116 -0
  63. j2py_converter-0.1.0a1/tests/behavior/__init__.py +1 -0
  64. j2py_converter-0.1.0a1/tests/behavior/test_equivalence.py +196 -0
  65. j2py_converter-0.1.0a1/tests/cli/test_main.py +539 -0
  66. j2py_converter-0.1.0a1/tests/config/test_loader.py +27 -0
  67. j2py_converter-0.1.0a1/tests/conftest.py +20 -0
  68. j2py_converter-0.1.0a1/tests/corpus/test_translate_spring_sample.py +236 -0
  69. j2py_converter-0.1.0a1/tests/fixtures/behavior/enhanced_for_list/Main.java +13 -0
  70. j2py_converter-0.1.0a1/tests/fixtures/behavior/fields_methods/Main.java +29 -0
  71. j2py_converter-0.1.0a1/tests/fixtures/behavior/hello_print/Main.java +5 -0
  72. j2py_converter-0.1.0a1/tests/fixtures/behavior/if_else_arithmetic/Main.java +15 -0
  73. j2py_converter-0.1.0a1/tests/fixtures/behavior/loops_sum/Main.java +14 -0
  74. j2py_converter-0.1.0a1/tests/fixtures/corpus/constructs/AdvancedEnum.java +42 -0
  75. j2py_converter-0.1.0a1/tests/fixtures/corpus/constructs/AdvancedStreams.java +47 -0
  76. j2py_converter-0.1.0a1/tests/fixtures/corpus/constructs/AnonymousAndInner.java +61 -0
  77. j2py_converter-0.1.0a1/tests/fixtures/corpus/constructs/ComplexRecords.java +35 -0
  78. j2py_converter-0.1.0a1/tests/fixtures/corpus/constructs/InterfaceDefaults.java +40 -0
  79. j2py_converter-0.1.0a1/tests/fixtures/corpus/constructs/README.md +50 -0
  80. j2py_converter-0.1.0a1/tests/fixtures/corpus/constructs/SealedClasses.java +36 -0
  81. j2py_converter-0.1.0a1/tests/fixtures/corpus/constructs/SuperMethodCalls.java +33 -0
  82. j2py_converter-0.1.0a1/tests/fixtures/corpus/constructs/SwitchFallthrough.java +43 -0
  83. j2py_converter-0.1.0a1/tests/fixtures/corpus/constructs/TextBlocks.java +40 -0
  84. j2py_converter-0.1.0a1/tests/fixtures/corpus/constructs/VarKeyword.java +34 -0
  85. j2py_converter-0.1.0a1/tests/fixtures/corpus/spring-dense-baseline.json +1362 -0
  86. j2py_converter-0.1.0a1/tests/fixtures/corpus/spring-sample-baseline.json +1442 -0
  87. j2py_converter-0.1.0a1/tests/fixtures/java/Fields.java +17 -0
  88. j2py_converter-0.1.0a1/tests/fixtures/java/HelloWorld.java +36 -0
  89. j2py_converter-0.1.0a1/tests/fixtures/java/PartialUnsupported.java +8 -0
  90. j2py_converter-0.1.0a1/tests/fixtures/java/targets/ArrayCreation.java +8 -0
  91. j2py_converter-0.1.0a1/tests/fixtures/java/targets/BitwiseOperators.java +16 -0
  92. j2py_converter-0.1.0a1/tests/fixtures/java/targets/CastExpression.java +8 -0
  93. j2py_converter-0.1.0a1/tests/fixtures/java/targets/CommentsAnnotations.java +13 -0
  94. j2py_converter-0.1.0a1/tests/fixtures/java/targets/CompoundAssignment.java +10 -0
  95. j2py_converter-0.1.0a1/tests/fixtures/java/targets/ControlFlow.java +32 -0
  96. j2py_converter-0.1.0a1/tests/fixtures/java/targets/Exceptions.java +18 -0
  97. j2py_converter-0.1.0a1/tests/fixtures/java/targets/Expressions.java +13 -0
  98. j2py_converter-0.1.0a1/tests/fixtures/java/targets/Functional.java +14 -0
  99. j2py_converter-0.1.0a1/tests/fixtures/java/targets/InstanceofExpression.java +11 -0
  100. j2py_converter-0.1.0a1/tests/fixtures/java/targets/NestedTypes.java +61 -0
  101. j2py_converter-0.1.0a1/tests/fixtures/java/targets/OverloadChains.java +36 -0
  102. j2py_converter-0.1.0a1/tests/fixtures/java/targets/OverloadDispatch.java +41 -0
  103. j2py_converter-0.1.0a1/tests/fixtures/java/targets/Overloads.java +22 -0
  104. j2py_converter-0.1.0a1/tests/fixtures/java/targets/StaticAndSynchronized.java +14 -0
  105. j2py_converter-0.1.0a1/tests/fixtures/java/targets/TryWithResources.java +12 -0
  106. j2py_converter-0.1.0a1/tests/fixtures/python/Fields.py +13 -0
  107. j2py_converter-0.1.0a1/tests/fixtures/python/HelloWorld.py +25 -0
  108. j2py_converter-0.1.0a1/tests/llm/__init__.py +0 -0
  109. j2py_converter-0.1.0a1/tests/llm/test_client.py +194 -0
  110. j2py_converter-0.1.0a1/tests/llm/test_e2e_llm.py +136 -0
  111. j2py_converter-0.1.0a1/tests/llm/test_prompts.py +41 -0
  112. j2py_converter-0.1.0a1/tests/parse/__init__.py +0 -0
  113. j2py_converter-0.1.0a1/tests/parse/test_java_ast.py +36 -0
  114. j2py_converter-0.1.0a1/tests/targets/test_translation_targets.py +143 -0
  115. j2py_converter-0.1.0a1/tests/test_pipeline.py +460 -0
  116. j2py_converter-0.1.0a1/tests/translate/__init__.py +0 -0
  117. j2py_converter-0.1.0a1/tests/translate/skeleton/__init__.py +1 -0
  118. j2py_converter-0.1.0a1/tests/translate/skeleton/helpers.py +26 -0
  119. j2py_converter-0.1.0a1/tests/translate/skeleton/test_config.py +67 -0
  120. j2py_converter-0.1.0a1/tests/translate/skeleton/test_control_flow.py +577 -0
  121. j2py_converter-0.1.0a1/tests/translate/skeleton/test_expressions.py +843 -0
  122. j2py_converter-0.1.0a1/tests/translate/skeleton/test_fields_enums.py +319 -0
  123. j2py_converter-0.1.0a1/tests/translate/skeleton/test_fixtures.py +340 -0
  124. j2py_converter-0.1.0a1/tests/translate/skeleton/test_misc.py +98 -0
  125. j2py_converter-0.1.0a1/tests/translate/skeleton/test_overloads.py +150 -0
  126. j2py_converter-0.1.0a1/tests/translate/skeleton/test_streams.py +421 -0
  127. j2py_converter-0.1.0a1/tests/translate/test_diagnostics.py +18 -0
  128. j2py_converter-0.1.0a1/tests/translate/test_literals.py +34 -0
  129. j2py_converter-0.1.0a1/tests/translate/test_naming.py +38 -0
  130. j2py_converter-0.1.0a1/tests/translate/test_runtime_dispatch.py +175 -0
  131. j2py_converter-0.1.0a1/tests/translate/test_types.py +54 -0
  132. j2py_converter-0.1.0a1/tests/validate/__init__.py +0 -0
  133. j2py_converter-0.1.0a1/tests/validate/test_checks.py +43 -0
  134. j2py_converter-0.1.0a1/tests/verify/test_structure.py +87 -0
@@ -0,0 +1,17 @@
1
+ .venv/
2
+ .env
3
+ __pycache__/
4
+ *.pyc
5
+ *.pyo
6
+ .pytest_cache/
7
+ .mypy_cache/
8
+ .ruff_cache/
9
+ .coverage
10
+ dist/
11
+ *.egg-info/
12
+ .eggs/
13
+ build/
14
+ *.so
15
+ .DS_Store
16
+ .corpus/
17
+ corpus-reports/
@@ -0,0 +1,132 @@
1
+ # Changelog
2
+
3
+ All notable changes to j2py will be documented in this file.
4
+
5
+ The format follows the repository commit types: `feat`, `fix`, `refactor`, `test`,
6
+ `docs`, `chore`, and `adr`.
7
+
8
+ ## Unreleased
9
+
10
+ No changes yet.
11
+
12
+ ## 0.1.0a1 - 2026-06-11
13
+
14
+ ### Added
15
+ - GitHub Actions corpus workflow (`.github/workflows/corpus.yml`) comparing the pinned
16
+ Spring sample against the committed baseline on translation/corpus path changes.
17
+ - `j2py analyze` dependency graph and translation-order output for file and directory modes.
18
+ - Skeleton translator tests split under `tests/translate/skeleton/` by concern (#69).
19
+ - ADR 0010: `synchronized(this)` translates to `self._j2py_lock` with `threading.Lock()`
20
+ initialization in constructors or synthetic `__init__`.
21
+ - Preferred dense Spring + curated-construct corpus baseline workflow:
22
+ `corpus-spring-dense-check`, `corpus-spring-dense-update-baseline`, and
23
+ `tests/fixtures/corpus/spring-dense-baseline.json`.
24
+ - Future corpus target for `super.method(...)` receiver calls identified by the dense
25
+ Spring corpus.
26
+ - Shared `tests/conftest.py` with session `cfg` fixture and fixture path constants.
27
+ - `TranslationDiagnostics.semantic_warning_count` and `rule_coverage` alias documenting
28
+ that warnings do not reduce node coverage.
29
+ - Strict xfail `FUTURE_TARGETS` for two corpus constructs still below full rule coverage
30
+ (`AdvancedStreams`, `SuperMethodCalls`).
31
+ - Graduated corpus construct regression tests in `make check` for eight constructs that
32
+ reach full skeleton coverage (`AdvancedEnum`, `ComplexRecords`, `InterfaceDefaults`,
33
+ `SealedClasses`, `TextBlocks`, `VarKeyword`, `SwitchFallthrough`, `AnonymousAndInner`).
34
+ - Record declarations (`record_declaration`) in the symbol table: component fields,
35
+ body methods, inner records, and `is_record` on `ClassSymbol`.
36
+ - `TranslationResult.parse_ok` and `PARSE_ERROR_LLM_SKIP_MSG`: malformed Java with
37
+ tree-sitter `ERROR`/`MISSING` nodes skips LLM completion and reports `confidence=0.0`.
38
+
39
+ ### Changed
40
+ - Anonymous class instance fields translate to helper-class `__init__` assignments with
41
+ `self.` field access in methods (#74).
42
+ - Switch fall-through translates to reviewable prefix `elif`/`if` chains with explicit
43
+ default guards (`elif subject not in (...)` after fall-through blocks) (#73).
44
+ - Local `var` declarations infer Python types from initializers; enhanced-for `var` binds
45
+ element types from iterable annotations (#72).
46
+ - Prepared the first MIT-licensed PyPI alpha release as distribution `j2py-converter`
47
+ with import package and CLI name `j2py`.
48
+ - README known gaps refreshed to match graduated targets/corpus constructs and remaining
49
+ `FUTURE_TARGETS` xfail items (#69).
50
+ - Non-`this` synchronized blocks keep `with <expr>:` but warn that lock semantics need review.
51
+ - LLM system prompt aligned with the `_j2py_lock` instance-monitor pattern.
52
+ - Dependency graph resolves simple type names only when unambiguous; ambiguous `User`-style
53
+ collisions no longer pick an arbitrary file.
54
+ - `j2py analyze` prints class inventory plus dependency graph and translation order (#69).
55
+ - `TranslationResult.confidence` documented as rule-layer coverage (unchanged after LLM).
56
+ - Agent docs (`AGENTS.md`, `CLAUDE.md`) updated for graduated vs xfail test tiers.
57
+ - Graduated target fixtures (`tests/fixtures/java/targets/`) now run in `make check` and
58
+ CI; `make test-targets` is reserved for strict `xfail` entries in `FUTURE_TARGETS`.
59
+ - CLI `analyze` reports record types, nested declarations, and parse-error status.
60
+ - CLI translate summaries surface `parse_ok=False` and parse-error warnings.
61
+ - Directory translation aggregates per-file parse-error warnings in `batch.warnings`.
62
+
63
+ ### Added
64
+ - Two-tier overload translation (ADR 0009, issue #44): chained `this(...)`
65
+ constructor delegation and builder-style forwarding method overloads now merge
66
+ into default parameters (immutable literals inline; constructed values become
67
+ `None` sentinels with normalization lines). Overload groups that genuinely
68
+ dispatch on parameter types emit each Java overload as a same-named def behind
69
+ a vendored `@overloaded` runtime dispatcher (`j2py_runtime.py`, stdlib-only,
70
+ written next to translated output by the CLI). The manual-dispatch
71
+ `NotImplementedError` fallback now only remains for static overload groups and
72
+ erased-signature collisions (e.g. `int` vs `long`).
73
+ - Java varargs parameters (`Type... name`) now translate to `*name: Type` in
74
+ method signatures instead of being dropped.
75
+ - Deterministic translation for `instanceof` expressions, `instanceof` pattern
76
+ variable bindings, cast expressions with review warnings, and bitwise/shift
77
+ operators including compound bitwise assignment.
78
+ - Block lambdas (`x -> { statements; return v; }`) are now supported deterministically. They are turned into a local nested helper (`_j2py_lambda_N`) emitted near the top of the enclosing method; the helper name is used at the call site. The block body structure is preserved for reviewability.
79
+ - Complex stream pipelines/collectors: extended deterministic support for toSet, basic joining, .distinct(), .sorted() (simple or with key via method ref), and basic groupingBy (via emitted accumulation helpers using defaultdict). Builds on prior block lambda work; many cases now rewrite to clean comps or stdlib helpers (per review feedback favoring itertools/functools where used).
80
+
81
+ ### Fixed
82
+ - Constructor overload merging no longer emits invalid self-referential defaults
83
+ (`name: str = name`) or raw Java generic types in annotations when a delegating
84
+ constructor passes its own parameters through alongside constructed values; the
85
+ pass-through prefix rule in ADR 0009 rejects or correctly composes these.
86
+ - `_stream_item_name`: improved plural stripping with explicit map for common cases ("statuses"→"status", "types"→"type", "classes"→"class" etc.) to avoid "statu"/"addres"/"typ" etc. in stream listcomps.
87
+ - Integer division (`int / int`): now uses `diagnostics.warn()` (visible for review) instead of `record(supported=False)`. Correct `//` output no longer forces LLM or lowers coverage.
88
+ - Lambda/alias context in expressions: added `try/finally` around mutable `TranslationContext` updates (`local_names`, `variable_types`, `expression_aliases`) so exceptions during body translation cannot leak state to callers.
89
+ - Overload merge paths: no longer downgrade `class_field_types` to all `"object"`. Real field types (including collections) are now preserved in the shared implementation body, enabling correct specializations (e.g. list `get`).
90
+ - Removed misleading claim that the `switch_expression` dispatch in `translate_statement` was dead; kept it (with expanded comment) because tree-sitter-java uses the same node type for traditional colon switch *statements*. Added clarifying comments + tests.
91
+
92
+ ### Added (historical)
93
+
94
+ - Initial deterministic skeleton translator for simple Java classes.
95
+ - Structured rule-layer diagnostics and coverage reporting.
96
+ - Spring corpus scoreboard with a pinned baseline.
97
+ - Roadmap target tests for unsupported Java-to-Python constructs.
98
+ - Dependency-ordered directory translation with package-relative output paths.
99
+ - Config-driven import emission, type maps, collection maps, exception maps, and
100
+ translation flags.
101
+ - Deterministic translation for common control flow, exception handling, comments,
102
+ nested type declarations, overload stubs, constructor delegation, and common
103
+ expression shapes.
104
+ - Deterministic translation for standalone expression lambdas and basic method
105
+ references, with block lambdas kept as explicit unresolved regions.
106
+ - Deterministic translation for safe traditional switch cases and switch expressions,
107
+ with fall-through and complex switch blocks left as diagnostics.
108
+ - Deterministic translation for simple stream `map`/`filter`/`toList` pipelines when
109
+ mapper and predicate expressions are supported.
110
+ - LLM prompt context for project symbols, rule diagnostics, config fingerprints, and
111
+ validation feedback.
112
+ - On-demand LLM exploration helper for manually inspecting the tree-sitter skeleton,
113
+ diagnostics, final LLM output, and validation results outside the normal test suite.
114
+
115
+ ### Changed
116
+
117
+ - Clarified the target-test workflow: current roadmap fixtures now run as graduated
118
+ deterministic regression checks, while future unsupported targets remain strict xfails.
119
+ - Split skeleton translation into class, statement, expression, diagnostic, and node helper
120
+ modules.
121
+ - Updated contributor and architecture docs to describe the implemented deterministic
122
+ visitor layer and the remaining unsupported constructs.
123
+ - Generalized CLI help text for configured LLM usage without changing the Anthropic
124
+ backend contract.
125
+
126
+ ### Fixed
127
+
128
+ - Preserved Java `Map.get` missing-key semantics, translated `.equals(...)`, and made
129
+ integer division and ambiguous `get` calls honest through diagnostics.
130
+ - Preserved Java left-to-right evaluation for string concatenation with leading numeric
131
+ operands.
132
+ - Removed tracked `.pyc` and `__pycache__` files from version control.
@@ -0,0 +1,121 @@
1
+ # Contributing to j2py
2
+
3
+ ## Setup
4
+
5
+ ```bash
6
+ git clone git@github.com:tomanizer/j2py.git
7
+ cd j2py
8
+ uv sync --locked
9
+ ```
10
+
11
+ Python 3.11 required. `uv` manages the virtualenv automatically.
12
+
13
+ ## Workflow
14
+
15
+ 1. **Branch from `main`**: `git checkout -b feat/my-feature`
16
+ 2. **Run checks before committing**: `make check` (lint + typecheck + test)
17
+ 3. **Run `make ci-local-pr`** before pushing — this is what CI runs
18
+ 4. **Open a PR** using the template — fill every section
19
+
20
+ ### Commit style
21
+
22
+ ```
23
+ <type>: <short imperative summary>
24
+
25
+ <optional body — why, not what>
26
+ ```
27
+
28
+ Types: `feat` · `fix` · `refactor` · `test` · `docs` · `chore` · `adr`
29
+
30
+ Examples:
31
+ ```
32
+ feat: translate enhanced for-loops to Python for comprehensions
33
+ fix: preserve Optional<T> in nested generic types
34
+ adr: document choice of tree-sitter over javalang (ADR 0002)
35
+ ```
36
+
37
+ ## Adding a translation rule
38
+
39
+ Every new Java construct translation needs:
40
+
41
+ 1. **Java fixture** — `tests/fixtures/java/<Feature>.java`
42
+ 2. **Expected Python fixture** — `tests/fixtures/python/<Feature>.py`
43
+ 3. **Test** — parametrised entry in `tests/translate/` (or a new test file)
44
+ 4. **Implementation** — rule in `j2py/translate/rules/` or `skeleton.py`
45
+
46
+ The fixture pair is the contract. CI runs exact fixture equality tests in `make check`.
47
+
48
+ For unsupported but planned Java constructs, add or update a roadmap target test first.
49
+ Graduated target tests live under `tests/targets/` and run in `make check`. Future
50
+ `xfail` roadmap contracts use the `target_translation` marker and run with:
51
+
52
+ ```bash
53
+ make test-targets
54
+ ```
55
+
56
+ Once a target is supported, remove it from `FUTURE_TARGETS` so it runs in the graduated
57
+ target check, or move the behavior into the normal fixture suite. See
58
+ [Translation Target Tests](docs/TRANSLATION_TARGETS.md) for the target-test workflow and
59
+ graduation rules.
60
+
61
+ For real-corpus progress checks, run the preferred dense Spring + curated-construct
62
+ scoreboard:
63
+
64
+ ```bash
65
+ make corpus-spring-dense-check
66
+ ```
67
+
68
+ See [Spring Corpus Scoreboard](docs/CORPUS_SCOREBOARD.md) for the preferred dense
69
+ baseline, historical lexical baseline, comparison mode, and intentional baseline refresh
70
+ workflow.
71
+
72
+ ## Material changes
73
+
74
+ A **material change** is any of:
75
+ - Changing how a Java construct is translated (different Python idiom)
76
+ - Adding a new pipeline stage
77
+ - Changing the LLM model or prompt structure
78
+ - Changing the Python output version target
79
+ - Breaking the `translate_file()` public API
80
+
81
+ Material changes require:
82
+ 1. A new ADR in `docs/decisions/` ([template](docs/decisions/0001-record-architecture-decisions.md))
83
+ 2. Updated `docs/ARCHITECTURE.md` if the pipeline shape changes
84
+ 3. Explicit note in the PR body linking the ADR
85
+ 4. A `CHANGELOG.md` entry when the change affects user-visible behavior or project
86
+ workflow
87
+
88
+ ## PR rules
89
+
90
+ - One concern per PR — translation rules, refactor, or docs; not all three
91
+ - `Closes #N` in the PR body to auto-close issues (checkboxes in the issue do **not** close it)
92
+ - `make ci-local-pr` must pass before requesting review
93
+ - No version bumps on feature PRs — version is bumped in a dedicated release PR
94
+
95
+ ## Release
96
+
97
+ Alpha releases are published to PyPI as the `j2py-converter` distribution. The import
98
+ package and console script remain `j2py`; the `j2py` PyPI project name is already owned
99
+ by an unrelated project.
100
+
101
+ Releases are tagged `vX.Y.Z` on `main`; pre-releases use PEP 440 suffixes such as
102
+ `v0.1.0a1`. Versioning follows [SemVer](https://semver.org/) for stable releases:
103
+
104
+ - `MAJOR` — breaking change to `translate_file()` API or output format
105
+ - `MINOR` — new Java construct support, new CLI flag
106
+ - `PATCH` — bug fix, doc fix, test improvement
107
+
108
+ Update `CHANGELOG.md`, `pyproject.toml`, and `j2py/__init__.py` in the release PR.
109
+ Feature and fix PRs should add notes under `## Unreleased`; the release PR moves those
110
+ notes under the tagged version.
111
+
112
+ Before publishing:
113
+
114
+ ```bash
115
+ make release-check
116
+ ```
117
+
118
+ The release workflow builds the wheel/sdist and publishes through PyPI trusted
119
+ publishing when a GitHub release is published. PyPI trusted publishing is configured for
120
+ repository `tomanizer/j2py`, workflow `.github/workflows/publish.yml`, environment
121
+ `pypi`, and project `j2py-converter`.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Thomas Haederle
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,81 @@
1
+ .PHONY: check lint format typecheck test test-behavior test-targets test-llm-e2e test-cov corpus-spring corpus-spring-smoke corpus-spring-update-baseline corpus-spring-dense corpus-spring-dense-check corpus-spring-dense-update-baseline corpus-spring-broad clean ci-local-pr ci-local-governance build dist-check release-check
2
+
3
+ SPRING_DENSE_BASELINE := tests/fixtures/corpus/spring-dense-baseline.json
4
+ SPRING_DENSE_ARGS := --strategy density --max-loc 250 --min-constructs 5 --include-constructs --baseline $(SPRING_DENSE_BASELINE)
5
+
6
+ # ── Primary targets ──────────────────────────────────────────────────────────
7
+
8
+ check: lint typecheck test ## Run all checks (alias for ci-local-pr)
9
+
10
+ lint: ## Lint with ruff
11
+ uv run --extra dev ruff check j2py/ tests/
12
+
13
+ format: ## Format with ruff
14
+ uv run --extra dev ruff format j2py/ tests/
15
+
16
+ typecheck: ## Type-check with mypy (strict)
17
+ uv run --extra dev mypy j2py/
18
+
19
+ test: ## Run test suite
20
+ uv run --extra dev pytest -m "not behavior and not live_llm"
21
+
22
+ test-behavior: ## Run Java/Python behavior-equivalence tests (requires a local JDK)
23
+ uv run --extra dev pytest tests/behavior -m behavior
24
+
25
+ test-targets: ## Run future Java-to-Python roadmap xfail targets only
26
+ uv run --extra dev pytest tests/targets -m target_translation -rxXs
27
+
28
+ test-llm-e2e: ## Run the on-demand live-LLM exploratory test (requires ANTHROPIC_API_KEY)
29
+ @echo "Running live LLM exploratory test. This is excluded from normal make check."
30
+ uv run --extra dev pytest -m live_llm tests/llm/test_e2e_llm.py -v -s
31
+
32
+ test-cov: ## Run tests with coverage report
33
+ uv run --extra dev pytest --cov=j2py --cov-report=term-missing --cov-report=xml
34
+
35
+ corpus-spring: ## Compare the Spring corpus sample against the committed baseline
36
+ uv run python scripts/corpus/translate_spring_sample.py --compare-baseline
37
+
38
+ corpus-spring-smoke: ## Run a quick 25-file Spring corpus smoke sample without baseline comparison
39
+ uv run python scripts/corpus/translate_spring_sample.py --limit 25
40
+
41
+ corpus-spring-update-baseline: ## Regenerate the committed Spring corpus baseline intentionally
42
+ uv run python scripts/corpus/translate_spring_sample.py --update-baseline --compare-baseline
43
+
44
+ corpus-spring-dense: ## Run the preferred dense Spring + curated-construct corpus without comparing the baseline
45
+ uv run python scripts/corpus/translate_spring_sample.py $(SPRING_DENSE_ARGS)
46
+
47
+ corpus-spring-dense-check: ## Compare the preferred dense Spring + curated-construct corpus against its baseline
48
+ uv run python scripts/corpus/translate_spring_sample.py $(SPRING_DENSE_ARGS) --compare-baseline --fail-on-regression
49
+
50
+ corpus-spring-dense-update-baseline: ## Regenerate the preferred dense Spring + curated-construct corpus baseline intentionally
51
+ uv run python scripts/corpus/translate_spring_sample.py $(SPRING_DENSE_ARGS) --update-baseline
52
+
53
+ corpus-spring-broad: ## Broader + more extensive sample (more modules + curated construct files for the new roadmap items)
54
+ # Note: does not compare to the default baseline (different sampling parameters)
55
+ uv run python scripts/corpus/translate_spring_sample.py \
56
+ --module spring-context/src/main/java \
57
+ --include-constructs \
58
+ --limit 150 \
59
+ --strategy density
60
+
61
+ # ── CI local presets ─────────────────────────────────────────────────────────
62
+ # These mirror exactly what GitHub Actions runs. If make ci-local-pr passes,
63
+ # CI will pass.
64
+
65
+ ci-local-pr: check ## For code/test/docs PRs — lint + typecheck + test
66
+
67
+ ci-local-governance: check ## For CI/tooling/dependency PRs — same gates, explicit label
68
+
69
+ # ── Utility ──────────────────────────────────────────────────────────────────
70
+
71
+ clean: ## Remove build artifacts and caches
72
+ rm -rf dist/ .mypy_cache/ .ruff_cache/ .pytest_cache/ htmlcov/ .coverage coverage.xml corpus-reports/
73
+ find . -type d -name __pycache__ -not -path './.venv/*' -exec rm -rf {} +
74
+
75
+ build: ## Build wheel and sdist
76
+ uv build
77
+
78
+ dist-check: build ## Validate built distributions with twine
79
+ uv run --extra dev twine check dist/*
80
+
81
+ release-check: check test-targets test-behavior dist-check ## Run alpha release readiness checks
@@ -0,0 +1,199 @@
1
+ Metadata-Version: 2.4
2
+ Name: j2py-converter
3
+ Version: 0.1.0a1
4
+ Summary: Java to Python source converter with line-level semantic equivalence
5
+ Project-URL: Homepage, https://github.com/tomanizer/j2py
6
+ Project-URL: Repository, https://github.com/tomanizer/j2py
7
+ Project-URL: Issues, https://github.com/tomanizer/j2py/issues
8
+ Project-URL: Changelog, https://github.com/tomanizer/j2py/blob/main/CHANGELOG.md
9
+ Author-email: Thomas Haederle <thomas.haederle@gmail.com>
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: java,python,source-conversion,translation,tree-sitter
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Environment :: Console
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Programming Language :: Java
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Topic :: Software Development :: Code Generators
22
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
23
+ Requires-Python: >=3.11
24
+ Requires-Dist: anthropic>=0.30
25
+ Requires-Dist: diskcache>=5.6
26
+ Requires-Dist: networkx>=3.3
27
+ Requires-Dist: pydantic>=2.7
28
+ Requires-Dist: rich>=13.7
29
+ Requires-Dist: tenacity>=8.3
30
+ Requires-Dist: tree-sitter-java>=0.23
31
+ Requires-Dist: tree-sitter>=0.23
32
+ Requires-Dist: typer>=0.12
33
+ Provides-Extra: dev
34
+ Requires-Dist: mypy>=1.10; extra == 'dev'
35
+ Requires-Dist: pytest-cov>=5.0; extra == 'dev'
36
+ Requires-Dist: pytest-snapshot>=0.9; extra == 'dev'
37
+ Requires-Dist: pytest>=8.2; extra == 'dev'
38
+ Requires-Dist: ruff>=0.4; extra == 'dev'
39
+ Requires-Dist: twine>=5.0; extra == 'dev'
40
+ Description-Content-Type: text/markdown
41
+
42
+ # j2py
43
+
44
+ j2py converts Java source to reviewable Python with line-level structural
45
+ correspondence. The goal is not a fully idiomatic rewrite; the goal is Python that a
46
+ reviewer can compare against the original Java side by side.
47
+
48
+ ## Current Status
49
+
50
+ j2py is a rule-development and measurement harness for Java-to-Python translation. It is
51
+ not yet a production Spring porting tool.
52
+
53
+ Current deterministic rule support includes:
54
+
55
+ - tree-sitter Java parsing and symbol extraction
56
+ - class, nested class, basic local/anonymous class helpers, interface,
57
+ basic and constructor-backed enum, and record skeletons
58
+ - interface abstract methods, default methods, and static methods
59
+ - fields, constructors, methods, and overloads: chained constructor delegation and
60
+ builder-style forwarding merge into default parameters; type-dispatch overload
61
+ groups emit same-named defs behind a vendored `@overloaded` runtime dispatcher
62
+ (ADR 0009)
63
+ - common expressions: literals, identifiers, field access, arrays, class literals,
64
+ assignments, updates, ternaries, null checks, common collection calls, and string concat
65
+ - common stream pipelines: `map`, `filter`, `distinct`, `sorted`, simple collectors
66
+ such as `toList`, `toSet`, `joining`, basic `groupingBy`/`toMap`, and supported
67
+ block lambdas
68
+ - control flow: `if`/`else`, enhanced and classic `for`, `while`, `do while`,
69
+ safe `switch` forms, `try`/`catch`/`finally`, `throw`, `break`, and `continue`
70
+ - configured import emission, naming policy, type maps, exception maps, and comment flags
71
+ - dependency-ordered directory translation
72
+ - structured diagnostics, confidence, default validation, post-LLM structural
73
+ verification, and optional Anthropic completion for partial translations
74
+ - side-by-side Java/Python review through the `j2py compare` CLI command
75
+
76
+ Known gaps include:
77
+
78
+ - two corpus constructs still tracked as strict xfail targets: advanced stream collectors
79
+ and long chains (`AdvancedStreams`), and `super.method(...)` receiver calls
80
+ (`SuperMethodCalls`)
81
+ - overload groups whose erased Python signatures collide (e.g. `int` vs `long`)
82
+ and static-method overload groups still fall back to manual-dispatch TODOs
83
+ - enum constant class bodies, complex enum static initialization, and annotation semantics
84
+ - behavioral equivalence testing between Java and Python
85
+ - framework semantics such as Spring dependency injection or Hibernate mappings
86
+
87
+ Graduated in `make check` (no longer listed as gaps): common switch forms, interface
88
+ defaults/statics, text blocks, sealed classes, records, instance `synchronized(this)`,
89
+ local `var` inference, switch fall-through, and anonymous class instance fields.
90
+
91
+ ## Quick Start
92
+
93
+ Install the alpha from PyPI:
94
+
95
+ ```bash
96
+ pip install --pre j2py-converter
97
+ j2py --help
98
+ ```
99
+
100
+ The PyPI distribution is `j2py-converter`; the import package and console command remain
101
+ `j2py`.
102
+
103
+ For local development:
104
+
105
+ ```bash
106
+ uv sync --locked
107
+ make check
108
+ ```
109
+
110
+ Translate a fixture without LLM completion:
111
+
112
+ ```bash
113
+ uv run j2py translate tests/fixtures/java/HelloWorld.java --no-llm --no-validate --dry-run
114
+ ```
115
+
116
+ Translate a directory in dependency order:
117
+
118
+ ```bash
119
+ uv run j2py translate path/to/java/root --output translated_py --no-llm
120
+ ```
121
+
122
+ Open a side-by-side Java/Python diff in VS Code, generating the Python file first if
123
+ needed:
124
+
125
+ ```bash
126
+ uv run j2py compare tests/fixtures/java/HelloWorld.java --no-llm
127
+ ```
128
+
129
+ Print the compare paths without opening an editor:
130
+
131
+ ```bash
132
+ uv run j2py compare tests/fixtures/java/HelloWorld.java --no-open --no-llm
133
+ ```
134
+
135
+ Use LLM completion only when `ANTHROPIC_API_KEY` is set:
136
+
137
+ ```bash
138
+ ANTHROPIC_API_KEY=... uv run j2py translate SomeClass.java
139
+ ```
140
+
141
+ ## Quality Gates
142
+
143
+ ```bash
144
+ make check # ruff + mypy strict + normal pytest suite (excludes behavior, live_llm)
145
+ make test-behavior # Java/Python stdout/stderr/exit-code equivalence tests (requires a JDK)
146
+ make test-targets # future xfail roadmap targets only (graduated targets run in make check)
147
+ make release-check # alpha release gate: check + targets + behavior + distribution check
148
+ make corpus-spring-dense-check # preferred Spring + curated-construct corpus comparison
149
+ make corpus-spring # historical lexical Spring-only corpus comparison
150
+
151
+ # Corpus modes:
152
+ make corpus-spring-dense # preferred density-based Spring + curated-construct sample
153
+ make corpus-spring-broad # extra modules + curated constructs/ mini-corpus
154
+
155
+ # On-demand only (requires ANTHROPIC_API_KEY):
156
+ make test-llm-e2e # exploratory live-LLM test of current skeleton quality
157
+ # or: ANTHROPIC_API_KEY=... uv run pytest -m live_llm tests/llm/test_e2e_llm.py -v -s
158
+ ```
159
+
160
+ The preferred dense corpus baseline includes Spring files plus curated non-Spring
161
+ construct fixtures and is stored at `tests/fixtures/corpus/spring-dense-baseline.json`.
162
+
163
+ The historical lexical Spring-only baseline is:
164
+
165
+ - parse success: 100.00%
166
+ - generated Python syntax success: 93.00%
167
+ - average skeleton coverage: 94.71% across 92 coverage-bearing files
168
+ - full-coverage files: 65 of 92 coverage-bearing files
169
+ - files with unhandled constructs: 27 of 100
170
+ - files below 80% coverage: 4 of 92 coverage-bearing files
171
+ - sample size: 100 files with committed per-file failure metrics
172
+
173
+ See [docs/CORPUS_SCOREBOARD.md](docs/CORPUS_SCOREBOARD.md) and
174
+ [docs/TRANSLATION_TARGETS.md](docs/TRANSLATION_TARGETS.md) for the implementation
175
+ workflow.
176
+
177
+ ## Adding Translation Support
178
+
179
+ 1. Add or update a target fixture if the construct is not yet supported.
180
+ 2. Implement the smallest deterministic rule in `j2py/translate/`.
181
+ 3. Graduate the behavior into normal tests once it passes.
182
+ 4. Run `make check`, `make test-targets`, and `make corpus-spring-dense-check`.
183
+ 5. Update the dense corpus baseline only when the comparison has no regressions.
184
+
185
+ Material translation policy changes should get an ADR under `docs/decisions/`.
186
+
187
+ ## Alpha Release Notes
188
+
189
+ `j2py-converter` is published as an alpha package. Expect incomplete Java construct
190
+ coverage, diagnostics for unsupported regions, and non-production behavior on large
191
+ framework-heavy codebases. The existing `j2py` PyPI name is owned by an unrelated
192
+ Jupyter notebook converter, so this project uses the distinct distribution name
193
+ `j2py-converter`.
194
+
195
+ See [docs/RELEASING.md](docs/RELEASING.md) for the alpha release checklist.
196
+
197
+ ## License
198
+
199
+ MIT. See [LICENSE](LICENSE).