xtce2py 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 (37) hide show
  1. xtce2py-0.1.0/LICENSE +21 -0
  2. xtce2py-0.1.0/PKG-INFO +27 -0
  3. xtce2py-0.1.0/README.md +4 -0
  4. xtce2py-0.1.0/pyproject.toml +90 -0
  5. xtce2py-0.1.0/src/xtce2py/__init__.py +12 -0
  6. xtce2py-0.1.0/src/xtce2py/_validation.py +31 -0
  7. xtce2py-0.1.0/src/xtce2py/config.py +88 -0
  8. xtce2py-0.1.0/src/xtce2py/context_models.py +76 -0
  9. xtce2py-0.1.0/src/xtce2py/generator.py +209 -0
  10. xtce2py-0.1.0/src/xtce2py/main.py +332 -0
  11. xtce2py-0.1.0/src/xtce2py/static/_decoding.py +90 -0
  12. xtce2py-0.1.0/src/xtce2py/static/setup.py +6 -0
  13. xtce2py-0.1.0/src/xtce2py/templates/README.md.j2 +48 -0
  14. xtce2py-0.1.0/src/xtce2py/templates/__init__.py.j2 +11 -0
  15. xtce2py-0.1.0/src/xtce2py/templates/models.py.j2 +47 -0
  16. xtce2py-0.1.0/src/xtce2py/templates/pyproject.toml.j2 +37 -0
  17. xtce2py-0.1.0/src/xtce2py/templates/simple_parser.py.j2 +0 -0
  18. xtce2py-0.1.0/src/xtce2py/templates/tree_parser.py.j2 +312 -0
  19. xtce2py-0.1.0/src/xtce2py/utils.py +78 -0
  20. xtce2py-0.1.0/src/xtce2py/xtce.py +142 -0
  21. xtce2py-0.1.0/src/xtce2py/xtce_1_1/__init__.py +281 -0
  22. xtce2py-0.1.0/src/xtce2py/xtce_1_1/context_models.py +4 -0
  23. xtce2py-0.1.0/src/xtce2py/xtce_1_1/dtc-06-11-06.xsd +3229 -0
  24. xtce2py-0.1.0/src/xtce2py/xtce_1_1/dtc_06_11_06.py +6589 -0
  25. xtce2py-0.1.0/src/xtce2py/xtce_1_1/parser.py +902 -0
  26. xtce2py-0.1.0/src/xtce2py/xtce_1_2/__init__.py +635 -0
  27. xtce2py-0.1.0/src/xtce2py/xtce_1_2/dtc-18-02-04.xsd +5918 -0
  28. xtce2py-0.1.0/src/xtce2py/xtce_1_2/dtc_18_02_04.py +10370 -0
  29. xtce2py-0.1.0/src/xtce2py/xtce_1_2/parser.py +27 -0
  30. xtce2py-0.1.0/src/xtce2py/xtce_1_3/__init__.py +647 -0
  31. xtce2py-0.1.0/src/xtce2py/xtce_1_3/dtc-25-02-18.xsd +6363 -0
  32. xtce2py-0.1.0/src/xtce2py/xtce_1_3/dtc_25_02_18.py +11011 -0
  33. xtce2py-0.1.0/src/xtce2py/xtce_1_3/parser.py +27 -0
  34. xtce2py-0.1.0/src/xtce2py/xtce_common/__init__.py +8 -0
  35. xtce2py-0.1.0/src/xtce2py/xtce_common/context_models.py +101 -0
  36. xtce2py-0.1.0/src/xtce2py/xtce_common/data_types.py +57 -0
  37. xtce2py-0.1.0/tests/test.py +16 -0
xtce2py-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 nrmiersen
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.
xtce2py-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,27 @@
1
+ Metadata-Version: 2.4
2
+ Name: xtce2py
3
+ Version: 0.1.0
4
+ Summary: A generator for creating a Python package from an XTCE file.
5
+ Author-Email: Nathan Miersen <nrmiersen@gmail.com>
6
+ License-Expression: MIT
7
+ Classifier: Development Status :: 3 - Alpha
8
+ Classifier: Programming Language :: Python :: 3
9
+ Project-URL: Homepage, https://github.com/nrmiersen/xtce2py
10
+ Project-URL: Repository, https://github.com/nrmiersen/xtce2py
11
+ Requires-Python: >=3.11
12
+ Requires-Dist: pydantic>=2.11.7
13
+ Requires-Dist: xsdata>=25.7
14
+ Requires-Dist: jinja2>=3.1.6
15
+ Requires-Dist: ruff>=0.12.4
16
+ Requires-Dist: docformatter>=1.7.7
17
+ Requires-Dist: typer[rich]>=0.16.0
18
+ Requires-Dist: setuptools>=80.9.0
19
+ Requires-Dist: lxml>=6.0.0
20
+ Requires-Dist: lxml-stubs>=0.5.1
21
+ Requires-Dist: pydantic-settings>=2.11.0
22
+ Description-Content-Type: text/markdown
23
+
24
+ # xtce2py
25
+ Generates a Python package from a source XTCE file.
26
+
27
+ **Alpha Software:** This package is currently in the alpha stage of development. The API is not stable and is subject to breaking changes in future releases. Please use with caution and report any bugs or issues you find.
@@ -0,0 +1,4 @@
1
+ # xtce2py
2
+ Generates a Python package from a source XTCE file.
3
+
4
+ **Alpha Software:** This package is currently in the alpha stage of development. The API is not stable and is subject to breaking changes in future releases. Please use with caution and report any bugs or issues you find.
@@ -0,0 +1,90 @@
1
+ [build-system]
2
+ requires = [
3
+ "pdm-backend",
4
+ ]
5
+ build-backend = "pdm.backend"
6
+
7
+ [project]
8
+ name = "xtce2py"
9
+ version = "0.1.0"
10
+ description = "A generator for creating a Python package from an XTCE file."
11
+ authors = [
12
+ { name = "Nathan Miersen", email = "nrmiersen@gmail.com" },
13
+ ]
14
+ classifiers = [
15
+ "Development Status :: 3 - Alpha",
16
+ "Programming Language :: Python :: 3",
17
+ ]
18
+ dependencies = [
19
+ "pydantic>=2.11.7",
20
+ "xsdata>=25.7",
21
+ "jinja2>=3.1.6",
22
+ "ruff>=0.12.4",
23
+ "docformatter>=1.7.7",
24
+ "typer[rich]>=0.16.0",
25
+ "setuptools>=80.9.0",
26
+ "lxml>=6.0.0",
27
+ "lxml-stubs>=0.5.1",
28
+ "pydantic-settings>=2.11.0",
29
+ ]
30
+ requires-python = ">=3.11"
31
+ readme = "README.md"
32
+ license = "MIT"
33
+
34
+ [project.scripts]
35
+ xtce2py = "xtce2py.main:app"
36
+
37
+ [project.urls]
38
+ Homepage = "https://github.com/nrmiersen/xtce2py"
39
+ Repository = "https://github.com/nrmiersen/xtce2py"
40
+
41
+ [dependency-groups]
42
+ dev = [
43
+ "xsdata[cli]>=25.7",
44
+ "bitstring>=4.3.1",
45
+ ]
46
+
47
+ [tool.pdm]
48
+ distribution = true
49
+
50
+ [tool.pdm.scripts]
51
+ xtce2py = "python -m xtce2py.main"
52
+
53
+ [tool.setuptools.package-data]
54
+ xtce2py = [
55
+ "static/*",
56
+ "templates/*",
57
+ "xtce_1_1/*.xsd",
58
+ "xtce_1_2/*.xsd",
59
+ "xtce_1_3/*.xsd",
60
+ ]
61
+
62
+ [tool.ruff]
63
+ line-length = 88
64
+ exclude = [
65
+ "src/xtce2py/xtce_1_1/dtc_06_11_06.py",
66
+ "src/xtce2py/xtce_1_2/dtc_18_02_04.py",
67
+ "src/xtce2py/xtce_1_3/dtc_25_02_18.py",
68
+ ]
69
+
70
+ [tool.ruff.lint]
71
+ select = [
72
+ "D",
73
+ "I",
74
+ ]
75
+ ignore = [
76
+ "D203",
77
+ "D213",
78
+ ]
79
+
80
+ [tool.ruff.lint.isort]
81
+ known-first-party = [
82
+ "xtce2py",
83
+ ]
84
+
85
+ [tool.ruff.format]
86
+ docstring-code-format = true
87
+
88
+ [tool.docformatter]
89
+ wrap-summaries = 72
90
+ wrap-descriptions = 72
@@ -0,0 +1,12 @@
1
+ """Top level package for xtce2py."""
2
+
3
+ from xtce2py import config, generator, xtce_1_1, xtce_1_2, xtce_1_3, xtce_common
4
+
5
+ __all__ = [
6
+ "config",
7
+ "generator",
8
+ "xtce_1_1",
9
+ "xtce_1_2",
10
+ "xtce_1_3",
11
+ "xtce_common",
12
+ ]
@@ -0,0 +1,31 @@
1
+ """Validation-related data structures and exceptions."""
2
+
3
+ import enum
4
+ from dataclasses import dataclass
5
+ from typing import List
6
+
7
+
8
+ class ValidationSeverity(enum.Enum):
9
+ """Enumeration for the severity of a validation issue."""
10
+
11
+ ERROR = "ERROR"
12
+ WARNING = "WARNING"
13
+
14
+
15
+ @dataclass
16
+ class ValidationResult:
17
+ """A structured container for a single validation finding."""
18
+
19
+ severity: ValidationSeverity
20
+ message: str
21
+ location: str
22
+
23
+
24
+ class XtceSemanticValidationError(Exception):
25
+ """Custom exception raised when fatal semantic errors are found."""
26
+
27
+ def __init__(self, errors: List[ValidationResult]):
28
+ """Initialize with a list of validation errors."""
29
+ self.errors = errors
30
+ error_list = "\n".join(f" - [in {e.location}]: {e.message}" for e in errors)
31
+ super().__init__(f"XTCE file has semantic validation errors:\n{error_list}")
@@ -0,0 +1,88 @@
1
+ """Global configuration settings."""
2
+
3
+ import functools
4
+ from pathlib import Path
5
+ from typing import Literal
6
+
7
+ from pydantic import BaseModel, field_validator
8
+ from pydantic_settings import (
9
+ BaseSettings,
10
+ PydanticBaseSettingsSource,
11
+ SettingsConfigDict,
12
+ TomlConfigSettingsSource,
13
+ )
14
+
15
+
16
+ class LoggingSettings(BaseModel):
17
+ """Logging configuration settings."""
18
+
19
+ level: Literal["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"] | None = None
20
+ file: Path | None = None
21
+
22
+ @field_validator("file", mode="before")
23
+ @classmethod
24
+ def expand_path(cls, v):
25
+ """Expand user home directory and resolve path."""
26
+ if v is None:
27
+ return v
28
+ if isinstance(v, str):
29
+ # Expand ~ to user home directory
30
+ return Path(v).expanduser()
31
+ return v
32
+
33
+
34
+ class AuthorSettings(BaseModel):
35
+ """Author information for output package."""
36
+
37
+ name: str = "Anonymous"
38
+ email: str = "user@example.com"
39
+
40
+
41
+ class PackageDefaults(BaseModel):
42
+ """Default values for package generation."""
43
+
44
+ suffix: str = "toolkit"
45
+ version: str = "1.0.0"
46
+ license: str = "MIT"
47
+
48
+
49
+ class NamingSettings(BaseModel):
50
+ """Naming conventions for generated package."""
51
+
52
+ use_existing_names: bool = True
53
+ acronyms: list[str] = ["CCSDS"]
54
+
55
+
56
+ class Settings(BaseSettings):
57
+ """Settings model."""
58
+
59
+ author: AuthorSettings = AuthorSettings()
60
+ package_defaults: PackageDefaults = PackageDefaults()
61
+ naming_convention: NamingSettings = NamingSettings()
62
+ logging: LoggingSettings = LoggingSettings()
63
+
64
+ model_config = SettingsConfigDict(toml_file="xtce2py.toml")
65
+
66
+ @classmethod
67
+ def settings_customise_sources(
68
+ cls,
69
+ settings_cls: type[BaseSettings],
70
+ init_settings: PydanticBaseSettingsSource,
71
+ env_settings: PydanticBaseSettingsSource,
72
+ dotenv_settings: PydanticBaseSettingsSource,
73
+ file_secret_settings: PydanticBaseSettingsSource,
74
+ ) -> tuple[PydanticBaseSettingsSource, ...]:
75
+ """Define the order of precedence for settings sources."""
76
+ return (
77
+ init_settings,
78
+ env_settings,
79
+ dotenv_settings,
80
+ file_secret_settings,
81
+ TomlConfigSettingsSource(settings_cls),
82
+ )
83
+
84
+
85
+ @functools.lru_cache(maxsize=1)
86
+ def get_settings() -> Settings:
87
+ """Load and validate the settings, then cache the result."""
88
+ return Settings()
@@ -0,0 +1,76 @@
1
+ """Context models for Jinja2 templates."""
2
+
3
+ from dataclasses import dataclass, field
4
+ from typing import Any, Optional
5
+
6
+ from xtce2py.xtce_common.context_models import ContainerDetailsContext
7
+
8
+
9
+ @dataclass
10
+ class XtceMetadataContext:
11
+ """Container for XTCE metadata information."""
12
+
13
+ name: str = "unknown"
14
+ description: Optional[str] = ""
15
+ version: Optional[str] = "1.0.0"
16
+ date: Optional[str] = ""
17
+ classification: Optional[str] = ""
18
+ authors: list[str] = field(default_factory=list)
19
+ notes: list[str] = field(default_factory=list)
20
+ history: list[str] = field(default_factory=list)
21
+
22
+
23
+ @dataclass
24
+ class PyprojectContext:
25
+ """Container for the data needed by the pyproject.toml template."""
26
+
27
+ dist_name: str
28
+ package_name: str
29
+ version: str
30
+ metadata: XtceMetadataContext
31
+
32
+
33
+ @dataclass
34
+ class ReadMeContext:
35
+ """Container for the data needed by the README.md template."""
36
+
37
+ dist_name: str
38
+ package_name: str
39
+ xtce_version: str
40
+ metadata: XtceMetadataContext
41
+
42
+
43
+ @dataclass
44
+ class InitContext:
45
+ """Container for the data needed by the __init__.py template."""
46
+
47
+ metadata: XtceMetadataContext
48
+
49
+
50
+ @dataclass
51
+ class ModelContext:
52
+ """Container for the data needed by a model within the models.py template."""
53
+
54
+ name: str
55
+ parent: str = "PacketBase"
56
+ entries: list[dict[str, Any]] = field(default_factory=list)
57
+ description: Optional[str] = ""
58
+
59
+
60
+ @dataclass
61
+ class ModelsContext:
62
+ """Container for the data needed by the models.py template."""
63
+
64
+ imports: dict[str, list[str]] = field(default_factory=dict)
65
+ containers: list[ModelContext] = field(default_factory=list)
66
+
67
+
68
+ @dataclass
69
+ class ParserContext:
70
+ """Container for the data needed by the parser template."""
71
+
72
+ container_tree: dict[str, Any] = field(default_factory=dict)
73
+ concrete_container_names: set[str] = field(default_factory=set)
74
+ container_details_map: dict[str, ContainerDetailsContext] = field(
75
+ default_factory=dict
76
+ )
@@ -0,0 +1,209 @@
1
+ """Contains the core logic for generating parser package files.
2
+
3
+ It includes functions for creating directory layouts, rendering Jinja2
4
+ templates, and formatting the final output.
5
+ """
6
+
7
+ import importlib.resources as pkg_resources
8
+ import logging
9
+ import shutil
10
+ from pathlib import Path
11
+ from typing import Any
12
+
13
+ import jinja2
14
+
15
+ from xtce2py import config, xtce_1_1, xtce_1_2, xtce_1_3
16
+ from xtce2py.context_models import (
17
+ InitContext,
18
+ ModelContext,
19
+ ModelsContext,
20
+ PyprojectContext,
21
+ ReadMeContext,
22
+ )
23
+
24
+ log = logging.getLogger(__name__)
25
+
26
+
27
+ def setup_jinja_environment() -> jinja2.Environment:
28
+ """Set up the Jinja2 environment for template rendering."""
29
+ template_dir_ref = pkg_resources.files("xtce2py").joinpath("templates")
30
+
31
+ with pkg_resources.as_file(template_dir_ref) as template_dir:
32
+ loader = jinja2.FileSystemLoader(template_dir)
33
+
34
+ return jinja2.Environment(loader=loader)
35
+
36
+
37
+ TEMPLATE_ENV = setup_jinja_environment()
38
+ STATIC_FILE_MAP = [
39
+ ("setup.py", "setup.py"),
40
+ ("_decoding.py", "src/{package_name}/_decoding.py"),
41
+ ]
42
+
43
+
44
+ def create_project_names(
45
+ space_system_name: str, package_name_suffix: str
46
+ ) -> tuple[str, str]:
47
+ """Create a package name based on the space system's name."""
48
+ dist_name = f"{space_system_name.lower().replace(' ', '-').replace('_', '-')}-{package_name_suffix}"
49
+ package_name = f"{space_system_name.lower().replace(' ', '_').replace('-', '_')}_{package_name_suffix}"
50
+ return dist_name, package_name
51
+
52
+
53
+ def create_directory_structure(
54
+ package_dir: Path,
55
+ package_name: str,
56
+ parser: xtce_1_1.XtceParser, # | xtce_1_2.XtceParser | xtce_1_3.XtceParser,
57
+ ) -> None:
58
+ """Create the necessary directory structure for the generated package."""
59
+ # Delete existing output directory if it exists
60
+ if package_dir.exists():
61
+ for item in package_dir.iterdir():
62
+ if item.is_dir():
63
+ shutil.rmtree(item)
64
+ else:
65
+ item.unlink()
66
+ package_dir.mkdir(parents=True, exist_ok=True)
67
+ (package_dir / "src").mkdir(parents=True, exist_ok=True)
68
+
69
+ # Create main package directory
70
+ main_package_dir = package_dir / "src" / package_name
71
+ main_package_dir.mkdir(parents=True, exist_ok=True)
72
+
73
+ # Create sub-directories for each sub-space system
74
+ hierarchy = parser.get_space_system_hierarchy()
75
+ for module_name in hierarchy["sub_systems"].keys():
76
+ sub_module_dir = main_package_dir / module_name
77
+ sub_module_dir.mkdir(parents=True, exist_ok=True)
78
+
79
+ log.info(f"Generated directory structure at {package_dir}")
80
+
81
+
82
+ def copy_static_files(package_dir: Path):
83
+ """Copy static files to the generated package."""
84
+ for src_filename, dest_template_path in STATIC_FILE_MAP:
85
+ dest_path = package_dir / dest_template_path.format(
86
+ package_name=package_dir.name
87
+ )
88
+
89
+ with pkg_resources.as_file(
90
+ pkg_resources.files("xtce2py").joinpath(f"static/{src_filename}")
91
+ ) as src_path:
92
+ shutil.copy2(src_path, dest_path)
93
+
94
+ log.info(f"Copied static files to {package_dir}")
95
+
96
+
97
+ def generate_readme(package_dir: Path, readme_context: ReadMeContext):
98
+ """Generate a README.md file in the output package directory."""
99
+ template = TEMPLATE_ENV.get_template("README.md.j2")
100
+
101
+ generated_code = template.render(context=readme_context)
102
+
103
+ output_filename = package_dir / "README.md"
104
+ with open(output_filename, "w", encoding="utf-8") as f:
105
+ f.write(generated_code)
106
+
107
+ log.info(f"Generated {output_filename.name} at {output_filename}")
108
+
109
+
110
+ def generate_pyproject_toml(
111
+ package_dir: Path,
112
+ pyproject_context: PyprojectContext,
113
+ ):
114
+ """Generate a pyproject.toml file in the output package directory."""
115
+ template = TEMPLATE_ENV.get_template("pyproject.toml.j2")
116
+
117
+ generated_code = template.render(context=pyproject_context)
118
+
119
+ output_filename = package_dir / "pyproject.toml"
120
+ with open(output_filename, "w", encoding="utf-8") as f:
121
+ f.write(generated_code)
122
+
123
+ log.info(f"Generated {output_filename.name} at {output_filename}")
124
+
125
+
126
+ def generate_init(
127
+ package_src_dir: Path,
128
+ init_context: InitContext,
129
+ parser: xtce_1_1.XtceParser, # | xtce_1_2.XtceParser | xtce_1_3.XtceParser,
130
+ ):
131
+ """Generate a __init__.py file in the output src directory."""
132
+ template = TEMPLATE_ENV.get_template("__init__.py.j2")
133
+
134
+ model_class_names = [
135
+ container.name for container in parser.generate_model_context()
136
+ ]
137
+ public_api_names = ["parse_packet", "parse_packets", "PacketBase"]
138
+ all_public_names = sorted(model_class_names + public_api_names)
139
+
140
+ generated_code = template.render(
141
+ context=init_context,
142
+ model_class_names=model_class_names,
143
+ all_public_names=all_public_names,
144
+ )
145
+
146
+ output_filename = package_src_dir / "__init__.py"
147
+ with open(output_filename, "w", encoding="utf-8") as f:
148
+ f.write(generated_code)
149
+
150
+ log.info(f"Generated {output_filename.name} at {output_filename}")
151
+
152
+
153
+ def generate_models(
154
+ package_src_dir: Path,
155
+ parser: xtce_1_1.XtceParser, # | xtce_1_2.XtceParser | xtce_1_3.XtceParser,
156
+ ):
157
+ """Generate models.py files for the main package and sub-systems."""
158
+ template = TEMPLATE_ENV.get_template("models.py.j2")
159
+
160
+ hierarchy = parser.get_space_system_hierarchy()
161
+
162
+ # Generate models for the root space system
163
+ root_system = hierarchy["root"]
164
+ models_context = ModelsContext(
165
+ imports={
166
+ "typing": ["Literal"],
167
+ "pydantic": ["BaseModel", "Field", "field_validator"],
168
+ },
169
+ containers=list(parser.generate_model_context()),
170
+ )
171
+ generated_code = template.render(context=models_context)
172
+
173
+ output_filename = package_src_dir / "models.py"
174
+ with open(output_filename, "w", encoding="utf-8") as f:
175
+ f.write(generated_code)
176
+
177
+ log.info(f"Generated {output_filename.name} at {output_filename}")
178
+
179
+ # Generate models for each sub-system in separate modules
180
+ for module_name, sub_system in hierarchy["sub_systems"].items():
181
+ print(f"Generating models for sub-system: {sub_system.name} -> {module_name}")
182
+ sub_module_dir = package_src_dir / module_name
183
+ # TODO: Generate models.py in sub_module_dir
184
+
185
+
186
+ def generate_parser(
187
+ package_src_dir: Path,
188
+ parser: xtce_1_1.XtceParser, # | xtce_1_2.XtceParser | xtce_1_3.XtceParser,
189
+ ):
190
+ """Generate a parser.py file in the output src directory."""
191
+ if parser.is_simple_dispatcher:
192
+ log.info("Generating simple dispatcher parser.")
193
+ # template = TEMPLATE_ENV.get_template("simple_parser.py.j2") # TODO
194
+ template = TEMPLATE_ENV.get_template("tree_parser.py.j2")
195
+ else:
196
+ log.info("Generating tree parser.")
197
+ template = TEMPLATE_ENV.get_template("tree_parser.py.j2")
198
+
199
+ parser_context = parser.generate_parser_context()
200
+
201
+ generated_code = template.render(
202
+ context=parser_context, dispatcher_parameter=parser.dispatcher_parameter
203
+ )
204
+
205
+ output_filename = package_src_dir / "parser.py"
206
+ with open(output_filename, "w", encoding="utf-8") as f:
207
+ f.write(generated_code)
208
+
209
+ log.info(f"Generated {output_filename.name} at {output_filename}")