11import copy
2+ import traceback
23import csv
34import logging
45import math
@@ -214,13 +215,16 @@ def get_property_value_type(self, property_id):
214215 Uses a dictionary attribute for caching.
215216 """
216217 endpoint = f"/entities/properties/{ property_id } "
217- url = self .wikibase_url (endpoint )
218218
219219 try :
220- res = self .session . get ( url ). json ( )
220+ res = self .wikibase_request_wrapper ( "get" , endpoint , {} )
221221 data_type = res ["data_type" ]
222222 except (KeyError , UserError ):
223223 raise NonexistantPropertyOrNoDataType (property_id )
224+ except Exception as e :
225+ logger .error (f"Error while trying to get data type: { e } " )
226+ traceback .print_exc ()
227+ raise NonexistantPropertyOrNoDataType (property_id )
224228
225229 try :
226230 value_type = self .data_type_to_value_type (data_type )
@@ -285,6 +289,8 @@ def wikibase_entity_endpoint(entity_id, entity_endpoint=""):
285289 base = "/entities/items"
286290 elif entity_id .startswith ("P" ):
287291 base = "/entities/properties"
292+ elif entity_id .upper () == "LAST" :
293+ raise LastCouldNotBeEvaluated ()
288294 else :
289295 raise EntityTypeNotImplemented (entity_id )
290296
@@ -985,7 +991,7 @@ def start(self):
985991 def finish (self ):
986992 logger .info (f"[{ self } ] finished" )
987993 self .status = BatchCommand .STATUS_DONE
988- if self .is_id_last_or_create_item ():
994+ if self .is_entity_creation ():
989995 self .set_entity_id (self .response_id )
990996 self .save ()
991997 self .propagate_to_previous_commands ()
@@ -999,6 +1005,7 @@ def error_with_value(self, value: Error, message: str = None):
9991005
10001006 def error_with_exception (self , exception : Exception ):
10011007 message = getattr (exception , "message" , str (exception ))
1008+ traceback .print_exc ()
10021009 self .error_with_message (message )
10031010
10041011 def error_with_message (self , message ):
@@ -1015,7 +1022,7 @@ def propagate_to_previous_commands(self):
10151022 if self .is_error_status ():
10161023 cmd .error = self .Error .COMBINING_COMMAND_FAILED
10171024 cmd .message = cmd .error .label
1018- elif cmd .is_id_last_or_create_item ():
1025+ elif cmd .is_entity_creation ():
10191026 cmd .set_entity_id (self .entity_id )
10201027 cmd .save ()
10211028
@@ -1084,6 +1091,10 @@ def sitelink(self):
10841091 def what (self ):
10851092 return self .json .get ("what" , "" ).upper ()
10861093
1094+ @property
1095+ def property_data_type (self ):
1096+ return self .json .get ("data" , "" ).lower ()
1097+
10871098 @property
10881099 def related_identifiers_set (self ):
10891100 """
@@ -1337,11 +1348,27 @@ def is_sitelink_command(self):
13371348 def is_error_status (self ):
13381349 return self .status == BatchCommand .STATUS_ERROR
13391350
1340- def is_not_create_item (self ):
1341- return self .operation != self .Operation .CREATE_ITEM
1351+ def is_not_create_entity (self ):
1352+ return self .operation not in [ self .Operation .CREATE_ITEM , self . Operation . CREATE_PROPERTY ]
13421353
1343- def is_id_last_or_create_item (self ):
1344- return self .entity_id == "LAST" or self .operation == self .Operation .CREATE_ITEM
1354+ def get_first_command_operation (self ):
1355+ first_command = self
1356+ previous = getattr (self , "previous_commands" , [])
1357+ if len (previous ) > 0 :
1358+ first_command = previous [- 1 ]
1359+ return first_command .operation
1360+
1361+ def is_item_creation (self ):
1362+ operation = self .get_first_command_operation ()
1363+ return operation == self .Operation .CREATE_ITEM
1364+
1365+ def is_property_creation (self ):
1366+ operation = self .get_first_command_operation ()
1367+ return operation == self .Operation .CREATE_PROPERTY
1368+
1369+ def is_entity_creation (self ):
1370+ operation = self .get_first_command_operation ()
1371+ return operation in [self .Operation .CREATE_ITEM , self .Operation .CREATE_PROPERTY ]
13451372
13461373 # # -----------------
13471374 # # LAST related methods
@@ -1447,6 +1474,7 @@ def operation_is_combinable(self):
14471474 self .Operation .CREATE_ITEM ,
14481475 self .Operation .SET_STATEMENT ,
14491476 self .Operation .CREATE_STATEMENT ,
1477+ self .Operation .CREATE_PROPERTY ,
14501478 self .Operation .REMOVE_STATEMENT_BY_VALUE ,
14511479 self .Operation .REMOVE_QUALIFIER ,
14521480 self .Operation .REMOVE_REFERENCE ,
@@ -1480,18 +1508,19 @@ def check_combination(self, state: CombiningState, next: Optional["BatchCommand"
14801508 and self .operation_is_combinable ()
14811509 and next is not None
14821510 and next .operation_is_combinable ()
1483- and next .is_not_create_item ()
1511+ and next .is_not_create_entity ()
14841512 and self .has_combinable_id_with (next )
14851513 )
14861514 self .previous_entity_json = state .entity
14871515 self .previous_commands = state .commands
14881516
14891517 def has_combinable_id_with (self , next : "BatchCommand" ):
14901518 """
1491- Returns True if `self` is CREATE_ITEM and `next`
1519+ Returns True if `self` is CREATE_ITEM or CREATE_PROPERTY and `next`
14921520 has LAST as entity id, or if both have the same entity id.
14931521 """
1494- return (self .operation == self .Operation .CREATE_ITEM and next .entity_id == "LAST" ) or (
1522+ create_operations = [self .Operation .CREATE_ITEM , self .Operation .CREATE_PROPERTY ]
1523+ return (self .operation in create_operations and next .entity_id == "LAST" ) or (
14951524 self .entity_id == next .entity_id
14961525 )
14971526
@@ -1528,10 +1557,11 @@ def get_original_entity_json(self, client: Client):
15281557 self .previous_entity_json = copy .deepcopy (entity )
15291558 return entity
15301559
1531- def get_entity_or_empty_item (self , client : Client ):
1560+ def get_entity_or_empty_entity (self , client : Client ):
15321561 """
15331562 Calls the API to get the entity json or returns
1534- an empty item if this command is a CREATE_ITEM.
1563+ an empty entity. Items for CREATE_ITEM and
1564+ properties for CREATE_PROPERTY.
15351565 """
15361566 if self .operation == self .Operation .CREATE_ITEM :
15371567 return {
@@ -1543,6 +1573,16 @@ def get_entity_or_empty_item(self, client: Client):
15431573 "sitelinks" : {},
15441574 "id" : None ,
15451575 }
1576+ elif self .operation == self .Operation .CREATE_PROPERTY :
1577+ return {
1578+ "type" : "property" ,
1579+ "data_type" : self .property_data_type ,
1580+ "labels" : {},
1581+ "descriptions" : {},
1582+ "aliases" : {},
1583+ "statements" : {},
1584+ "id" : None ,
1585+ }
15461586 else :
15471587 if self .entity_id == "LAST" :
15481588 raise LastCouldNotBeEvaluated ()
@@ -1556,7 +1596,7 @@ def get_previous_entity_json(self, client: Client):
15561596 to the next command.
15571597 """
15581598 cached = getattr (self , "previous_entity_json" , None )
1559- entity = cached if cached else self .get_entity_or_empty_item (client )
1599+ entity = cached if cached else self .get_entity_or_empty_entity (client )
15601600 return entity
15611601
15621602 def get_final_entity_json (self , client : Client ) -> dict :
@@ -1712,9 +1752,13 @@ def api_payload(self, client: Client):
17121752 """
17131753 if self .operation == self .Operation .CREATE_ITEM :
17141754 return {"item" : {}}
1755+ if self .operation == self .Operation .CREATE_PROPERTY :
1756+ return {"property" : {"data_type" : self .property_data_type }}
17151757 if self .operation_is_combinable ():
1716- if self .is_id_last_or_create_item ():
1758+ if self .is_item_creation ():
17171759 return {"item" : self .get_final_entity_json (client )}
1760+ elif self .is_property_creation ():
1761+ return {"property" : self .get_final_entity_json (client )}
17181762 else :
17191763 return {"patch" : self .entity_patch (client )}
17201764 return {}
@@ -1739,8 +1783,6 @@ def send_to_api(self, client: Client) -> dict:
17391783 - `NotImplementedError` if the operation
17401784 is not implemented.
17411785 """
1742- if self .operation == self .Operation .CREATE_PROPERTY :
1743- raise NotImplementedError ()
17441786 method , endpoint = self .operation_method_and_endpoint (client )
17451787 body = self .api_body (client )
17461788 return client .wikibase_request_wrapper (method , endpoint , body )
@@ -1755,8 +1797,10 @@ def operation_method_and_endpoint(self, client: Client):
17551797 necessary for the operation.
17561798 """
17571799 if self .operation_is_combinable ():
1758- if self .is_id_last_or_create_item ():
1800+ if self .is_item_creation ():
17591801 return ("POST" , "/entities/items" )
1802+ elif self .is_property_creation ():
1803+ return ("POST" , "/entities/properties" )
17601804 else :
17611805 return ("PATCH" , Client .wikibase_entity_endpoint (self .entity_id ))
17621806 match self .operation :
0 commit comments