pywire 0.1.0__py3-none-any.whl → 0.1.1__py3-none-any.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.
- {pywire-0.1.0.dist-info → pywire-0.1.1.dist-info}/METADATA +23 -1
- pywire-0.1.1.dist-info/RECORD +9 -0
- pywire/__init__.py +0 -2
- pywire/cli/__init__.py +0 -1
- pywire/cli/generators.py +0 -48
- pywire/cli/main.py +0 -309
- pywire/cli/tui.py +0 -563
- pywire/cli/validate.py +0 -26
- pywire/client/.prettierignore +0 -8
- pywire/client/.prettierrc +0 -7
- pywire/client/build.mjs +0 -73
- pywire/client/eslint.config.js +0 -46
- pywire/client/package.json +0 -39
- pywire/client/pnpm-lock.yaml +0 -2971
- pywire/client/src/core/app.ts +0 -263
- pywire/client/src/core/dom-updater.test.ts +0 -78
- pywire/client/src/core/dom-updater.ts +0 -321
- pywire/client/src/core/index.ts +0 -5
- pywire/client/src/core/transport-manager.test.ts +0 -179
- pywire/client/src/core/transport-manager.ts +0 -159
- pywire/client/src/core/transports/base.ts +0 -122
- pywire/client/src/core/transports/http.ts +0 -142
- pywire/client/src/core/transports/index.ts +0 -13
- pywire/client/src/core/transports/websocket.ts +0 -97
- pywire/client/src/core/transports/webtransport.ts +0 -149
- pywire/client/src/dev/dev-app.ts +0 -93
- pywire/client/src/dev/error-trace.test.ts +0 -97
- pywire/client/src/dev/error-trace.ts +0 -76
- pywire/client/src/dev/index.ts +0 -4
- pywire/client/src/dev/status-overlay.ts +0 -63
- pywire/client/src/events/handler.test.ts +0 -318
- pywire/client/src/events/handler.ts +0 -454
- pywire/client/src/pywire.core.ts +0 -22
- pywire/client/src/pywire.dev.ts +0 -27
- pywire/client/tsconfig.json +0 -17
- pywire/client/vitest.config.ts +0 -15
- pywire/compiler/__init__.py +0 -6
- pywire/compiler/ast_nodes.py +0 -304
- pywire/compiler/attributes/__init__.py +0 -6
- pywire/compiler/attributes/base.py +0 -24
- pywire/compiler/attributes/conditional.py +0 -37
- pywire/compiler/attributes/events.py +0 -55
- pywire/compiler/attributes/form.py +0 -37
- pywire/compiler/attributes/loop.py +0 -75
- pywire/compiler/attributes/reactive.py +0 -34
- pywire/compiler/build.py +0 -28
- pywire/compiler/build_artifacts.py +0 -342
- pywire/compiler/codegen/__init__.py +0 -5
- pywire/compiler/codegen/attributes/__init__.py +0 -6
- pywire/compiler/codegen/attributes/base.py +0 -19
- pywire/compiler/codegen/attributes/events.py +0 -35
- pywire/compiler/codegen/directives/__init__.py +0 -6
- pywire/compiler/codegen/directives/base.py +0 -16
- pywire/compiler/codegen/directives/path.py +0 -53
- pywire/compiler/codegen/generator.py +0 -2341
- pywire/compiler/codegen/template.py +0 -2178
- pywire/compiler/directives/__init__.py +0 -7
- pywire/compiler/directives/base.py +0 -20
- pywire/compiler/directives/component.py +0 -33
- pywire/compiler/directives/context.py +0 -93
- pywire/compiler/directives/layout.py +0 -49
- pywire/compiler/directives/no_spa.py +0 -24
- pywire/compiler/directives/path.py +0 -71
- pywire/compiler/directives/props.py +0 -88
- pywire/compiler/exceptions.py +0 -19
- pywire/compiler/interpolation/__init__.py +0 -6
- pywire/compiler/interpolation/base.py +0 -28
- pywire/compiler/interpolation/jinja.py +0 -272
- pywire/compiler/parser.py +0 -750
- pywire/compiler/paths.py +0 -29
- pywire/compiler/preprocessor.py +0 -43
- pywire/core/wire.py +0 -119
- pywire/py.typed +0 -0
- pywire/runtime/__init__.py +0 -7
- pywire/runtime/aioquic_server.py +0 -194
- pywire/runtime/app.py +0 -889
- pywire/runtime/compile_error_page.py +0 -195
- pywire/runtime/debug.py +0 -203
- pywire/runtime/dev_server.py +0 -434
- pywire/runtime/dev_server.py.broken +0 -268
- pywire/runtime/error_page.py +0 -64
- pywire/runtime/error_renderer.py +0 -23
- pywire/runtime/escape.py +0 -23
- pywire/runtime/files.py +0 -40
- pywire/runtime/helpers.py +0 -97
- pywire/runtime/http_transport.py +0 -253
- pywire/runtime/loader.py +0 -272
- pywire/runtime/logging.py +0 -72
- pywire/runtime/page.py +0 -384
- pywire/runtime/pydantic_integration.py +0 -52
- pywire/runtime/router.py +0 -229
- pywire/runtime/server.py +0 -25
- pywire/runtime/style_collector.py +0 -31
- pywire/runtime/upload_manager.py +0 -76
- pywire/runtime/validation.py +0 -449
- pywire/runtime/websocket.py +0 -665
- pywire/runtime/webtransport_handler.py +0 -195
- pywire-0.1.0.dist-info/RECORD +0 -104
- {pywire-0.1.0.dist-info → pywire-0.1.1.dist-info}/WHEEL +0 -0
- {pywire-0.1.0.dist-info → pywire-0.1.1.dist-info}/entry_points.txt +0 -0
- {pywire-0.1.0.dist-info → pywire-0.1.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
"""Directive parsers."""
|
|
2
|
-
|
|
3
|
-
from pywire.compiler.directives.base import DirectiveParser
|
|
4
|
-
from pywire.compiler.directives.no_spa import NoSpaDirectiveParser
|
|
5
|
-
from pywire.compiler.directives.path import PathDirectiveParser
|
|
6
|
-
|
|
7
|
-
__all__ = ["DirectiveParser", "PathDirectiveParser", "NoSpaDirectiveParser"]
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
"""Base directive parser."""
|
|
2
|
-
|
|
3
|
-
from abc import ABC, abstractmethod
|
|
4
|
-
from typing import Optional
|
|
5
|
-
|
|
6
|
-
from pywire.compiler.ast_nodes import Directive
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
class DirectiveParser(ABC):
|
|
10
|
-
"""Base class for parsing directives - extensible for new directives."""
|
|
11
|
-
|
|
12
|
-
@abstractmethod
|
|
13
|
-
def can_parse(self, line: str) -> bool:
|
|
14
|
-
"""Check if this parser can handle the given line."""
|
|
15
|
-
pass
|
|
16
|
-
|
|
17
|
-
@abstractmethod
|
|
18
|
-
def parse(self, line: str, line_num: int, col_num: int) -> Optional[Directive]:
|
|
19
|
-
"""Parse directive from line. Returns None if not applicable."""
|
|
20
|
-
pass
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import re
|
|
2
|
-
from typing import Optional
|
|
3
|
-
|
|
4
|
-
from pywire.compiler.ast_nodes import ComponentDirective, Directive
|
|
5
|
-
from pywire.compiler.directives.base import DirectiveParser
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class ComponentDirectiveParser(DirectiveParser):
|
|
9
|
-
"""Parses !component 'path' as Name"""
|
|
10
|
-
|
|
11
|
-
def can_parse(self, line: str) -> bool:
|
|
12
|
-
return line.startswith("!component")
|
|
13
|
-
|
|
14
|
-
def parse(self, line: str, line_num: int, col_num: int) -> Optional[Directive]:
|
|
15
|
-
# Format: !component 'path/to/file' as ComponentName
|
|
16
|
-
# or !component "path/to/file" as ComponentName
|
|
17
|
-
|
|
18
|
-
# Regex to match: !component\s+['"](.+?)['"]\s+as\s+(\w+)
|
|
19
|
-
match = re.search(r"^!component\s+['\"](.+?)['\"]\s+as\s+(\w+)", line)
|
|
20
|
-
if not match:
|
|
21
|
-
# Maybe invalid format
|
|
22
|
-
return None
|
|
23
|
-
|
|
24
|
-
path = match.group(1)
|
|
25
|
-
name = match.group(2)
|
|
26
|
-
|
|
27
|
-
return ComponentDirective(
|
|
28
|
-
line=line_num,
|
|
29
|
-
column=col_num,
|
|
30
|
-
name="!component",
|
|
31
|
-
path=path,
|
|
32
|
-
component_name=name,
|
|
33
|
-
)
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
import ast
|
|
2
|
-
from typing import Optional
|
|
3
|
-
|
|
4
|
-
from pywire.compiler.ast_nodes import Directive, InjectDirective, ProvideDirective
|
|
5
|
-
from pywire.compiler.directives.base import DirectiveParser
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class ContextDirectiveParser(DirectiveParser):
|
|
9
|
-
"""Parses !inject and !provide"""
|
|
10
|
-
|
|
11
|
-
def can_parse(self, line: str) -> bool:
|
|
12
|
-
return line.startswith("!inject") or line.startswith("!provide")
|
|
13
|
-
|
|
14
|
-
def parse(self, line: str, line_num: int, col_num: int) -> Optional[Directive]:
|
|
15
|
-
is_inject = line.startswith("!inject")
|
|
16
|
-
directive_name = "!inject" if is_inject else "!provide"
|
|
17
|
-
|
|
18
|
-
content = line[len(directive_name) :].strip()
|
|
19
|
-
|
|
20
|
-
# Wrapped in dict braces?
|
|
21
|
-
if not content.startswith("{") or not content.endswith("}"):
|
|
22
|
-
# Maybe they omitted braces? Let's assume strict syntax for now as per design doc
|
|
23
|
-
# !inject { ... }
|
|
24
|
-
return None
|
|
25
|
-
|
|
26
|
-
try:
|
|
27
|
-
# Parse as a dictionary expression
|
|
28
|
-
# code: _ = { ... }
|
|
29
|
-
dummy_code = f"_ = {content}"
|
|
30
|
-
mod = ast.parse(dummy_code)
|
|
31
|
-
assign = mod.body[0]
|
|
32
|
-
if not isinstance(assign, ast.Assign) or not isinstance(
|
|
33
|
-
assign.value, ast.Dict
|
|
34
|
-
):
|
|
35
|
-
return None
|
|
36
|
-
|
|
37
|
-
dict_node = assign.value
|
|
38
|
-
|
|
39
|
-
mapping = {}
|
|
40
|
-
|
|
41
|
-
for key_node, value_node in zip(dict_node.keys, dict_node.values):
|
|
42
|
-
if is_inject:
|
|
43
|
-
# !inject { local_var: 'GLOBAL_KEY' }
|
|
44
|
-
# key should be the local variable name (Name node or Constant string)
|
|
45
|
-
# value should be the context key (Constant string)
|
|
46
|
-
|
|
47
|
-
local_var = None
|
|
48
|
-
if isinstance(key_node, ast.Name):
|
|
49
|
-
local_var = key_node.id
|
|
50
|
-
elif isinstance(key_node, ast.Constant) and isinstance(
|
|
51
|
-
key_node.value, str
|
|
52
|
-
):
|
|
53
|
-
local_var = key_node.value
|
|
54
|
-
|
|
55
|
-
global_key = None
|
|
56
|
-
if isinstance(value_node, ast.Constant) and isinstance(
|
|
57
|
-
value_node.value, str
|
|
58
|
-
):
|
|
59
|
-
global_key = value_node.value
|
|
60
|
-
|
|
61
|
-
if local_var and global_key:
|
|
62
|
-
mapping[local_var] = global_key
|
|
63
|
-
|
|
64
|
-
else:
|
|
65
|
-
# !provide { 'GLOBAL_KEY': local_expr }
|
|
66
|
-
# key must be string
|
|
67
|
-
# value is expression to be evaluated at runtime
|
|
68
|
-
|
|
69
|
-
global_key = None
|
|
70
|
-
if isinstance(key_node, ast.Constant) and isinstance(
|
|
71
|
-
key_node.value, str
|
|
72
|
-
):
|
|
73
|
-
global_key = key_node.value
|
|
74
|
-
|
|
75
|
-
# Convert value node back to source string to be put in generated code
|
|
76
|
-
val_expr = ""
|
|
77
|
-
if hasattr(ast, "unparse"):
|
|
78
|
-
val_expr = ast.unparse(value_node)
|
|
79
|
-
|
|
80
|
-
if global_key:
|
|
81
|
-
mapping[global_key] = val_expr
|
|
82
|
-
|
|
83
|
-
if is_inject:
|
|
84
|
-
return InjectDirective(
|
|
85
|
-
line=line_num, column=col_num, name="!inject", mapping=mapping
|
|
86
|
-
)
|
|
87
|
-
else:
|
|
88
|
-
return ProvideDirective(
|
|
89
|
-
line=line_num, column=col_num, name="!provide", mapping=mapping
|
|
90
|
-
)
|
|
91
|
-
|
|
92
|
-
except Exception:
|
|
93
|
-
return None
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
"""Layout directive parser."""
|
|
2
|
-
|
|
3
|
-
import ast
|
|
4
|
-
import re
|
|
5
|
-
from typing import Optional
|
|
6
|
-
|
|
7
|
-
from pywire.compiler.ast_nodes import LayoutDirective
|
|
8
|
-
from pywire.compiler.directives.base import DirectiveParser
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
class LayoutDirectiveParser(DirectiveParser):
|
|
12
|
-
"""Parses !layout directives."""
|
|
13
|
-
|
|
14
|
-
PATTERN = re.compile(r"^!layout\s+(.+)$", re.DOTALL)
|
|
15
|
-
|
|
16
|
-
def can_parse(self, line: str) -> bool:
|
|
17
|
-
"""Check if line starts with !layout."""
|
|
18
|
-
return line.strip().startswith("!layout")
|
|
19
|
-
|
|
20
|
-
def parse(
|
|
21
|
-
self, line: str, line_num: int, col_num: int
|
|
22
|
-
) -> Optional[LayoutDirective]:
|
|
23
|
-
"""Parse !layout "path/to/layout" directive."""
|
|
24
|
-
match = self.PATTERN.match(line.strip())
|
|
25
|
-
if not match:
|
|
26
|
-
return None
|
|
27
|
-
|
|
28
|
-
path_str = match.group(1).strip()
|
|
29
|
-
if not path_str:
|
|
30
|
-
return None
|
|
31
|
-
|
|
32
|
-
try:
|
|
33
|
-
# Parse python string
|
|
34
|
-
# We expect a simple string literal
|
|
35
|
-
expr_ast = ast.parse(path_str, mode="eval")
|
|
36
|
-
|
|
37
|
-
if isinstance(expr_ast.body, ast.Constant) and isinstance(
|
|
38
|
-
expr_ast.body.value, str
|
|
39
|
-
):
|
|
40
|
-
return LayoutDirective(
|
|
41
|
-
name="layout",
|
|
42
|
-
layout_path=expr_ast.body.value,
|
|
43
|
-
line=line_num,
|
|
44
|
-
column=col_num,
|
|
45
|
-
)
|
|
46
|
-
|
|
47
|
-
return None
|
|
48
|
-
except (SyntaxError, ValueError, AttributeError):
|
|
49
|
-
return None
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
"""No-SPA directive parser."""
|
|
2
|
-
|
|
3
|
-
import re
|
|
4
|
-
from typing import Optional
|
|
5
|
-
|
|
6
|
-
from pywire.compiler.ast_nodes import NoSpaDirective
|
|
7
|
-
from pywire.compiler.directives.base import DirectiveParser
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
class NoSpaDirectiveParser(DirectiveParser):
|
|
11
|
-
"""Parses !no_spa directive to disable client-side navigation."""
|
|
12
|
-
|
|
13
|
-
PATTERN = re.compile(r"^!no_spa\s*$")
|
|
14
|
-
|
|
15
|
-
def can_parse(self, line: str) -> bool:
|
|
16
|
-
"""Check if line is !no_spa."""
|
|
17
|
-
return line.strip() == "!no_spa"
|
|
18
|
-
|
|
19
|
-
def parse(self, line: str, line_num: int, col_num: int) -> Optional[NoSpaDirective]:
|
|
20
|
-
"""Parse !no_spa directive."""
|
|
21
|
-
if not self.PATTERN.match(line.strip()):
|
|
22
|
-
return None
|
|
23
|
-
|
|
24
|
-
return NoSpaDirective(name="no_spa", line=line_num, column=col_num)
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
"""Path directive parser."""
|
|
2
|
-
|
|
3
|
-
import ast
|
|
4
|
-
import re
|
|
5
|
-
from typing import Dict, Optional
|
|
6
|
-
|
|
7
|
-
from pywire.compiler.ast_nodes import PathDirective
|
|
8
|
-
from pywire.compiler.directives.base import DirectiveParser
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
class PathDirectiveParser(DirectiveParser):
|
|
12
|
-
"""Parses !path directives."""
|
|
13
|
-
|
|
14
|
-
PATTERN = re.compile(r"^!path\s+(.+)$", re.DOTALL)
|
|
15
|
-
|
|
16
|
-
def can_parse(self, line: str) -> bool:
|
|
17
|
-
"""Check if line starts with !path."""
|
|
18
|
-
return line.strip().startswith("!path")
|
|
19
|
-
|
|
20
|
-
def parse(self, line: str, line_num: int, col_num: int) -> Optional[PathDirective]:
|
|
21
|
-
"""Parse !path { 'name': '/route' } directive."""
|
|
22
|
-
match = self.PATTERN.match(line.strip())
|
|
23
|
-
if not match:
|
|
24
|
-
return None
|
|
25
|
-
|
|
26
|
-
routes_str = match.group(1).strip()
|
|
27
|
-
if not routes_str:
|
|
28
|
-
return None
|
|
29
|
-
|
|
30
|
-
try:
|
|
31
|
-
# Parse python expression
|
|
32
|
-
expr_ast = ast.parse(routes_str, mode="eval")
|
|
33
|
-
|
|
34
|
-
# Case 1: Dictionary !path {'main': '/'}
|
|
35
|
-
if isinstance(expr_ast.body, ast.Dict):
|
|
36
|
-
routes: Dict[str, str] = {}
|
|
37
|
-
for key_node, value_node in zip(
|
|
38
|
-
expr_ast.body.keys, expr_ast.body.values
|
|
39
|
-
):
|
|
40
|
-
if (
|
|
41
|
-
not isinstance(key_node, ast.Constant)
|
|
42
|
-
or not isinstance(key_node.value, str)
|
|
43
|
-
or not isinstance(value_node, ast.Constant)
|
|
44
|
-
or not isinstance(value_node.value, str)
|
|
45
|
-
):
|
|
46
|
-
return None
|
|
47
|
-
routes[key_node.value] = value_node.value
|
|
48
|
-
|
|
49
|
-
return PathDirective(
|
|
50
|
-
name="path",
|
|
51
|
-
routes=routes,
|
|
52
|
-
is_simple_string=False,
|
|
53
|
-
line=line_num,
|
|
54
|
-
column=col_num,
|
|
55
|
-
)
|
|
56
|
-
|
|
57
|
-
# Case 2: String !path '/test'
|
|
58
|
-
elif isinstance(expr_ast.body, ast.Constant) and isinstance(
|
|
59
|
-
expr_ast.body.value, str
|
|
60
|
-
):
|
|
61
|
-
return PathDirective(
|
|
62
|
-
name="path",
|
|
63
|
-
routes={"main": expr_ast.body.value},
|
|
64
|
-
is_simple_string=True,
|
|
65
|
-
line=line_num,
|
|
66
|
-
column=col_num,
|
|
67
|
-
)
|
|
68
|
-
|
|
69
|
-
return None
|
|
70
|
-
except (SyntaxError, ValueError, AttributeError):
|
|
71
|
-
return None
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import ast
|
|
2
|
-
from typing import List, Optional, Tuple
|
|
3
|
-
|
|
4
|
-
from pywire.compiler.ast_nodes import Directive, PropsDirective
|
|
5
|
-
from pywire.compiler.directives.base import DirectiveParser
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class PropsDirectiveParser(DirectiveParser):
|
|
9
|
-
"""Parses !props(name: type, arg=default)"""
|
|
10
|
-
|
|
11
|
-
def can_parse(self, line: str) -> bool:
|
|
12
|
-
return line.startswith("!props")
|
|
13
|
-
|
|
14
|
-
def parse(self, line: str, line_num: int, col_num: int) -> Optional[Directive]:
|
|
15
|
-
# Format: !props(arg: type, arg2=default)
|
|
16
|
-
|
|
17
|
-
# 1. Extract content inside parentheses
|
|
18
|
-
# Note: 'line' might be multiline string passed from parser.
|
|
19
|
-
# We assume the parser handles accumulation until matching parens if needed.
|
|
20
|
-
# Or we rely on the fact that directives are usually single line or we need to handle it.
|
|
21
|
-
# The main parser accumulates if braces/brackets match, but what about parens?
|
|
22
|
-
# The main parser logic: "Count open braces/brackets". It does NOT count parens currently.
|
|
23
|
-
# We might need to update the main parser to also count parens for !props?
|
|
24
|
-
# For now, let's assume it's passed correctly or single line.
|
|
25
|
-
|
|
26
|
-
# Strip '!props'
|
|
27
|
-
content = line[len("!props") :].strip()
|
|
28
|
-
if not content.startswith("(") or not content.endswith(")"):
|
|
29
|
-
return None
|
|
30
|
-
|
|
31
|
-
# content is "(...)"
|
|
32
|
-
|
|
33
|
-
# 2. Use AST parsing by wrapping in a function def
|
|
34
|
-
# This handles complex types, strings with commas, etc.
|
|
35
|
-
dummy_code = f"def _p{content}: pass"
|
|
36
|
-
|
|
37
|
-
try:
|
|
38
|
-
mod = ast.parse(dummy_code)
|
|
39
|
-
func_def = mod.body[0]
|
|
40
|
-
if not isinstance(func_def, ast.FunctionDef):
|
|
41
|
-
return None
|
|
42
|
-
|
|
43
|
-
args = func_def.args
|
|
44
|
-
|
|
45
|
-
parsed_args: List[Tuple[str, str, Optional[str]]] = []
|
|
46
|
-
|
|
47
|
-
# Helper to get source segment if possible, or unparse
|
|
48
|
-
def unparse_node(node: ast.AST) -> str:
|
|
49
|
-
if hasattr(ast, "unparse"):
|
|
50
|
-
source = ast.unparse(node)
|
|
51
|
-
# ast.unparse might return something slightly different formatted,
|
|
52
|
-
# which is fine for type strings
|
|
53
|
-
return source
|
|
54
|
-
return "" # Fallback for older python if needed, but we likely preserve 3.9+
|
|
55
|
-
|
|
56
|
-
# Process args (normal arguments)
|
|
57
|
-
# defaults are at the end of the list.
|
|
58
|
-
# e.g. args.args = [a, b], args.defaults = [def_b] -> a has no default, b has def_b
|
|
59
|
-
|
|
60
|
-
num_args = len(args.args)
|
|
61
|
-
num_defaults = len(args.defaults)
|
|
62
|
-
offset = num_args - num_defaults
|
|
63
|
-
|
|
64
|
-
for i, arg in enumerate(args.args):
|
|
65
|
-
name = arg.arg
|
|
66
|
-
type_hint = "Any"
|
|
67
|
-
if arg.annotation:
|
|
68
|
-
type_hint = unparse_node(arg.annotation)
|
|
69
|
-
|
|
70
|
-
default_val = None
|
|
71
|
-
if i >= offset:
|
|
72
|
-
default_idx = i - offset
|
|
73
|
-
default_val = unparse_node(args.defaults[default_idx])
|
|
74
|
-
|
|
75
|
-
parsed_args.append((name, type_hint, default_val))
|
|
76
|
-
|
|
77
|
-
# TODO: Handle kwonlyargs if we want to enforce keyword only props?
|
|
78
|
-
# For now simple args.
|
|
79
|
-
|
|
80
|
-
return PropsDirective(
|
|
81
|
-
line=line_num, column=col_num, name="!props", args=parsed_args
|
|
82
|
-
)
|
|
83
|
-
|
|
84
|
-
except SyntaxError:
|
|
85
|
-
# Invalid python syntax in props
|
|
86
|
-
return None
|
|
87
|
-
except Exception:
|
|
88
|
-
return None
|
pywire/compiler/exceptions.py
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
"""Compiler exceptions."""
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
class PyWireSyntaxError(Exception):
|
|
5
|
-
"""Raised when PyWire syntax is invalid."""
|
|
6
|
-
|
|
7
|
-
def __init__(
|
|
8
|
-
self, message: str, file_path: str = "", line: int = 0, column: int = 0
|
|
9
|
-
):
|
|
10
|
-
self.message = message
|
|
11
|
-
self.file_path = file_path
|
|
12
|
-
self.line = line
|
|
13
|
-
self.column = column
|
|
14
|
-
super().__init__(message)
|
|
15
|
-
|
|
16
|
-
def __str__(self) -> str:
|
|
17
|
-
if self.file_path and self.line:
|
|
18
|
-
return f"{self.file_path}:{self.line}: {self.message}"
|
|
19
|
-
return self.message
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
"""Base interpolation parser."""
|
|
2
|
-
|
|
3
|
-
from abc import ABC, abstractmethod
|
|
4
|
-
from typing import List, Union
|
|
5
|
-
|
|
6
|
-
from pywire.compiler.ast_nodes import InterpolationNode
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
class InterpolationParser(ABC):
|
|
10
|
-
"""Base class for parsing interpolations - can swap Jinja for custom later."""
|
|
11
|
-
|
|
12
|
-
@abstractmethod
|
|
13
|
-
def parse(
|
|
14
|
-
self, text: str, line: int, col: int
|
|
15
|
-
) -> List[Union[str, InterpolationNode]]:
|
|
16
|
-
"""
|
|
17
|
-
Parse text with interpolations into mix of strings and InterpolationNodes.
|
|
18
|
-
Returns: ['Hello, ', InterpolationNode(expr='name'), '!']
|
|
19
|
-
"""
|
|
20
|
-
pass
|
|
21
|
-
|
|
22
|
-
@abstractmethod
|
|
23
|
-
def compile(self, text: str) -> str:
|
|
24
|
-
"""
|
|
25
|
-
Compile to Python code for runtime.
|
|
26
|
-
'Hello {name}!' → f'Hello {self.name}!'
|
|
27
|
-
"""
|
|
28
|
-
pass
|