Exemple #1
0
def arg_from_dict(*, artifacts: types.ColumnSchemaArtifacts) -> str:
    """
    Calculate the Python type of a column for the arguments of from_dict.

    Args:
        artifacts: The artifacts from the schema of the column.

    Returns:
        The equivalent Python type for the argument for the column.

    """
    # Calculate type the same way as for the model
    init_type = arg_init(artifacts=artifacts)

    # No more checks if JSON
    if artifacts.extension.json:
        return init_type

    # Modify the type in case of object or array
    if artifacts.open_api.type in {"object", "array"}:
        if artifacts.extension.de_ref is None:
            raise exceptions.MissingArgumentError(
                "The schema for the property of an object reference must include "
                "x-de-$ref with the name of the model being referenced."
            )
        init_type = init_type.replace(
            f"T{artifacts.extension.de_ref}", f"{artifacts.extension.de_ref}Dict"
        )

    return init_type
def typed_dict(*, artifacts: types.ColumnSchemaArtifacts) -> str:
    """
    Calculate the Python type of a column for a TypedDict.

    Args:
        artifacts: The artifacts from the schema of the column.

    Returns:
        The equivalent Python type for the TypedDict.

    """
    # Calculate type the same way as for the model
    model_type = model(artifacts=artifacts)

    # Modify the type in case of object or array
    if artifacts.type in {"object", "array"}:
        if artifacts.de_ref is None:
            raise exceptions.MissingArgumentError(
                "The schema for the property of an object reference must include "
                "x-de-$ref with the name of the model being referenced."
            )
        model_type = model_type.replace(
            f"T{artifacts.de_ref}", f"{artifacts.de_ref}Dict"
        )

    return model_type
Exemple #3
0
def typed_dict(*, artifacts: types.ColumnSchemaArtifacts) -> str:
    """
    Calculate the Python type of a column for a TypedDict.

    Args:
        artifacts: The artifacts from the schema of the column.

    Returns:
        The equivalent Python type for the TypedDict.

    """
    # Calculate type the same way as for the model
    model_type = model(artifacts=artifacts)

    # No more checks if JSON
    if artifacts.extension.json:
        return model_type

    # Modify the type in case of object or array
    if artifacts.open_api.type in {"object", "array"}:
        if artifacts.extension.de_ref is None:
            raise exceptions.MissingArgumentError(
                "The schema for the property of an object reference must include "
                "x-de-$ref with the name of the model being referenced."
            )
        model_type = model_type.replace(
            f"T{artifacts.extension.de_ref}", f"{artifacts.extension.de_ref}Dict"
        )
    # Revert back to str for binary, date and date-time
    if artifacts.open_api.format == "binary":
        model_type = model_type.replace("bytes", "str")
    if artifacts.open_api.format == "date":
        model_type = model_type.replace("datetime.date", "str")
    if artifacts.open_api.format == "date-time":
        model_type = model_type.replace("datetime.datetime", "str")

    return model_type
Exemple #4
0
def _calculate_schema(*, artifacts: types.ObjectArtifacts,
                      ref_from_array: bool, model_name: str) -> types.Schema:
    """
    Calculate the schema for a backref.

    The key decision is whether the backref is an array. If the reference is from
    an object it is an array unless uselist is False. If the reference is from an array,
    it is not unless secondary is set to a table name.

    Args:
        artifacts: The artifacts for the object reference.
        ref_from_array: Whether the reference was from within an array.
        model_name: The name of the model defining the reference.

    Returns:
        The schema for the backref.

    """
    back_reference = artifacts.relationship.back_reference
    # Handle where back reference is None, this should not happen
    if back_reference is None:
        raise exceptions.MissingArgumentError(
            "To construct the back reference schema, back reference artifacts cannot "
            "be None")

    if (not ref_from_array and
        (back_reference.uselist is None or back_reference.uselist is True)
        ) or (ref_from_array and artifacts.relationship.secondary is not None):
        return {
            "type": "array",
            "items": {
                "type": "object",
                "x-de-$ref": model_name
            }
        }
    return {"type": "object", "x-de-$ref": model_name}
Exemple #5
0
    def get_schemas(self, *, context: str) -> types.Schema:
        """
        Retrieve the schemas for a context.

        Raise MissingArgumentError if the context for the original OpenAPI specification
            has not been set.
        Raise SchemaNotFoundError if the context doesn't exist or is not a json nor yaml
            file.

        Args:
            context: The path, relative to the original OpenAPI specification, for the
                file containing the schemas.

        Returns:
            The schemas.

        """
        # Check whether the context is already loaded
        if context in self._schemas:
            return self._schemas[context]

        if self.spec_context is None:
            raise exceptions.MissingArgumentError(
                "Cannot find the file containing the remote reference, either "
                "initialize OpenAlchemy with init_json or init_yaml or pass the path "
                "to the OpenAPI specification to OpenAlchemy.")

        # Check for json, yaml or yml file extension
        _, extension = os.path.splitext(context)
        extension = extension.lower()
        if extension not in {".json", ".yaml", ".yml"}:
            raise exceptions.SchemaNotFoundError(
                "The remote context is not a JSON nor YAML file. The path is: "
                f"{context}")

        # Get context manager with file
        try:
            if _URL_REF_PATTERN.search(context) is not None:
                file_cm = request.urlopen(context)
            else:
                spec_dir = os.path.dirname(self.spec_context)
                remote_spec_filename = os.path.join(spec_dir, context)
                file_cm = open(remote_spec_filename)
        except (FileNotFoundError, error.HTTPError) as exc:
            raise exceptions.SchemaNotFoundError(
                "The file with the remote reference was not found. The path is: "
                f"{context}") from exc

        # Calculate location of schemas
        with file_cm as in_file:
            if extension == ".json":
                try:
                    schemas = json.load(in_file)
                except json.JSONDecodeError as exc:
                    raise exceptions.SchemaNotFoundError(
                        "The remote reference file is not valid JSON. The path "
                        f"is: {context}") from exc
            else:
                # Import as needed to make yaml optional
                import yaml  # pylint: disable=import-outside-toplevel

                try:
                    schemas = yaml.safe_load(in_file)
                except yaml.scanner.ScannerError as exc:
                    raise exceptions.SchemaNotFoundError(
                        "The remote reference file is not valid YAML. The path "
                        f"is: {context}") from exc

        # Store for faster future retrieval
        self._schemas[context] = schemas
        return schemas