type-python 0.3.0__py3-none-win_amd64.whl → 0.4.0__py3-none-win_amd64.whl

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.
@@ -0,0 +1,175 @@
1
+ Metadata-Version: 2.4
2
+ Name: type-python
3
+ Version: 0.4.0
4
+ Summary: A statically-typed authoring language that compiles to standard Python
5
+ Author: unadlib
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/type-python/type-python
8
+ Project-URL: Repository, https://github.com/type-python/type-python
9
+ Project-URL: Documentation, https://github.com/type-python/type-python/tree/main/docs
10
+ Project-URL: Issues, https://github.com/type-python/type-python/issues
11
+ Keywords: typepython,type-checking,compiler,python,static-typing
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.9
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Programming Language :: Python :: 3.14
21
+ Classifier: Programming Language :: Rust
22
+ Classifier: Topic :: Software Development :: Compilers
23
+ Classifier: Topic :: Software Development :: Quality Assurance
24
+ Classifier: Typing :: Typed
25
+ Requires-Python: >=3.9
26
+ Description-Content-Type: text/markdown
27
+ License-File: LICENSE
28
+ Dynamic: license-file
29
+
30
+ <p align="center">
31
+ <img src="https://raw.githubusercontent.com/type-python/type-python/main/logo.png" alt="TypePython" width="160" />
32
+ </p>
33
+
34
+ <h1 align="center">TypePython</h1>
35
+
36
+ <p align="center">
37
+ <strong>Write richer types in <code>.tpy</code>. Ship plain <code>.py</code> + <code>.pyi</code>.</strong>
38
+ </p>
39
+
40
+ ---
41
+
42
+ TypePython is a typed dialect of Python that compiles to standard `.py` + `.pyi`.
43
+ It brings TypeScript-class ergonomics — `sealed` classes, exhaustive `match`,
44
+ strict null checks, `unknown`, `interface`, `data class` — to a language whose
45
+ output runs anywhere CPython runs.
46
+
47
+ **No custom runtime. No per-checker plugin. No vendor lock-in.**
48
+
49
+ > Status: **Core v1 Beta** (v0.4.0). Core syntax, config, `init`/`check`/`build`/
50
+ > `clean`/`verify`, diagnostic code identity, and emitted `.py`/`.pyi` compatibility
51
+ > are the stable Beta surfaces. LSP UX, adapter manifests, runtime validators, and
52
+ > migration heuristics remain prototype/experimental.
53
+ > Bug reports and contributions are very welcome.
54
+
55
+ ## Install
56
+
57
+ ```bash
58
+ pip install type-python
59
+ typepython init --dir hello && cd hello
60
+ typepython check --project .
61
+ typepython build --project .
62
+ ```
63
+
64
+ You now have `.typepython/build/` with `.py` + `.pyi` + `py.typed` ready for
65
+ any Python interpreter, IDE, or downstream type checker.
66
+
67
+ - **Wheels** are prebuilt for Windows AMD64, macOS x86_64, macOS arm64, and Linux x86_64.
68
+ Other platforms fall back to source and need Rust + `cargo`.
69
+ - **Python**: the package bridge supports 3.9+; generated projects target Python 3.10 through 3.14.
70
+
71
+ ## See it in 15 lines
72
+
73
+ ```python
74
+ # src/app/expr.tpy
75
+
76
+ sealed class Expr:
77
+ pass
78
+
79
+ class Num(Expr): value: int
80
+ class Add(Expr): left: Expr; right: Expr
81
+ class Neg(Expr): operand: Expr
82
+
83
+ def evaluate(expr: Expr) -> int:
84
+ match expr:
85
+ case Num(value=v): return v
86
+ case Add(left=l, right=r): return evaluate(l) + evaluate(r)
87
+ case Neg(operand=o): return -evaluate(o)
88
+ # No default branch needed — the compiler proves the match is exhaustive.
89
+ # Add a fourth subclass and TypePython tells you exactly where to update.
90
+ ```
91
+
92
+ `typepython build` lowers that to ordinary Python and writes a matching `.pyi`
93
+ that any modern type checker can consume — no TypePython runtime required.
94
+
95
+ ## What you write vs. what ships
96
+
97
+ | You write (`.tpy`) | TypePython emits (`.py` / `.pyi`) |
98
+ | ------------------------------------- | --------------------------------------------------------- |
99
+ | `interface Drawable:` | `class Drawable(Protocol):` |
100
+ | `data class User:` | `@dataclass class User:` |
101
+ | `sealed class Expr:` | ordinary class + `tpy:sealed` marker |
102
+ | `overload def parse(...)` | `@overload def parse(...)` |
103
+ | `typealias Pair[T] = tuple[T, T]` | `T = TypeVar("T")` + `Pair: TypeAlias = tuple[T, T]` |
104
+ | `def first[T](xs: list[T]) -> T:` | inline generic on 3.13+, `TypeVar`-based on 3.10 – 3.12 |
105
+ | `unsafe: eval(expr)` | valid Python, marker erased — runtime behavior preserved |
106
+ | `unknown` (must narrow before use) | `object` in `.pyi` |
107
+ | `Partial[Config]` / `Pick[Config, …]` | expanded `TypedDict` shapes (PEP 655 / 705) |
108
+
109
+ ## Why not just mypy / pyright / PEP 695?
110
+
111
+ | Capability | mypy strict | pyright strict | PEP 695 `.py` | **TypePython `.tpy`** |
112
+ | ------------------------------------------------------- | :---------: | :------------: | :-----------: | :-------------------: |
113
+ | `sealed class` + compiler-proved exhaustiveness | — | — | — | ✅ |
114
+ | `unknown` — safe dynamic boundary, must narrow | — | — | — | ✅ |
115
+ | `unsafe:` audit fence for `eval` / `exec` / `setattr` | — | — | — | ✅ |
116
+ | First-class `interface` / `data class` / `typealias` | via | via | via | keyword |
117
+ | Inline generics `def f[T]` on **any** target ≥ 3.10 | 3.12+ | 3.12+ | 3.12+ | ✅ |
118
+ | `TypedDict` transforms (`Partial`, `Pick`, `Readonly`…) | — | — | — | ✅ |
119
+ | Output consumed by mypy / pyright / ty unmodified | N/A | N/A | ✅ | ✅ |
120
+
121
+ TypePython doesn't replace those checkers. It sits **one step earlier**: you
122
+ author in `.tpy`, the compiler emits standard typed Python that those tools
123
+ then consume normally.
124
+
125
+ ## What you also get
126
+
127
+ - **Rust-native, incremental compiler** — public-API fingerprints skip
128
+ downstream rechecks when only a body changes.
129
+ - **Full toolchain** — `init`, `check`, `build`, `watch`, `clean`, `verify`,
130
+ `compat`, `api-diff`, `type-health`, `migrate`, `lsp`.
131
+ - **LSP server** — hover, go to definition, references, rename, completions,
132
+ signature help, real-time diagnostics, and code-action quick fixes.
133
+ Bring your own LSP-capable editor (VS Code, Neovim, Helix, Sublime, Emacs).
134
+ - **Standard, portable output** — emitted `.py` + `.pyi` work with mypy,
135
+ pyright, and ty out of the box. PEP 561 `py.typed` is written automatically.
136
+ - **Mixed projects** — `.tpy`, `.py`, and `.pyi` live in the same source tree.
137
+ `.py` is pass-through; `.pyi` is stub-authoritative.
138
+
139
+ ## For library authors
140
+
141
+ Five commands aimed at people who *publish* typed Python:
142
+
143
+ ```bash
144
+ typepython build --project .
145
+ typepython verify --project . --checker-preset all
146
+ typepython compat --project . --profile library-portable
147
+ typepython api-diff dist/previous.whl .typepython/build
148
+ typepython type-health --project . --fail-under 85
149
+ ```
150
+
151
+ These catch missing/stale `py.typed`, wheel ↔ build-tree drift, multi-checker
152
+ portability gaps, public-API drift between releases, and runtime-annotation
153
+ hazards for frameworks that introspect annotations.
154
+
155
+ ## Documentation
156
+
157
+ - [Getting Started](https://github.com/type-python/type-python/blob/main/docs/getting-started.md)
158
+ - [Syntax Guide](https://github.com/type-python/type-python/blob/main/docs/syntax-guide.md)
159
+ - [Type System](https://github.com/type-python/type-python/blob/main/docs/type-system.md)
160
+ - [Configuration](https://github.com/type-python/type-python/blob/main/docs/configuration.md)
161
+ - [CLI Reference](https://github.com/type-python/type-python/blob/main/docs/cli-reference.md)
162
+ - [Diagnostics (TPYxxxx codes)](https://github.com/type-python/type-python/blob/main/docs/diagnostics.md)
163
+ - [LSP Integration](https://github.com/type-python/type-python/blob/main/docs/lsp.md)
164
+ - [Interoperability](https://github.com/type-python/type-python/blob/main/docs/interop.md)
165
+ - [Migration Guide](https://github.com/type-python/type-python/blob/main/docs/migration-guide.md)
166
+ - [Framework Adapters](https://github.com/type-python/type-python/blob/main/docs/framework-adapters.md)
167
+ - [Beta Readiness](https://github.com/type-python/type-python/blob/main/docs/beta-readiness.md)
168
+ - [Language Spec v1](https://github.com/type-python/type-python/blob/main/docs/spec/language-spec-v1.md)
169
+
170
+ ## Links
171
+
172
+ - [Repository](https://github.com/type-python/type-python)
173
+ - [Issues / bug reports](https://github.com/type-python/type-python/issues)
174
+ - [Contributing](https://github.com/type-python/type-python/blob/main/docs/contributing.md)
175
+ - [License (MIT)](https://github.com/type-python/type-python/blob/main/LICENSE)
@@ -0,0 +1,11 @@
1
+ type_python-0.4.0.dist-info/licenses/LICENSE,sha256=BMHUZ3id_LOrEdv_GmAbL1ttlKsqjZz14f1_M1tn73k,1089
2
+ typepython/__init__.py,sha256=ysHyCeLjWKlxEnJRLBsdi0p3jq5OJrH7AqhO6N4FbQE,532
3
+ typepython/__main__.py,sha256=m8cggQyLAOSPtb8r-uUv_g53whMoPXtF2NX9yLuPyLg,89
4
+ typepython/_runner.py,sha256=DySWPTud0FIAv2-0xhmwAyt_kk3w3kFJWK8FcYSe858,1777
5
+ typepython/annotation_compat.py,sha256=F_dLOYhFHtOyGn-vTn22VayGMZKfGF4OoM-YvD_352I,13916
6
+ typepython/bin/typepython.exe,sha256=sLjMbU6ZeWGa2QSFpJ_5Bs6dzF6Jtw3-FHBH5lr038I,13957120
7
+ type_python-0.4.0.dist-info/METADATA,sha256=3jpBkrYGONaxOzsiM6dS-O95iR8yrPQPDhG06tGUjPE,9178
8
+ type_python-0.4.0.dist-info/WHEEL,sha256=GjDPPQwEcripVP6P2r3RxLa-h5Lb9ifGB7FYYtbLDT0,98
9
+ type_python-0.4.0.dist-info/entry_points.txt,sha256=B5Yjdi-RWaeRy7YUcni1lU_ya2lVZXM8llSFNSKEq0U,56
10
+ type_python-0.4.0.dist-info/top_level.txt,sha256=JFRFjt3AXvRQ99SKMxUVu9e3TOp2QpspvE-jk85uMjU,11
11
+ type_python-0.4.0.dist-info/RECORD,,
typepython/__init__.py CHANGED
@@ -1,13 +1,26 @@
1
1
  from ._runner import main
2
- from .annotation_compat import AnnotationFormat, AnnotationSupport, get_annotations, supported_formats
2
+ from .annotation_compat import (
3
+ AnnotationAudit,
4
+ AnnotationAuditFinding,
5
+ AnnotationConsumer,
6
+ AnnotationFormat,
7
+ AnnotationSupport,
8
+ audit_source,
9
+ get_annotations,
10
+ supported_formats,
11
+ )
3
12
 
4
13
  __all__ = [
5
14
  "__version__",
6
15
  "AnnotationFormat",
16
+ "AnnotationAudit",
17
+ "AnnotationAuditFinding",
18
+ "AnnotationConsumer",
7
19
  "AnnotationSupport",
20
+ "audit_source",
8
21
  "get_annotations",
9
22
  "main",
10
23
  "supported_formats",
11
24
  ]
12
25
 
13
- __version__ = "0.3.0"
26
+ __version__ = "0.4.0"
@@ -2,6 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  import inspect
4
4
  import sys
5
+ import ast
5
6
  from dataclasses import dataclass
6
7
  from enum import Enum
7
8
  from types import ModuleType
@@ -28,12 +29,51 @@ class AnnotationSupport:
28
29
  string: bool
29
30
 
30
31
 
32
+ class AnnotationConsumer(str, Enum):
33
+ TYPING_GET_TYPE_HINTS = "typing.get_type_hints"
34
+ INSPECT_GET_ANNOTATIONS = "inspect.get_annotations"
35
+ ANNOTATIONLIB_GET_ANNOTATIONS = "annotationlib.get_annotations"
36
+ DATACLASS_DECORATOR = "dataclasses.dataclass"
37
+ FASTAPI_ROUTE_DECORATOR = "fastapi.route_decorator"
38
+ FASTAPI_DEPENDS = "fastapi.Depends"
39
+ PYDANTIC_BASEMODEL = "pydantic.BaseModel"
40
+ PYDANTIC_FIELD = "pydantic.Field"
41
+
42
+
43
+ @dataclass(frozen=True)
44
+ class AnnotationAuditFinding:
45
+ code: str
46
+ message: str
47
+ line: int
48
+ column: int
49
+
50
+
51
+ @dataclass(frozen=True)
52
+ class AnnotationAudit:
53
+ consumers: tuple[AnnotationConsumer, ...]
54
+ findings: tuple[AnnotationAuditFinding, ...]
55
+
56
+ @property
57
+ def safe_for_runtime_introspection(self) -> bool:
58
+ return not self.findings
59
+
60
+
31
61
  def supported_formats() -> AnnotationSupport:
32
62
  if HAS_ANNOTATIONLIB:
33
63
  return AnnotationSupport(value=True, forwardref=True, string=True)
34
64
  return AnnotationSupport(value=True, forwardref=False, string=False)
35
65
 
36
66
 
67
+ def audit_source(source: str, *, filename: str = "<source>") -> AnnotationAudit:
68
+ tree = ast.parse(source, filename=filename)
69
+ visitor = _AnnotationAuditVisitor()
70
+ visitor.visit(tree)
71
+ return AnnotationAudit(
72
+ consumers=tuple(sorted(visitor.consumers, key=lambda consumer: consumer.value)),
73
+ findings=tuple(visitor.findings),
74
+ )
75
+
76
+
37
77
  def get_annotations(
38
78
  obj: Any,
39
79
  *,
@@ -140,3 +180,214 @@ def _legacy_eval_namespaces(
140
180
  module = sys.modules.get(getattr(obj, "__module__", ""))
141
181
  namespace = vars(module) if module is not None else {}
142
182
  return namespace, namespace
183
+
184
+
185
+ class _AnnotationAuditVisitor(ast.NodeVisitor):
186
+ def __init__(self) -> None:
187
+ self.consumers: set[AnnotationConsumer] = set()
188
+ self.findings: list[AnnotationAuditFinding] = []
189
+ self._type_checking_only_names: set[str] = set()
190
+ self._scope_depth = 0
191
+
192
+ def visit_If(self, node: ast.If) -> None:
193
+ if _is_type_checking_guard(node.test):
194
+ self._record_type_checking_only_imports(node.body)
195
+ for statement in node.orelse:
196
+ self.visit(statement)
197
+ return
198
+ self.generic_visit(node)
199
+
200
+ def visit_FunctionDef(self, node: ast.FunctionDef) -> None:
201
+ for decorator in node.decorator_list:
202
+ consumer = _decorator_consumer(decorator)
203
+ if consumer is not None:
204
+ self.consumers.add(consumer)
205
+ self._visit_callable_or_class(node)
206
+
207
+ def visit_AsyncFunctionDef(self, node: ast.AsyncFunctionDef) -> None:
208
+ for decorator in node.decorator_list:
209
+ consumer = _decorator_consumer(decorator)
210
+ if consumer is not None:
211
+ self.consumers.add(consumer)
212
+ self._visit_callable_or_class(node)
213
+
214
+ def visit_ClassDef(self, node: ast.ClassDef) -> None:
215
+ if any(_is_pydantic_base(base) for base in node.bases):
216
+ self.consumers.add(AnnotationConsumer.PYDANTIC_BASEMODEL)
217
+ for decorator in node.decorator_list:
218
+ consumer = _decorator_consumer(decorator)
219
+ if consumer is not None:
220
+ self.consumers.add(consumer)
221
+ self._visit_callable_or_class(node)
222
+
223
+ def visit_Call(self, node: ast.Call) -> None:
224
+ consumer = _call_consumer(node.func)
225
+ if consumer is not None:
226
+ self.consumers.add(consumer)
227
+ self.generic_visit(node)
228
+
229
+ def _visit_callable_or_class(
230
+ self,
231
+ node: ast.FunctionDef | ast.AsyncFunctionDef | ast.ClassDef,
232
+ ) -> None:
233
+ if self._scope_depth > 0:
234
+ self._record_nested_annotation_findings(node)
235
+ self._record_type_checking_annotation_findings(node)
236
+ self._scope_depth += 1
237
+ self.generic_visit(node)
238
+ self._scope_depth -= 1
239
+
240
+ def _record_type_checking_only_imports(self, statements: list[ast.stmt]) -> None:
241
+ for statement in statements:
242
+ if isinstance(statement, ast.Import):
243
+ for alias in statement.names:
244
+ self._type_checking_only_names.add(alias.asname or alias.name.split(".", 1)[0])
245
+ elif isinstance(statement, ast.ImportFrom):
246
+ for alias in statement.names:
247
+ if alias.name == "*":
248
+ continue
249
+ self._type_checking_only_names.add(alias.asname or alias.name)
250
+ elif isinstance(statement, ast.If) and _is_type_checking_guard(statement.test):
251
+ self._record_type_checking_only_imports(statement.body)
252
+
253
+ def _record_type_checking_annotation_findings(
254
+ self,
255
+ node: ast.FunctionDef | ast.AsyncFunctionDef | ast.ClassDef,
256
+ ) -> None:
257
+ if not self._type_checking_only_names:
258
+ return
259
+ for annotation in _node_annotations(node):
260
+ names = _annotation_names(annotation)
261
+ blocked = sorted(names & self._type_checking_only_names)
262
+ if not blocked:
263
+ continue
264
+ self.findings.append(
265
+ AnnotationAuditFinding(
266
+ code="TPY-A002",
267
+ message=(
268
+ "annotation references TYPE_CHECKING-only import(s) "
269
+ f"{', '.join(blocked)}; runtime annotation evaluation can fail or "
270
+ "reintroduce import cycles"
271
+ ),
272
+ line=annotation.lineno,
273
+ column=annotation.col_offset + 1,
274
+ )
275
+ )
276
+
277
+ def _record_nested_annotation_findings(
278
+ self,
279
+ node: ast.FunctionDef | ast.AsyncFunctionDef | ast.ClassDef,
280
+ ) -> None:
281
+ annotations = _node_annotations(node)
282
+ for annotation in annotations:
283
+ if _annotation_mentions_local_name(annotation):
284
+ self.findings.append(
285
+ AnnotationAuditFinding(
286
+ code="TPY-A001",
287
+ message=(
288
+ "annotation inside a local scope may be unavailable to runtime "
289
+ "consumers such as typing.get_type_hints or annotationlib.get_annotations"
290
+ ),
291
+ line=annotation.lineno,
292
+ column=annotation.col_offset + 1,
293
+ )
294
+ )
295
+
296
+
297
+ def _node_annotations(
298
+ node: ast.FunctionDef | ast.AsyncFunctionDef | ast.ClassDef,
299
+ ) -> list[ast.expr]:
300
+ annotations: list[ast.expr] = []
301
+ if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)):
302
+ for arg in [*node.args.posonlyargs, *node.args.args, *node.args.kwonlyargs]:
303
+ if arg.annotation is not None:
304
+ annotations.append(arg.annotation)
305
+ if node.args.vararg is not None and node.args.vararg.annotation is not None:
306
+ annotations.append(node.args.vararg.annotation)
307
+ if node.args.kwarg is not None and node.args.kwarg.annotation is not None:
308
+ annotations.append(node.args.kwarg.annotation)
309
+ if node.returns is not None:
310
+ annotations.append(node.returns)
311
+ return annotations
312
+
313
+ for statement in node.body:
314
+ if isinstance(statement, ast.AnnAssign) and statement.annotation is not None:
315
+ annotations.append(statement.annotation)
316
+ return annotations
317
+
318
+
319
+ def _annotation_mentions_local_name(annotation: ast.expr) -> bool:
320
+ if isinstance(annotation, ast.Constant) and isinstance(annotation.value, str):
321
+ return True
322
+ return any(isinstance(child, ast.Name) for child in ast.walk(annotation))
323
+
324
+
325
+ def _annotation_names(annotation: ast.expr) -> set[str]:
326
+ if isinstance(annotation, ast.Constant) and isinstance(annotation.value, str):
327
+ try:
328
+ annotation = ast.parse(annotation.value, mode="eval").body
329
+ except SyntaxError:
330
+ return set()
331
+ return {child.id for child in ast.walk(annotation) if isinstance(child, ast.Name)}
332
+
333
+
334
+ def _is_type_checking_guard(test: ast.expr) -> bool:
335
+ return _dotted_name(test) in {"TYPE_CHECKING", "typing.TYPE_CHECKING"}
336
+
337
+
338
+ def _call_consumer(func: ast.expr) -> AnnotationConsumer | None:
339
+ dotted = _dotted_name(func)
340
+ if dotted in {"typing.get_type_hints", "get_type_hints"}:
341
+ return AnnotationConsumer.TYPING_GET_TYPE_HINTS
342
+ if dotted == "inspect.get_annotations":
343
+ return AnnotationConsumer.INSPECT_GET_ANNOTATIONS
344
+ if dotted == "annotationlib.get_annotations":
345
+ return AnnotationConsumer.ANNOTATIONLIB_GET_ANNOTATIONS
346
+ if dotted in {"Depends", "fastapi.Depends"}:
347
+ return AnnotationConsumer.FASTAPI_DEPENDS
348
+ if dotted in {"Field", "pydantic.Field"}:
349
+ return AnnotationConsumer.PYDANTIC_FIELD
350
+ return None
351
+
352
+
353
+ def _decorator_consumer(decorator: ast.expr) -> AnnotationConsumer | None:
354
+ dotted = _dotted_name(decorator.func if isinstance(decorator, ast.Call) else decorator)
355
+ if dotted in {"dataclass", "dataclasses.dataclass"}:
356
+ return AnnotationConsumer.DATACLASS_DECORATOR
357
+ if _is_fastapi_route_decorator_name(dotted):
358
+ return AnnotationConsumer.FASTAPI_ROUTE_DECORATOR
359
+ return None
360
+
361
+
362
+ def _is_pydantic_base(expr: ast.expr) -> bool:
363
+ dotted = _dotted_name(expr)
364
+ return dotted in {"BaseModel", "pydantic.BaseModel"}
365
+
366
+
367
+ def _is_fastapi_route_decorator_name(dotted: str | None) -> bool:
368
+ if dotted is None:
369
+ return False
370
+ route_suffixes = {
371
+ "get",
372
+ "post",
373
+ "put",
374
+ "delete",
375
+ "patch",
376
+ "options",
377
+ "head",
378
+ "websocket",
379
+ "api_route",
380
+ }
381
+ suffix = dotted.rsplit(".", 1)[-1]
382
+ return suffix in route_suffixes
383
+
384
+
385
+ def _dotted_name(expr: ast.expr) -> str | None:
386
+ if isinstance(expr, ast.Name):
387
+ return expr.id
388
+ if isinstance(expr, ast.Attribute):
389
+ parent = _dotted_name(expr.value)
390
+ if parent is None:
391
+ return None
392
+ return f"{parent}.{expr.attr}"
393
+ return None
Binary file
@@ -1,118 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: type-python
3
- Version: 0.3.0
4
- Summary: A statically-typed authoring language that compiles to standard Python
5
- Author: unadlib
6
- License-Expression: MIT
7
- Project-URL: Homepage, https://github.com/type-python/type-python
8
- Project-URL: Repository, https://github.com/type-python/type-python
9
- Project-URL: Documentation, https://github.com/type-python/type-python/tree/main/docs
10
- Project-URL: Issues, https://github.com/type-python/type-python/issues
11
- Keywords: typepython,type-checking,compiler,python,static-typing
12
- Classifier: Development Status :: 3 - Alpha
13
- Classifier: Intended Audience :: Developers
14
- Classifier: Programming Language :: Python :: 3
15
- Classifier: Programming Language :: Python :: 3.9
16
- Classifier: Programming Language :: Python :: 3.10
17
- Classifier: Programming Language :: Python :: 3.11
18
- Classifier: Programming Language :: Python :: 3.12
19
- Classifier: Programming Language :: Rust
20
- Classifier: Topic :: Software Development :: Compilers
21
- Classifier: Topic :: Software Development :: Quality Assurance
22
- Classifier: Typing :: Typed
23
- Requires-Python: >=3.9
24
- Description-Content-Type: text/markdown
25
- License-File: LICENSE
26
- Dynamic: license-file
27
-
28
- <p align="center">
29
- <img src="https://raw.githubusercontent.com/type-python/type-python/main/logo.png" alt="TypePython" width="128" />
30
- </p>
31
-
32
- <h1 align="center">TypePython</h1>
33
-
34
- <p align="center">
35
- <strong>Write richer types. Emit standard Python.</strong>
36
- </p>
37
-
38
- ---
39
-
40
- A statically-typed authoring language that compiles to standard Python.
41
-
42
- Write `.tpy` source files with `interface`, `data class`, `sealed class`, inline generics, and strict null safety. The compiler emits standard `.py` + `.pyi` files for Python 3.10-3.14. No custom runtime, no vendor lock-in.
43
-
44
- ## Install
45
-
46
- ```bash
47
- pip install type-python
48
- typepython --help
49
- ```
50
-
51
- The Python package bridge supports **Python 3.9+**. Generated projects can target **Python 3.10 through 3.14**.
52
-
53
- Published wheels bundle the Rust CLI binary. Prebuilt wheels are available for Windows AMD64, macOS x86_64, macOS arm64, and Linux x86_64. Other platforms fall back to the source distribution and require Rust + `cargo`.
54
-
55
- ## Quick Start
56
-
57
- ```bash
58
- typepython init --dir my-project
59
- cd my-project
60
- typepython check --project .
61
- typepython build --project .
62
- ```
63
-
64
- Example source:
65
-
66
- ```python
67
- # src/app/__init__.tpy
68
-
69
- sealed class Expr:
70
- pass
71
-
72
- data class Num(Expr):
73
- value: int
74
-
75
- data class Add(Expr):
76
- left: Expr
77
- right: Expr
78
-
79
- def evaluate(expr: Expr) -> int:
80
- match expr:
81
- case Num(value=v):
82
- return v
83
- case Add(left=l, right=r):
84
- return evaluate(l) + evaluate(r)
85
- # Compiler proves all cases are covered -- no default needed.
86
- ```
87
-
88
- ## What You Get
89
-
90
- | Your code (`.tpy`) | Emitted output (`.py` / `.pyi`) |
91
- | --------------------------------- | -------------------------------------------------- |
92
- | `sealed class Expr:` | `class Expr: # tpy:sealed` |
93
- | `data class Num(Expr):` | `@dataclass` plus ordinary `class Num(Expr):` |
94
- | `interface Drawable:` | `class Drawable(Protocol):` |
95
- | `overload def f(x: int) -> int:` | `@overload` plus ordinary `def f(x: int) -> int:` |
96
- | `typealias Pair[T] = tuple[T, T]` | `T = TypeVar("T"); Pair: TypeAlias = tuple[T, T]` |
97
-
98
- - **Rich type system** -- `unknown`, `dynamic`, `Never`, strict nulls, sealed exhaustiveness, generic defaults, TypeVarTuple
99
- - **TypedDict utilities** -- `Partial`, `Required_`, `Readonly`, `Mutable`, `Pick`, `Omit`
100
- - **Full toolchain** -- `init`, `check`, `build`, `watch`, `clean`, `verify`, `lsp`, `migrate`
101
- - **LSP server** -- hover, go-to-definition, references, rename, completions, signature help, diagnostics
102
- - **Standard output** -- emitted `.py` + `.pyi` work with mypy, pyright, and ty out of the box
103
-
104
- ## Documentation
105
-
106
- - [Getting Started](https://github.com/type-python/type-python/blob/main/docs/getting-started.md)
107
- - [Syntax Guide](https://github.com/type-python/type-python/blob/main/docs/syntax-guide.md)
108
- - [Type System](https://github.com/type-python/type-python/blob/main/docs/type-system.md)
109
- - [Configuration](https://github.com/type-python/type-python/blob/main/docs/configuration.md)
110
- - [CLI Reference](https://github.com/type-python/type-python/blob/main/docs/cli-reference.md)
111
- - [Interoperability](https://github.com/type-python/type-python/blob/main/docs/interop.md)
112
- - [Language Spec](https://github.com/type-python/type-python/blob/main/docs/spec/language-spec-v1.md)
113
-
114
- ## Links
115
-
116
- - [Repository](https://github.com/type-python/type-python)
117
- - [Issues](https://github.com/type-python/type-python/issues)
118
- - [License (MIT)](https://github.com/type-python/type-python/blob/main/LICENSE)
@@ -1,11 +0,0 @@
1
- type_python-0.3.0.dist-info/licenses/LICENSE,sha256=BMHUZ3id_LOrEdv_GmAbL1ttlKsqjZz14f1_M1tn73k,1089
2
- typepython/__init__.py,sha256=j68Z_JZemkGBrmytvTfDu3VOUxN8C5Ajo7ZEpVt1gxY,308
3
- typepython/__main__.py,sha256=m8cggQyLAOSPtb8r-uUv_g53whMoPXtF2NX9yLuPyLg,89
4
- typepython/_runner.py,sha256=DySWPTud0FIAv2-0xhmwAyt_kk3w3kFJWK8FcYSe858,1777
5
- typepython/annotation_compat.py,sha256=VKUJEAj9NdDWr1j5cB2OIWlupmDyWVYvQkpJ2Jer2m8,4223
6
- typepython/bin/typepython.exe,sha256=TaX26_INBP-1J0PyIAIBlY3tAtKHiPppnUdH0HpJh0o,11883008
7
- type_python-0.3.0.dist-info/METADATA,sha256=YuEUMYng1t8GVUNRkFlbaIznUDQm44k4-CdksuxHLEc,4864
8
- type_python-0.3.0.dist-info/WHEEL,sha256=GjDPPQwEcripVP6P2r3RxLa-h5Lb9ifGB7FYYtbLDT0,98
9
- type_python-0.3.0.dist-info/entry_points.txt,sha256=B5Yjdi-RWaeRy7YUcni1lU_ya2lVZXM8llSFNSKEq0U,56
10
- type_python-0.3.0.dist-info/top_level.txt,sha256=JFRFjt3AXvRQ99SKMxUVu9e3TOp2QpspvE-jk85uMjU,11
11
- type_python-0.3.0.dist-info/RECORD,,