def test_convert_python_types():
    """Convert various Python types to OPTIMADE Data types"""
    from datetime import datetime

    expected_data_type = [
        DataType.STRING,
        DataType.INTEGER,
        DataType.FLOAT,
        DataType.LIST,
        DataType.DICTIONARY,
        DataType.UNKNOWN,
        DataType.TIMESTAMP,
    ]

    python_types_as_strings = [
        "str",
        "int",
        "float",
        "list",
        "dict",
        "None",
        "datetime",
    ]
    python_types_as_types = [str, int, float, list, dict, None, datetime]

    test_none = None
    python_types_as_objects = [
        str("Test"),
        42,
        42.42,
        ["Test", 42],
        {
            "Test": 42
        },
        test_none,
        datetime.now(),
    ]

    for list_of_python_types in [
            python_types_as_strings,
            python_types_as_types,
            python_types_as_objects,
    ]:
        for index, python_type in enumerate(list_of_python_types):
            assert isinstance(DataType.from_python_type(python_type),
                              DataType), f"python_type: {python_type}"
            assert DataType.from_python_type(
                python_type) == expected_data_type[index]
Exemplo n.º 2
0
def retrieve_queryable_properties(schema: dict,
                                  queryable_properties: list) -> dict:
    properties = {}
    for name, value in schema["properties"].items():
        if name in queryable_properties:
            if "$ref" in value:
                path = value["$ref"].split("/")[1:]
                sub_schema = schema.copy()
                while path:
                    next_key = path.pop(0)
                    sub_schema = sub_schema[next_key]
                sub_queryable_properties = sub_schema["properties"].keys()
                properties.update(
                    retrieve_queryable_properties(sub_schema,
                                                  sub_queryable_properties))
            else:
                properties[name] = {
                    "description": value.get("description", "")
                }
                if "unit" in value:
                    properties[name]["unit"] = value["unit"]
                # All properties are sortable with the MongoDB backend.
                # While the result for sorting lists may not be as expected, they are still sorted.
                properties[name]["sortable"] = True
                # Try to get OpenAPI-specific "format" if possible, else get "type"; a mandatory OpenAPI key.
                properties[name]["type"] = DataType.from_json_type(
                    value.get("format", value["type"]))
    return properties
Exemplo n.º 3
0
 def test_properties_type(self):
     types = {
         _.get("type", None)
         for _ in self.json_response.get("data", {}).get("properties",
                                                         {}).values()
     }
     for data_type in types:
         if data_type is None:
             continue
         assert isinstance(DataType(data_type), DataType)
def test_convert_json_types():
    """Convert various JSON and OpenAPI types to OPTIMADE Data types"""
    json_types = [
        ("string", DataType.STRING),
        ("integer", DataType.INTEGER),
        ("number", DataType.FLOAT),
        ("array", DataType.LIST),
        ("object", DataType.DICTIONARY),
        ("null", DataType.UNKNOWN),
    ]
    openapi_formats = [
        ("date-time", DataType.TIMESTAMP),
        ("email", DataType.STRING),
        ("uri", DataType.STRING),
    ]

    for list_of_schema_types in [json_types, openapi_formats]:
        for schema_type, optimade_type in list_of_schema_types:
            assert isinstance(DataType.from_json_type(schema_type),
                              DataType), f"json_type: {schema_type}"
            assert DataType.from_json_type(schema_type) == optimade_type
def test_get_values():
    """Check all data values are returned sorted with get_values()"""
    sorted_data_types = [
        "boolean",
        "dictionary",
        "float",
        "integer",
        "list",
        "string",
        "timestamp",
        "unknown",
    ]
    assert DataType.get_values() == sorted_data_types
Exemplo n.º 6
0
def retrieve_queryable_properties(schema: dict,
                                  queryable_properties: list = None) -> dict:
    """Recursively loops through the schema of a pydantic model and
    resolves all references, returning a dictionary of all the
    OPTIMADE-queryable properties of that model.

    Parameters:
        schema: The schema of the pydantic model.
        queryable_properties: The list of properties to find in the schema.

    Returns:
        A flat dictionary with properties as keys, containing the field
        description, unit, sortability, support level, queryability
        and type, where provided.

    """
    properties = {}
    for name, value in schema["properties"].items():
        if not queryable_properties or name in queryable_properties:
            if "$ref" in value:
                path = value["$ref"].split("/")[1:]
                sub_schema = schema.copy()
                while path:
                    next_key = path.pop(0)
                    sub_schema = sub_schema[next_key]
                sub_queryable_properties = sub_schema["properties"].keys()
                properties.update(
                    retrieve_queryable_properties(sub_schema,
                                                  sub_queryable_properties))
            else:
                properties[name] = {
                    "description": value.get("description", "")
                }
                # Update schema with extension keys provided they are not None
                for key in [
                        _ for _ in ("unit", "queryable", "support")
                        if _ in value
                ]:
                    properties[name][key] = value[key]
                # All properties are sortable with the MongoDB backend.
                # While the result for sorting lists may not be as expected, they are still sorted.
                properties[name]["sortable"] = value.get("sortable", True)
                # Try to get OpenAPI-specific "format" if possible, else get "type"; a mandatory OpenAPI key.
                properties[name]["type"] = DataType.from_json_type(
                    value.get("format", value.get("type")))

    return properties
Exemplo n.º 7
0
def retrieve_queryable_properties(
    schema: dict, queryable_properties: list
) -> Tuple[dict, dict]:
    """Get all queryable properties from an OPTIMADE schema"""
    properties = {}
    all_properties = {}

    for name, value in schema["properties"].items():
        if name in queryable_properties:
            if "$ref" in value:
                path = value["$ref"].split("/")[1:]
                sub_schema = schema.copy()
                while path:
                    next_key = path.pop(0)
                    sub_schema = sub_schema[next_key]
                sub_queryable_properties = sub_schema["properties"].keys()
                new_properties, new_all_properties = retrieve_queryable_properties(
                    sub_schema, sub_queryable_properties
                )
                properties.update(new_properties)
                all_properties.update(new_all_properties)
            else:
                all_properties[name] = value
                properties[name] = {"description": value.get("description", "")}
                for extra_key in ["unit"]:
                    if extra_key in value:
                        properties[name][extra_key] = value[extra_key]
                # AiiDA's QueryBuilder can sort everything that isn't a list (array)
                # or dict (object)
                properties[name]["sortable"] = value.get("type", "") not in [
                    "array",
                    "object",
                ]
                # Try to get OpenAPI-specific "format" if possible,
                # else get "type"; a mandatory OpenAPI key.
                properties[name]["type"] = DataType.from_json_type(
                    value.get("format", value["type"])
                )

    return properties, all_properties
def retrieve_queryable_properties(
    schema: dict,
    queryable_properties: list = None,
    entry_type: str = None,
) -> dict:
    """Recursively loops through the schema of a pydantic model and
    resolves all references, returning a dictionary of all the
    OPTIMADE-queryable properties of that model.

    Parameters:
        schema: The schema of the pydantic model.
        queryable_properties: The list of properties to find in the schema.
        entry_type: An optional entry type for the model. Will be used to
            lookup schemas for any config-defined fields.

    Returns:
        A flat dictionary with properties as keys, containing the field
        description, unit, sortability, support level, queryability
        and type, where provided.

    """
    properties = {}
    for name, value in schema["properties"].items():
        if not queryable_properties or name in queryable_properties:
            if "$ref" in value:
                path = value["$ref"].split("/")[1:]
                sub_schema = schema.copy()
                while path:
                    next_key = path.pop(0)
                    sub_schema = sub_schema[next_key]
                sub_queryable_properties = sub_schema["properties"].keys()
                properties.update(
                    retrieve_queryable_properties(sub_schema, sub_queryable_properties)
                )
            else:
                properties[name] = {"description": value.get("description", "")}
                # Update schema with extension keys provided they are not None
                for key in [_ for _ in ("unit", "queryable", "support") if _ in value]:
                    properties[name][key] = value[key]
                # All properties are sortable with the MongoDB backend.
                # While the result for sorting lists may not be as expected, they are still sorted.
                properties[name]["sortable"] = value.get("sortable", True)
                # Try to get OpenAPI-specific "format" if possible, else get "type"; a mandatory OpenAPI key.
                properties[name]["type"] = DataType.from_json_type(
                    value.get("format", value.get("type"))
                )

    # If specified, check the config for any additional well-described provider fields
    if entry_type:
        from optimade.server.config import CONFIG

        described_provider_fields = [
            field
            for field in CONFIG.provider_fields.get(entry_type, {})
            if isinstance(field, dict)
        ]
        for field in described_provider_fields:
            name = f"_{CONFIG.provider.prefix}_{field['name']}"
            properties[name] = {k: field[k] for k in field if k != "name"}
            properties[name]["sortable"] = field.get("sortable", True)

    return properties