Coverage for src/configuration/openapi.py: 99%
352 statements
« prev ^ index » next coverage.py v7.6.10, created at 2025-03-25 22:39 -0400
« prev ^ index » next coverage.py v7.6.10, created at 2025-03-25 22:39 -0400
1"""OpenAPI 3.1 Object for creating function calls and storing API info in postgres
2Docs from https://swagger.io/specification"""
4# pylint: skip-file
5import json
6from collections import defaultdict
7from contextvars import ContextVar
8from typing import Any, Callable, List, Optional, cast
9from uuid import NAMESPACE_URL, UUID, uuid4, uuid5
11from pydantic import ( # type: ignore
12 AliasGenerator,
13 BaseModel,
14 ConfigDict,
15 Field,
16 field_validator,
17 model_validator,
18 validator,
19)
20from pydantic.alias_generators import to_camel, to_snake # type: ignore
21from sqlalchemy import select
22from sqlalchemy.orm import scoped_session
23from sqlalchemy.orm.util import identity_key
24from typing_extensions import Self
26from common.models import openapi_entity, openapi_server
28# context_session: ContextVar = ContextVar("session")
30# context_relationships: ContextVar = ContextVar("relationships")
33# config_info: dict = defaultdict(lambda: defaultdict(dict))
36class ExampleObject(BaseModel):
37 """An object grouping an internal or external example value with basic
38 summary and description metadata. This object is typically used in fields
39 named examples (plural), and is a referenceable alternative to older example
40 (singular) fields that do not support referencing or metadata.
42 Examples allow demonstration of the usage of properties, parameters and
43 objects within OpenAPI."""
45 model_config = ConfigDict(
46 alias_generator=AliasGenerator(
47 validation_alias=to_snake,
48 serialization_alias=to_camel,
49 ),
50 populate_by_name=True,
51 extra="allow",
52 )
53 """This object MAY be extended with Specification Extensions."""
55 summary: str | None = None
56 """Short description for the example."""
58 description: str | None = None
59 """Long description for the example.
60 [CommonMark syntax](https://spec.commonmark.org/)
61 MAY be used for rich text representation."""
63 # TODO: parse as plaintext string
64 value: object | None = None
65 """Embedded literal example. The value field and externalValue field are
66 mutually exclusive. To represent examples of media types that cannot
67 naturally represented in JSON or YAML, use a string value to contain the
68 example, escaping where necessary."""
70 external_value: str | None = None
71 """A URI that identifies the literal example.
72 This provides the capability to reference examples that cannot easily be
73 included in JSON or YAML documents. The value field and externalValue field
74 are mutually exclusive. See the rules for resolving Relative References."""
77class ContactObject(BaseModel):
78 """Contact information for the exposed API."""
80 model_config = ConfigDict(
81 alias_generator=AliasGenerator(
82 validation_alias=to_snake,
83 serialization_alias=to_camel,
84 ),
85 populate_by_name=True,
86 extra="allow",
87 )
88 """This object MAY be extended with Specification Extensions."""
90 name: str | None = None
91 """The identifying name of the contact person/organization."""
93 url: str | None = None
94 """The URI for the contact information. This MUST be in the form of a URI."""
96 email: str | None = None
97 """The email address of the contact person/organization.
98 This MUST be in the form of an email address."""
101class LicenseObject(BaseModel):
102 """The license information for the exposed API"""
104 model_config = ConfigDict(
105 alias_generator=AliasGenerator(
106 validation_alias=to_snake,
107 serialization_alias=to_camel,
108 ),
109 populate_by_name=True,
110 extra="allow",
111 )
112 """This object MAY be extended with Specification Extensions."""
114 name: str
115 """REQUIRED. The license name used for the API."""
117 identifier: str | None = None
118 """An [SPDX](https://spdx.org/licenses/) license expression for the API.
119 The identifier field is mutually exclusive of the url field."""
121 url: str | None = None
122 """A URI for the license used for the API.
123 This MUST be in the form of a URI.
124 The url field is mutually exclusive of the identifier field."""
127class InfoObject(BaseModel):
128 """OpenAPI Info Object"""
130 model_config = ConfigDict(
131 alias_generator=AliasGenerator(
132 validation_alias=to_snake,
133 serialization_alias=to_camel,
134 ),
135 populate_by_name=True,
136 extra="allow",
137 )
138 """This object MAY be extended with Specification Extensions."""
140 title: str
141 """REQUIRED. The title of the API."""
143 version: str
144 """REQUIRED. The version of the OpenAPI Document
145 (which is distinct from the OpenAPI Specification version
146 or the version of the API being described or the version
147 of the OpenAPI Description)."""
149 summary: str | None = None
150 """A short summary of the API."""
152 description: str | None = None
153 """A description of the API.
154 [CommonMark syntax](https://spec.commonmark.org/)
155 MAY be used for rich text representation."""
157 terms_of_service: str | None = None
158 """A URI for the Terms of Service for the API.
159 This MUST be in the form of a URI."""
161 contact: ContactObject | None = None
162 """The contact information for the exposed API."""
164 license_: LicenseObject | None = None
165 """The license information for the exposed API"""
168class ServerVariableObject(BaseModel):
169 """An object representing a Server Variable
170 for server URL template substitution."""
172 model_config = ConfigDict(
173 alias_generator=AliasGenerator(
174 validation_alias=to_snake,
175 serialization_alias=to_camel,
176 ),
177 populate_by_name=True,
178 extra="allow",
179 )
180 """This object MAY be extended with Specification Extensions."""
182 default: str
183 """REQUIRED. The default value to use for substitution,
184 which SHALL be sent if an alternate value is not supplied.
185 If the enum is defined, the value MUST exist in the enum's values.
186 Note that this behavior is different from the Schema Object's default keyword,
187 which documents the receiver's behavior
188 rather than inserting the value into the data."""
190 enum: List[str] | None = None
191 """An enumeration of string values to be used
192 if the substitution options are from a limited set.
193 The array MUST NOT be empty."""
195 description: str | None = None
196 """An optional description for the server variable.
197 [CommonMark syntax](https://spec.commonmark.org/)
198 MAY be used for rich text representation."""
201class ServerObject(BaseModel):
202 """An object representing a Server."""
204 model_config = ConfigDict(
205 alias_generator=AliasGenerator(
206 validation_alias=to_snake,
207 serialization_alias=to_camel,
208 ),
209 populate_by_name=True,
210 extra="allow",
211 )
212 """This object MAY be extended with Specification Extensions."""
214 url: str
215 """REQUIRED. A URL to the target host.
216 This URL supports Server Variables and MAY be relative,
217 to indicate that the host location is relative to the location where
218 the document containing the Server Object is being served.
219 Variable substitutions will be made when a variable is named in {braces}."""
221 # oas_uuid: UUID
222 # """The UUID of the containing OpenAPI spec"""
224 # uuid: UUID
225 # """a unique UUID for storing in the database"""
227 # @validator("uuid", always=True)
228 # @classmethod
229 # def validate_uuid(cls, value, values):
230 # return uuid5(namespace=cls.uuid.NAMESPACE_URL, name=values["url"])
232 # @validator("oas_uuid", always=True)
233 # @classmethod
234 # def validate_oas_uuid(cls, value):
235 # return openapi_spec_id.get()
237 description: str | None = None
238 """An optional string describing the host designated by the URL.
239 [CommonMark syntax](https://spec.commonmark.org/)
240 MAY be used for rich text representation."""
242 variables: dict[str, ServerVariableObject] | None = None
243 """A map between a variable name and its value.
244 The value is used for substitution in the server's URL template."""
246 # @model_validator(mode="after")
247 # def finish(self) -> Self:
248 # session: scoped_session = config_info[openapi_spec_id.get()]["session"]
250 # db_object = openapi_server.OpenAPIServer(
251 # openapi_server_id=self.uuid, spec_id=self.oas_uuid
252 # )
253 # if session.query(db_object).scalar() is None:
254 # session.add(db_object)
255 # return self
258class ExternalDocumentationObject(BaseModel):
259 """Allows referencing an external resource for extended documentation"""
261 model_config = ConfigDict(
262 alias_generator=AliasGenerator(
263 validation_alias=to_snake,
264 serialization_alias=to_camel,
265 ),
266 populate_by_name=True,
267 extra="allow",
268 )
269 """This object MAY be extended with Specification Extensions."""
271 url: str
272 """REQUIRED. The URI for the target documentation.
273 This MUST be in the form of a URI."""
275 description: str | None = None
276 """A description of the target documentation.
277 [CommonMark syntax](https://spec.commonmark.org/)
278 MAY be used for rich text representation."""
281class ParameterObject(BaseModel):
282 """Describes a single operation parameter.
284 A unique parameter is defined by a combination of a name and location.
286 See [Appendix E](https://swagger.io/specification/#appendix-e-percent-encoding-and-form-media-types)
287 for a detailed examination of percent-encoding concerns,
288 including interactions with the
289 application/x-www-form-urlencoded query string format.
291 # Parameter Locations
293 There are four possible parameter locations specified by the in field:
295 path - Used together with Path Templating, where the parameter value is
296 actually part of the operation's URL.
297 This does not include the host or base path of the API.
298 For example, in /items/{itemId}, the path parameter is itemId.
299 query - Parameters that are appended to the URL.
300 For example, in /items?id=###, the query parameter is id.
301 header - Custom headers that are expected as part of the request.
302 Note that RFC7230 states header names are case insensitive.
303 cookie - Used to pass a specific cookie value to the API.
305 # Fixed Fields
307 The rules for serialization of the parameter are specified in one of two ways.
308 Parameter Objects MUST include either a content field or a schema field,
309 but not both. See Appendix B for a discussion of converting values of
310 various types to string representations.
312 # Common Fixed Fields
313 """
315 model_config = ConfigDict(
316 alias_generator=AliasGenerator(
317 validation_alias=to_snake,
318 serialization_alias=to_camel,
319 ),
320 populate_by_name=True,
321 extra="allow",
322 )
323 """These fields MAY be used with either content or schema."""
325 name: str
326 """REQUIRED. The name of the parameter. Parameter names are case sensitive.
328 - If `in` is "path", the name field MUST correspond to
329 a template expression occurring within the path field in the Paths Object.
330 See Path Templating for further information.
331 - If `in` is "header" and the name field is "Accept", "Content-Type" or
332 "Authorization", the parameter definition SHALL be ignored.
333 - For all other cases, the name corresponds to
334 the parameter name used by the `in` field."""
336 in_: str = Field(alias="in")
337 """REQUIRED. The location of the parameter.
338 Possible values are "query", "header", "path" or "cookie"."""
340 description: str | None = None
341 """A brief description of the parameter.
342 This could contain examples of use.
343 [CommonMark syntax](https://spec.commonmark.org/)
344 MAY be used for rich text representation."""
346 required: Optional[bool] = False
347 """Determines whether this parameter is mandatory. If the parameter location is "path", this field is REQUIRED and its value MUST be True. Otherwise, the field MAY be included and its default value is false."""
349 deprecated: Optional[bool] = False
351 allow_empty_value: Optional[bool] = False
352 """If True, clients MAY pass a zero-length string value in place of
353 parameters that would otherwise be omitted entirely,
354 which the server SHOULD interpret as the parameter being unused.
355 Default value is false.
356 If style is used, and if behavior is n/a (cannot be serialized),
357 the value of allowEmptyValue SHALL be ignored.
358 Interactions between this field and the parameter's Schema Object are
359 implementation-defined. This field is valid only for query parameters.
360 Use of this field is NOT RECOMMENDED,
361 and it is likely to be removed in a later revision."""
363 x_cuecode: str | None = Field(default=None, alias="x-cuecode")
365 # @model_validator(mode="after")
366 # def finish(self) -> Self:
367 # session: scoped_session = config_info[openapi_spec_id.get()]["session"]
368 # noun_prompt = self.x_cuecode
369 # if noun_prompt is None:
370 # noun_prompt = self.description
371 # if self.description is None:
372 # noun_prompt = self.name
373 # if (
374 # session.execute(
375 # select(openapi_entity.OpenAPIEntity).where(
376 # openapi_entity.OpenAPIEntity.noun_prompt == noun_prompt
377 # )
378 # ).scalar()
379 # is None
380 # ):
381 # session.add(
382 # openapi_entity.OpenAPIEntity(
383 # openapi_entity_id=uuid4(),
384 # contained_in_oa_spec_id=openapi_spec_id.get(),
385 # noun_prompt=noun_prompt,
386 # )
387 # )
388 # return self
391class ParameterObjectSchema(ParameterObject):
392 model_config = ConfigDict(
393 alias_generator=AliasGenerator(
394 validation_alias=to_snake,
395 serialization_alias=to_camel,
396 ),
397 populate_by_name=True,
398 extra="allow",
399 )
401 style: str
403 # @model_validator(mode="before")
404 # def validate_style(cls, values):
405 # if not "style" in data:
406 # if values["in"] == "query" or "cookie":
407 # values["style"] = "form"
408 # elif values["in"] == "path" or "header":
409 # values["style"] = "simple"
411 explode: bool = False
413 allow_reserved: bool = False
415 schema_: dict[str, Any] | None = Field(default=None, alias="schema")
416 """Schema for parameters"""
418 example: Any | None = None
420 examples: dict[str, ExampleObject] | None = None
423class ParameterObjectContent(ParameterObject):
424 model_config = ConfigDict(
425 alias_generator=AliasGenerator(
426 validation_alias=to_snake,
427 serialization_alias=to_camel,
428 ),
429 populate_by_name=True,
430 extra="allow",
431 )
432 content: dict[str, "MediaTypeObject"] | None = None
435class DiscriminatorObject(BaseModel):
436 """When request bodies or response payloads may be one of a number of
437 different schemas, a Discriminator Object gives a hint about the expected
438 schema of the document. This hint can be used to aid in serialization,
439 deserialization, and validation. The Discriminator Object does this by
440 implicitly or explicitly associating the possible values of a named property
441 with alternative schemas.
443 Note that discriminator MUST NOT change the validation outcome of the
444 schema."""
446 model_config = ConfigDict(
447 alias_generator=AliasGenerator(
448 validation_alias=to_snake,
449 serialization_alias=to_camel,
450 ),
451 populate_by_name=True,
452 extra="allow",
453 )
454 """This object MAY be extended with Specification Extensions."""
456 propety_name: str
457 """REQUIRED. The name of the property in the payload that will hold the
458 discriminating value. This property SHOULD be required in the payload
459 schema, as the behavior when the property is absent is undefined."""
461 mapping: dict[str, str] | None = None
462 """An object to hold mappings between payload values and schema names or
463 URI references."""
466class XMLObject(BaseModel):
467 """A metadata object that allows for more fine-tuned XML model definitions.
469 When using arrays, XML element names are not inferred
470 (for singular/plural forms) and the name field SHOULD be used to add that
471 information."""
473 model_config = ConfigDict(
474 alias_generator=AliasGenerator(
475 validation_alias=to_snake,
476 serialization_alias=to_camel,
477 ),
478 populate_by_name=True,
479 extra="allow",
480 )
481 """This object MAY be extended with Specification Extensions."""
483 name: str | None = None
484 """Replaces the name of the element/attribute used for the described schema
485 property. When defined within items, it will affect the name of the
486 individual XML elements within the list. When defined alongside type being
487 "array" (outside the items), it will affect the wrapping element if and only
488 if wrapped is True. If wrapped is false, it will be ignored."""
490 namespace: str | None = None
491 """The URI of the namespace definition.
492 Value MUST be in the form of a non-relative URI."""
494 prefix: str | None = None
495 """The prefix to be used for the name."""
497 attribute: Optional[bool] = False
498 """Declares whether the property definition translates to an attribute
499 instead of an element. Default value is false."""
501 wrapped: Optional[bool] = False
502 """MAY be used only for an array definition.
503 Signifies whether the array is wrapped
504 (for example, <books><book/><book/></books>) or unwrapped (<book/><book/>).
505 Default value is false.
506 The definition takes effect only when defined alongside type being "array"
507 (outside the items)."""
510class SchemaObject(BaseModel):
511 """https://swagger.io/specification/#schema-object"""
513 model_config = ConfigDict(
514 alias_generator=AliasGenerator(
515 validation_alias=to_snake,
516 serialization_alias=to_camel,
517 ),
518 populate_by_name=True,
519 extra="allow",
520 )
522 discriminator: DiscriminatorObject | None = None
523 """Adds support for polymorphism.
524 The discriminator is used to determine which of a set of schemas a payload
525 is expected to satisfy.
526 See [Composition and Inheritance](https://swagger.io/specification/#composition-and-inheritance-polymorphism)
527 for more details."""
529 xml: XMLObject | None = None
530 """This MAY be used only on property schemas.
531 It has no effect on root schemas.
532 Adds additional metadata to describe the XML representation of this
533 property."""
535 external_docs: ExternalDocumentationObject | None = None
536 """Additional external documentation for this schema."""
538 example: object | None = None
539 """A free-form field to include an example of an instance for this schema.
540 To represent examples that cannot be naturally represented in JSON or YAML,
541 a string value can be used to contain the example with escaping
542 where necessary.
544 Deprecated: The example field has been deprecated in favor of the
545 JSON Schema examples keyword. Use of example is discouraged,
546 and later versions of this specification may remove it."""
549class HeaderObject(BaseModel):
550 """Describes a single header for HTTP responses and for individual parts in
551 multipart representations; see the relevant Response Object and
552 Encoding Object documentation for restrictions on which headers can be
553 described.
555 The Header Object follows the structure of the Parameter Object,
556 including determining its serialization strategy based on whether schema or
557 content is present, with the following changes:
559 1. `name` MUST NOT be specified, it is given in the corresponding headers
560 map.
561 2. `in` MUST NOT be specified, it is implicitly in header.
562 3. All traits that are affected by the location MUST be applicable to a
563 location of header (for example, style). This means that allowEmptyValue and
564 allowReserved MUST NOT be used, and style, if used, MUST be limited to
565 "simple".
567 # Fixed Fields
568 ## Common Fixed Fields
570 These fields MAY be used with either content or schema."""
572 model_config = ConfigDict(
573 alias_generator=AliasGenerator(
574 validation_alias=to_snake,
575 serialization_alias=to_camel,
576 ),
577 populate_by_name=True,
578 extra="allow",
579 )
580 """This object MAY be extended with Specification Extensions."""
582 description: str | None = None
583 """A brief description of the header. This could contain examples of use.
584 [CommonMark syntax](https://spec.commonmark.org/)
585 MAY be used for rich text representation."""
587 required: bool = False
588 """Determines whether this header is mandatory."""
590 deprecated: bool = False
591 """Specifies that the header is deprecated and
592 SHOULD be transitioned out of usage."""
595class HeaderObjectSchema(HeaderObject):
596 style: str | None = "simple"
597 """Describes how the header value will be serialized.
598 The default (and only legal value for headers) is "simple"."""
600 explode: bool = False
601 """When this is true, header values of type array or object generate a
602 single header whose value is a comma-separated list of the array items or
603 key-value pairs of the map, see Style Examples. For other data types this
604 field has no effect. The default value is false."""
606 schema_: SchemaObject | None = Field(alias="schema", default=None)
608 example: Any
610 examples: dict[str, ExampleObject] | None = None
613class HeaderObjectContent(HeaderObject):
614 content: dict[str, "MediaTypeObject"] | None = None
615 """A map containing the representations for the header.
616 The key is the media type and the value describes it.
617 The map MUST only contain one entry."""
620class EncodingObject(BaseModel):
621 """A single encoding definition applied to a single schema property.
622 See Appendix B for a discussion of converting values of various types to
623 string representations.
625 Properties are correlated with multipart parts using the name parameter of
626 Content-Disposition: form-data, and with application/x-www-form-urlencoded
627 using the query string parameter names. In both cases, their order is
628 implementation-defined.
630 See Appendix E for a detailed examination of percent-encoding concerns for
631 form media types.
632 # Fixed Fields
633 ## Common Fixed Fields
635 These fields MAY be used either with or without the RFC6570-style
636 serialization fields defined in the next section below."""
638 model_config = ConfigDict(
639 alias_generator=AliasGenerator(
640 validation_alias=to_snake,
641 serialization_alias=to_camel,
642 ),
643 populate_by_name=True,
644 extra="allow",
645 )
646 """This object MAY be extended with Specification Extensions."""
648 content_type: str | None = None
649 """The Content-Type for encoding a specific property.
650 The value is a comma-separated list, each element of which is either a
651 specific media type (e.g. image/png) or a wildcard media type (e.g. image/*).
652 Default value depends on the property type as shown in the table below."""
654 headers: dict[str, HeaderObject] | None = None
655 """A map allowing additional information to be provided as headers.
656 Content-Type is described separately and SHALL be ignored in this section.
657 This field SHALL be ignored if the request body media type is not a
658 multipart."""
661class MediaTypeObject(BaseModel):
662 """Each Media Type Object provides schema and examples for the media type
663 identified by its key.
665 When example or examples are provided, the example SHOULD match the
666 specified schema and be in the correct format as specified by the media
667 type and its encoding.
668 The example and examples fields are mutually exclusive,
669 and if either is present it SHALL override any example in the schema.
670 See [Working With Examples](https://swagger.io/specification/#working-with-examples)
671 for further guidance regarding the different ways of specifying examples,
672 including non-JSON/YAML values."""
674 model_config = ConfigDict(
675 alias_generator=AliasGenerator(
676 validation_alias=to_snake,
677 serialization_alias=to_camel,
678 ),
679 populate_by_name=True,
680 extra="allow",
681 )
682 """This object MAY be extended with Specification Extensions."""
684 # TODO: make this always be parsed as a string
685 example: object | None = None
686 """Example of the media type"""
688 examples: dict[str, ExampleObject] | None = None
689 """Examples of the media type"""
691 encoding: dict[str, EncodingObject] | None = None
692 """A map between a property name and its encoding information.
693 The key, being the property name, MUST exist in the schema as a property.
694 The encoding field SHALL only apply to Request Body Objects,
695 and only when the media type is multipart or
696 application/x-www-form-urlencoded.
697 If no Encoding Object is provided for a property,
698 the behavior is determined by the default values documented for the
699 Encoding Object."""
701 schema_: dict[str, Any] | None = Field(alias="schema", default=None)
702 """The schema defining the content of the request,
703 response, parameter, or header."""
706class RequestBodyObject(BaseModel):
707 """Describes a single request body."""
709 model_config = ConfigDict(
710 alias_generator=AliasGenerator(
711 validation_alias=to_snake,
712 serialization_alias=to_camel,
713 ),
714 populate_by_name=True,
715 extra="allow",
716 )
717 """This object MAY be extended with Specification Extensions."""
719 content: dict[str, MediaTypeObject]
720 """REQUIRED. The content of the request body.
721 The key is a media type or media type range and the value describes it.
722 For requests that match multiple keys,
723 only the most specific key is applicable.
724 e.g. \"text/plain\" overrides \"text/*\""""
726 description: str | None = None
727 """A brief description of the request body.
728 This could contain examples of use.
729 CommonMark syntax MAY be used for rich text representation."""
731 required: Optional[bool] = False
732 """Determines if the request body is required in the request.
733 Defaults to false."""
736class LinkObject(BaseModel):
737 """The Link Object represents a possible design-time link for a response.
738 The presence of a link does not guarantee the caller's ability to
739 successfully invoke it, rather it provides a known relationship and
740 traversal mechanism between responses and other operations.
742 Unlike dynamic links (i.e. links provided in the response payload),
743 the OAS linking mechanism does not require link information in the runtime
744 response.
746 For computing links and providing instructions to execute them,
747 a runtime expression is used for accessing values in an operation
748 and using them as parameters while invoking the linked operation."""
750 model_config = ConfigDict(
751 alias_generator=AliasGenerator(
752 validation_alias=to_snake,
753 serialization_alias=to_camel,
754 ),
755 populate_by_name=True,
756 extra="allow",
757 )
758 """This object MAY be extended with Specification Extensions."""
760 operation_ref: str | None = None
762 operation_id: str | None = None
764 # TODO: evaluate constants/expressions
765 parameters: dict[str, object] | None = None
766 """A map representing parameters to pass to an operation as specified with
767 operationId or identified via operationRef. The key is the parameter name
768 to be used (optionally qualified with the parameter location,
769 e.g. path.id for an id parameter in the path),
770 whereas the value can be a constant or an expression to be evaluated and
771 passed to the linked operation."""
773 # TODO: evaluate constants/expressions
774 request_body: object | None = None
775 """A literal value or {expression} to use as a request body when calling
776 the target operation."""
778 description: str | None = None
779 """A description of the link.
780 [CommonMark syntax](https://spec.commonmark.org/)
781 MAY be used for rich text representation."""
783 server: ServerObject | None = None
786class ResponseObject(BaseModel):
787 """Describes a single response from an API operation,
788 including design-time, static links to operations based on the response."""
790 model_config = ConfigDict(
791 alias_generator=AliasGenerator(
792 validation_alias=to_snake,
793 serialization_alias=to_camel,
794 ),
795 populate_by_name=True,
796 extra="allow",
797 )
798 """This object MAY be extended with Specification Extensions."""
800 description: str
801 """REQUIRED. A description of the response.
802 [CommonMark syntax](https://spec.commonmark.org/)
803 MAY be used for rich text representation."""
805 headers: dict[str, HeaderObject] | None = None
806 """Maps a header name to its definition.
807 RFC7230 states header names are case insensitive.
808 If a response header is defined with the name "Content-Type",
809 it SHALL be ignored."""
811 content: dict[str, MediaTypeObject] | None = None
812 """A map containing descriptions of potential response payloads.
813 The key is a media type or media type range and the value describes it.
814 For responses that match multiple keys, only the most specific key is
815 applicable. e.g. \"text/plain\" overrides \"text/*\""""
817 links: dict[str, LinkObject] | None = None
818 """A map of operations links that can be followed from the response.
819 The key of the map is a short name for the link,
820 following the naming constraints of the names for Component Objects."""
823SecurityRequirementObjects = List[dict[str, List[str]]]
826class OperationObject(BaseModel):
827 """Describes a single API operation on a path."""
829 model_config = ConfigDict(
830 alias_generator=AliasGenerator(
831 validation_alias=to_snake,
832 serialization_alias=to_camel,
833 ),
834 populate_by_name=True,
835 extra="allow",
836 )
837 """This object MAY be extended with Specification Extensions."""
839 tags: List[str] | None = None
840 """A list of tags for API documentation control.
841 Tags can be used for logical grouping of operations
842 by resources or any other qualifier."""
844 summary: str | None = None
845 """A short summary of what the operation does."""
847 description: str | None = None
848 """
849 A verbose explanation of the operation behavior.
850 [CommonMark syntax](https://spec.commonmark.org/)
851 MAY be used for rich text representation.
852 """
854 external_docs: ExternalDocumentationObject | None = None
855 """Additional external documentation for this operation."""
857 operation_id: str | None = None
858 """Unique string used to identify the operation.
859 The id MUST be unique among all operations described in the API.
860 The operationId value is case-sensitive.
861 Tools and libraries MAY use the operationId to uniquely identify an
862 operation, therefore, it is RECOMMENDED to follow
863 common programming naming conventions."""
865 parameters: List[ParameterObject] | None = None
866 """A list of parameters that are applicable for this operation.
867 If a parameter is already defined at the Path Item, the new definition will
868 override it but can never remove it.
869 The list MUST NOT include duplicated parameters.
870 A unique parameter is defined by a combination of a name and location.
871 The list can use the Reference Object to link to parameters that are
872 defined in the OpenAPI Object's components.parameters."""
874 request_body: RequestBodyObject | None = None
875 """The request body applicable for this operation.
876 The requestBody is fully supported in HTTP methods where the HTTP 1.1
877 specification RFC7231 has explicitly defined semantics for request bodies.
878 In other cases where the HTTP spec is vague (such as GET, HEAD and DELETE),
879 requestBody is permitted but does not have well-defined semantics and
880 SHOULD be avoided if possible."""
882 responses: dict[str, ResponseObject] | None = None
883 """The list of possible responses as they are returned from executing this
884 operation."""
886 callbacks: dict[str, dict[object, "PathItemObject"]] | None = None
887 """A map of possible out-of band callbacks related to the parent operation.
888 The key is a unique identifier for the Callback Object.
889 Each value in the map is a Callback Object that describes a request that
890 may be initiated by the API provider and the expected responses."""
892 security: SecurityRequirementObjects | None = None
893 """Each name MUST correspond to a security scheme which is declared in the
894 Security Schemes under the Components Object.
895 If the security scheme is of type "oauth2" or "openIdConnect",
896 then the value is a list of scope names required for the execution,
897 and the list MAY be empty if authorization does not require a specified
898 scope. For other security scheme types, the array MAY contain a list of
899 role names which are required for the execution, but are not otherwise
900 defined or exchanged in-band."""
902 servers: List[ServerObject] | None = None
903 """An alternative servers array to service this operation.
904 If a servers array is specified at the Path Item Object or OpenAPI Object
905 level, it will be overridden by this value."""
907 deprecated: bool | None = None
908 """Declares this operation to be deprecated. Consumers SHOULD refrain from
909 usage of the declared operation."""
911 x_cuecode_prompt: str | None = Field(alias="x-cuecode-prompt", default=None)
912 x_cuecode_skip: bool | None = Field(alias="x-cuecode-skip", default=False)
915class PathItemObject(BaseModel):
916 """Describes the operations available on a single path.
917 A Path Item MAY be empty, due to
918 [ACL constraints](https://swagger.io/specification/#security-filtering).
919 The path itself is still exposed to the documentation viewer
920 but they will not know which operations and parameters are available."""
922 model_config = ConfigDict(
923 alias_generator=AliasGenerator(
924 validation_alias=to_snake, serialization_alias=to_camel
925 ),
926 populate_by_name=True,
927 extra="allow",
928 )
929 """This object MAY be extended with Specification Extensions."""
931 summary: str | None = None
932 """An optional string summary,
933 intended to apply to all operations in this path."""
935 description: str | None = None
936 """An optional string description,
937 intended to apply to all operations in this path.
938 [CommonMark syntax](https://spec.commonmark.org/)
939 MAY be used for rich text representation."""
941 get: OperationObject | None = None
942 """A definition of a GET operation on this path."""
944 put: OperationObject | None = None
945 """A definition of a PUT operation on this path."""
947 post: OperationObject | None = None
948 """A definition of a POST operation on this path."""
950 delete: OperationObject | None = None
951 """A definition of a DELETE operation on this path."""
953 options: OperationObject | None = None
954 """A definition of a OPTIONS operation on this path."""
956 head: OperationObject | None = None
957 """A definition of a HEAD operation on this path."""
959 patch: OperationObject | None = None
960 """A definition of a PATCH operation on this path."""
962 trace: OperationObject | None = None
963 """A definition of a TRACE operation on this path."""
965 servers: List[ServerObject] | None = None
966 """An alternative servers array to service all operations in this path.
967 If a servers array is specified at the OpenAPI Object level,
968 it will be overridden by this value."""
970 parameters: List[ParameterObject] | None = None
971 """A list of parameters that are applicable for all the operations
972 described under this path. These parameters can be overridden at the
973 operation level, but cannot be removed there. The list MUST NOT include
974 duplicated parameters. A unique parameter is defined by a combination of a
975 name and location. The list can use the Reference Object to link to
976 parameters that are defined in the OpenAPI Object's
977 components.parameters."""
979 ref_: str | None = Field(alias="$ref", default=None)
980 """Allows for a referenced definition of this path item.
981 The value MUST be in the form of a URI,
982 and the referenced structure MUST be in the form of a Path Item Object.
983 In case a Path Item Object field appears both in the defined object
984 and the referenced object, the behavior is undefined.
985 See the rules for resolving
986 [Relative References](https://swagger.io/specification/#relative-references-in-api-description-uris)."""
988 x_cuecode_prompt: str | None = Field(alias="x-cuecode-prompt", default=None)
989 x_cuecode_skip: bool | None = Field(alias="x-cuecode-skip", default=False)
991 @model_validator(mode="after")
992 def finish(self) -> Self:
993 # TODO: After validation for Path Object
994 return self
997context_tag_uuids: ContextVar[dict] = ContextVar("tag_uuids")
998context_tags: ContextVar[dict] = ContextVar("tags")
1001class TagObject(BaseModel):
1002 """Tag Object"""
1004 model_config = ConfigDict(
1005 alias_generator=AliasGenerator(
1006 validation_alias=to_snake, serialization_alias=to_camel
1007 ),
1008 populate_by_name=True,
1009 extra="allow",
1010 )
1011 name: str
1012 """REQUIRED. The name of the tag."""
1014 description: str | None = None
1015 """A description for the tag.
1016 CommonMark syntax MAY be used for rich text representation."""
1018 x_cuecode: str | None = Field(default=None, alias="x-cuecode")
1020 externalDocs: ExternalDocumentationObject | None = None
1022 openapi_entity_id: UUID = Field(default_factory=lambda: uuid4())
1024 @model_validator(mode="after")
1025 def finish(self) -> Self:
1027 # tag_noun_prompt=self.x_cuecode
1028 # if tag_noun_prompt is None:
1029 # tag_noun_prompt = self.description
1030 # if tag_noun_prompt is None:
1031 # tag_noun_prompt = self.name
1033 # session: scoped_session = context_session.get()
1034 # entity = openapi_entity.OpenAPIEntity(
1035 # openapi_entity_id = self.openapi_entity_id,
1036 # contained_in_oa_spec_id = openapi_spec_id.get(),
1037 # noun_prompt=tag_noun_prompt
1038 # )
1039 # if session.execute(
1040 # select(openapi_entity.OpenAPIEntity)
1041 # .where(openapi_entity.OpenAPIEntity.noun_prompt == tag_noun_prompt)
1042 # ).scalar() is None:
1043 # session.add(entity)
1044 # tag_map: dict = context_tag_uuids.get()
1045 # tag_map[self.name] = self.openapi_entity_id
1046 # context_tag_uuids.set(tag_map)
1048 return self
1051class OAuthFlowObject(BaseModel):
1052 """Individual OAuth Flow Object"""
1054 model_config = ConfigDict(
1055 alias_generator=AliasGenerator(
1056 validation_alias=to_snake,
1057 serialization_alias=to_camel,
1058 ),
1059 populate_by_name=True,
1060 extra="allow",
1061 )
1063 authorization_url: str | None
1064 """only applies to oauth2 (\"implicit\", \"authorizationCode\")
1065 REQUIRED. The authorization URL to be used for this flow.
1066 This MUST be in the form of a URL.
1067 The OAuth2 standard requires the use of TLS."""
1069 token_url: str | None = None
1070 """only applies to oauth2(\"password\",
1071 \"clientCredentials\", \"authorizationCode\"). REQUIRED.
1072 The token URL to be used for this flow. This MUST be in the form of a URL.
1073 The OAuth2 standard requires the use of TLS."""
1075 refresh_url: str | None = None
1076 """The URL to be used for obtaining refresh tokens.
1077 This MUST be in the form of a URL.
1078 The OAuth2 standard requires the use of TLS."""
1080 scopes: dict[str, str] = {}
1081 """REQUIRED. The available scopes for the OAuth2 security scheme.
1082 A map between the scope name and a short description for it.
1083 The map MAY be empty."""
1086class OAuthFlowsObject(BaseModel):
1087 """OAsuth Flows object"""
1089 model_config = ConfigDict(
1090 alias_generator=AliasGenerator(
1091 validation_alias=to_snake,
1092 serialization_alias=to_camel,
1093 ),
1094 populate_by_name=True,
1095 extra="allow",
1096 )
1098 implicit: OAuthFlowObject | None = None
1099 password: OAuthFlowObject | None = None
1100 client_credentials: OAuthFlowObject | None = None
1101 authorization_code: OAuthFlowObject | None = None
1104class SecuritySchemeObject(BaseModel):
1105 """Security Scheme Object"""
1107 model_config = ConfigDict(
1108 alias_generator=AliasGenerator(
1109 validation_alias=to_snake,
1110 serialization_alias=to_camel,
1111 ),
1112 populate_by_name=True,
1113 extra="allow",
1114 )
1116 type: str
1117 """REQUIRED: type of security scheme; Valid values are 'apiKey', 'http',
1118 'mutualTLS', 'oath2', 'openIdConnect'."""
1120 description: str | None = None
1122 name: str | None = None
1123 """only applies to apiKey. REQUIRED.
1124 The name of the header, query or cookie parameter to be used."""
1126 in_: str | None = Field(alias="in", default=None)
1127 """only applies to apiKey. REQUIRED. The location of the API key.
1128 Valid values are \"query\", \"header\" or \"cookie\"."""
1130 scheme: str | None = None
1131 """only applies to http. REQUIRED.
1132 The name of the HTTP Authorization scheme to be used in the
1133 Authorization header as defined in [RFC7235] Section 5.1.
1134 The values used SHOULD be registered in the IANA Authentication Scheme
1135 registry."""
1137 bearer_format: str | None = None
1138 """only applies to http ("bearer). A hint to the client to identify how the
1139 bearer token is formatted. Bearer tokens are usually generated by an
1140 authorization server, so this information is primarily for documentation
1141 purposes."""
1143 flows: OAuthFlowsObject | None = None
1144 """only applies to oauth2. REQUIRED. An object containing configuration
1145 information for the flow types supported"""
1147 open_id_connect_url: str | None = None
1148 """only applies to openIdConnect. REQUIRED.
1149 OpenId Connect URL to discover OAuth2 configuration values.
1150 This MUST be in the form of a URL.
1151 The OpenID Connect standard requires the use of TLS."""
1154class ComponentsObject(BaseModel):
1155 """Components Object Removing this might be beneficial,
1156 since references are already resolved. Testing needed."""
1158 model_config = ConfigDict(
1159 alias_generator=AliasGenerator(
1160 validation_alias=to_snake,
1161 serialization_alias=to_camel,
1162 ),
1163 populate_by_name=True,
1164 extra="allow",
1165 )
1167 schemas: dict[str, SchemaObject] | None = None
1168 responses: dict[str, ResponseObject] | None = None
1169 parameters: dict[str, ParameterObject] | None = None
1170 examples: dict[str, ExampleObject] | None = None
1171 request_bodies: dict[str, RequestBodyObject] | None = None
1172 headers: dict[str, HeaderObject] | None = None
1173 security_schemes: dict[str, SecuritySchemeObject] | None = None
1176openapi_spec_id: ContextVar = ContextVar("openapi_spec_id")
1177"""generate a new OpenAPI Spec UUID for storing in the database"""
1180class OpenAPIObject(BaseModel):
1181 """Deserialized OpenAPI 3.1 Specification"""
1183 openapi_spec_uuid: UUID
1185 # db_session: scoped_session
1187 base_url: str
1189 session_errors_encountered: bool = False
1191 model_config = ConfigDict(
1192 alias_generator=AliasGenerator(
1193 validation_alias=to_snake, serialization_alias=to_camel
1194 ),
1195 populate_by_name=True,
1196 extra="allow",
1197 )
1198 """This object MAY be extended with Specification Extensions."""
1200 openapi: str
1201 """REQUIRED. This string MUST be the version number of the OpenAPI
1202 Specification that the OpenAPI Document uses.
1203 The openapi field SHOULD be used by tooling to interpret the
1204 OpenAPI Document. This is not related to the API info.version string."""
1206 info: InfoObject
1207 """REQUIRED. Provides metadata about the API.
1208 The metadata MAY be used by tooling as required."""
1210 paths: dict[str, PathItemObject]
1211 """The available paths and operations for the API."""
1213 json_schema_dialect: str | None = None
1214 """The default value for the $schema keyword within Schema Objects
1215 contained within this OAS document. This MUST be in the form of a URI."""
1217 webhooks: dict[str, PathItemObject] | None = None
1219 security: SecurityRequirementObjects | None = None
1221 servers: List[ServerObject]
1222 """An array of Server Objects,
1223 which provide connectivity information to a target server.
1224 If the servers field is not provided, or is an empty array,
1225 the default value would be a Server Object with a url value of `/`."""
1227 tags: List[TagObject] | None = None
1229 components: ComponentsObject | None = None