Skip to content

oapi.model

ModelModule

ModelModule(
    open_api: (
        str | sob.abc.Readable | oapi.oas.model.OpenAPI
    ),
    get_class_name_from_pointer: typing.Callable[
        [str, str], str
    ] = oapi.model.get_default_class_name_from_pointer,
)

This class parses an Open API document and generates a module defining classes to represent each schema defined in the Open API document as a subclass of sob.Object, sob.Array, or sob.Dictionary.

Parameters:

  • open_api (str | sob.abc.Readable | oapi.oas.model.OpenAPI) –

    An OpenAPI document. This can be a URL, file-path, an HTTP response (http.client.HTTPResponse), a file object, or an instance of oapi.oas.OpenAPI.

  • get_class_name_from_pointer (typing.Callable[[str, str], str], default: oapi.model.get_default_class_name_from_pointer ) –

    This argument defaults to oapi.model.get_default_class_name_from_pointer. If an alternate function is provided, it should accept two arguments, both being str instances. The first argument is a JSON pointer, or concatenated relative URL + JSON pointer, and the second being either an empty string or a parameter name, where applicable. The function should return a str which is a valid, unique, class name.

Source code in src/oapi/model.py
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
def __init__(
    self,
    open_api: str | sob.abc.Readable | OpenAPI,
    get_class_name_from_pointer: Callable[
        [str, str], str
    ] = get_default_class_name_from_pointer,
) -> None:
    message: str
    self._parser = _ModuleParser()
    self._modeler: _Modeler
    if isinstance(open_api, str):
        if os.path.exists(open_api):
            self._modeler = _get_path_modeler(open_api)
        else:
            self._modeler = _get_url_modeler(open_api)
    elif isinstance(open_api, sob.abc.Readable):
        self._modeler = _get_io_modeler(open_api)
    elif isinstance(open_api, OpenAPI):
        self._modeler = _get_open_api_modeler(open_api)
    else:
        message = (
            f"`{get_calling_function_qualified_name()}` requires an "
            f"instance of `str`, `{get_qualified_name(OpenAPI)}`, or "
            "a file-like object for the `open_api` parameter—not: "
            f"{open_api!r}"
        )
        raise TypeError(message)
    self._modeler.get_class_name_from_pointer = get_class_name_from_pointer

save

save(path: str | pathlib.Path) -> None

This method will save the generated module to a given path. If there is an existing module at that path--the existing module will be imported and the pre-existing class names will be utilized for any schemas defined by elements residing at the same location as the documented JSON pointer in the pre-existing classes' docstrings.

Source code in src/oapi/model.py
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
def save(self, path: str | Path) -> None:
    """
    This method will save the generated module to a given path. If there is
    an existing module at that path--the existing module will be imported
    and the pre-existing class names will be utilized for any schemas
    defined by elements residing at the same location as the documented
    JSON pointer in the pre-existing classes' docstrings.
    """
    # Make sure that any matching, existing classes use the same names
    self._parse_existing_module(path)
    model_source: str = str(self)
    # Save the module
    with open(path, "w") as model_io:
        model_io.write(model_source)

get_default_class_name_from_pointer

get_default_class_name_from_pointer(
    pointer: str,
    name: str = "",
    log: (
        logging.Logger | typing.Callable[[str], None] | None
    ) = None,
) -> str

This function infers a class name from a JSON pointer (or from a relative URL concatenated with a JSON pointer) + parameter name (or empty string when a parameter name is not applicable). This function is the default naming function used by oapi.model.Module.

Parameters:

  • pointer (str) –

    A JSON pointer referencing a schema within an OpenAPI document, or a concatenation of a relative URL + "#" + a JSON pointer.

  • name (str, default: '' ) –

    The parameter name, or "" if the element is not a parameter.

  • log (logging.Logger | typing.Callable[[str], None] | None, default: None ) –

    A logger, or a callback function for log messages

Examples:

print( ... get_default_class_name_from_pointer( ... "#/paths/~1directory~1sub-directory~1name/get/parameters/1", ... name="argument-name", ... ) ... ) DirectorySubDirectoryNameGetArgumentName

print( ... get_default_class_name_from_pointer( ... "#/paths/~1directory~1sub-directory~1name/get/parameters/1" # ... "/item", ... name="argument-name", ... ) ... ) DirectorySubDirectoryNameGetArgumentNameItem

Source code in src/oapi/model.py
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
def get_default_class_name_from_pointer(
    pointer: str,
    name: str = "",
    log: Logger | Callable[[str], None] | None = None,
) -> str:
    """
    This function infers a class name from a JSON pointer (or from a
    relative URL concatenated with a JSON pointer) + parameter name (or
    empty string when a parameter name is not applicable). This function is
    the default naming function used by `oapi.model.Module`.

    Parameters:
        pointer: A JSON pointer referencing a schema within an OpenAPI
            document, or a concatenation of a relative URL + "#" + a JSON
            pointer.
        name: The parameter name, or "" if the element is not a
            parameter.
        log: A logger, or a callback function for log messages

    Examples:

    >>> print(
    ...     get_default_class_name_from_pointer(
    ...         "#/paths/~1directory~1sub-directory~1name/get/parameters/1",
    ...         name="argument-name",
    ...     )
    ... )
    DirectorySubDirectoryNameGetArgumentName

    >>> print(
    ...     get_default_class_name_from_pointer(
    ...         "#/paths/~1directory~1sub-directory~1name/get/parameters/1"  #
    ...         "/item",
    ...         name="argument-name",
    ...     )
    ... )
    DirectorySubDirectoryNameGetArgumentNameItem
    """
    relative_url: str = ""
    if "#" in pointer:
        relative_url, pointer = pointer.split("#", 1)
    class_name_: str = pointer.lstrip("/")
    pattern: str
    repl: str
    for pattern, repl in (
        (
            r"/([^\/]+)/responses/200/(content/[^\/]+/)?schema\b",
            r"/\1/response",
        ),
        (
            r"/([^\/]+)/responses/(\d+)/(content/[^\/]+/)?schema\b",
            r"/\1/response/\2",
        ),
        (
            r"/(anyOf|allOf|oneOf)/\d+/",
            "/",
        ),
        (
            r"(?:^components)?(/|^)parameters/([^/]+)/schema(/|$)",
            r"\1\2\3",
        ),
        (
            r"^(components/[^/]+/|definitions/|paths/)",
            "/",
        ),
        (
            r"/properties/",
            "/",
        ),
        (
            r"/items(/|$)",
            r"/item\1",
        ),
        (
            r"~1",
            "/",
        ),
        (
            r"~0",
            "~",
        ),
    ):
        class_name_ = re.sub(pattern, repl, class_name_)
    # For parameters, include the parameter name in the class name *if* the
    # parameter is defined inline (if it's not defined inline, the path to
    # the parameter definition will usually be sufficiently descriptive),
    # and don't include "/parameters/" or the parameter # in the class
    # name.
    if name and not (
        pointer.startswith(("/components/parameters/", "/definitions/"))
    ):
        parameters_pattern: Pattern = re.compile(r"/parameters/\d+((?:/.+)?)$")
        if parameters_pattern.search(class_name_):
            class_name_ = parameters_pattern.sub(f"/{name}/\\1", class_name_)
        else:
            class_name_ = f"{class_name_}/{name}"
    if relative_url:
        class_name_ = f"{relative_url}/{class_name_}"
    if log is not None:  # pragma: no cover
        message: str = (
            f"{pointer} -> {class_name_} (JSON Pointer -> Class Name)"
        )
        if isinstance(log, Logger):
            log.info(message)
        elif callable(log):
            log(message)
    return sob.utilities.get_class_name(class_name_)

write_model_module

write_model_module(
    model_path: str | pathlib.Path,
    *,
    open_api: (
        str | sob.abc.Readable | oapi.oas.model.OpenAPI
    ),
    get_class_name_from_pointer: typing.Callable[
        [str, str], str
    ] = oapi.model.get_default_class_name_from_pointer
) -> None

This function creates or updates a module defining classes to represent each schema in an Open API document as a subclass of sob.Object, sob.Array, or sob.Dictionary.

Parameters:

  • model_path (str | pathlib.Path) –

    The file path where the model module will be saved (created or updated).

  • open_api (str | sob.abc.Readable | oapi.oas.model.OpenAPI) –

    An OpenAPI document. This can be a URL, file-path, an HTTP response (http.client.HTTPResponse), a file object, or an instance of oapi.oas.model.OpenAPI.

  • get_class_name_from_pointer (typing.Callable[[str, str], str], default: oapi.model.get_default_class_name_from_pointer ) –

    This argument defaults to oapi.model.get_default_class_name_from_pointer. If an alternate function is provided, it should accept two arguments, both being str instances. The first argument is a JSON pointer, or concatenated relative URL + JSON pointer, and the second being either an empty string or a parameter name, where applicable. The function should return a str which is a valid, unique, class name.

Source code in src/oapi/model.py
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
def write_model_module(
    model_path: str | Path,
    *,
    open_api: str | sob.abc.Readable | OpenAPI,
    get_class_name_from_pointer: Callable[
        [str, str], str
    ] = get_default_class_name_from_pointer,
) -> None:
    """
    This function creates or updates a module defining classes to represent
    each schema in an Open API document as a subclass of `sob.Object`,
    `sob.Array`, or `sob.Dictionary`.

    Parameters:
        model_path: The file path where the model module will be saved
            (created or updated).
        open_api: An OpenAPI document. This can be a URL, file-path, an
            HTTP response (`http.client.HTTPResponse`), a file object, or an
            instance of `oapi.oas.model.OpenAPI`.
        get_class_name_from_pointer: This argument defaults to
            `oapi.model.get_default_class_name_from_pointer`. If an alternate
            function is provided, it should accept two arguments, both being
            `str` instances. The first argument is a JSON pointer, or
            concatenated relative URL + JSON pointer, and the second being
            either an empty string or a parameter name, where applicable.
            The function should return a `str` which is a valid, unique,
            class name.
    """
    locals_: dict[str, Any] = dict(locals())
    locals_.pop("model_path")
    model_module: ModelModule = ModelModule(**locals_)
    model_module.save(model_path)