Skip to content

Commit 3bd1ec2

Browse files
Added FI support.
Co-Authored-By: Raphael Gomes Santos <[email protected]>
1 parent cbcca31 commit 3bd1ec2

19 files changed

+801
-21
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
.DS_Store
22
ign-*
3+
*.patch
34

45
#IDE
56
.idea/

hkpy/hkbase/hkrepository.py

+152-16
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,13 @@
99
import copy
1010
import json
1111
import requests
12+
from urllib.parse import quote
1213
from io import TextIOWrapper, BufferedReader, BufferedIOBase
1314

1415
from . import HKTransaction, generate_id, constants
1516
from ..hklib import hkfy, HKEntity, HKContext
17+
from ..hklib.fi.fi import FI
18+
from ..hklib.node import HKDataNode
1619
from ..oops import HKBError, HKpyError
1720
from ..utils import response_validator
1821
from ..common.result_set import ResultSet
@@ -73,29 +76,96 @@ def add_entities(self, entities: Union[HKEntity, List[HKEntity]], transaction: O
7376

7477
url = f'{self.base._repository_uri}/{self.name}/entity/'
7578

79+
filtered_data_objects = []
80+
7681
if not isinstance(entities, (list,tuple)):
7782
entities = [entities]
78-
83+
7984
if isinstance(entities[0], HKEntity):
8085
entities = [x.to_dict() for x in entities]
8186
elif isinstance(entities[0], dict):
8287
pass
83-
# entities = list(map(hkfy, entities))
8488
else:
8589
raise ValueError
8690

91+
data_entities, entities = self.filter_data_entities(entities)
92+
if data_entities:
93+
self.add_data_entities(data_entities)
94+
8795
headers = copy.deepcopy(self._headers)
8896
headers['Content-Type'] = 'application/json'
8997

9098
response = requests.put(url=url, data=json.dumps(entities), headers=headers)
9199
response_validator(response=response)
92100

93-
def filter_entities(self, filter_: Union[str, Dict]) -> List[HKEntity]:
101+
def filter_data_entities(self, entities: Union[HKEntity, List[HKEntity]]):
102+
""" filter the entities with raw data.
103+
Return two lists:
104+
dataentities: entities with raw data.
105+
nondataentites: entities without raw data.
106+
107+
Parameters
108+
----------
109+
entities : (Union[HKDataNode, List[HKDataNode]]) entity or list of entities
110+
transaction : (Optional[HKTransaction]) connection transaction
111+
112+
Returns
113+
-------
114+
dataentities: (List[HKEntity]) list of entities with raw data
115+
nondataentites: (List[HKEntity]) list of entities without raw data
116+
"""
117+
118+
dataentities = []
119+
nondataentites = []
120+
for entity in entities:
121+
if 'raw_data' in entity:
122+
dataentities.append(entity)
123+
else:
124+
nondataentites.append(entity)
125+
return dataentities, nondataentites
126+
127+
def add_data_entities(self, dataentities: Union[HKDataNode, List[HKDataNode]], transaction: Optional[HKTransaction]=None) -> None:
128+
""" Add entities with raw data to repository.
129+
130+
Parameters
131+
----------
132+
entities : (Union[HKDataNode, List[HKDataNode]]) data node or list of data nodes
133+
transaction : (Optional[HKTransaction]) connection transaction
134+
"""
135+
136+
url = f'{self.base._repository_uri}/{self.name}/entity/'
137+
138+
if not dataentities:
139+
return
140+
141+
if not isinstance(dataentities, (list,tuple)):
142+
dataentities = [dataentities]
143+
144+
if isinstance(dataentities[0], HKEntity):
145+
dataentities = [x.to_dict() for x in entities]
146+
elif isinstance(dataentities[0], dict):
147+
pass
148+
else:
149+
raise ValueError
150+
151+
files = {}
152+
data = {}
153+
for entity in dataentities:
154+
file = entity.pop('raw_data')
155+
files[entity['id']] = (entity['id'], file, entity['properties']['mimeType'])
156+
data[entity['id']] = json.dumps(entity)
157+
158+
response = requests.put(url=url, data=data, files=files)
159+
response_validator(response=response)
160+
161+
162+
def filter_entities(self, filter_: Union[str, Dict], bring_raw_data: Optional[bool]=False) -> List[HKEntity]:
94163
""" Get entities filtered by a css filter or json filter.
95164
96165
Parameters
97166
----------
98167
filter_ : (Union[str, Dict]) retrieval filter
168+
bring_raw_data: Optional[bool] flag to define whether raw data should be fetched or not
99169
100170
Returns
101171
-------
@@ -135,15 +205,20 @@ def check_list(the_filter, depth=0):
135205
except Exception as err:
136206
raise HKBError(message='Could not retrieve the entities.', error=err)
137207

138-
return [hkfy(entity) for entity in data.values()]
208+
entities = [hkfy(entity) for entity in data.values()]
209+
if bring_raw_data:
210+
entities = self.retrieve_raw_data_from_data_entities(entities)
211+
212+
return entities
139213

140-
def get_entities(self, ids: List[Union[str, Dict]]) -> List[HKEntity]:
214+
def get_entities(self, ids: List[Union[str, Dict]], bring_raw_data: Optional[bool]=False) -> List[HKEntity]:
141215
""" Get entities by an array of ids, where the id can be a string or an object containing remote information of
142216
virtual entities.
143217
144218
Parameters
145219
----------
146220
ids : List[Union[str, Dict]] entities identifiers
221+
bring_raw_data: Optional[bool] flag to define whether raw data should be fetched or not
147222
148223
Returns
149224
-------
@@ -163,7 +238,32 @@ def get_entities(self, ids: List[Union[str, Dict]]) -> List[HKEntity]:
163238
except Exception as err:
164239
raise HKBError(message='Could not retrieve the entities.', error=err)
165240

166-
return [hkfy(entity) for entity in data.values()]
241+
entities = [hkfy(entity) for entity in data.values()]
242+
if bring_raw_data:
243+
entities = self.retrieve_raw_data_from_data_entities(entities)
244+
245+
return entities
246+
247+
def retrieve_raw_data_from_data_entities(self, entities: List[HKEntity]) -> List[HKEntity]:
248+
""" Retrive data from storage from data entities
249+
250+
Obs.: This is probably temporary. Probably the data will come from hkbase directly
251+
252+
Parameters
253+
----------
254+
ids : List[HKEntity] entities
255+
256+
Returns
257+
-------
258+
(List[HKEntity]) list of data entities filled with their raw data
259+
"""
260+
261+
for i in range(len(entities)):
262+
if 'mimeType' in entities[i].properties:
263+
raw_data = self.get_object(entities[i].id_)
264+
entities[i] = HKDataNode(raw_data, id_=entities[i].id_, parent=entities[i].parent, properties=entities[i].properties, metaproperties=entities[i].metaproperties)
265+
266+
return entities
167267

168268
def delete_entities(self, ids: Optional[Union[str, List[str], HKEntity, List[HKEntity]]] = None, transaction: Optional[HKTransaction]=None) -> None:
169269
""" Delete entities from the repository using their ids.
@@ -175,15 +275,12 @@ def delete_entities(self, ids: Optional[Union[str, List[str], HKEntity, List[HKE
175275

176276
url = f'{self.base._repository_uri}/{self.name}/entity/'
177277

178-
if ids is None or len(ids) == 0:
179-
ids = {}
180-
else:
181-
if not isinstance(ids, (list,tuple)):
182-
ids = [ids]
183-
184-
if isinstance(ids[0], HKEntity):
185-
ids = [x.id_ for x in ids]
186-
278+
if not isinstance(ids, (list,tuple)):
279+
ids = [ids]
280+
281+
if isinstance(ids[0], HKEntity):
282+
ids = [x.id_ for x in ids]
283+
187284
response = requests.delete(url=url, data=json.dumps(ids), headers=self._headers)
188285
response_validator(response=response)
189286

@@ -216,7 +313,9 @@ def import_data(self, fd: Union[str, TextIOWrapper], datatype: constants.Content
216313
raise HKpyError(message='Data formaat not supported.')
217314

218315
if 'as_hk' in options and options['as_hk'] == True:
219-
self.add_entities(entities=json.loads(fd))
316+
entities = json.loads(fd)
317+
entities = list(map(hkfy, entities.values()))
318+
self.add_entities(list(entities))
220319

221320
else:
222321
url = f'{self.base._repository_uri}/{self.name}/rdf'
@@ -323,6 +422,10 @@ def add_object(self, object_: [str, TextIOWrapper, BufferedReader, BufferedIOBas
323422
elif isinstance(object_, str) and os.path.isfile(object_):
324423
with open(object_ ,'rb') as f:
325424
object_ = f.read()
425+
elif isinstance(object_, str):
426+
pass # do nothing
427+
elif isinstance(object_, bytes):
428+
pass # do nothing
326429
else:
327430
raise HKpyError(message='Object not valid.')
328431

@@ -475,3 +578,36 @@ def _build_sparql_result(self, data) -> Union[SPARQLResultSet, bool]:
475578
if not ('results' in data and 'bindings' in data['results'] and 'head' in data):
476579
raise HKpyError(f'The given data is not of the expected format')
477580
return SPARQLResultSet(data)
581+
582+
def resolve_fi(self, fi: FI, raw = False) -> Union[bytes, List[HKEntity]] :
583+
"""
584+
Resolve a full FI. Set raw to True in order to get raw output. Otherwise the function will try to
585+
interpret the response (i.e. into hk objects)
586+
"""
587+
quoted_fi = quote(fi.__str__(), safe="");
588+
url = f'{self.base._repository_uri}/{self.name}/fi/{quoted_fi}'
589+
590+
response = requests.get(url=url, headers=self._headers)
591+
_, data = response_validator(response=response, content='.')
592+
593+
if raw:
594+
return data
595+
596+
# some extra response data converter
597+
content_type = response.headers['Content-Type']
598+
if content_type.startswith('hyperknowledge/graph'):
599+
return hkfy(response.json())
600+
elif content_type.startswith('hyperknowledge/node'):
601+
return hkfy(response.json())
602+
elif content_type.startswith('text'):
603+
return response.content.decode()
604+
else:
605+
return data
606+
607+
def persist_fi(self, fi):
608+
609+
quoted_fi = quote(fi.__str__(), safe="");
610+
url = f'{self.base._repository_uri}/{self.name}/fi/{quoted_fi}'
611+
612+
response = requests.put(url=url, headers=self._headers)
613+
response_validator(response=response)

hkpy/hklib/__init__.py

+11-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111
from .entity import HKEntity
1212
from .connector import HKConnector
1313
from .link import HKLink
14-
from .node import HKNode, HKContext, HKReferenceNode, HKTrail, HKAnyNode
14+
from .node import HKNode, HKContext, HKReferenceNode, HKTrail, HKAnyNode, HKDataNode
15+
from .graphbuilder import HKGraphBuilder
1516

1617
def hkfy(entity: Union[str, Dict]) -> HKEntity:
1718
""" Convert an entity in string or dict format to a HKEntity object.
@@ -43,7 +44,7 @@ def hkfy(entity: Union[str, Dict]) -> HKEntity:
4344
hke = HKNode(id_=entity['id'], parent=entity.get('parent'))
4445
elif entity['type'] == constants.HKType.REFERENCENODE:
4546
ref = entity['ref'] if 'ref' in entity else None
46-
hke = HKReferenceNode(id_=entity['id'], ref=ref, parent=entity.get('parent'))
47+
hke = HKReferenceNode(id_=entity['id'], ref=ref, parent=entity.get('parent'))
4748
if 'interfaces' in entity:
4849
hke.interfaces = entity['interfaces']
4950

@@ -52,6 +53,14 @@ def hkfy(entity: Union[str, Dict]) -> HKEntity:
5253

5354
elif entity['type'] == constants.HKType.ANCHOR:
5455
raise NotImplementedError
56+
elif entity['type'] == constants.HKType.GRAPH:
57+
hke = HKGraph()
58+
entities = []
59+
for entity_type, graph_entity in entity.items():
60+
if entity_type != 'type':
61+
for eid, e in graph_entity.items():
62+
entities.append(hkfy(e))
63+
hke.add_entities(entities)
5564

5665
if 'properties' in entity:
5766
hke.add_properties(properties=entity['properties'])

hkpy/hklib/entity.py

+3
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ def add_properties(self, **kwargs) -> None:
5555
else:
5656
self.properties.update(kwargs)
5757

58+
def set_property(self, property, value):
59+
self.properties[property] = value
60+
5861
def add_metaproperties(self, **kwargs) -> None:
5962
""" Add metaproperties in the HKEntity.
6063

hkpy/hklib/fi/__init__.py

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
2+
3+
4+
from .fi import FI
5+
from .fianchor import FIAnchor
6+
from .fioperator import FIOperator
7+
from .fiparser import parse_anchor, parse_fi, parse_id

0 commit comments

Comments
 (0)