jopy 0.1.0__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 (61) hide show
  1. jopy-0.1.0/LICENSE +21 -0
  2. jopy-0.1.0/PKG-INFO +275 -0
  3. jopy-0.1.0/README.md +250 -0
  4. jopy-0.1.0/jopy/__init__.py +167 -0
  5. jopy-0.1.0/jopy/__main__.py +10 -0
  6. jopy-0.1.0/jopy/api.py +570 -0
  7. jopy-0.1.0/jopy/ast_nodes.py +542 -0
  8. jopy-0.1.0/jopy/cli.py +555 -0
  9. jopy-0.1.0/jopy/codegen/__init__.py +74 -0
  10. jopy-0.1.0/jopy/codegen/classes.py +846 -0
  11. jopy-0.1.0/jopy/codegen/collections.py +338 -0
  12. jopy-0.1.0/jopy/codegen/core.py +571 -0
  13. jopy-0.1.0/jopy/codegen/expressions.py +1447 -0
  14. jopy-0.1.0/jopy/codegen/functions.py +839 -0
  15. jopy-0.1.0/jopy/codegen/module.py +478 -0
  16. jopy-0.1.0/jopy/codegen/patterns.py +277 -0
  17. jopy-0.1.0/jopy/codegen/statements.py +1192 -0
  18. jopy-0.1.0/jopy/codegen/values.py +268 -0
  19. jopy-0.1.0/jopy/errors.py +270 -0
  20. jopy-0.1.0/jopy/features.py +201 -0
  21. jopy-0.1.0/jopy/inference.py +799 -0
  22. jopy-0.1.0/jopy/javatypes.py +451 -0
  23. jopy-0.1.0/jopy/jdk.py +902 -0
  24. jopy-0.1.0/jopy/lexer.py +768 -0
  25. jopy-0.1.0/jopy/mappings.py +708 -0
  26. jopy-0.1.0/jopy/parser.py +1566 -0
  27. jopy-0.1.0/jopy/progress.py +411 -0
  28. jopy-0.1.0/jopy/py.typed +0 -0
  29. jopy-0.1.0/jopy/runtime/Coroutine.java +535 -0
  30. jopy-0.1.0/jopy/runtime/JoPy.java +2800 -0
  31. jopy-0.1.0/jopy/runtime/Json.java +90 -0
  32. jopy-0.1.0/jopy/runtime/PyCallable.java +94 -0
  33. jopy-0.1.0/jopy/runtime/PyOperand.java +69 -0
  34. jopy-0.1.0/jopy/runtime/Reflection.java +64 -0
  35. jopy-0.1.0/jopy/runtime/Task.java +280 -0
  36. jopy-0.1.0/jopy/runtime/__init__.py +24 -0
  37. jopy-0.1.0/jopy/tokens.py +154 -0
  38. jopy-0.1.0/jopy.egg-info/PKG-INFO +275 -0
  39. jopy-0.1.0/jopy.egg-info/SOURCES.txt +59 -0
  40. jopy-0.1.0/jopy.egg-info/dependency_links.txt +1 -0
  41. jopy-0.1.0/jopy.egg-info/entry_points.txt +2 -0
  42. jopy-0.1.0/jopy.egg-info/requires.txt +4 -0
  43. jopy-0.1.0/jopy.egg-info/top_level.txt +1 -0
  44. jopy-0.1.0/pyproject.toml +51 -0
  45. jopy-0.1.0/setup.cfg +4 -0
  46. jopy-0.1.0/tests/test_api.py +428 -0
  47. jopy-0.1.0/tests/test_cli.py +308 -0
  48. jopy-0.1.0/tests/test_codegen.py +620 -0
  49. jopy-0.1.0/tests/test_end_to_end.py +242 -0
  50. jopy-0.1.0/tests/test_errors.py +282 -0
  51. jopy-0.1.0/tests/test_features.py +194 -0
  52. jopy-0.1.0/tests/test_jdk.py +1000 -0
  53. jopy-0.1.0/tests/test_lexer.py +360 -0
  54. jopy-0.1.0/tests/test_multiple_inheritance.py +330 -0
  55. jopy-0.1.0/tests/test_operator_regressions.py +85 -0
  56. jopy-0.1.0/tests/test_packaging.py +125 -0
  57. jopy-0.1.0/tests/test_parser.py +599 -0
  58. jopy-0.1.0/tests/test_progress.py +394 -0
  59. jopy-0.1.0/tests/test_runtime_contract.py +764 -0
  60. jopy-0.1.0/tests/test_runtime_self_test.py +47 -0
  61. jopy-0.1.0/tests/test_version_matrix.py +532 -0
jopy-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 jopy contributors
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.
jopy-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,275 @@
1
+ Metadata-Version: 2.4
2
+ Name: jopy
3
+ Version: 0.1.0
4
+ Summary: Python to Java transpiler: translate Python source into readable Java 9-21 source code.
5
+ Author: jopy contributors
6
+ License-Expression: MIT
7
+ Keywords: python,java,transpiler,compiler,code-generation,source-to-source
8
+ Classifier: Development Status :: 4 - Beta
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.9
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Java
16
+ Classifier: Topic :: Software Development :: Compilers
17
+ Classifier: Topic :: Software Development :: Code Generators
18
+ Requires-Python: >=3.9
19
+ Description-Content-Type: text/markdown
20
+ License-File: LICENSE
21
+ Provides-Extra: dev
22
+ Requires-Dist: pytest>=7.0; extra == "dev"
23
+ Requires-Dist: pytest-cov>=4.0; extra == "dev"
24
+ Dynamic: license-file
25
+
26
+ # jopy
27
+
28
+ **jopy** is a Python-to-Java transpiler written in pure Python. It reads Python
29
+ source with a hand written lexer and recursive descent parser, infers Java
30
+ types, and emits readable Java source that targets every release from **Java 9
31
+ to Java 21**. It never executes the Python it reads: it only parses, analyses
32
+ and re-emits it.
33
+
34
+ Generated code can call a small Java runtime (`jopy.runtime.JoPy`) that mirrors
35
+ Python semantics where Java differs: floor division, modulo sign, negative
36
+ indexing, truthiness, slices, integer overflow checks.
37
+
38
+ - Version: 0.1.0
39
+ - Language: Python 3.9+ (the translator), Java 9-21 (the output)
40
+ - Dependencies: standard library only
41
+ - Entry points: `import jopy` and `python -m jopy <file.py>`
42
+
43
+ ## Two usage modes
44
+
45
+ **Library.** Import the package and translate text, files or whole trees:
46
+
47
+ ```python
48
+ import jopy
49
+
50
+ result = jopy.translate("def add(a: int, b: int) -> int:\n return a + b\n",
51
+ filename="math_utils.py")
52
+ print(result.java)
53
+ print(result.stats["java_lines"], "Java lines")
54
+ ```
55
+
56
+ **Command line.** Translate from a shell, optionally compiling the result with
57
+ `javac`:
58
+
59
+ ```bash
60
+ python -m jopy math_utils.py --java-version 17 --compile -o build/java
61
+ ```
62
+
63
+ ## Quick start
64
+
65
+ ```bash
66
+ # 1. work from a checkout of this repository
67
+ cd /path/to/jopy
68
+
69
+ # 2. translate one file and print the Java on stdout
70
+ python -m jopy examples/greeting.py
71
+
72
+ # 3. write files, copy the runtime and verify with javac
73
+ python -m jopy examples/greeting.py -o build --java-version 17 --compile
74
+
75
+ # 4. run the compiled program
76
+ java -cp build/classes Greeting
77
+ ```
78
+
79
+ Step 3 and 4 are verified for `examples/greeting.py`: the translation exits 0,
80
+ javac accepts the output and the program prints the same lines as
81
+ `python examples/greeting.py`. The `examples/` directory holds runnable
82
+ programs that show one feature each; they are checked by hand rather than by
83
+ the suite (the automated fixtures live in `tests/fixtures/`), and
84
+ `examples/shapes_and_matching.py` currently fails `--compile` because of the
85
+ `match` guard defect in [docs/08-limitations.md](docs/08-limitations.md#known-defects-in-010).
86
+ See [examples/README.md](examples/README.md).
87
+
88
+ Machine readable progress is written to stderr as JSON lines whenever stderr is
89
+ not a terminal, so a pipeline stays clean:
90
+
91
+ ```bash
92
+ python -m jopy src/ -o build --progress json 2> progress.jsonl
93
+ ```
94
+
95
+ ## Before and after
96
+
97
+ Input, `greet.py`:
98
+
99
+ ```python
100
+ def greet(name: str) -> str:
101
+ return "Hello, " + name + "!"
102
+
103
+
104
+ def main() -> None:
105
+ for i in range(3):
106
+ print(greet("world"), i)
107
+
108
+
109
+ if __name__ == "__main__":
110
+ main()
111
+ ```
112
+
113
+ Output (`python -m jopy greet.py --java-version 17`):
114
+
115
+ ```java
116
+ import jopy.runtime.JoPy;
117
+
118
+ public class Greet {
119
+ public static void main(String[] args) {
120
+ main();
121
+ }
122
+
123
+ public static String greet(String name) {
124
+ return (("Hello, " + name) + "!");
125
+ }
126
+
127
+ public static void main() {
128
+ for (int i = 0; i < 3; i++) {
129
+ System.out.println(JoPy.joinStrings(" ", greet("world"), i));
130
+ }
131
+ }
132
+ }
133
+ ```
134
+
135
+ `print(a, b)` becomes one call because Python prints space separated values,
136
+ and `range(3)` becomes a counting loop because jopy can prove the bounds are
137
+ integral. Compiling and running that Java prints exactly what the Python
138
+ prints.
139
+
140
+ ## Feature matrix
141
+
142
+ | Area | Support | Notes |
143
+ | --- | --- | --- |
144
+ | Lexer, parser, AST | Full Python 3.8-3.12 grammar subset | INDENT/DEDENT tokenising, f-strings, match statements, walrus, PEP 604 unions |
145
+ | Type inference | Heuristic, never fatal | Annotations plus a usage driven narrowing pass; what stays unprovable becomes `Object`, dispatches through `JoPy` helpers and is reported with a manual-fix note |
146
+ | Functions | Parameters, defaults, `*args`, `**kwargs`, decorators | Defaults expand into overloads, unknown decorators become comments plus a manual note |
147
+ | Classes | Inheritance, static/class methods, properties, dunder methods | Single inheritance; extra bases become manual work |
148
+ | Modules | 30+ stdlib modules mapped | Unknown modules produce a manual note and a commented import |
149
+ | Containers | list / dict / set / tuple | Tuples are `List`, dicts are `Map`, sets are `Set` |
150
+ | Exceptions | try / except / else / finally, multi-catch | Checked exceptions are caught as `Exception` and rethrown with `JoPy.sneakyThrow` |
151
+ | Comprehensions | list / set / dict / generator expressions | Emitted as `Stream` pipelines |
152
+ | Generators | `yield` / `yield from` inside a function | Lazy `Coroutine` on one daemon thread; `next`, `send`, `throw` and `close` work, unbounded generators are fine |
153
+ | Nested functions | `def` inside a `def` | `PyCallable` closures that capture the enclosing locals |
154
+ | Operator overloading | `__add__`, `__lt__`, `__len__`, `__getitem__`, ... | The class implements `PyOperand`, so `a + b`, `a < b`, `len(a)` and `a[i]` keep working at the call site |
155
+ | `async` / `await` | `async def`, `await`, `asyncio.run` | `Task` on a daemon thread; `asyncio.gather`/`sleep` map to `JoPy` helpers |
156
+ | Context managers | `with open(...) as f:` | Becomes try-with-resources when the manager is `AutoCloseable` |
157
+ | Match statements | Sequence, mapping, class, value, singleton, or, as, wildcard | Emitted as an if/else chain on every target release |
158
+ | Comments and docstrings | Preserved by default | `--no-comments` / `--no-javadoc` drop them |
159
+ | Progress reporting | Terminal bar or JSON lines | Same events, two renderers, plus a `progress_callback` hook |
160
+ | Manual-fix reporting | Structured diagnostics | `--report report.json` writes every diagnostic as JSON |
161
+ | JDK provisioning | Automatic download or local archive | `--install-jdk` fetches Temurin into `~/.jopy/jdks` (or `$JOPY_HOME/jdks`), `--jdk-archive FILE` installs a downloaded archive without a network, `--list-jdks` shows what is managed, and `find_javac()` finds it |
162
+
163
+ Constructs jopy cannot express faithfully are **not** silently dropped: they are
164
+ reported as `manual-fix` diagnostics, embedded as `// MANUAL: ...` comments in
165
+ the generated Java and listed by `--explain`. See
166
+ [docs/07-manual-work.md](docs/07-manual-work.md).
167
+
168
+ ## Architecture
169
+
170
+ ```text
171
+ Python source (.py)
172
+ |
173
+ v
174
+ +------------------+ tokens + comments + INDENT/DEDENT
175
+ | lexer.py |-------------------------------------+
176
+ +------------------+ |
177
+ | |
178
+ v v
179
+ +------------------+ syntax tree (ast_nodes) +-----------+
180
+ | parser.py |-----------------------------> | tokens.py |
181
+ +------------------+ +-----------+
182
+ |
183
+ v
184
+ +------------------+ Java types (javatypes) +-------------+
185
+ | inference.py |-----------------------------> | mappings.py |
186
+ +------------------+ builtins, modules, ... +-------------+
187
+ |
188
+ v
189
+ +------------------+ Java source + diagnostics + line map
190
+ | codegen/ |-------------------------------------+
191
+ +------------------+ |
192
+ | v
193
+ v +-------------------------+
194
+ +------------------+ TranslationResult | runtime/JoPy.java |
195
+ | api.py |------------------------> | runtime/PyCallable.java |
196
+ +------------------+ progress.py events | runtime/PyOperand.java |
197
+ | | runtime/Coroutine.java |
198
+ | | runtime/Task.java |
199
+ | +-------------------------+
200
+ v
201
+ +------------------+ exit codes 0/1/2/3
202
+ | cli.py |
203
+ +------------------+
204
+ ```
205
+
206
+ More detail, including how comments and source lines survive the round trip,
207
+ lives in [docs/06-architecture.md](docs/06-architecture.md).
208
+
209
+ ## Requirements
210
+
211
+ - **Python 3.9 or newer** to run jopy itself. Only the standard library is used.
212
+ - **A JDK is optional.** It is needed only for `--compile`, `javac_release_supported()`
213
+ and the `--javac-output` workflow. The JDK must be at least as new as the
214
+ `--java-version` you target (`javac --release N` cannot target a newer release).
215
+ When none is installed, `jopy --install-jdk` fetches one into the managed root
216
+ (`~/.jopy/jdks`, or `$JOPY_HOME/jdks`) and prints its path; a manually downloaded
217
+ archive installs offline with `--jdk-archive FILE`, and `--list-jdks` shows what
218
+ is already there. See [docs/02-cli-reference.md](docs/02-cli-reference.md#jdk-management-options).
219
+ - Verified during the writing of this documentation with Python 3.11.9 and
220
+ `javac 17.0.19`.
221
+
222
+ ## Installation
223
+
224
+ The checkout is directly runnable, because the package lives in the `jopy/`
225
+ directory at the repository root:
226
+
227
+ ```bash
228
+ cd /path/to/jopy
229
+ python -m jopy --version # jopy 0.1.0
230
+ ```
231
+
232
+ From another working directory, put the checkout on the import path:
233
+
234
+ ```bash
235
+ export PYTHONPATH=/path/to/jopy # Windows: set PYTHONPATH=D:\path\to\jopy
236
+ python -m jopy my_script.py
237
+ ```
238
+
239
+ Editable install:
240
+
241
+ ```bash
242
+ cd /path/to/jopy
243
+ pip install -e .
244
+ ```
245
+
246
+ This installs the `jopy` console script (entry point `jopy.cli:main`), which is
247
+ equivalent to `python -m jopy`, and ships `jopy/runtime/*.java` as package data,
248
+ so the runtime sources stay available to `--compile` and to
249
+ `jopy.write_runtime()`.
250
+
251
+ **Known defect:** the `packages` list in `pyproject.toml` is
252
+ `["jopy", "jopy.runtime"]` and therefore omits `jopy.codegen`, so an installed
253
+ wheel cannot import at all (`ModuleNotFoundError: No module named
254
+ 'jopy.codegen'`). Run from the checkout, or add `jopy.codegen` to that list;
255
+ see [docs/08-limitations.md](docs/08-limitations.md#known-defects-in-010).
256
+
257
+ ## Documentation
258
+
259
+ | Document | Contents |
260
+ | --- | --- |
261
+ | [docs/01-getting-started.md](docs/01-getting-started.md) | Install, first translation, output layout, javac, running, troubleshooting |
262
+ | [docs/02-cli-reference.md](docs/02-cli-reference.md) | Every flag, default and example, exit codes, stream conventions |
263
+ | [docs/03-python-api.md](docs/03-python-api.md) | `translate`, `Translator`, `TranslationResult`, runtime and compile helpers, errors |
264
+ | [docs/04-progress-reporting.md](docs/04-progress-reporting.md) | Bar vs JSON renderers, event schema, stage weights, callbacks |
265
+ | [docs/05-language-mapping.md](docs/05-language-mapping.md) | The construct-by-construct Python to Java reference |
266
+ | [docs/06-architecture.md](docs/06-architecture.md) | Pipeline, module responsibilities, codegen mechanisms |
267
+ | [docs/07-manual-work.md](docs/07-manual-work.md) | Every diagnostic that asks a human to finish the job |
268
+ | [docs/08-limitations.md](docs/08-limitations.md) | What jopy will not translate, unsupported modules, performance |
269
+ | [docs/09-testing.md](docs/09-testing.md) | Verification scripts, end-to-end javac testing, adding fixtures |
270
+ | [CONTRIBUTING.md](CONTRIBUTING.md) | Dev setup, style, adding a mapping, review checklist |
271
+ | [CHANGELOG.md](CHANGELOG.md) | Release history |
272
+
273
+ ## License
274
+
275
+ MIT. See [LICENSE](LICENSE).
jopy-0.1.0/README.md ADDED
@@ -0,0 +1,250 @@
1
+ # jopy
2
+
3
+ **jopy** is a Python-to-Java transpiler written in pure Python. It reads Python
4
+ source with a hand written lexer and recursive descent parser, infers Java
5
+ types, and emits readable Java source that targets every release from **Java 9
6
+ to Java 21**. It never executes the Python it reads: it only parses, analyses
7
+ and re-emits it.
8
+
9
+ Generated code can call a small Java runtime (`jopy.runtime.JoPy`) that mirrors
10
+ Python semantics where Java differs: floor division, modulo sign, negative
11
+ indexing, truthiness, slices, integer overflow checks.
12
+
13
+ - Version: 0.1.0
14
+ - Language: Python 3.9+ (the translator), Java 9-21 (the output)
15
+ - Dependencies: standard library only
16
+ - Entry points: `import jopy` and `python -m jopy <file.py>`
17
+
18
+ ## Two usage modes
19
+
20
+ **Library.** Import the package and translate text, files or whole trees:
21
+
22
+ ```python
23
+ import jopy
24
+
25
+ result = jopy.translate("def add(a: int, b: int) -> int:\n return a + b\n",
26
+ filename="math_utils.py")
27
+ print(result.java)
28
+ print(result.stats["java_lines"], "Java lines")
29
+ ```
30
+
31
+ **Command line.** Translate from a shell, optionally compiling the result with
32
+ `javac`:
33
+
34
+ ```bash
35
+ python -m jopy math_utils.py --java-version 17 --compile -o build/java
36
+ ```
37
+
38
+ ## Quick start
39
+
40
+ ```bash
41
+ # 1. work from a checkout of this repository
42
+ cd /path/to/jopy
43
+
44
+ # 2. translate one file and print the Java on stdout
45
+ python -m jopy examples/greeting.py
46
+
47
+ # 3. write files, copy the runtime and verify with javac
48
+ python -m jopy examples/greeting.py -o build --java-version 17 --compile
49
+
50
+ # 4. run the compiled program
51
+ java -cp build/classes Greeting
52
+ ```
53
+
54
+ Step 3 and 4 are verified for `examples/greeting.py`: the translation exits 0,
55
+ javac accepts the output and the program prints the same lines as
56
+ `python examples/greeting.py`. The `examples/` directory holds runnable
57
+ programs that show one feature each; they are checked by hand rather than by
58
+ the suite (the automated fixtures live in `tests/fixtures/`), and
59
+ `examples/shapes_and_matching.py` currently fails `--compile` because of the
60
+ `match` guard defect in [docs/08-limitations.md](docs/08-limitations.md#known-defects-in-010).
61
+ See [examples/README.md](examples/README.md).
62
+
63
+ Machine readable progress is written to stderr as JSON lines whenever stderr is
64
+ not a terminal, so a pipeline stays clean:
65
+
66
+ ```bash
67
+ python -m jopy src/ -o build --progress json 2> progress.jsonl
68
+ ```
69
+
70
+ ## Before and after
71
+
72
+ Input, `greet.py`:
73
+
74
+ ```python
75
+ def greet(name: str) -> str:
76
+ return "Hello, " + name + "!"
77
+
78
+
79
+ def main() -> None:
80
+ for i in range(3):
81
+ print(greet("world"), i)
82
+
83
+
84
+ if __name__ == "__main__":
85
+ main()
86
+ ```
87
+
88
+ Output (`python -m jopy greet.py --java-version 17`):
89
+
90
+ ```java
91
+ import jopy.runtime.JoPy;
92
+
93
+ public class Greet {
94
+ public static void main(String[] args) {
95
+ main();
96
+ }
97
+
98
+ public static String greet(String name) {
99
+ return (("Hello, " + name) + "!");
100
+ }
101
+
102
+ public static void main() {
103
+ for (int i = 0; i < 3; i++) {
104
+ System.out.println(JoPy.joinStrings(" ", greet("world"), i));
105
+ }
106
+ }
107
+ }
108
+ ```
109
+
110
+ `print(a, b)` becomes one call because Python prints space separated values,
111
+ and `range(3)` becomes a counting loop because jopy can prove the bounds are
112
+ integral. Compiling and running that Java prints exactly what the Python
113
+ prints.
114
+
115
+ ## Feature matrix
116
+
117
+ | Area | Support | Notes |
118
+ | --- | --- | --- |
119
+ | Lexer, parser, AST | Full Python 3.8-3.12 grammar subset | INDENT/DEDENT tokenising, f-strings, match statements, walrus, PEP 604 unions |
120
+ | Type inference | Heuristic, never fatal | Annotations plus a usage driven narrowing pass; what stays unprovable becomes `Object`, dispatches through `JoPy` helpers and is reported with a manual-fix note |
121
+ | Functions | Parameters, defaults, `*args`, `**kwargs`, decorators | Defaults expand into overloads, unknown decorators become comments plus a manual note |
122
+ | Classes | Inheritance, static/class methods, properties, dunder methods | Single inheritance; extra bases become manual work |
123
+ | Modules | 30+ stdlib modules mapped | Unknown modules produce a manual note and a commented import |
124
+ | Containers | list / dict / set / tuple | Tuples are `List`, dicts are `Map`, sets are `Set` |
125
+ | Exceptions | try / except / else / finally, multi-catch | Checked exceptions are caught as `Exception` and rethrown with `JoPy.sneakyThrow` |
126
+ | Comprehensions | list / set / dict / generator expressions | Emitted as `Stream` pipelines |
127
+ | Generators | `yield` / `yield from` inside a function | Lazy `Coroutine` on one daemon thread; `next`, `send`, `throw` and `close` work, unbounded generators are fine |
128
+ | Nested functions | `def` inside a `def` | `PyCallable` closures that capture the enclosing locals |
129
+ | Operator overloading | `__add__`, `__lt__`, `__len__`, `__getitem__`, ... | The class implements `PyOperand`, so `a + b`, `a < b`, `len(a)` and `a[i]` keep working at the call site |
130
+ | `async` / `await` | `async def`, `await`, `asyncio.run` | `Task` on a daemon thread; `asyncio.gather`/`sleep` map to `JoPy` helpers |
131
+ | Context managers | `with open(...) as f:` | Becomes try-with-resources when the manager is `AutoCloseable` |
132
+ | Match statements | Sequence, mapping, class, value, singleton, or, as, wildcard | Emitted as an if/else chain on every target release |
133
+ | Comments and docstrings | Preserved by default | `--no-comments` / `--no-javadoc` drop them |
134
+ | Progress reporting | Terminal bar or JSON lines | Same events, two renderers, plus a `progress_callback` hook |
135
+ | Manual-fix reporting | Structured diagnostics | `--report report.json` writes every diagnostic as JSON |
136
+ | JDK provisioning | Automatic download or local archive | `--install-jdk` fetches Temurin into `~/.jopy/jdks` (or `$JOPY_HOME/jdks`), `--jdk-archive FILE` installs a downloaded archive without a network, `--list-jdks` shows what is managed, and `find_javac()` finds it |
137
+
138
+ Constructs jopy cannot express faithfully are **not** silently dropped: they are
139
+ reported as `manual-fix` diagnostics, embedded as `// MANUAL: ...` comments in
140
+ the generated Java and listed by `--explain`. See
141
+ [docs/07-manual-work.md](docs/07-manual-work.md).
142
+
143
+ ## Architecture
144
+
145
+ ```text
146
+ Python source (.py)
147
+ |
148
+ v
149
+ +------------------+ tokens + comments + INDENT/DEDENT
150
+ | lexer.py |-------------------------------------+
151
+ +------------------+ |
152
+ | |
153
+ v v
154
+ +------------------+ syntax tree (ast_nodes) +-----------+
155
+ | parser.py |-----------------------------> | tokens.py |
156
+ +------------------+ +-----------+
157
+ |
158
+ v
159
+ +------------------+ Java types (javatypes) +-------------+
160
+ | inference.py |-----------------------------> | mappings.py |
161
+ +------------------+ builtins, modules, ... +-------------+
162
+ |
163
+ v
164
+ +------------------+ Java source + diagnostics + line map
165
+ | codegen/ |-------------------------------------+
166
+ +------------------+ |
167
+ | v
168
+ v +-------------------------+
169
+ +------------------+ TranslationResult | runtime/JoPy.java |
170
+ | api.py |------------------------> | runtime/PyCallable.java |
171
+ +------------------+ progress.py events | runtime/PyOperand.java |
172
+ | | runtime/Coroutine.java |
173
+ | | runtime/Task.java |
174
+ | +-------------------------+
175
+ v
176
+ +------------------+ exit codes 0/1/2/3
177
+ | cli.py |
178
+ +------------------+
179
+ ```
180
+
181
+ More detail, including how comments and source lines survive the round trip,
182
+ lives in [docs/06-architecture.md](docs/06-architecture.md).
183
+
184
+ ## Requirements
185
+
186
+ - **Python 3.9 or newer** to run jopy itself. Only the standard library is used.
187
+ - **A JDK is optional.** It is needed only for `--compile`, `javac_release_supported()`
188
+ and the `--javac-output` workflow. The JDK must be at least as new as the
189
+ `--java-version` you target (`javac --release N` cannot target a newer release).
190
+ When none is installed, `jopy --install-jdk` fetches one into the managed root
191
+ (`~/.jopy/jdks`, or `$JOPY_HOME/jdks`) and prints its path; a manually downloaded
192
+ archive installs offline with `--jdk-archive FILE`, and `--list-jdks` shows what
193
+ is already there. See [docs/02-cli-reference.md](docs/02-cli-reference.md#jdk-management-options).
194
+ - Verified during the writing of this documentation with Python 3.11.9 and
195
+ `javac 17.0.19`.
196
+
197
+ ## Installation
198
+
199
+ The checkout is directly runnable, because the package lives in the `jopy/`
200
+ directory at the repository root:
201
+
202
+ ```bash
203
+ cd /path/to/jopy
204
+ python -m jopy --version # jopy 0.1.0
205
+ ```
206
+
207
+ From another working directory, put the checkout on the import path:
208
+
209
+ ```bash
210
+ export PYTHONPATH=/path/to/jopy # Windows: set PYTHONPATH=D:\path\to\jopy
211
+ python -m jopy my_script.py
212
+ ```
213
+
214
+ Editable install:
215
+
216
+ ```bash
217
+ cd /path/to/jopy
218
+ pip install -e .
219
+ ```
220
+
221
+ This installs the `jopy` console script (entry point `jopy.cli:main`), which is
222
+ equivalent to `python -m jopy`, and ships `jopy/runtime/*.java` as package data,
223
+ so the runtime sources stay available to `--compile` and to
224
+ `jopy.write_runtime()`.
225
+
226
+ **Known defect:** the `packages` list in `pyproject.toml` is
227
+ `["jopy", "jopy.runtime"]` and therefore omits `jopy.codegen`, so an installed
228
+ wheel cannot import at all (`ModuleNotFoundError: No module named
229
+ 'jopy.codegen'`). Run from the checkout, or add `jopy.codegen` to that list;
230
+ see [docs/08-limitations.md](docs/08-limitations.md#known-defects-in-010).
231
+
232
+ ## Documentation
233
+
234
+ | Document | Contents |
235
+ | --- | --- |
236
+ | [docs/01-getting-started.md](docs/01-getting-started.md) | Install, first translation, output layout, javac, running, troubleshooting |
237
+ | [docs/02-cli-reference.md](docs/02-cli-reference.md) | Every flag, default and example, exit codes, stream conventions |
238
+ | [docs/03-python-api.md](docs/03-python-api.md) | `translate`, `Translator`, `TranslationResult`, runtime and compile helpers, errors |
239
+ | [docs/04-progress-reporting.md](docs/04-progress-reporting.md) | Bar vs JSON renderers, event schema, stage weights, callbacks |
240
+ | [docs/05-language-mapping.md](docs/05-language-mapping.md) | The construct-by-construct Python to Java reference |
241
+ | [docs/06-architecture.md](docs/06-architecture.md) | Pipeline, module responsibilities, codegen mechanisms |
242
+ | [docs/07-manual-work.md](docs/07-manual-work.md) | Every diagnostic that asks a human to finish the job |
243
+ | [docs/08-limitations.md](docs/08-limitations.md) | What jopy will not translate, unsupported modules, performance |
244
+ | [docs/09-testing.md](docs/09-testing.md) | Verification scripts, end-to-end javac testing, adding fixtures |
245
+ | [CONTRIBUTING.md](CONTRIBUTING.md) | Dev setup, style, adding a mapping, review checklist |
246
+ | [CHANGELOG.md](CHANGELOG.md) | Release history |
247
+
248
+ ## License
249
+
250
+ MIT. See [LICENSE](LICENSE).