def _create_complex_properties_from_class(self, schema_class: dict) -> None: """ Add crossreferences to already existing class. Parameters ---------- schema_class : dict Description of the class that should be added. Raises ------ requests.ConnectionError If the network connection to weaviate fails. weaviate.UnexpectedStatusCodeException If weaviate reports a none OK status. """ if "properties" not in schema_class: # Class has no properties nothing to do return for property_ in schema_class["properties"]: if _property_is_primitive(property_["dataType"]): continue # create the property object ## All complex dataTypes should be capitalized. schema_property = { "dataType": [ _capitalize_first_letter(dtype) for dtype in property_["dataType"] ], "description": property_["description"], "name": property_["name"] } if "indexInverted" in property_: schema_property["indexInverted"] = property_["indexInverted"] if "moduleConfig" in property_: schema_property["moduleConfig"] = property_["moduleConfig"] path = "/schema/" + _capitalize_first_letter( schema_class["class"]) + "/properties" try: response = self._connection.post( path=path, weaviate_object=schema_property) except RequestsConnectionError as conn_err: raise RequestsConnectionError('Property may not have been created properly.')\ from conn_err if response.status_code != 200: raise UnexpectedStatusCodeException( "Add properties to classes", response)
def helper_test(nr_calls=1): mock_rest = mock_connection_method('post') schema = Schema(mock_rest) schema._create_complex_properties_from_class(properties) self.assertEqual(mock_rest.post.call_count, nr_calls) properties_copy = deepcopy(properties['properties']) for prop in properties_copy: prop['dataType'] = [ _capitalize_first_letter(dt) for dt in prop['dataType'] ] mock_rest.post.assert_called_with( path="/schema/" + _capitalize_first_letter(properties["class"]) + "/properties", weaviate_object=properties_copy[0])
def add_reference(self, from_object_uuid: str, from_object_class_name: str, from_property_name: str, to_object_uuid: str) -> None: """ Add one reference to this batch. Parameters ---------- from_object_uuid : str The UUID or URL of the object that should reference another object. from_object_class_name : str The name of the class that should reference another object. from_property_name : str The name of the property that contains the reference. to_object_uuid : str The UUID or URL of the object that is actually referenced. Raises ------ TypeError If arguments are not of type str. ValueError If 'uuid' is not valid or cannot be extracted. """ self._reference_batch.add( from_object_class_name=_capitalize_first_letter( from_object_class_name), from_object_uuid=from_object_uuid, from_property_name=from_property_name, to_object_uuid=to_object_uuid, ) if self._batching_type: self._auto_create()
def update_config(self, class_name: str, config: dict) -> None: """ Update a schema configuration for a specific class. Parameters ---------- class_name : str The class for which to update the schema configuration. config : dict The configurations to update (MUST follow schema format). Raises ------ requests.ConnectionError If the network connection to weaviate fails. weaviate.UnexpectedStatusCodeException If weaviate reports a none OK status. """ class_name = _capitalize_first_letter(class_name) class_schema = self.get(class_name) new_class_schema = _update_nested_dict(class_schema, config) check_class(new_class_schema) path = "/schema/" + class_name try: response = self._connection.put(path=path, weaviate_object=new_class_schema) except RequestsConnectionError as conn_err: raise RequestsConnectionError('Class schema configuration could not be updated.')\ from conn_err if response.status_code != 200: raise UnexpectedStatusCodeException( "Update class schema configuration", response)
def create(self, schema_class_name: str, schema_property: dict) -> None: """ Create a class property. Parameters ---------- schema_class_name : str The name of the class in the schema to which the property should be added. schema_property : dict The property that should be added. Examples -------- >>> property_age = { ... "dataType": [ ... "int" ... ], ... "description": "The Author's age", ... "name": "age" ... } >>> client.schema.property.create('Author', property_age) Raises ------ TypeError If 'schema_class_name' is of wrong type. weaviate.exceptions.UnexpectedStatusCodeException If weaviate reports a none OK status. requests.ConnectionError If the network connection to weaviate fails. weaviate.SchemaValidationException If the 'schema_property' is not valid. """ if not isinstance(schema_class_name, str): raise TypeError( f"Class name must be of type str but is {type(schema_class_name)}" ) loaded_schema_property = _get_dict_from_object(schema_property) # check if valid property check_property(loaded_schema_property) schema_class_name = _capitalize_first_letter(schema_class_name) path = f"/schema/{schema_class_name}/properties" try: response = self._connection.post( path=path, weaviate_object=loaded_schema_property) except RequestsConnectionError as conn_err: raise RequestsConnectionError( 'Property was created properly.') from conn_err if response.status_code != 200: raise UnexpectedStatusCodeException("Add property to class", response)
def _create_class_with_premitives(self, weaviate_class: dict) -> None: """ Create class with only primitives. Parameters ---------- weaviate_class : dict A single weaviate formated class Raises ------ requests.ConnectionError If the network connection to weaviate fails. weaviate.UnexpectedStatusCodeException If weaviate reports a none OK status. """ # Create the class schema_class = { "class": _capitalize_first_letter(weaviate_class['class']), "properties": [] } if "description" in weaviate_class: schema_class['description'] = weaviate_class['description'] if "vectorIndexType" in weaviate_class: schema_class['vectorIndexType'] = weaviate_class['vectorIndexType'] if "vectorIndexConfig" in weaviate_class: schema_class['vectorIndexConfig'] = weaviate_class[ 'vectorIndexConfig'] if "vectorizer" in weaviate_class: schema_class['vectorizer'] = weaviate_class['vectorizer'] if "moduleConfig" in weaviate_class: schema_class["moduleConfig"] = weaviate_class["moduleConfig"] if "shardingConfig" in weaviate_class: schema_class["shardingConfig"] = weaviate_class["shardingConfig"] if "properties" in weaviate_class: schema_class["properties"] = _get_primitive_properties( weaviate_class["properties"]) # Add the item try: response = self._connection.post(path="/schema", weaviate_object=schema_class) except RequestsConnectionError as conn_err: raise RequestsConnectionError('Class may not have been created properly.')\ from conn_err if response.status_code != 200: raise UnexpectedStatusCodeException("Create class", response)
def __init__(self, class_name: str, properties: Union[List[str], str], connection: Connection): """ Initialize a GetBuilder class instance. Parameters ---------- class_name : str Class name of the objects to interact with. properties : str or list of str Properties of the objects to interact with. connection : weaviate.connect.Connection Connection object to an active and running Weaviate instance. Raises ------ TypeError If argument/s is/are of wrong type. """ super().__init__(connection) if not isinstance(class_name, str): raise TypeError( f"class name must be of type str but was {type(class_name)}") if not isinstance(properties, (list, str)): raise TypeError("properties must be of type str or " f"list of str but was {type(properties)}") if isinstance(properties, str): properties = [properties] for prop in properties: if not isinstance(prop, str): raise TypeError("All the `properties` must be of type `str`!") self._class_name: str = _capitalize_first_letter(class_name) self._properties: List[str] = properties self._additional: dict = {'__one_level': set()} # '__one_level' refers to the additional properties that are just a single word, not a dict # thus '__one_level', only one level of complexity self._where: Optional[ Where] = None # To store the where filter if it is added self._limit: Optional[ str] = None # To store the limit filter if it is added self._offset: Optional[ str] = None # To store the offset filter if it is added self._near_ask: Optional[ Filter] = None # To store the `near`/`ask` clause if it is added self._contains_filter = False # true if any filter is added
def with_class_name(self, class_name: str) -> 'ConfigBuilder': """ What Object type to classify. Parameters ---------- class_name : str Name of the class to be classified. Returns ------- ConfigBuilder Updated ConfigBuilder. """ self._config["class"] = _capitalize_first_letter(class_name) return self
def __init__(self, class_name: str, connection: Connection): """ Initialize a AggregateBuilder class instance. Parameters ---------- class_name : str Class name of the objects to be aggregated. connection : weaviate.connect.Connection Connection object to an active and running Weaviate instance. """ super().__init__(connection) self._class_name = _capitalize_first_letter(class_name) self._with_meta_count = False self._fields: List[str] = [] self._where: Optional[Where] = None self._group_by_properties: Optional[List[str]] = None self._uses_filter = False
def add_data_object(self, data_object: dict, class_name: str, uuid: Optional[str] = None, vector: Optional[Sequence] = None) -> None: """ Add one object to this batch. NOTE: If the UUID of one of the objects already exists then the existing object will be replaced by the new object. Parameters ---------- data_object : dict Object to be added as a dict datatype. class_name : str The name of the class this object belongs to. uuid : str, optional UUID of the object as a string, by default None vector: Sequence, optional The embedding of the object that should be created. Used only class objects that do not have a vectorization module. Supported types are `list`, 'numpy.ndarray`, `torch.Tensor` and `tf.Tensor`, by default None. Raises ------ TypeError If an argument passed is not of an appropriate type. ValueError If 'uuid' is not of a propper form. """ self._objects_batch.add( class_name=_capitalize_first_letter(class_name), data_object=data_object, uuid=uuid, vector=vector, ) if self._batching_type: self._auto_create()
def validate(self, data_object: Union[dict, str], class_name: str, uuid: Union[str, uuid_lib.UUID, None]=None, vector: Sequence=None ) -> dict: """ Validate an object against weaviate. Parameters ---------- data_object : dict or str Object to be validated. If type is str it should be either an URL or a file. class_name : str Name of the class of the object that should be validated. uuid : str, uuid.UUID or None, optional The UUID of the object that should be validated against weaviate. by default None. vector: Sequence, optional The embedding of the object that should be validated. Used only class objects that do not have a vectorization module. Supported types are `list`, 'numpy.ndarray`, `torch.Tensor` and `tf.Tensor`, by default None. Examples -------- Assume we have a Author class only 'name' property, NO 'age'. >>> client1.data_object.validate( ... data_object = {'name': 'H. Lovecraft'}, ... class_name = 'Author' ... ) {'error': None, 'valid': True} >>> client1.data_object.validate( ... data_object = {'name': 'H. Lovecraft', 'age': 46}, ... class_name = 'Author' ... ) { "error": [ { "message": "invalid object: no such prop with name 'age' found in class 'Author' in the schema. Check your schema files for which properties in this class are available" } ], "valid": false } Returns ------- dict Validation result. E.g. {"valid": bool, "error": None or list} Raises ------ TypeError If argument is of wrong type. ValueError If argument contains an invalid value. weaviate.UnexpectedStatusCodeException If validating the object against Weaviate failed with a different reason. requests.ConnectionError If the network connection to weaviate fails. """ loaded_data_object = _get_dict_from_object(data_object) if not isinstance(class_name, str): raise TypeError(f"Expected class_name of type `str` but was: {type(class_name)}") weaviate_obj = { "class": _capitalize_first_letter(class_name), "properties": loaded_data_object } if uuid is not None: weaviate_obj['id'] = get_valid_uuid(uuid) if vector is not None: weaviate_obj['vector'] = get_vector(vector) path = "/objects/validate" try: response = self._connection.post( path=path, weaviate_object=weaviate_obj ) except RequestsConnectionError as conn_err: raise RequestsConnectionError('Object was not validated against weaviate.')\ from conn_err result: dict = { "error": None } if response.status_code == 200: result["valid"] = True return result if response.status_code == 422: result["valid"] = False result["error"] = response.json()["error"] return result raise UnexpectedStatusCodeException("Validate object", response)
def create(self, data_object: Union[dict, str], class_name: str, uuid: Union[str, uuid_lib.UUID, None]=None, vector: Sequence=None ) -> str: """ Takes a dict describing the object and adds it to weaviate. Parameters ---------- data_object : dict or str Object to be added. If type is str it should be either an URL or a file. class_name : str Class name associated with the object given. uuid : str, uuid.UUID or None, optional Object will be created under this uuid if it is provided. Otherwise weaviate will generate a uuid for this object, by default None. vector: Sequence, optional The embedding of the object that should be created. Used only class objects that do not have a vectorization module. Supported types are `list`, 'numpy.ndarray`, `torch.Tensor` and `tf.Tensor`, by default None. Examples -------- Schema contains a class Author with only 'name' and 'age' primitive property. >>> client.data_object.create( ... data_object = {'name': 'Neil Gaiman', 'age': 60}, ... class_name = 'Author', ... ) '46091506-e3a0-41a4-9597-10e3064d8e2d' >>> client.data_object.create( ... data_object = {'name': 'Andrzej Sapkowski', 'age': 72}, ... class_name = 'Author', ... uuid = 'e067f671-1202-42c6-848b-ff4d1eb804ab' ... ) 'e067f671-1202-42c6-848b-ff4d1eb804ab' Returns ------- str Returns the UUID of the created object if successful. Raises ------ TypeError If argument is of wrong type. ValueError If argument contains an invalid value. weaviate.ObjectAlreadyExistsException If an object with the given uuid already exists within weaviate. weaviate.UnexpectedStatusCodeException If creating the object in Weaviate failed for a different reason, more information is given in the exception. requests.ConnectionError If the network connection to weaviate fails. """ if not isinstance(class_name, str): raise TypeError("Expected class_name of type str but was: "\ + str(type(class_name))) loaded_data_object = _get_dict_from_object(data_object) weaviate_obj = { "class": _capitalize_first_letter(class_name), "properties": loaded_data_object } if uuid is not None: weaviate_obj["id"] = get_valid_uuid(uuid) if vector is not None: weaviate_obj["vector"] = get_vector(vector) path = "/objects" try: response = self._connection.post( path=path, weaviate_object=weaviate_obj ) except RequestsConnectionError as conn_err: raise RequestsConnectionError('Object was not added to Weaviate.') from conn_err if response.status_code == 200: return str(response.json()["id"]) object_does_already_exist = False try: if 'already exists' in response.json()['error'][0]['message']: object_does_already_exist = True except KeyError: pass if object_does_already_exist: raise ObjectAlreadyExistsException(str(uuid)) raise UnexpectedStatusCodeException("Creating object", response)
def replace(self, data_object: Union[dict, str], class_name: str, uuid: Union[str, uuid_lib.UUID], vector: Sequence=None ) -> None: """ Replace an already existing object with the given data object. This method replaces the whole object. Parameters ---------- data_object : dict or str Describes the new values. It may be an URL or path to a json or a python dict describing the new values. class_name : str Name of the class of the object that should be updated. uuid : str or uuid.UUID The UUID of the object that should be changed. vector: Sequence, optional The embedding of the object that should be replaced. Used only class objects that do not have a vectorization module. Supported types are `list`, 'numpy.ndarray`, `torch.Tensor` and `tf.Tensor`, by default None. Examples -------- >>> author_id = client.data_object.create( ... data_object = {'name': 'H. Lovecraft', 'age': 46}, ... class_name = 'Author' ... ) >>> client.data_object.get(author_id) { "additional": {}, "class": "Author", "creationTimeUnix": 1617112817487, "id": "d842a0f4-ad8c-40eb-80b4-bfefc7b1b530", "lastUpdateTimeUnix": 1617112817487, "properties": { "age": 46, "name": "H. Lovecraft" }, "vectorWeights": null } >>> client.data_object.replace( ... data_object = {'name': 'H.P. Lovecraft'}, ... class_name = 'Author', ... uuid = author_id ... ) >>> client.data_object.get(author_id) { "additional": {}, "class": "Author", "id": "d842a0f4-ad8c-40eb-80b4-bfefc7b1b530", "lastUpdateTimeUnix": 1617112838668, "properties": { "name": "H.P. Lovecraft" }, "vectorWeights": null } Raises ------ TypeError If argument is of wrong type. ValueError If argument contains an invalid value. requests.ConnectionError If the network connection to weaviate fails. weaviate.UnexpectedStatusCodeException If weaviate reports a none OK status. """ parsed_object = _get_dict_from_object(data_object) uuid = get_valid_uuid(uuid) weaviate_obj = { "id": uuid, "class": _capitalize_first_letter(class_name), "properties": parsed_object } if vector is not None: weaviate_obj['vector'] = get_vector(vector) path = f"/objects/{uuid}" try: response = self._connection.put( path=path, weaviate_object=weaviate_obj ) except RequestsConnectionError as conn_err: raise RequestsConnectionError('Object was not replaced.') from conn_err if response.status_code == 200: # Successful update return raise UnexpectedStatusCodeException("Replace object", response)
def update(self, data_object: Union[dict, str], class_name: str, uuid: Union[str, uuid_lib.UUID], vector: Sequence=None ) -> None: """ Update the given object with the already existing object in weaviate. Overwrites only the specified fields, the unspecified ones remain unchanged. Parameters ---------- data_object : dict or str The object states the fields that should be updated. Fields not specified by in the 'data_object' remain unchanged. Fields that are None will not be changed. If type is str it should be either an URL or a file. class_name : str The class name of the object. uuid : str or uuid.UUID The ID of the object that should be changed. vector: Sequence, optional The embedding of the object that should be updated. Used only class objects that do not have a vectorization module. Supported types are `list`, 'numpy.ndarray`, `torch.Tensor` and `tf.Tensor`, by default None. Examples -------- >>> author_id = client.data_object.create( ... data_object = {'name': 'Philip Pullman', 'age': 64}, ... class_name = 'Author' ... ) >>> client.data_object.get(author_id) { "additional": {}, "class": "Author", "creationTimeUnix": 1617111215172, "id": "bec2bca7-264f-452a-a5bb-427eb4add068", "lastUpdateTimeUnix": 1617111215172, "properties": { "age": 64, "name": "Philip Pullman" }, "vectorWeights": null } >>> client.data_object.update( ... data_object = {'age': 74}, ... class_name = 'Author', ... uuid = author_id ... ) >>> client.data_object.get(author_id) { "additional": {}, "class": "Author", "creationTimeUnix": 1617111215172, "id": "bec2bca7-264f-452a-a5bb-427eb4add068", "lastUpdateTimeUnix": 1617111215172, "properties": { "age": 74, "name": "Philip Pullman" }, "vectorWeights": null } Raises ------ TypeError If argument is of wrong type. ValueError If argument contains an invalid value. requests.ConnectionError If the network connection to weaviate fails. weaviate.UnexpectedStatusCodeException If weaviate reports a none successful status. """ if not isinstance(class_name, str): raise TypeError("Class must be type str") uuid = get_valid_uuid(uuid) object_dict = _get_dict_from_object(data_object) weaviate_obj = { "id": uuid, "class": _capitalize_first_letter(class_name), "properties": object_dict } if vector is not None: weaviate_obj['vector'] = get_vector(vector) path = f"/objects/{uuid}" try: response = self._connection.patch( path=path, weaviate_object=weaviate_obj ) except RequestsConnectionError as conn_err: raise RequestsConnectionError('Object was not updated.') from conn_err if response.status_code == 204: # Successful merge return raise UnexpectedStatusCodeException("Update of the object not successful", response)