pyopenapi-gen 0.8.3__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.
- pyopenapi_gen/__init__.py +114 -0
- pyopenapi_gen/__main__.py +6 -0
- pyopenapi_gen/cli.py +86 -0
- pyopenapi_gen/context/file_manager.py +52 -0
- pyopenapi_gen/context/import_collector.py +382 -0
- pyopenapi_gen/context/render_context.py +630 -0
- pyopenapi_gen/core/__init__.py +0 -0
- pyopenapi_gen/core/auth/base.py +22 -0
- pyopenapi_gen/core/auth/plugins.py +89 -0
- pyopenapi_gen/core/exceptions.py +25 -0
- pyopenapi_gen/core/http_transport.py +219 -0
- pyopenapi_gen/core/loader/__init__.py +12 -0
- pyopenapi_gen/core/loader/loader.py +158 -0
- pyopenapi_gen/core/loader/operations/__init__.py +12 -0
- pyopenapi_gen/core/loader/operations/parser.py +155 -0
- pyopenapi_gen/core/loader/operations/post_processor.py +60 -0
- pyopenapi_gen/core/loader/operations/request_body.py +85 -0
- pyopenapi_gen/core/loader/parameters/__init__.py +10 -0
- pyopenapi_gen/core/loader/parameters/parser.py +121 -0
- pyopenapi_gen/core/loader/responses/__init__.py +10 -0
- pyopenapi_gen/core/loader/responses/parser.py +104 -0
- pyopenapi_gen/core/loader/schemas/__init__.py +11 -0
- pyopenapi_gen/core/loader/schemas/extractor.py +184 -0
- pyopenapi_gen/core/pagination.py +64 -0
- pyopenapi_gen/core/parsing/__init__.py +13 -0
- pyopenapi_gen/core/parsing/common/__init__.py +1 -0
- pyopenapi_gen/core/parsing/common/ref_resolution/__init__.py +9 -0
- pyopenapi_gen/core/parsing/common/ref_resolution/helpers/__init__.py +0 -0
- pyopenapi_gen/core/parsing/common/ref_resolution/helpers/cyclic_properties.py +66 -0
- pyopenapi_gen/core/parsing/common/ref_resolution/helpers/direct_cycle.py +33 -0
- pyopenapi_gen/core/parsing/common/ref_resolution/helpers/existing_schema.py +22 -0
- pyopenapi_gen/core/parsing/common/ref_resolution/helpers/list_response.py +54 -0
- pyopenapi_gen/core/parsing/common/ref_resolution/helpers/missing_ref.py +52 -0
- pyopenapi_gen/core/parsing/common/ref_resolution/helpers/new_schema.py +50 -0
- pyopenapi_gen/core/parsing/common/ref_resolution/helpers/stripped_suffix.py +51 -0
- pyopenapi_gen/core/parsing/common/ref_resolution/resolve_schema_ref.py +86 -0
- pyopenapi_gen/core/parsing/common/type_parser.py +74 -0
- pyopenapi_gen/core/parsing/context.py +184 -0
- pyopenapi_gen/core/parsing/cycle_helpers.py +123 -0
- pyopenapi_gen/core/parsing/keywords/__init__.py +1 -0
- pyopenapi_gen/core/parsing/keywords/all_of_parser.py +77 -0
- pyopenapi_gen/core/parsing/keywords/any_of_parser.py +79 -0
- pyopenapi_gen/core/parsing/keywords/array_items_parser.py +69 -0
- pyopenapi_gen/core/parsing/keywords/one_of_parser.py +72 -0
- pyopenapi_gen/core/parsing/keywords/properties_parser.py +98 -0
- pyopenapi_gen/core/parsing/schema_finalizer.py +166 -0
- pyopenapi_gen/core/parsing/schema_parser.py +610 -0
- pyopenapi_gen/core/parsing/transformers/__init__.py +0 -0
- pyopenapi_gen/core/parsing/transformers/inline_enum_extractor.py +285 -0
- pyopenapi_gen/core/parsing/transformers/inline_object_promoter.py +117 -0
- pyopenapi_gen/core/parsing/unified_cycle_detection.py +293 -0
- pyopenapi_gen/core/postprocess_manager.py +161 -0
- pyopenapi_gen/core/schemas.py +40 -0
- pyopenapi_gen/core/streaming_helpers.py +86 -0
- pyopenapi_gen/core/telemetry.py +67 -0
- pyopenapi_gen/core/utils.py +409 -0
- pyopenapi_gen/core/warning_collector.py +83 -0
- pyopenapi_gen/core/writers/code_writer.py +135 -0
- pyopenapi_gen/core/writers/documentation_writer.py +222 -0
- pyopenapi_gen/core/writers/line_writer.py +217 -0
- pyopenapi_gen/core/writers/python_construct_renderer.py +274 -0
- pyopenapi_gen/core_package_template/README.md +21 -0
- pyopenapi_gen/emit/models_emitter.py +143 -0
- pyopenapi_gen/emitters/client_emitter.py +51 -0
- pyopenapi_gen/emitters/core_emitter.py +181 -0
- pyopenapi_gen/emitters/docs_emitter.py +44 -0
- pyopenapi_gen/emitters/endpoints_emitter.py +223 -0
- pyopenapi_gen/emitters/exceptions_emitter.py +52 -0
- pyopenapi_gen/emitters/models_emitter.py +428 -0
- pyopenapi_gen/generator/client_generator.py +562 -0
- pyopenapi_gen/helpers/__init__.py +1 -0
- pyopenapi_gen/helpers/endpoint_utils.py +552 -0
- pyopenapi_gen/helpers/type_cleaner.py +341 -0
- pyopenapi_gen/helpers/type_helper.py +112 -0
- pyopenapi_gen/helpers/type_resolution/__init__.py +1 -0
- pyopenapi_gen/helpers/type_resolution/array_resolver.py +57 -0
- pyopenapi_gen/helpers/type_resolution/composition_resolver.py +79 -0
- pyopenapi_gen/helpers/type_resolution/finalizer.py +89 -0
- pyopenapi_gen/helpers/type_resolution/named_resolver.py +174 -0
- pyopenapi_gen/helpers/type_resolution/object_resolver.py +212 -0
- pyopenapi_gen/helpers/type_resolution/primitive_resolver.py +57 -0
- pyopenapi_gen/helpers/type_resolution/resolver.py +48 -0
- pyopenapi_gen/helpers/url_utils.py +14 -0
- pyopenapi_gen/http_types.py +20 -0
- pyopenapi_gen/ir.py +167 -0
- pyopenapi_gen/py.typed +1 -0
- pyopenapi_gen/types/__init__.py +11 -0
- pyopenapi_gen/types/contracts/__init__.py +13 -0
- pyopenapi_gen/types/contracts/protocols.py +106 -0
- pyopenapi_gen/types/contracts/types.py +30 -0
- pyopenapi_gen/types/resolvers/__init__.py +7 -0
- pyopenapi_gen/types/resolvers/reference_resolver.py +71 -0
- pyopenapi_gen/types/resolvers/response_resolver.py +203 -0
- pyopenapi_gen/types/resolvers/schema_resolver.py +367 -0
- pyopenapi_gen/types/services/__init__.py +5 -0
- pyopenapi_gen/types/services/type_service.py +133 -0
- pyopenapi_gen/visit/client_visitor.py +228 -0
- pyopenapi_gen/visit/docs_visitor.py +38 -0
- pyopenapi_gen/visit/endpoint/__init__.py +1 -0
- pyopenapi_gen/visit/endpoint/endpoint_visitor.py +103 -0
- pyopenapi_gen/visit/endpoint/generators/__init__.py +1 -0
- pyopenapi_gen/visit/endpoint/generators/docstring_generator.py +121 -0
- pyopenapi_gen/visit/endpoint/generators/endpoint_method_generator.py +87 -0
- pyopenapi_gen/visit/endpoint/generators/request_generator.py +103 -0
- pyopenapi_gen/visit/endpoint/generators/response_handler_generator.py +497 -0
- pyopenapi_gen/visit/endpoint/generators/signature_generator.py +88 -0
- pyopenapi_gen/visit/endpoint/generators/url_args_generator.py +183 -0
- pyopenapi_gen/visit/endpoint/processors/__init__.py +1 -0
- pyopenapi_gen/visit/endpoint/processors/import_analyzer.py +76 -0
- pyopenapi_gen/visit/endpoint/processors/parameter_processor.py +171 -0
- pyopenapi_gen/visit/exception_visitor.py +52 -0
- pyopenapi_gen/visit/model/__init__.py +0 -0
- pyopenapi_gen/visit/model/alias_generator.py +89 -0
- pyopenapi_gen/visit/model/dataclass_generator.py +197 -0
- pyopenapi_gen/visit/model/enum_generator.py +200 -0
- pyopenapi_gen/visit/model/model_visitor.py +197 -0
- pyopenapi_gen/visit/visitor.py +97 -0
- pyopenapi_gen-0.8.3.dist-info/METADATA +224 -0
- pyopenapi_gen-0.8.3.dist-info/RECORD +122 -0
- pyopenapi_gen-0.8.3.dist-info/WHEEL +4 -0
- pyopenapi_gen-0.8.3.dist-info/entry_points.txt +2 -0
- pyopenapi_gen-0.8.3.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,97 @@
|
|
1
|
+
"""
|
2
|
+
Implementation of the visitor pattern for OpenAPI IR model traversal.
|
3
|
+
|
4
|
+
This module provides the core visitor pattern implementation used throughout the PyOpenAPI
|
5
|
+
Generator to transform IR (Intermediate Representation) nodes into Python code. It defines
|
6
|
+
the base Visitor class that all specific visitors inherit from, and a Registry class for
|
7
|
+
managing visitor method registration.
|
8
|
+
"""
|
9
|
+
|
10
|
+
from typing import Callable, Dict, Generic, Optional, Type, TypeVar
|
11
|
+
|
12
|
+
from ..context.render_context import RenderContext
|
13
|
+
|
14
|
+
# Type variables for node and return type
|
15
|
+
tNode = TypeVar("tNode") # Type variable for IR node types
|
16
|
+
tRet = TypeVar("tRet") # Type variable for visitor return types
|
17
|
+
|
18
|
+
|
19
|
+
class Visitor(Generic[tNode, tRet]):
|
20
|
+
"""
|
21
|
+
Base class for all visitors implementing the visitor pattern.
|
22
|
+
|
23
|
+
This class provides the foundation for traversing and transforming IR nodes
|
24
|
+
into Python code representations. Subclasses should implement visit_<NodeType>
|
25
|
+
methods for each IR node type they want to handle.
|
26
|
+
|
27
|
+
Type parameters:
|
28
|
+
tNode: The type of node being visited
|
29
|
+
tRet: The return type of the visitor methods
|
30
|
+
"""
|
31
|
+
|
32
|
+
def visit(self, node: tNode, context: "RenderContext") -> tRet:
|
33
|
+
"""
|
34
|
+
Visit a node and dispatch to the appropriate visit_* method.
|
35
|
+
|
36
|
+
Args:
|
37
|
+
node: The IR node to visit
|
38
|
+
context: The rendering context containing state for the code generation
|
39
|
+
|
40
|
+
Returns:
|
41
|
+
The result of visiting the node, type depends on the specific visitor
|
42
|
+
"""
|
43
|
+
method_name = f"visit_{type(node).__name__}"
|
44
|
+
visitor: Callable[[tNode, "RenderContext"], tRet] = getattr(self, method_name, self.generic_visit)
|
45
|
+
return visitor(node, context)
|
46
|
+
|
47
|
+
def generic_visit(self, node: tNode, context: "RenderContext") -> tRet:
|
48
|
+
"""
|
49
|
+
Default handler for node types without a specific visitor method.
|
50
|
+
|
51
|
+
Args:
|
52
|
+
node: The IR node to visit
|
53
|
+
context: The rendering context containing state for the code generation
|
54
|
+
|
55
|
+
Raises:
|
56
|
+
NotImplementedError: Always raised to indicate missing visitor implementation
|
57
|
+
"""
|
58
|
+
raise NotImplementedError(f"No visit_{type(node).__name__} method defined.")
|
59
|
+
|
60
|
+
|
61
|
+
class Registry(Generic[tNode, tRet]):
|
62
|
+
"""
|
63
|
+
Registry for associating IR node types with visitor handler functions.
|
64
|
+
|
65
|
+
This registry allows for plugins or extensions to register custom handlers
|
66
|
+
for specific IR node types, enabling extensibility in the code generation process.
|
67
|
+
|
68
|
+
Type parameters:
|
69
|
+
tNode: The type of node being visited
|
70
|
+
tRet: The return type of the visitor methods
|
71
|
+
"""
|
72
|
+
|
73
|
+
def __init__(self) -> None:
|
74
|
+
"""Initialize an empty visitor registry."""
|
75
|
+
self._registry: Dict[Type[tNode], Callable[[tNode, "RenderContext"], tRet]] = {}
|
76
|
+
|
77
|
+
def register(self, node_type: Type[tNode], visitor: Callable[[tNode, "RenderContext"], tRet]) -> None:
|
78
|
+
"""
|
79
|
+
Register a visitor function for a specific node type.
|
80
|
+
|
81
|
+
Args:
|
82
|
+
node_type: The IR node type to register a handler for
|
83
|
+
visitor: The function that will handle visiting nodes of this type
|
84
|
+
"""
|
85
|
+
self._registry[node_type] = visitor
|
86
|
+
|
87
|
+
def get_visitor(self, node_type: Type[tNode]) -> Optional[Callable[[tNode, "RenderContext"], tRet]]:
|
88
|
+
"""
|
89
|
+
Retrieve the visitor function for a specific node type.
|
90
|
+
|
91
|
+
Args:
|
92
|
+
node_type: The IR node type to get a handler for
|
93
|
+
|
94
|
+
Returns:
|
95
|
+
The registered visitor function or None if no handler is registered
|
96
|
+
"""
|
97
|
+
return self._registry.get(node_type)
|
@@ -0,0 +1,224 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: pyopenapi-gen
|
3
|
+
Version: 0.8.3
|
4
|
+
Summary: Python OpenAPI client generator - core library
|
5
|
+
Author-email: PyOpenAPI Team <dev@example.com>
|
6
|
+
License: MIT
|
7
|
+
License-File: LICENSE
|
8
|
+
Keywords: async,client,generator,openapi,python,swagger
|
9
|
+
Classifier: Intended Audience :: Developers
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
11
|
+
Classifier: Operating System :: MacOS
|
12
|
+
Classifier: Operating System :: POSIX :: Linux
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
17
|
+
Classifier: Topic :: Software Development :: Code Generators
|
18
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
19
|
+
Classifier: Typing :: Typed
|
20
|
+
Requires-Python: <4.0.0,>=3.10
|
21
|
+
Requires-Dist: httpx>=0.24.0
|
22
|
+
Requires-Dist: jinja2>=3.0
|
23
|
+
Requires-Dist: openapi-core>=0.19
|
24
|
+
Requires-Dist: openapi-spec-validator>=0.7
|
25
|
+
Requires-Dist: pyyaml>=6.0
|
26
|
+
Requires-Dist: typer<0.15.0,>=0.12.0
|
27
|
+
Provides-Extra: dev
|
28
|
+
Requires-Dist: bandit[toml]>=1.7.0; extra == 'dev'
|
29
|
+
Requires-Dist: black>=23.0; extra == 'dev'
|
30
|
+
Requires-Dist: httpx>=0.24.0; extra == 'dev'
|
31
|
+
Requires-Dist: mypy>=1.7; extra == 'dev'
|
32
|
+
Requires-Dist: pytest-asyncio>=0.20.0; extra == 'dev'
|
33
|
+
Requires-Dist: pytest-cov>=4.0; extra == 'dev'
|
34
|
+
Requires-Dist: pytest-timeout>=2.1.0; extra == 'dev'
|
35
|
+
Requires-Dist: pytest-xdist>=3.0.0; extra == 'dev'
|
36
|
+
Requires-Dist: pytest>=7.0; extra == 'dev'
|
37
|
+
Requires-Dist: ruff>=0.4; extra == 'dev'
|
38
|
+
Requires-Dist: safety>=2.0.0; extra == 'dev'
|
39
|
+
Requires-Dist: types-pyyaml>=6.0.12; extra == 'dev'
|
40
|
+
Requires-Dist: types-toml>=0.10.8; extra == 'dev'
|
41
|
+
Description-Content-Type: text/markdown
|
42
|
+
|
43
|
+
# PyOpenAPI Generator
|
44
|
+
|
45
|
+
Modern, async-first Python client generator for OpenAPI specifications. Creates robust, type-safe clients that require no runtime dependencies on this generator.
|
46
|
+
|
47
|
+
## Quick Start
|
48
|
+
|
49
|
+
### Install
|
50
|
+
```bash
|
51
|
+
pip install pyopenapi-gen
|
52
|
+
```
|
53
|
+
|
54
|
+
### Generate Client
|
55
|
+
```bash
|
56
|
+
pyopenapi-gen gen openapi.yaml \
|
57
|
+
--project-root . \
|
58
|
+
--output-package my_api_client
|
59
|
+
```
|
60
|
+
|
61
|
+
### Use Generated Client
|
62
|
+
```python
|
63
|
+
import asyncio
|
64
|
+
from my_api_client.client import APIClient
|
65
|
+
from my_api_client.core.config import ClientConfig
|
66
|
+
|
67
|
+
async def main():
|
68
|
+
config = ClientConfig(base_url="https://api.example.com")
|
69
|
+
async with APIClient(config) as client:
|
70
|
+
users = await client.users.list_users(page=1)
|
71
|
+
print(users)
|
72
|
+
|
73
|
+
asyncio.run(main())
|
74
|
+
```
|
75
|
+
|
76
|
+
## Configuration Options
|
77
|
+
|
78
|
+
### Standalone Client (Default)
|
79
|
+
```bash
|
80
|
+
pyopenapi-gen gen openapi.yaml \
|
81
|
+
--project-root . \
|
82
|
+
--output-package my_api_client
|
83
|
+
```
|
84
|
+
Creates self-contained client with embedded core dependencies.
|
85
|
+
|
86
|
+
### Shared Core (Multiple Clients)
|
87
|
+
```bash
|
88
|
+
pyopenapi-gen gen openapi.yaml \
|
89
|
+
--project-root . \
|
90
|
+
--output-package clients.api_client \
|
91
|
+
--core-package clients.core
|
92
|
+
```
|
93
|
+
Multiple clients share a single core implementation.
|
94
|
+
|
95
|
+
### Additional Options
|
96
|
+
```bash
|
97
|
+
--force # Overwrite without prompting
|
98
|
+
--no-postprocess # Skip formatting and type checking
|
99
|
+
```
|
100
|
+
|
101
|
+
## Features
|
102
|
+
|
103
|
+
✨ **Type Safety**: Full type hints and dataclass models
|
104
|
+
⚡ **Async-First**: Built for modern Python async/await patterns
|
105
|
+
🏗️ **Modular**: Pluggable authentication, pagination, and HTTP transport
|
106
|
+
🧠 **Smart IDE Support**: Rich docstrings and auto-completion
|
107
|
+
📦 **Zero Dependencies**: Generated clients are self-contained
|
108
|
+
🛡️ **Robust**: Graceful handling of incomplete specs
|
109
|
+
🎯 **Error Handling**: Structured exceptions, only successful responses returned
|
110
|
+
|
111
|
+
## Generated Client Structure
|
112
|
+
|
113
|
+
```
|
114
|
+
my_api_client/
|
115
|
+
├── client.py # Main APIClient with tag-grouped methods
|
116
|
+
├── core/ # Self-contained runtime dependencies
|
117
|
+
│ ├── config.py # Configuration management
|
118
|
+
│ ├── http_transport.py # HTTP client abstraction
|
119
|
+
│ ├── exceptions.py # Error hierarchy
|
120
|
+
│ └── auth/ # Authentication plugins
|
121
|
+
├── models/ # Dataclass models from schemas
|
122
|
+
│ └── user.py
|
123
|
+
├── endpoints/ # Operation methods grouped by tag
|
124
|
+
│ └── users.py
|
125
|
+
└── __init__.py
|
126
|
+
```
|
127
|
+
|
128
|
+
## Client Features
|
129
|
+
|
130
|
+
- **Tag Organization**: Operations grouped by OpenAPI tags (`client.users.list_users()`)
|
131
|
+
- **Type Safety**: Full dataclass models with type hints
|
132
|
+
- **Async Iterators**: Auto-detected pagination patterns
|
133
|
+
- **Rich Auth**: Bearer, API key, OAuth2, and custom strategies
|
134
|
+
- **Error Handling**: Structured `HTTPError`, `ClientError`, `ServerError` hierarchy
|
135
|
+
- **Response Unwrapping**: Automatic extraction of `{ "data": ... }` patterns
|
136
|
+
|
137
|
+
## Known Limitations
|
138
|
+
|
139
|
+
Some OpenAPI features have simplified implementations:
|
140
|
+
|
141
|
+
- **Parameter Serialization**: Uses HTTP client defaults rather than OpenAPI `style`/`explode` directives
|
142
|
+
- **Complex Multipart**: Basic file upload support; complex multipart schemas simplified
|
143
|
+
- **Response Headers**: Only response body is returned, not headers
|
144
|
+
- **Parameter Defaults**: OpenAPI schema defaults not automatically applied to method signatures
|
145
|
+
|
146
|
+
Contributions welcome to enhance OpenAPI specification coverage!
|
147
|
+
|
148
|
+
### Bearer Token
|
149
|
+
```python
|
150
|
+
from .core.auth.plugins import BearerAuth
|
151
|
+
auth = BearerAuth("your-token")
|
152
|
+
```
|
153
|
+
|
154
|
+
### API Key
|
155
|
+
```python
|
156
|
+
from .core.auth.plugins import ApiKeyAuth
|
157
|
+
# Header, query, or cookie
|
158
|
+
auth = ApiKeyAuth("key", location="header", name="X-API-Key")
|
159
|
+
```
|
160
|
+
|
161
|
+
### OAuth2 with Refresh
|
162
|
+
```python
|
163
|
+
from .core.auth.plugins import OAuth2Auth
|
164
|
+
auth = OAuth2Auth("token", refresh_callback=refresh_func)
|
165
|
+
```
|
166
|
+
|
167
|
+
### Custom Headers
|
168
|
+
```python
|
169
|
+
from .core.auth.plugins import HeadersAuth
|
170
|
+
auth = HeadersAuth({"X-Custom": "value"})
|
171
|
+
```
|
172
|
+
|
173
|
+
### Composite Auth
|
174
|
+
```python
|
175
|
+
from .core.auth.base import CompositeAuth
|
176
|
+
auth = CompositeAuth(BearerAuth("token"), HeadersAuth({"X-Key": "val"}))
|
177
|
+
```
|
178
|
+
|
179
|
+
## Development
|
180
|
+
|
181
|
+
### Setup
|
182
|
+
```bash
|
183
|
+
git clone https://github.com/your-org/pyopenapi_gen.git
|
184
|
+
cd pyopenapi_gen
|
185
|
+
source .venv/bin/activate # Activate virtual environment
|
186
|
+
poetry install --with dev # Install dependencies with Poetry
|
187
|
+
```
|
188
|
+
|
189
|
+
### Quality Workflow
|
190
|
+
```bash
|
191
|
+
# Before committing - auto-fix what's possible
|
192
|
+
make quality-fix
|
193
|
+
|
194
|
+
# Run all quality checks (matches CI pipeline)
|
195
|
+
make quality
|
196
|
+
|
197
|
+
# Individual commands
|
198
|
+
make format # Auto-format with Black
|
199
|
+
make lint-fix # Auto-fix linting with Ruff
|
200
|
+
make typecheck # Type checking with mypy
|
201
|
+
make security # Security scanning with Bandit
|
202
|
+
make test # Run all tests in parallel with 4 workers (with 85% coverage requirement)
|
203
|
+
|
204
|
+
# Testing options
|
205
|
+
make test-serial # Run tests sequentially (if parallel tests hang)
|
206
|
+
pytest -n auto # Run tests in parallel (faster)
|
207
|
+
pytest -n 4 # Run tests with specific number of workers
|
208
|
+
pytest --no-cov # Run tests without coverage (fastest)
|
209
|
+
```
|
210
|
+
|
211
|
+
### Contributing
|
212
|
+
|
213
|
+
Contributions welcome! Please ensure:
|
214
|
+
|
215
|
+
- **Code Quality**: All `make quality` checks pass
|
216
|
+
- **Testing**: pytest with ≥85% branch coverage
|
217
|
+
- **Compatibility**: Python 3.10-3.12 support
|
218
|
+
- **Documentation**: Update relevant docs for new features
|
219
|
+
|
220
|
+
The `make quality-fix` command will auto-fix most formatting and linting issues. All pull requests must pass the full `make quality` check suite.
|
221
|
+
|
222
|
+
## License
|
223
|
+
|
224
|
+
MIT License - Generated clients are Apache-2.0 by default.
|
@@ -0,0 +1,122 @@
|
|
1
|
+
pyopenapi_gen/__init__.py,sha256=YHJFfK7_we3-eCQ1foq2FcLP7IjwmKUM4_hNN_JhikQ,2998
|
2
|
+
pyopenapi_gen/__main__.py,sha256=4-SCaCNhBd7rtyRK58uoDbdl93J0KhUeajP_b0CPpLE,110
|
3
|
+
pyopenapi_gen/cli.py,sha256=f3FeF1csLoULYByEXd569_iB73NplEfePJMdyQnT8Dc,2947
|
4
|
+
pyopenapi_gen/http_types.py,sha256=EMMYZBt8PNVZKPFu77TQija-JI-nOKyXvpiQP9-VSWE,467
|
5
|
+
pyopenapi_gen/ir.py,sha256=OWQk53_iVi9JZxVeKRjagF0nhw57skkNPd-4jDsyD7M,7354
|
6
|
+
pyopenapi_gen/py.typed,sha256=Nqnn8clbgv-5l0PgxcTOldg8mkMKrFn4TvPL-rYUUGg,1
|
7
|
+
pyopenapi_gen/context/file_manager.py,sha256=vpbRByO5SH6COdjb6C-pXkdSIRu7QFqrXxi69VLKBnM,1691
|
8
|
+
pyopenapi_gen/context/import_collector.py,sha256=rnOgR5-GsHs_oS1iUVbOF3tagcH5namNWvp7k44kugw,15262
|
9
|
+
pyopenapi_gen/context/render_context.py,sha256=AS08ha9WVjgRUsM1LFPjMCgrsHbczHH7c60Z5PbojhY,30320
|
10
|
+
pyopenapi_gen/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
11
|
+
pyopenapi_gen/core/exceptions.py,sha256=KemyLDXl8pBgzxxV6ZhsGi7WjwKGooKU6Idy63eC2ko,553
|
12
|
+
pyopenapi_gen/core/http_transport.py,sha256=77ZOTyl0_CLuDtSCOVDQoxHDQBnclJgz6f3Hs6cy7hY,9675
|
13
|
+
pyopenapi_gen/core/pagination.py,sha256=aeDOKo-Lu8mcSDqv0TlPXV9Ul-Nca76ZuKhQHKlsMUs,2301
|
14
|
+
pyopenapi_gen/core/postprocess_manager.py,sha256=8s3VH2q4-kGRMdWbKeHtXPms8wtid6IKvVSHuXSxpzY,5785
|
15
|
+
pyopenapi_gen/core/schemas.py,sha256=WAh7VypQtgNj92R7cr4Yr2_yjd_EOGBYK8lAs19Tkhc,1555
|
16
|
+
pyopenapi_gen/core/streaming_helpers.py,sha256=XToNnm-EDAqiKh9ZS4GRxyastFkfSyNR0av-NDTZMPg,2706
|
17
|
+
pyopenapi_gen/core/telemetry.py,sha256=l6z972882MRzNOXU2leAvtnlYFLMSKKQ_oHz4qU5_n0,2225
|
18
|
+
pyopenapi_gen/core/utils.py,sha256=_qCXID5wkEGK9KRZ1Ob-A16mI6QPaLio7leIjsbsVTE,14016
|
19
|
+
pyopenapi_gen/core/warning_collector.py,sha256=DYl9D7eZYs04mDU84KeonS-5-d0aM7hNqraXTex31ss,2799
|
20
|
+
pyopenapi_gen/core/auth/base.py,sha256=E2KUerA_mYv9D7xulUm-lenIxqZHqanjA4oRKpof2ZE,792
|
21
|
+
pyopenapi_gen/core/auth/plugins.py,sha256=bDWx4MTRFsCKp1i__BsQtZEvQPGU-NKI137-zoxmrgs,3465
|
22
|
+
pyopenapi_gen/core/loader/__init__.py,sha256=bt-MQ35fbq-f1YnCcopPg53TuXCI9_7wcMzQZoWVpjU,391
|
23
|
+
pyopenapi_gen/core/loader/loader.py,sha256=bogAgDr2XvJWmMAFE006b3K_5AmC8eg2uj_TpYtLAfg,5591
|
24
|
+
pyopenapi_gen/core/loader/operations/__init__.py,sha256=7se21D-BOy7Qw6C9auJ9v6D3NCuRiDpRlhqxGq11fJs,366
|
25
|
+
pyopenapi_gen/core/loader/operations/parser.py,sha256=ai5iZZA2nicouC77iEvo8jKGXbHKbX_NcTy44lkwOVQ,6896
|
26
|
+
pyopenapi_gen/core/loader/operations/post_processor.py,sha256=3FZ5o59J2bSpZP-tNIec0A2hw095cC27GKqkhGrgHZA,2437
|
27
|
+
pyopenapi_gen/core/loader/operations/request_body.py,sha256=qz-wh014ejb1SGTuVRNODSXc95_iOLAjw05aDRhbXoo,3099
|
28
|
+
pyopenapi_gen/core/loader/parameters/__init__.py,sha256=p13oSibCRC5RCfsP6w7yD9MYs5TXcdI4WwPv7oGUYKk,284
|
29
|
+
pyopenapi_gen/core/loader/parameters/parser.py,sha256=4-p9s8VRm2hukXvvMF8zkd2YqSZsB18NYccVS3rwqIg,4773
|
30
|
+
pyopenapi_gen/core/loader/responses/__init__.py,sha256=6APWoH3IdNkgVmI0KsgZoZ6knDaG-S-pnUCa6gkzT8E,216
|
31
|
+
pyopenapi_gen/core/loader/responses/parser.py,sha256=T0QXH_3c-Y6_S6DvveKHPfV_tID7qhBoX0nFtdLCa0A,3896
|
32
|
+
pyopenapi_gen/core/loader/schemas/__init__.py,sha256=rlhujYfw_IzWgzhVhYMJ3eIhE6C5Vi1Ylba-BHEVqOg,296
|
33
|
+
pyopenapi_gen/core/loader/schemas/extractor.py,sha256=7-lpDhs9W9wVhG1OCASdyft_V1kUH7NdP8D4x-raGjk,8364
|
34
|
+
pyopenapi_gen/core/parsing/__init__.py,sha256=RJsIR6cHaNoI4tBcpMlAa0JsY64vsHb9sPxPg6rd8FQ,486
|
35
|
+
pyopenapi_gen/core/parsing/context.py,sha256=0QpIT4Iwgsvbna-NU_CcztntZlCJAj4GA5ae-iEye2I,7934
|
36
|
+
pyopenapi_gen/core/parsing/cycle_helpers.py,sha256=nG5ysNavL_6lpnHWFUZR9qraBxqOzuNfI6NgSEa8a5M,5939
|
37
|
+
pyopenapi_gen/core/parsing/schema_finalizer.py,sha256=fsyuOenLJA3TndzYVETqKkSlo2Qz3TsD1YDtlbyOATQ,6839
|
38
|
+
pyopenapi_gen/core/parsing/schema_parser.py,sha256=qFdan2djgdRBtzVCLiDBooVqXgcuWy_JbzDGLTJpPeE,30502
|
39
|
+
pyopenapi_gen/core/parsing/unified_cycle_detection.py,sha256=3nplaCVh2dFwBPbmDc2kiU0SzTPXXktdQ5Rc0Q9Uu9s,10873
|
40
|
+
pyopenapi_gen/core/parsing/common/__init__.py,sha256=U3sHMO-l6S3Cm04CVOYmBCpqLEZvCylUI7yQfcTwxYU,27
|
41
|
+
pyopenapi_gen/core/parsing/common/type_parser.py,sha256=cK7xtxhoD43K2WjLP9TGip3As3akYeYW7L2XztXCecg,2562
|
42
|
+
pyopenapi_gen/core/parsing/common/ref_resolution/__init__.py,sha256=BZOSPQo8bongKYgA4w-KGNBCjfNKoe1mm91CrqNIaTk,150
|
43
|
+
pyopenapi_gen/core/parsing/common/ref_resolution/resolve_schema_ref.py,sha256=y2RBVA0Kk1Vd23NBnKRdggn0tYADbTfaW3v0Ji5K5aE,3636
|
44
|
+
pyopenapi_gen/core/parsing/common/ref_resolution/helpers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
45
|
+
pyopenapi_gen/core/parsing/common/ref_resolution/helpers/cyclic_properties.py,sha256=tsHnIdyznAxXz_yA9Ub1ONxi2GSYcVJwKogBkTm95jU,2160
|
46
|
+
pyopenapi_gen/core/parsing/common/ref_resolution/helpers/direct_cycle.py,sha256=UoqD9I7s-WwI50PlgwFmLhFQd3ai8YIJycfkQhq6QlI,1145
|
47
|
+
pyopenapi_gen/core/parsing/common/ref_resolution/helpers/existing_schema.py,sha256=mgHopKN9ZB2maLrPRNubrSavq0oLYjeJQac60IMRj1Q,627
|
48
|
+
pyopenapi_gen/core/parsing/common/ref_resolution/helpers/list_response.py,sha256=j_mcjyawpTsl4_2vn3DjBP2OckHL0vzfDajODxEGzNE,1801
|
49
|
+
pyopenapi_gen/core/parsing/common/ref_resolution/helpers/missing_ref.py,sha256=BsyO6eCNO9NDRmj-aWyQZ4DaXsqRtkc7KdIzUEyNKQ4,1843
|
50
|
+
pyopenapi_gen/core/parsing/common/ref_resolution/helpers/new_schema.py,sha256=MTaxiyqoPEaNFqF7tQHii3IH41M05wPKt6lBQi1SCDU,1625
|
51
|
+
pyopenapi_gen/core/parsing/common/ref_resolution/helpers/stripped_suffix.py,sha256=ukKU64ozHINPiVlHE9YBDz1Nq2i6Xh64jhoWSEqbK5c,1774
|
52
|
+
pyopenapi_gen/core/parsing/keywords/__init__.py,sha256=enTLacWXGXLIOjSJ3j7KNUDzU27Kq3Ww79sFElz02cM,27
|
53
|
+
pyopenapi_gen/core/parsing/keywords/all_of_parser.py,sha256=s0aav49R4LYAwfEimWa0ZuFwbNWkYpRAJmcmSVDsO-s,3594
|
54
|
+
pyopenapi_gen/core/parsing/keywords/any_of_parser.py,sha256=r9_0opPM75p0rPgdcRTBmae7Td3jPkJouuL_ksuFWtM,2856
|
55
|
+
pyopenapi_gen/core/parsing/keywords/array_items_parser.py,sha256=dIb3_VsEkqsR9W4rwXoTT9IW313TnH66sQzJL4K7EQQ,2645
|
56
|
+
pyopenapi_gen/core/parsing/keywords/one_of_parser.py,sha256=82SUPd0hk0QF4-hMr0QJmRSFa9nnJL8ncYmvgkIKKXs,2601
|
57
|
+
pyopenapi_gen/core/parsing/keywords/properties_parser.py,sha256=bm248ApsNskFPQF4fXq7mT5oJf6FF9yAcdVLmK6el3E,4426
|
58
|
+
pyopenapi_gen/core/parsing/transformers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
59
|
+
pyopenapi_gen/core/parsing/transformers/inline_enum_extractor.py,sha256=hXuht-t0Syi5vPO8qn9GcjEpyDcZnfFVHVIlwfMa8L0,13461
|
60
|
+
pyopenapi_gen/core/parsing/transformers/inline_object_promoter.py,sha256=4njv5raMVtspL6DoU9mxabU3yhgXHLTEhR8KmI9YMoA,5083
|
61
|
+
pyopenapi_gen/core/writers/code_writer.py,sha256=uWH5tRFIdT3RHsRV1haWQxESwhwMoM2G_CxnKB8uP88,4776
|
62
|
+
pyopenapi_gen/core/writers/documentation_writer.py,sha256=Vce-_kD4XDm3HfZb_ibSEKAu2fbTZCzzdojn9TPgFhU,8706
|
63
|
+
pyopenapi_gen/core/writers/line_writer.py,sha256=uhysxO6bh_9POUQHhoqYI4_savfAgjH4EcwBdNrVtPc,7759
|
64
|
+
pyopenapi_gen/core/writers/python_construct_renderer.py,sha256=llZZN7uV-Qa7WRybKJ0Ev7VchNYQDGxamkYN-JtdA70,10203
|
65
|
+
pyopenapi_gen/core_package_template/README.md,sha256=8YP-MS0KxphRbCGBf7kV3dYIFLU9piOJ3IMm3K_0hcI,1488
|
66
|
+
pyopenapi_gen/emit/models_emitter.py,sha256=Ty5yHGzvBDYa_qQwbyPNRLWPnHaWR_KLh6pYxT7uePY,7193
|
67
|
+
pyopenapi_gen/emitters/client_emitter.py,sha256=kmMVnG-wAOJm7TUm0xOQ5YnSJfYxz1SwtpiyoUCbcCA,1939
|
68
|
+
pyopenapi_gen/emitters/core_emitter.py,sha256=RcBsAYQ3ZKcWwtkzQmyHkL7VtDQjbIObFLXD9M_GdpI,8020
|
69
|
+
pyopenapi_gen/emitters/docs_emitter.py,sha256=aouKqhRdtVvYfGVsye_uqM80nONRy0SqN06cr1l3OgA,1137
|
70
|
+
pyopenapi_gen/emitters/endpoints_emitter.py,sha256=2VuJJF0hpzyN-TqY9XVLQtTJ-QgedZe5Vj8ITBGsJYE,9558
|
71
|
+
pyopenapi_gen/emitters/exceptions_emitter.py,sha256=qPTIPXDyqSUtpmBIp-V4ap1uMHUPmYziCSN62t7qcAE,1918
|
72
|
+
pyopenapi_gen/emitters/models_emitter.py,sha256=I3IKwtKVocD3UVrI7cINXI8NjLwUZqHuGgvS3hjWUJ8,22192
|
73
|
+
pyopenapi_gen/generator/client_generator.py,sha256=avYz5GCp7t6vRAFJCvXw0ipLQGX2QfgWtfOwr3QlOqY,28880
|
74
|
+
pyopenapi_gen/helpers/__init__.py,sha256=m4jSQ1sDH6CesIcqIl_kox4LcDFabGxBpSIWVwbHK0M,39
|
75
|
+
pyopenapi_gen/helpers/endpoint_utils.py,sha256=q6SIvPsfSowqhrlEDNdCJztMM6uirsAPpqcKScpWMRQ,22669
|
76
|
+
pyopenapi_gen/helpers/type_cleaner.py,sha256=PRBqeEUPyEKHwedB4RZPrEDxUJ6q_h5ANains0WHIwg,13613
|
77
|
+
pyopenapi_gen/helpers/type_helper.py,sha256=uWLmJ25FHnqPf0-Pqakk4-lJ4xr5VBOF6gQP26KBAms,4276
|
78
|
+
pyopenapi_gen/helpers/url_utils.py,sha256=IflBiOcCzLrOvC5P25y12pk88Zu3X071hq4bCeDDxK0,340
|
79
|
+
pyopenapi_gen/helpers/type_resolution/__init__.py,sha256=TbaQZp7jvBiYgmuzuG8Wp56xZq32xEKtpunHqZVG1VA,85
|
80
|
+
pyopenapi_gen/helpers/type_resolution/array_resolver.py,sha256=dFppBtA6CxmiWAMR6rwGnQPv4AibL3nxtzw1LbeXVn4,2023
|
81
|
+
pyopenapi_gen/helpers/type_resolution/composition_resolver.py,sha256=wq6CRGxGgOKK470ln5Tpk9SzHtMuwB22TXHsRLtUFyw,3015
|
82
|
+
pyopenapi_gen/helpers/type_resolution/finalizer.py,sha256=_BcOBmOvadhBTUAvIc0Ak8FNxFw1uYL4rkKWtU68_m4,4332
|
83
|
+
pyopenapi_gen/helpers/type_resolution/named_resolver.py,sha256=akHVthcD7cp9lHI-TCeABMacwQ2Z1gGp8zMGNsI_b5A,9403
|
84
|
+
pyopenapi_gen/helpers/type_resolution/object_resolver.py,sha256=jayEjBr4evzIVMMAPc7g_gKb6BShFbAXG1oHMgskOcI,12373
|
85
|
+
pyopenapi_gen/helpers/type_resolution/primitive_resolver.py,sha256=qTshZaye5ohibVfcJYCzh4v3CAshguMGWPt2FgvQeNM,1960
|
86
|
+
pyopenapi_gen/helpers/type_resolution/resolver.py,sha256=qQY6wAitBluA-tofiyJ67Gxx8ol1W528zDWd9izYN5s,1982
|
87
|
+
pyopenapi_gen/types/__init__.py,sha256=Tv4xouOXp1CeOcnhDdh_wWF9PBHAeZmCeVPSm71kouI,359
|
88
|
+
pyopenapi_gen/types/contracts/__init__.py,sha256=qf5kJbbZ8TuH79UQSHBvjE1odKfNJrt5NrBEmurFlSU,358
|
89
|
+
pyopenapi_gen/types/contracts/protocols.py,sha256=eyjsrvHQv1viNON9itrHO5TA-PtWUZERdK3aPO_3uXM,2887
|
90
|
+
pyopenapi_gen/types/contracts/types.py,sha256=ruZYB0JZcFm1h2mfYVpfIyT2oV_NeCtZTdBaxncYDoQ,829
|
91
|
+
pyopenapi_gen/types/resolvers/__init__.py,sha256=_5kA49RvyOTyXgt0GbbOfHJcdQw2zHxvU9af8GGyNWc,295
|
92
|
+
pyopenapi_gen/types/resolvers/reference_resolver.py,sha256=qnaZeLmtyh4_NBMcKib58s6o5ycUJaattYt8F38_qIo,2053
|
93
|
+
pyopenapi_gen/types/resolvers/response_resolver.py,sha256=kcuYyHvE3D-pgtITdMlYdCBF6aplaoJNRlvjHXEnSSI,7446
|
94
|
+
pyopenapi_gen/types/resolvers/schema_resolver.py,sha256=R0N03MDLVzaFBQcrFOOTre1zqIg6APiWdHAT96ldgQ0,16898
|
95
|
+
pyopenapi_gen/types/services/__init__.py,sha256=inSUKmY_Vnuym6tC-AhvjCTj16GbkfxCGLESRr_uQPE,123
|
96
|
+
pyopenapi_gen/types/services/type_service.py,sha256=doHOR1rxu5M1TgVUvDg4bN3M_AsmGELiFhu1XVYNjU4,5118
|
97
|
+
pyopenapi_gen/visit/client_visitor.py,sha256=vpLCGF353XtBjfS7W69-1b1d79opTb1i6qBue6vSz5g,11152
|
98
|
+
pyopenapi_gen/visit/docs_visitor.py,sha256=hqgd4DAoy7T5Bap4mpH4R-nIZSyAWwFYmrIuNHM03Rg,1644
|
99
|
+
pyopenapi_gen/visit/exception_visitor.py,sha256=6gWkjEWMYM35_rBNCgB-xdE0RvYwbj49wytAorLHK9k,2097
|
100
|
+
pyopenapi_gen/visit/visitor.py,sha256=PANoV9zXMUrefr0pBLXIKkDOaTIjQ2hyL82cidVBCLU,3645
|
101
|
+
pyopenapi_gen/visit/endpoint/__init__.py,sha256=DftIZSWp6Z8jKWoJE2VGKL4G_5cqwFXe9v-PALMmsGk,73
|
102
|
+
pyopenapi_gen/visit/endpoint/endpoint_visitor.py,sha256=SjUmzbhYjMDEN3axkU4nS7Ny5BHadKPYAng8h-cAR-A,4599
|
103
|
+
pyopenapi_gen/visit/endpoint/generators/__init__.py,sha256=-X-GYnJZ9twiEBr_U0obW8VuSoY6IJmYaxinn-seMzA,50
|
104
|
+
pyopenapi_gen/visit/endpoint/generators/docstring_generator.py,sha256=fhWlmzCXXgpGCWey09H6O-ctCy8SFvLJ_P8u6oLJJAk,5832
|
105
|
+
pyopenapi_gen/visit/endpoint/generators/endpoint_method_generator.py,sha256=Y_guTE3o3ZS6ZLbynMPVmPmxevD2enFFN5HZd-YU3wM,3914
|
106
|
+
pyopenapi_gen/visit/endpoint/generators/request_generator.py,sha256=OnkrkRk39_BrK9ZDvyWqJYLz1mocD2zY7j70yIpS0J4,5374
|
107
|
+
pyopenapi_gen/visit/endpoint/generators/response_handler_generator.py,sha256=A9WG6oW0P9AkjmaXfxxShcyJp-k671OlVOGQPe2oduQ,25353
|
108
|
+
pyopenapi_gen/visit/endpoint/generators/signature_generator.py,sha256=tV6NU-lrpX6aJc9DEshtoeaRclW0OFkzk6sOaIkIc04,4316
|
109
|
+
pyopenapi_gen/visit/endpoint/generators/url_args_generator.py,sha256=EsmNuVSkGfUqrmV7-1GiLPzdN86V5UqLfs1SVY0jsf0,9590
|
110
|
+
pyopenapi_gen/visit/endpoint/processors/__init__.py,sha256=_6RqpOdDuDheArqDBi3ykhsaetACny88WUuuAJvr_ME,29
|
111
|
+
pyopenapi_gen/visit/endpoint/processors/import_analyzer.py,sha256=FELhcWT63lEUQpu8GqTJnCzX6JC6T-B7YSfYqyPQPCU,3239
|
112
|
+
pyopenapi_gen/visit/endpoint/processors/parameter_processor.py,sha256=BygP8yzSTrxfvNpEQIHERjd2NpEXDiwpCtmMseJKRq0,7700
|
113
|
+
pyopenapi_gen/visit/model/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
114
|
+
pyopenapi_gen/visit/model/alias_generator.py,sha256=3iPFDjCXU0Vm59Hfp64jTDfHoUL8ouXTTfoEwiOVm4Q,3558
|
115
|
+
pyopenapi_gen/visit/model/dataclass_generator.py,sha256=7hZjMKrZhOPMV254b8LRixJQp83qQbQNJTNfmN1SCMA,8308
|
116
|
+
pyopenapi_gen/visit/model/enum_generator.py,sha256=QWsD-IAxGOxKQuC6LLNUvbT8Ot3NWrLFsaYT0DI16DU,9670
|
117
|
+
pyopenapi_gen/visit/model/model_visitor.py,sha256=PZeQd7-dlxZf5gY10BW-DhswmAGF903NccV6L56mjoE,9439
|
118
|
+
pyopenapi_gen-0.8.3.dist-info/METADATA,sha256=q-eA9iAEiLjZqdOze9ZUOiwNsS4Tu6EuWu_yZPDWzBY,7277
|
119
|
+
pyopenapi_gen-0.8.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
120
|
+
pyopenapi_gen-0.8.3.dist-info/entry_points.txt,sha256=gxSlNiwom50T3OEZnlocA6qRjGdV0bn6hN_Xr-Ub5wA,56
|
121
|
+
pyopenapi_gen-0.8.3.dist-info/licenses/LICENSE,sha256=UFAyTWKa4w10-QerlJaHJeep7G2gcwpf-JmvI2dS2Gc,1088
|
122
|
+
pyopenapi_gen-0.8.3.dist-info/RECORD,,
|
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2025 Ville Venäläinen, Mindhive Oy
|
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.
|