Skip to content

Commit 149accb

Browse files
committed
Implement new version of FastRun
1 parent dcebc22 commit 149accb

29 files changed

Lines changed: 899 additions & 935 deletions

README.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -869,7 +869,15 @@ for entrez_id, ensembl in raw_data.items():
869869

870870
Note: Fastrun mode checks for equality of property/value pairs, qualifiers (not including qualifier attributes), labels,
871871
aliases and description, but it ignores references by default!
872-
References can be checked in fast run mode by setting `use_refs` to `True`.
872+
References can be checked in fast run mode by setting `use_references` to `True`.
873+
874+
# Statistics #
875+
876+
| Dataset | partial fastrun | fastrun without qualifiers/references | fastrun with qualifiers | fastrun with qualifiers/references |
877+
|:----------------------------|----------------:|--------------------------------------:|------------------------:|-----------------------------------:|
878+
| Communes (34990 elements) | ? | 7min | 30s | 60s |
879+
| Cantons (2042 elements) | ? | ? | ? | ? |
880+
| Départements (100 elements) | 70min | 1s | 30s | 60s |
873881

874882
# Debugging #
875883

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ disable = [
120120

121121
[tool.pytest.ini_options]
122122
log_cli = true
123+
log_cli_level = 'DEBUG'
123124
testpaths = ["test"]
124125
markers = [
125126
"integration: tests running against a real Wikibase instance (deselected by default, see test/integration/README.md)"

test/test_datatypes.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ def test_all_datatypes(self):
163163
MonolingualText(text='xxx', language='fr', prop_nr='P7'),
164164
Quantity(amount=-5.04, prop_nr='P8'),
165165
Quantity(amount=5.06, upper_bound=9.99, lower_bound=-2.22, unit='Q11573', prop_nr='P8'),
166-
CommonsMedia(value='xxx', prop_nr='P9'),
166+
CommonsMedia(value='xxx.jpg', prop_nr='P9'),
167167
GlobeCoordinate(latitude=1.2345, longitude=-1.2345, precision=12, prop_nr='P10'),
168168
GeoShape(value='Data:xxx.map', prop_nr='P11'),
169169
Property(value='P123', prop_nr='P12'),

test/test_wbi_fastrun.py

Lines changed: 0 additions & 327 deletions
This file was deleted.

wikibaseintegrator/datatypes/basedatatype.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ class BaseDataType(Claim):
1111
The base class for all Wikibase data types, they inherit from it
1212
"""
1313
DTYPE = 'base-data-type'
14+
PTYPE = 'property-data-type'
1415
subclasses: list[type[BaseDataType]] = []
1516
sparql_query: str = '''
1617
SELECT * WHERE {{
@@ -28,7 +29,14 @@ def __init__(self, prop_nr: int | str | None = None, **kwargs: Any):
2829

2930
super().__init__(**kwargs)
3031

31-
self.mainsnak.property_number = prop_nr or None
32+
if isinstance(prop_nr, str):
33+
pattern = re.compile(r'^([a-z][a-z\d+.-]*):([^][<>\"\x00-\x20\x7F])+$')
34+
matches = pattern.match(str(prop_nr))
35+
36+
if matches:
37+
prop_nr = prop_nr.rsplit('/', 1)[-1]
38+
39+
self.mainsnak.property_number = prop_nr
3240
# self.subclasses.append(self)
3341

3442
# Allow registration of subclasses of BaseDataType into BaseDataType.subclasses
@@ -39,7 +47,7 @@ def __init_subclass__(cls, **kwargs):
3947
def set_value(self, value: Any | None = None):
4048
pass
4149

42-
def get_sparql_value(self) -> str:
50+
def get_sparql_value(self, **kwargs: Any) -> str | None:
4351
return '"' + self.mainsnak.datavalue['value'] + '"'
4452

4553
def parse_sparql_value(self, value, type='literal', unit='1') -> bool:
@@ -61,3 +69,6 @@ def parse_sparql_value(self, value, type='literal', unit='1') -> bool:
6169
raise ValueError
6270

6371
return True
72+
73+
def from_sparql_value(self, sparql_value: dict) -> BaseDataType: # type: ignore
74+
pass

wikibaseintegrator/datatypes/commonsmedia.py

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,30 @@
11
import re
22
import urllib.parse
33

4-
from wikibaseintegrator.datatypes.string import String
4+
from wikibaseintegrator.datatypes.url import URL
55

66

7-
class CommonsMedia(String):
7+
class CommonsMedia(URL):
88
"""
99
Implements the Wikibase data type for Wikimedia commons media files
1010
"""
1111
DTYPE = 'commonsMedia'
12+
PTYPE = 'http://wikiba.se/ontology#CommonsMedia'
1213

13-
def get_sparql_value(self) -> str:
14-
return '<' + self.mainsnak.datavalue['value'] + '>'
14+
def set_value(self, value: str | None = None):
15+
assert isinstance(value, str) or value is None, f"Expected str, found {type(value)} ({value})"
16+
17+
if value:
18+
pattern = re.compile(r'^.+\..+$')
19+
matches = pattern.match(value)
20+
21+
if not matches:
22+
raise ValueError(f"Invalid CommonsMedia {value}")
23+
24+
self.mainsnak.datavalue = {
25+
'value': value,
26+
'type': 'string'
27+
}
1528

1629
def parse_sparql_value(self, value, type='literal', unit='1') -> bool:
1730
pattern = re.compile(r'^<?.*?/?([^/]*?)>?$')

wikibaseintegrator/datatypes/externalid.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ class ExternalID(String):
66
Implements the Wikibase data type 'external-id'
77
"""
88
DTYPE = 'external-id'
9+
PTYPE = 'http://wikiba.se/ontology#ExternalId'

wikibaseintegrator/datatypes/form.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,16 @@
22
from typing import Any
33

44
from wikibaseintegrator.datatypes.basedatatype import BaseDataType
5+
from wikibaseintegrator.wbi_config import config
6+
from wikibaseintegrator.wbi_enums import WikibaseSnakType
57

68

79
class Form(BaseDataType):
810
"""
911
Implements the Wikibase data type 'wikibase-form'
1012
"""
1113
DTYPE = 'wikibase-form'
14+
PTYPE = 'http://wikiba.se/ontology#WikibaseForm'
1215
sparql_query = '''
1316
SELECT * WHERE {{
1417
?item_id <{wb_url}/prop/{pid}> ?s .
@@ -55,8 +58,14 @@ def set_value(self, value: str | None = None):
5558
'type': 'wikibase-entityid'
5659
}
5760

58-
def get_sparql_value(self) -> str:
59-
return self.mainsnak.datavalue['value']['id']
61+
# TODO: add from_sparql_value()
62+
63+
def get_sparql_value(self, **kwargs: Any) -> str | None:
64+
if self.mainsnak.snaktype == WikibaseSnakType.KNOWN_VALUE:
65+
wikibase_url = str(kwargs['wikibase_url'] if 'wikibase_url' in kwargs else config['WIKIBASE_URL'])
66+
return f'<{wikibase_url}/entity/' + self.mainsnak.datavalue['value']['id'] + '>'
67+
68+
return None
6069

6170
def get_lexeme_id(self) -> str:
6271
"""

wikibaseintegrator/datatypes/geoshape.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ class GeoShape(BaseDataType):
99
Implements the Wikibase data type 'geo-shape'
1010
"""
1111
DTYPE = 'geo-shape'
12+
PTYPE = 'http://wikiba.se/ontology#GeoShape'
1213
sparql_query = '''
1314
SELECT * WHERE {{
1415
?item_id <{wb_url}/prop/{pid}> ?s .
@@ -53,3 +54,7 @@ def set_value(self, value: str | None = None):
5354
'value': value,
5455
'type': 'string'
5556
}
57+
58+
# TODO: Does GeoShape need a full URL to wikimedia commons?
59+
def get_sparql_value(self, **kwargs: Any) -> str:
60+
return '<' + self.mainsnak.datavalue['value'] + '>'

wikibaseintegrator/datatypes/globecoordinate.py

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
1+
from __future__ import annotations
2+
13
import re
24
from typing import Any
35

46
from wikibaseintegrator.datatypes.basedatatype import BaseDataType
57
from wikibaseintegrator.models import Claim
68
from wikibaseintegrator.wbi_config import config
9+
from wikibaseintegrator.wbi_enums import WikibaseSnakType
710

811

912
class GlobeCoordinate(BaseDataType):
1013
"""
1114
Implements the Wikibase data type for globe coordinates
1215
"""
1316
DTYPE = 'globe-coordinate'
17+
PTYPE = 'http://wikiba.se/ontology#GlobeCoordinate'
1418
sparql_query = '''
1519
SELECT * WHERE {{
1620
?item_id <{wb_url}/prop/{pid}> ?s .
@@ -75,8 +79,37 @@ def rounded(datavalue: dict) -> dict:
7579

7680
return super().__eq__(other)
7781

78-
def get_sparql_value(self) -> str:
79-
return '"Point(' + str(self.mainsnak.datavalue['value']['longitude']) + ' ' + str(self.mainsnak.datavalue['value']['latitude']) + ')"'
82+
def from_sparql_value(self, sparql_value: dict) -> GlobeCoordinate:
83+
"""
84+
Parse data returned by a SPARQL endpoint and set the value to the object
85+
86+
:param sparql_value: A SPARQL value composed of datatype, type and value
87+
:return: True if the parsing is successful
88+
"""
89+
datatype = sparql_value['datatype']
90+
type = sparql_value['type']
91+
value = sparql_value['value']
92+
93+
if datatype != 'http://www.opengis.net/ont/geosparql#wktLiteral':
94+
raise ValueError('Wrong SPARQL datatype')
95+
96+
if type != 'literal':
97+
raise ValueError('Wrong SPARQL type')
98+
99+
if value.startswith('http://www.wikidata.org/.well-known/genid/'):
100+
self.mainsnak.snaktype = WikibaseSnakType.UNKNOWN_VALUE
101+
else:
102+
pattern = re.compile(r'^Point\((.*) (.*)\)$')
103+
matches = pattern.match(value)
104+
if not matches:
105+
raise ValueError('Invalid SPARQL value')
106+
107+
self.set_value(longitude=float(matches.group(1)), latitude=float(matches.group(2)))
108+
109+
return self
110+
111+
def get_sparql_value(self, **kwargs: Any) -> str:
112+
return '"Point(' + str(self.mainsnak.datavalue['value']['longitude']) + ' ' + str(self.mainsnak.datavalue['value']['latitude']) + ')"^^geo:wktLiteral'
80113

81114
def parse_sparql_value(self, value, type='literal', unit='1') -> bool:
82115
pattern = re.compile(r'^"?Point\((.*) (.*)\)"?(?:\^\^geo:wktLiteral)?$')

0 commit comments

Comments
 (0)