airbyte-agent-jira 0.1.22__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.
- airbyte_agent_jira/__init__.py +91 -0
- airbyte_agent_jira/_vendored/__init__.py +1 -0
- airbyte_agent_jira/_vendored/connector_sdk/__init__.py +82 -0
- airbyte_agent_jira/_vendored/connector_sdk/auth_strategies.py +1123 -0
- airbyte_agent_jira/_vendored/connector_sdk/auth_template.py +135 -0
- airbyte_agent_jira/_vendored/connector_sdk/cloud_utils/__init__.py +5 -0
- airbyte_agent_jira/_vendored/connector_sdk/cloud_utils/client.py +213 -0
- airbyte_agent_jira/_vendored/connector_sdk/connector_model_loader.py +965 -0
- airbyte_agent_jira/_vendored/connector_sdk/constants.py +78 -0
- airbyte_agent_jira/_vendored/connector_sdk/exceptions.py +23 -0
- airbyte_agent_jira/_vendored/connector_sdk/executor/__init__.py +31 -0
- airbyte_agent_jira/_vendored/connector_sdk/executor/hosted_executor.py +197 -0
- airbyte_agent_jira/_vendored/connector_sdk/executor/local_executor.py +1574 -0
- airbyte_agent_jira/_vendored/connector_sdk/executor/models.py +190 -0
- airbyte_agent_jira/_vendored/connector_sdk/extensions.py +694 -0
- airbyte_agent_jira/_vendored/connector_sdk/http/__init__.py +37 -0
- airbyte_agent_jira/_vendored/connector_sdk/http/adapters/__init__.py +9 -0
- airbyte_agent_jira/_vendored/connector_sdk/http/adapters/httpx_adapter.py +251 -0
- airbyte_agent_jira/_vendored/connector_sdk/http/config.py +98 -0
- airbyte_agent_jira/_vendored/connector_sdk/http/exceptions.py +119 -0
- airbyte_agent_jira/_vendored/connector_sdk/http/protocols.py +114 -0
- airbyte_agent_jira/_vendored/connector_sdk/http/response.py +102 -0
- airbyte_agent_jira/_vendored/connector_sdk/http_client.py +686 -0
- airbyte_agent_jira/_vendored/connector_sdk/introspection.py +262 -0
- airbyte_agent_jira/_vendored/connector_sdk/logging/__init__.py +11 -0
- airbyte_agent_jira/_vendored/connector_sdk/logging/logger.py +264 -0
- airbyte_agent_jira/_vendored/connector_sdk/logging/types.py +92 -0
- airbyte_agent_jira/_vendored/connector_sdk/observability/__init__.py +11 -0
- airbyte_agent_jira/_vendored/connector_sdk/observability/models.py +19 -0
- airbyte_agent_jira/_vendored/connector_sdk/observability/redactor.py +81 -0
- airbyte_agent_jira/_vendored/connector_sdk/observability/session.py +94 -0
- airbyte_agent_jira/_vendored/connector_sdk/performance/__init__.py +6 -0
- airbyte_agent_jira/_vendored/connector_sdk/performance/instrumentation.py +57 -0
- airbyte_agent_jira/_vendored/connector_sdk/performance/metrics.py +93 -0
- airbyte_agent_jira/_vendored/connector_sdk/schema/__init__.py +75 -0
- airbyte_agent_jira/_vendored/connector_sdk/schema/base.py +161 -0
- airbyte_agent_jira/_vendored/connector_sdk/schema/components.py +239 -0
- airbyte_agent_jira/_vendored/connector_sdk/schema/connector.py +131 -0
- airbyte_agent_jira/_vendored/connector_sdk/schema/extensions.py +109 -0
- airbyte_agent_jira/_vendored/connector_sdk/schema/operations.py +146 -0
- airbyte_agent_jira/_vendored/connector_sdk/schema/security.py +223 -0
- airbyte_agent_jira/_vendored/connector_sdk/secrets.py +182 -0
- airbyte_agent_jira/_vendored/connector_sdk/telemetry/__init__.py +10 -0
- airbyte_agent_jira/_vendored/connector_sdk/telemetry/config.py +32 -0
- airbyte_agent_jira/_vendored/connector_sdk/telemetry/events.py +58 -0
- airbyte_agent_jira/_vendored/connector_sdk/telemetry/tracker.py +151 -0
- airbyte_agent_jira/_vendored/connector_sdk/types.py +245 -0
- airbyte_agent_jira/_vendored/connector_sdk/utils.py +60 -0
- airbyte_agent_jira/_vendored/connector_sdk/validation.py +822 -0
- airbyte_agent_jira/connector.py +978 -0
- airbyte_agent_jira/connector_model.py +2827 -0
- airbyte_agent_jira/models.py +741 -0
- airbyte_agent_jira/types.py +117 -0
- airbyte_agent_jira-0.1.22.dist-info/METADATA +113 -0
- airbyte_agent_jira-0.1.22.dist-info/RECORD +56 -0
- airbyte_agent_jira-0.1.22.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Component models for OpenAPI 3.1: Schema, Parameter, RequestBody, Response, Components.
|
|
3
|
+
|
|
4
|
+
References:
|
|
5
|
+
- https://spec.openapis.org/oas/v3.1.0#components-object
|
|
6
|
+
- https://spec.openapis.org/oas/v3.1.0#schema-object
|
|
7
|
+
- https://spec.openapis.org/oas/v3.1.0#parameter-object
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from typing import Any, Dict, List, Literal, Optional, Union
|
|
11
|
+
|
|
12
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
13
|
+
|
|
14
|
+
from .security import SecurityScheme
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class Schema(BaseModel):
|
|
18
|
+
"""
|
|
19
|
+
JSON Schema definition for data models.
|
|
20
|
+
|
|
21
|
+
OpenAPI Reference: https://spec.openapis.org/oas/v3.1.0#schema-object
|
|
22
|
+
|
|
23
|
+
Note: Uses Dict[str, Any] for properties to support nested schemas and $ref.
|
|
24
|
+
Reference resolution happens at runtime in config_loader.py.
|
|
25
|
+
|
|
26
|
+
Extensions:
|
|
27
|
+
- x-airbyte-resource-name: Name of the resource this schema represents (Airbyte extension)
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
model_config = ConfigDict(populate_by_name=True, extra="forbid")
|
|
31
|
+
|
|
32
|
+
# Core JSON Schema fields
|
|
33
|
+
type: Optional[str] = None
|
|
34
|
+
format: Optional[str] = None
|
|
35
|
+
title: Optional[str] = None
|
|
36
|
+
description: Optional[str] = None
|
|
37
|
+
default: Optional[Any] = None
|
|
38
|
+
example: Optional[Any] = None
|
|
39
|
+
|
|
40
|
+
# Object properties
|
|
41
|
+
properties: Dict[str, Any] = Field(default_factory=dict) # May contain $ref
|
|
42
|
+
required: List[str] = Field(default_factory=list)
|
|
43
|
+
additional_properties: Optional[Any] = Field(None, alias="additionalProperties")
|
|
44
|
+
|
|
45
|
+
# Array properties
|
|
46
|
+
items: Optional[Any] = None # May be Schema or $ref
|
|
47
|
+
|
|
48
|
+
# Validation
|
|
49
|
+
enum: Optional[List[Any]] = None
|
|
50
|
+
min_length: Optional[int] = Field(None, alias="minLength")
|
|
51
|
+
max_length: Optional[int] = Field(None, alias="maxLength")
|
|
52
|
+
minimum: Optional[float] = None
|
|
53
|
+
maximum: Optional[float] = None
|
|
54
|
+
pattern: Optional[str] = None
|
|
55
|
+
|
|
56
|
+
# Composition
|
|
57
|
+
all_of: Optional[List[Any]] = Field(None, alias="allOf")
|
|
58
|
+
any_of: Optional[List[Any]] = Field(None, alias="anyOf")
|
|
59
|
+
one_of: Optional[List[Any]] = Field(None, alias="oneOf")
|
|
60
|
+
not_: Optional[Any] = Field(None, alias="not")
|
|
61
|
+
|
|
62
|
+
# Metadata
|
|
63
|
+
nullable: Optional[bool] = Field(None, deprecated="Use type union with null instead (OpenAPI 3.1)")
|
|
64
|
+
read_only: Optional[bool] = Field(None, alias="readOnly")
|
|
65
|
+
write_only: Optional[bool] = Field(None, alias="writeOnly")
|
|
66
|
+
deprecated: Optional[bool] = None
|
|
67
|
+
|
|
68
|
+
# Airbyte extensions
|
|
69
|
+
x_airbyte_entity_name: Optional[str] = Field(None, alias="x-airbyte-entity-name")
|
|
70
|
+
x_airbyte_stream_name: Optional[str] = Field(None, alias="x-airbyte-stream-name")
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class Parameter(BaseModel):
|
|
74
|
+
"""
|
|
75
|
+
Operation parameter definition.
|
|
76
|
+
|
|
77
|
+
OpenAPI Reference: https://spec.openapis.org/oas/v3.1.0#parameter-object
|
|
78
|
+
"""
|
|
79
|
+
|
|
80
|
+
model_config = ConfigDict(populate_by_name=True, extra="forbid")
|
|
81
|
+
|
|
82
|
+
name: str
|
|
83
|
+
in_: Literal["query", "header", "path", "cookie"] = Field(alias="in")
|
|
84
|
+
description: Optional[str] = None
|
|
85
|
+
required: Optional[bool] = None
|
|
86
|
+
deprecated: Optional[bool] = None
|
|
87
|
+
allow_empty_value: Optional[bool] = Field(None, alias="allowEmptyValue")
|
|
88
|
+
|
|
89
|
+
# Schema can be inline or reference
|
|
90
|
+
schema_: Optional[Dict[str, Any]] = Field(None, alias="schema")
|
|
91
|
+
|
|
92
|
+
# Style and examples
|
|
93
|
+
style: Optional[str] = None
|
|
94
|
+
explode: Optional[bool] = None
|
|
95
|
+
example: Optional[Any] = None
|
|
96
|
+
examples: Optional[Dict[str, Any]] = None
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
class MediaType(BaseModel):
|
|
100
|
+
"""
|
|
101
|
+
Media type object for request/response content.
|
|
102
|
+
|
|
103
|
+
OpenAPI Reference: https://spec.openapis.org/oas/v3.1.0#media-type-object
|
|
104
|
+
"""
|
|
105
|
+
|
|
106
|
+
model_config = ConfigDict(populate_by_name=True, extra="forbid")
|
|
107
|
+
|
|
108
|
+
schema_: Optional[Dict[str, Any]] = Field(None, alias="schema")
|
|
109
|
+
example: Optional[Any] = None
|
|
110
|
+
examples: Optional[Dict[str, Any]] = None
|
|
111
|
+
encoding: Optional[Dict[str, Any]] = None
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
class GraphQLBodyConfig(BaseModel):
|
|
115
|
+
"""
|
|
116
|
+
GraphQL body type configuration for x-airbyte-body-type extension.
|
|
117
|
+
|
|
118
|
+
Used when x-airbyte-body-type.type = "graphql"
|
|
119
|
+
"""
|
|
120
|
+
|
|
121
|
+
model_config = ConfigDict(populate_by_name=True, extra="forbid")
|
|
122
|
+
|
|
123
|
+
type: Literal["graphql"] = Field(..., description="Body type identifier (must be 'graphql')")
|
|
124
|
+
query: str = Field(
|
|
125
|
+
...,
|
|
126
|
+
description="GraphQL query or mutation string with optional template placeholders (e.g., {{ variable }})",
|
|
127
|
+
)
|
|
128
|
+
variables: Optional[Dict[str, Any]] = Field(
|
|
129
|
+
None,
|
|
130
|
+
description="Variables to substitute in the GraphQL query using template syntax (e.g., {{ param_name }})",
|
|
131
|
+
)
|
|
132
|
+
operationName: Optional[str] = Field(None, description="Operation name for queries with multiple operations")
|
|
133
|
+
default_fields: Optional[Union[str, List[str]]] = Field(
|
|
134
|
+
None,
|
|
135
|
+
description="Default fields to select if not provided in request parameters. Can be a string or array of field names.",
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
# Union type for all body type configs (extensible for future types like XML, SOAP, etc.)
|
|
140
|
+
BodyTypeConfig = Union[GraphQLBodyConfig]
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
class PathOverrideConfig(BaseModel):
|
|
144
|
+
"""
|
|
145
|
+
Path override configuration for x-airbyte-path-override extension.
|
|
146
|
+
|
|
147
|
+
Used when the OpenAPI path differs from the actual HTTP endpoint path.
|
|
148
|
+
Common for GraphQL APIs where multiple resources share the same endpoint (e.g., /graphql).
|
|
149
|
+
|
|
150
|
+
Example:
|
|
151
|
+
OpenAPI path: /graphql:repositories (for uniqueness)
|
|
152
|
+
Actual HTTP path: /graphql (configured here)
|
|
153
|
+
"""
|
|
154
|
+
|
|
155
|
+
model_config = ConfigDict(populate_by_name=True, extra="forbid")
|
|
156
|
+
|
|
157
|
+
path: str = Field(
|
|
158
|
+
...,
|
|
159
|
+
description=("Actual HTTP path to use for requests (e.g., '/graphql'). " "Must start with '/'"),
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
class RequestBody(BaseModel):
|
|
164
|
+
"""
|
|
165
|
+
Request body definition.
|
|
166
|
+
|
|
167
|
+
OpenAPI Reference: https://spec.openapis.org/oas/v3.1.0#request-body-object
|
|
168
|
+
|
|
169
|
+
Airbyte Extensions:
|
|
170
|
+
See connector_sdk.extensions for documentation:
|
|
171
|
+
- AIRBYTE_BODY_TYPE: Body type and configuration (nested structure)
|
|
172
|
+
"""
|
|
173
|
+
|
|
174
|
+
model_config = ConfigDict(populate_by_name=True, extra="forbid")
|
|
175
|
+
|
|
176
|
+
description: Optional[str] = None
|
|
177
|
+
content: Dict[str, MediaType] = Field(default_factory=dict)
|
|
178
|
+
required: Optional[bool] = None
|
|
179
|
+
|
|
180
|
+
# Airbyte extensions for GraphQL support
|
|
181
|
+
# See connector_sdk.extensions for AIRBYTE_BODY_TYPE constant
|
|
182
|
+
x_airbyte_body_type: Optional[BodyTypeConfig] = Field(
|
|
183
|
+
None,
|
|
184
|
+
alias="x-airbyte-body-type", # AIRBYTE_BODY_TYPE
|
|
185
|
+
description=(
|
|
186
|
+
"Body type and configuration. Contains 'type' field (e.g., 'graphql') " "and type-specific configuration (query, variables, etc.)."
|
|
187
|
+
),
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
class Header(BaseModel):
|
|
192
|
+
"""
|
|
193
|
+
Header definition.
|
|
194
|
+
|
|
195
|
+
OpenAPI Reference: https://spec.openapis.org/oas/v3.1.0#header-object
|
|
196
|
+
"""
|
|
197
|
+
|
|
198
|
+
model_config = ConfigDict(populate_by_name=True, extra="forbid")
|
|
199
|
+
|
|
200
|
+
description: Optional[str] = None
|
|
201
|
+
required: Optional[bool] = None
|
|
202
|
+
deprecated: Optional[bool] = None
|
|
203
|
+
schema_: Optional[Dict[str, Any]] = Field(None, alias="schema")
|
|
204
|
+
example: Optional[Any] = None
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
class Response(BaseModel):
|
|
208
|
+
"""
|
|
209
|
+
Response definition.
|
|
210
|
+
|
|
211
|
+
OpenAPI Reference: https://spec.openapis.org/oas/v3.1.0#response-object
|
|
212
|
+
"""
|
|
213
|
+
|
|
214
|
+
model_config = ConfigDict(populate_by_name=True, extra="forbid")
|
|
215
|
+
|
|
216
|
+
description: str
|
|
217
|
+
headers: Optional[Dict[str, Header]] = None
|
|
218
|
+
content: Optional[Dict[str, MediaType]] = None
|
|
219
|
+
links: Optional[Dict[str, Any]] = None
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
class Components(BaseModel):
|
|
223
|
+
"""
|
|
224
|
+
Reusable component definitions.
|
|
225
|
+
|
|
226
|
+
OpenAPI Reference: https://spec.openapis.org/oas/v3.1.0#components-object
|
|
227
|
+
"""
|
|
228
|
+
|
|
229
|
+
model_config = ConfigDict(populate_by_name=True, extra="forbid")
|
|
230
|
+
|
|
231
|
+
schemas: Dict[str, Schema] = Field(default_factory=dict)
|
|
232
|
+
responses: Dict[str, Response] = Field(default_factory=dict)
|
|
233
|
+
parameters: Dict[str, Parameter] = Field(default_factory=dict)
|
|
234
|
+
examples: Optional[Dict[str, Any]] = None
|
|
235
|
+
request_bodies: Dict[str, RequestBody] = Field(default_factory=dict, alias="requestBodies")
|
|
236
|
+
headers: Optional[Dict[str, Header]] = None
|
|
237
|
+
security_schemes: Dict[str, SecurityScheme] = Field(default_factory=dict, alias="securitySchemes")
|
|
238
|
+
links: Optional[Dict[str, Any]] = None
|
|
239
|
+
callbacks: Optional[Dict[str, Any]] = None
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Root OpenAPI 3.1 connector specification model.
|
|
3
|
+
|
|
4
|
+
References:
|
|
5
|
+
- https://spec.openapis.org/oas/v3.1.0#openapi-object
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from typing import Any
|
|
11
|
+
|
|
12
|
+
from pydantic import BaseModel, ConfigDict, Field, field_validator
|
|
13
|
+
|
|
14
|
+
from ..constants import OPENAPI_VERSION_PREFIX
|
|
15
|
+
|
|
16
|
+
from .base import Info, Server
|
|
17
|
+
from .components import Components
|
|
18
|
+
from .operations import PathItem
|
|
19
|
+
from .security import SecurityRequirement
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class Tag(BaseModel):
|
|
23
|
+
"""
|
|
24
|
+
Tag metadata for grouping operations.
|
|
25
|
+
|
|
26
|
+
OpenAPI Reference: https://spec.openapis.org/oas/v3.1.0#tag-object
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
model_config = ConfigDict(populate_by_name=True, extra="forbid")
|
|
30
|
+
|
|
31
|
+
name: str
|
|
32
|
+
description: str | None = None
|
|
33
|
+
external_docs: dict[str, Any] | None = Field(None, alias="externalDocs")
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class ExternalDocs(BaseModel):
|
|
37
|
+
"""
|
|
38
|
+
External documentation reference.
|
|
39
|
+
|
|
40
|
+
OpenAPI Reference: https://spec.openapis.org/oas/v3.1.0#external-documentation-object
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
model_config = ConfigDict(populate_by_name=True, extra="forbid")
|
|
44
|
+
|
|
45
|
+
description: str | None = None
|
|
46
|
+
url: str
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class OpenAPIConnector(BaseModel):
|
|
50
|
+
"""
|
|
51
|
+
Root OpenAPI 3.1 connector specification.
|
|
52
|
+
|
|
53
|
+
OpenAPI Reference: https://spec.openapis.org/oas/v3.1.0#openapi-object
|
|
54
|
+
|
|
55
|
+
This is the top-level model that represents a complete OpenAPI 3.1 specification
|
|
56
|
+
for an Airbyte connector. It enforces strict validation (extra='forbid') to catch
|
|
57
|
+
typos and unknown extensions.
|
|
58
|
+
"""
|
|
59
|
+
|
|
60
|
+
model_config = ConfigDict(populate_by_name=True, extra="forbid", validate_default=True)
|
|
61
|
+
|
|
62
|
+
# Required fields
|
|
63
|
+
openapi: str
|
|
64
|
+
info: Info
|
|
65
|
+
paths: dict[str, PathItem] = Field(default_factory=dict)
|
|
66
|
+
|
|
67
|
+
# Optional fields
|
|
68
|
+
servers: list[Server] = Field(default_factory=list)
|
|
69
|
+
components: Components | None = None
|
|
70
|
+
security: list[SecurityRequirement] | None = None
|
|
71
|
+
tags: list[Tag] | None = None
|
|
72
|
+
external_docs: ExternalDocs | None = Field(None, alias="externalDocs")
|
|
73
|
+
|
|
74
|
+
@field_validator("openapi")
|
|
75
|
+
@classmethod
|
|
76
|
+
def validate_openapi_version(cls, v: str) -> str:
|
|
77
|
+
"""Validate that OpenAPI version is 3.1.x."""
|
|
78
|
+
if not v.startswith(OPENAPI_VERSION_PREFIX):
|
|
79
|
+
raise ValueError(f"OpenAPI version must be {OPENAPI_VERSION_PREFIX}x, got: {v}")
|
|
80
|
+
return v
|
|
81
|
+
|
|
82
|
+
def get_entity_operations(self, entity_name: str) -> list[tuple[str, str, Any]]:
|
|
83
|
+
"""
|
|
84
|
+
Get all operations for a specific entity.
|
|
85
|
+
|
|
86
|
+
Args:
|
|
87
|
+
entity_name: The x-airbyte-entity value to filter by
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
List of tuples: (path, method, operation)
|
|
91
|
+
"""
|
|
92
|
+
results = []
|
|
93
|
+
for path, path_item in self.paths.items():
|
|
94
|
+
for method in [
|
|
95
|
+
"get",
|
|
96
|
+
"post",
|
|
97
|
+
"put",
|
|
98
|
+
"patch",
|
|
99
|
+
"delete",
|
|
100
|
+
"options",
|
|
101
|
+
"head",
|
|
102
|
+
"trace",
|
|
103
|
+
]:
|
|
104
|
+
operation = getattr(path_item, method, None)
|
|
105
|
+
if operation and operation.x_airbyte_entity == entity_name:
|
|
106
|
+
results.append((path, method, operation))
|
|
107
|
+
return results
|
|
108
|
+
|
|
109
|
+
def list_entities(self) -> list[str]:
|
|
110
|
+
"""
|
|
111
|
+
List all unique entity names defined in x-airbyte-entity extensions.
|
|
112
|
+
|
|
113
|
+
Returns:
|
|
114
|
+
Sorted list of unique entity names
|
|
115
|
+
"""
|
|
116
|
+
entities = set()
|
|
117
|
+
for path_item in self.paths.values():
|
|
118
|
+
for method in [
|
|
119
|
+
"get",
|
|
120
|
+
"post",
|
|
121
|
+
"put",
|
|
122
|
+
"patch",
|
|
123
|
+
"delete",
|
|
124
|
+
"options",
|
|
125
|
+
"head",
|
|
126
|
+
"trace",
|
|
127
|
+
]:
|
|
128
|
+
operation = getattr(path_item, method, None)
|
|
129
|
+
if operation and operation.x_airbyte_entity:
|
|
130
|
+
entities.add(operation.x_airbyte_entity)
|
|
131
|
+
return sorted(entities)
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Extension models for future features.
|
|
3
|
+
|
|
4
|
+
These models are defined but NOT yet added to the main schema models.
|
|
5
|
+
They serve as:
|
|
6
|
+
1. Type hints for future use
|
|
7
|
+
2. Documentation of planned extensions
|
|
8
|
+
3. Ready-to-use structures when features are implemented
|
|
9
|
+
|
|
10
|
+
NOTE: These are not currently active in the schema. They will be added
|
|
11
|
+
to Operation, Schema, or other models when their respective features
|
|
12
|
+
are implemented.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from typing import Literal, Optional
|
|
16
|
+
|
|
17
|
+
from pydantic import BaseModel, ConfigDict
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class PaginationConfig(BaseModel):
|
|
21
|
+
"""
|
|
22
|
+
Configuration for pagination support.
|
|
23
|
+
|
|
24
|
+
NOT YET USED - Defined for future implementation.
|
|
25
|
+
|
|
26
|
+
When active, will be added to Operation model as:
|
|
27
|
+
x_pagination: Optional[PaginationConfig] = Field(None, alias="x-pagination")
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
model_config = ConfigDict(populate_by_name=True, extra="forbid")
|
|
31
|
+
|
|
32
|
+
style: Literal["cursor", "offset", "page", "link"]
|
|
33
|
+
limit_param: str = "limit"
|
|
34
|
+
|
|
35
|
+
# Cursor-based pagination
|
|
36
|
+
cursor_param: Optional[str] = None
|
|
37
|
+
cursor_source: Optional[Literal["body", "headers"]] = "body"
|
|
38
|
+
cursor_path: Optional[str] = None
|
|
39
|
+
|
|
40
|
+
# Offset-based pagination
|
|
41
|
+
offset_param: Optional[str] = None
|
|
42
|
+
|
|
43
|
+
# Page-based pagination
|
|
44
|
+
page_param: Optional[str] = None
|
|
45
|
+
|
|
46
|
+
# Response parsing
|
|
47
|
+
data_path: str = "data"
|
|
48
|
+
has_more_path: Optional[str] = None
|
|
49
|
+
|
|
50
|
+
# Limits
|
|
51
|
+
max_page_size: Optional[int] = None
|
|
52
|
+
default_page_size: int = 100
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class RateLimitConfig(BaseModel):
|
|
56
|
+
"""
|
|
57
|
+
Configuration for rate limiting.
|
|
58
|
+
|
|
59
|
+
NOT YET USED - Defined for future implementation.
|
|
60
|
+
|
|
61
|
+
When active, might be added to Server or root OpenAPIConnector as:
|
|
62
|
+
x_rate_limit: Optional[RateLimitConfig] = Field(None, alias="x-rate-limit")
|
|
63
|
+
"""
|
|
64
|
+
|
|
65
|
+
model_config = ConfigDict(populate_by_name=True, extra="forbid")
|
|
66
|
+
|
|
67
|
+
max_requests: int
|
|
68
|
+
time_window_seconds: int
|
|
69
|
+
retry_after_header: Optional[str] = "Retry-After"
|
|
70
|
+
respect_retry_after: bool = True
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class RetryConfig(BaseModel):
|
|
74
|
+
"""
|
|
75
|
+
Configuration for retry strategy with exponential backoff.
|
|
76
|
+
|
|
77
|
+
Used to configure automatic retries for transient errors (429, 5xx, timeouts, network errors).
|
|
78
|
+
Can be specified at the connector level via x-airbyte-retry-config in the OpenAPI spec's info section.
|
|
79
|
+
|
|
80
|
+
By default, retries are enabled with max_attempts=3. To disable retries, set max_attempts=1
|
|
81
|
+
in your connector's x-airbyte-retry-config.
|
|
82
|
+
|
|
83
|
+
Example YAML usage:
|
|
84
|
+
info:
|
|
85
|
+
title: My API
|
|
86
|
+
x-airbyte-retry-config:
|
|
87
|
+
max_attempts: 5
|
|
88
|
+
initial_delay_seconds: 2.0
|
|
89
|
+
retry_after_header: "X-RateLimit-Reset"
|
|
90
|
+
retry_after_format: "unix_timestamp"
|
|
91
|
+
"""
|
|
92
|
+
|
|
93
|
+
model_config = ConfigDict(populate_by_name=True, extra="forbid")
|
|
94
|
+
|
|
95
|
+
# Core retry settings (max_attempts=3 enables retries by default)
|
|
96
|
+
max_attempts: int = 3
|
|
97
|
+
initial_delay_seconds: float = 1.0
|
|
98
|
+
max_delay_seconds: float = 60.0
|
|
99
|
+
exponential_base: float = 2.0
|
|
100
|
+
jitter: bool = True
|
|
101
|
+
|
|
102
|
+
# Which errors to retry
|
|
103
|
+
retry_on_status_codes: list[int] = [429, 500, 502, 503, 504]
|
|
104
|
+
retry_on_timeout: bool = True
|
|
105
|
+
retry_on_network_error: bool = True
|
|
106
|
+
|
|
107
|
+
# Header-based delay extraction
|
|
108
|
+
retry_after_header: str = "Retry-After"
|
|
109
|
+
retry_after_format: Literal["seconds", "milliseconds", "unix_timestamp"] = "seconds"
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Operation and PathItem models for OpenAPI 3.1.
|
|
3
|
+
|
|
4
|
+
References:
|
|
5
|
+
- https://spec.openapis.org/oas/v3.1.0#operation-object
|
|
6
|
+
- https://spec.openapis.org/oas/v3.1.0#path-item-object
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from typing import Any, Dict, List, Optional
|
|
10
|
+
|
|
11
|
+
from pydantic import BaseModel, ConfigDict, Field, model_validator
|
|
12
|
+
|
|
13
|
+
from ..extensions import ActionTypeLiteral
|
|
14
|
+
from .components import Parameter, PathOverrideConfig, RequestBody, Response
|
|
15
|
+
from .security import SecurityRequirement
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class Operation(BaseModel):
|
|
19
|
+
"""
|
|
20
|
+
Single API operation (GET, POST, PUT, PATCH, DELETE, etc.).
|
|
21
|
+
|
|
22
|
+
OpenAPI Reference: https://spec.openapis.org/oas/v3.1.0#operation-object
|
|
23
|
+
|
|
24
|
+
Extensions:
|
|
25
|
+
- x-airbyte-entity: Entity name (Airbyte extension)
|
|
26
|
+
- x-airbyte-action: Semantic action (Airbyte extension)
|
|
27
|
+
- x-airbyte-path-override: Path override (Airbyte extension)
|
|
28
|
+
- x-airbyte-record-extractor: JSONPath to extract records from response (Airbyte extension)
|
|
29
|
+
|
|
30
|
+
Future extensions (not yet active):
|
|
31
|
+
- x-airbyte-pagination: Pagination configuration for list operations
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
model_config = ConfigDict(populate_by_name=True, extra="forbid")
|
|
35
|
+
|
|
36
|
+
# Standard OpenAPI fields
|
|
37
|
+
tags: Optional[List[str]] = None
|
|
38
|
+
summary: Optional[str] = None
|
|
39
|
+
description: Optional[str] = None
|
|
40
|
+
external_docs: Optional[Dict[str, Any]] = Field(None, alias="externalDocs")
|
|
41
|
+
operation_id: Optional[str] = Field(None, alias="operationId")
|
|
42
|
+
parameters: Optional[List[Parameter]] = None
|
|
43
|
+
request_body: Optional[RequestBody] = Field(None, alias="requestBody")
|
|
44
|
+
responses: Dict[str, Response] = Field(default_factory=dict)
|
|
45
|
+
callbacks: Optional[Dict[str, Any]] = None
|
|
46
|
+
deprecated: Optional[bool] = None
|
|
47
|
+
security: Optional[List[SecurityRequirement]] = None
|
|
48
|
+
servers: Optional[List[Any]] = None # Can override root servers
|
|
49
|
+
|
|
50
|
+
# Airbyte extensions
|
|
51
|
+
x_airbyte_entity: str = Field(..., alias="x-airbyte-entity")
|
|
52
|
+
x_airbyte_action: ActionTypeLiteral = Field(..., alias="x-airbyte-action")
|
|
53
|
+
x_airbyte_path_override: Optional[PathOverrideConfig] = Field(
|
|
54
|
+
None,
|
|
55
|
+
alias="x-airbyte-path-override",
|
|
56
|
+
description=("Override path for HTTP requests when OpenAPI path " "differs from actual endpoint"),
|
|
57
|
+
)
|
|
58
|
+
x_airbyte_record_extractor: Optional[str] = Field(
|
|
59
|
+
None,
|
|
60
|
+
alias="x-airbyte-record-extractor",
|
|
61
|
+
description=(
|
|
62
|
+
"JSONPath expression to extract records from API response envelopes. "
|
|
63
|
+
"When specified, executor extracts data at this path instead of returning "
|
|
64
|
+
"full response. Returns array for list/search actions, single record for "
|
|
65
|
+
"get/create/update/delete actions."
|
|
66
|
+
),
|
|
67
|
+
)
|
|
68
|
+
x_airbyte_meta_extractor: Optional[Dict[str, str]] = Field(
|
|
69
|
+
None,
|
|
70
|
+
alias="x-airbyte-meta-extractor",
|
|
71
|
+
description=(
|
|
72
|
+
"Dictionary mapping field names to JSONPath expressions for extracting "
|
|
73
|
+
"metadata (pagination info, request IDs, etc.) from API response envelopes. "
|
|
74
|
+
"Each key becomes a field in ExecutionResult.meta with the value extracted "
|
|
75
|
+
"using the corresponding JSONPath expression. "
|
|
76
|
+
"Example: {'pagination': '$.pagination', 'request_id': '$.requestId'}"
|
|
77
|
+
),
|
|
78
|
+
)
|
|
79
|
+
x_airbyte_file_url: Optional[str] = Field(None, alias="x-airbyte-file-url")
|
|
80
|
+
x_airbyte_untested: Optional[bool] = Field(
|
|
81
|
+
None,
|
|
82
|
+
alias="x-airbyte-untested",
|
|
83
|
+
description=(
|
|
84
|
+
"Mark operation as untested to skip cassette validation in readiness checks. "
|
|
85
|
+
"Use this for operations that cannot be recorded (e.g., webhooks, real-time streams). "
|
|
86
|
+
"Validation will generate a warning instead of an error when cassettes are missing."
|
|
87
|
+
),
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
# Future extensions (commented out, defined for future use)
|
|
91
|
+
# from .extensions import PaginationConfig
|
|
92
|
+
# x_pagination: Optional[PaginationConfig] = Field(None, alias="x-airbyte-pagination")
|
|
93
|
+
|
|
94
|
+
@model_validator(mode="after")
|
|
95
|
+
def validate_download_action_requirements(self) -> "Operation":
|
|
96
|
+
"""
|
|
97
|
+
Validate download operation requirements.
|
|
98
|
+
|
|
99
|
+
Rules:
|
|
100
|
+
- If x-airbyte-action is "download":
|
|
101
|
+
- x-airbyte-file-url must be non-empty if provided
|
|
102
|
+
- If x-airbyte-action is not "download":
|
|
103
|
+
- x-airbyte-file-url must not be present
|
|
104
|
+
"""
|
|
105
|
+
action = self.x_airbyte_action
|
|
106
|
+
file_url = self.x_airbyte_file_url
|
|
107
|
+
|
|
108
|
+
if action == "download":
|
|
109
|
+
# If file_url is provided, it must be non-empty
|
|
110
|
+
if file_url is not None and not file_url.strip():
|
|
111
|
+
raise ValueError("x-airbyte-file-url must be non-empty when provided for download operations")
|
|
112
|
+
else:
|
|
113
|
+
# Non-download actions cannot have file_url
|
|
114
|
+
if file_url is not None:
|
|
115
|
+
raise ValueError(f"x-airbyte-file-url can only be used with x-airbyte-action: download, but action is '{action}'")
|
|
116
|
+
|
|
117
|
+
return self
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
class PathItem(BaseModel):
|
|
121
|
+
"""
|
|
122
|
+
Path item containing operations for different HTTP methods.
|
|
123
|
+
|
|
124
|
+
OpenAPI Reference: https://spec.openapis.org/oas/v3.1.0#path-item-object
|
|
125
|
+
"""
|
|
126
|
+
|
|
127
|
+
model_config = ConfigDict(populate_by_name=True, extra="forbid")
|
|
128
|
+
|
|
129
|
+
# Common fields for all operations
|
|
130
|
+
summary: Optional[str] = None
|
|
131
|
+
description: Optional[str] = None
|
|
132
|
+
servers: Optional[List[Any]] = None
|
|
133
|
+
parameters: Optional[List[Parameter]] = None
|
|
134
|
+
|
|
135
|
+
# HTTP methods (all optional)
|
|
136
|
+
get: Optional[Operation] = None
|
|
137
|
+
put: Optional[Operation] = None
|
|
138
|
+
post: Optional[Operation] = None
|
|
139
|
+
delete: Optional[Operation] = None
|
|
140
|
+
options: Optional[Operation] = None
|
|
141
|
+
head: Optional[Operation] = None
|
|
142
|
+
patch: Optional[Operation] = None
|
|
143
|
+
trace: Optional[Operation] = None
|
|
144
|
+
|
|
145
|
+
# Reference support
|
|
146
|
+
ref: Optional[str] = Field(None, alias="$ref")
|