pyLodStorage 0.0.26__tar.gz → 0.0.28__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pylodstorage-0.0.26 → pylodstorage-0.0.28}/PKG-INFO +1 -1
- {pylodstorage-0.0.26 → pylodstorage-0.0.28}/lodstorage/jsonable.py +149 -38
- {pylodstorage-0.0.26 → pylodstorage-0.0.28}/lodstorage/sample.py +39 -10
- {pylodstorage-0.0.26 → pylodstorage-0.0.28}/lodstorage/sql.py +1 -1
- {pylodstorage-0.0.26 → pylodstorage-0.0.28}/pylodstorage.egg-info/PKG-INFO +1 -1
- {pylodstorage-0.0.26 → pylodstorage-0.0.28}/setup.py +1 -1
- {pylodstorage-0.0.26 → pylodstorage-0.0.28}/README.md +0 -0
- {pylodstorage-0.0.26 → pylodstorage-0.0.28}/lodstorage/__init__.py +0 -0
- {pylodstorage-0.0.26 → pylodstorage-0.0.28}/lodstorage/lod.py +0 -0
- {pylodstorage-0.0.26 → pylodstorage-0.0.28}/lodstorage/mwTable.py +0 -0
- {pylodstorage-0.0.26 → pylodstorage-0.0.28}/lodstorage/query.py +0 -0
- {pylodstorage-0.0.26 → pylodstorage-0.0.28}/lodstorage/schema.py +0 -0
- {pylodstorage-0.0.26 → pylodstorage-0.0.28}/lodstorage/sparql.py +0 -0
- {pylodstorage-0.0.26 → pylodstorage-0.0.28}/lodstorage/uml.py +0 -0
- {pylodstorage-0.0.26 → pylodstorage-0.0.28}/pylodstorage.egg-info/SOURCES.txt +0 -0
- {pylodstorage-0.0.26 → pylodstorage-0.0.28}/pylodstorage.egg-info/dependency_links.txt +0 -0
- {pylodstorage-0.0.26 → pylodstorage-0.0.28}/pylodstorage.egg-info/requires.txt +0 -0
- {pylodstorage-0.0.26 → pylodstorage-0.0.28}/pylodstorage.egg-info/top_level.txt +0 -0
- {pylodstorage-0.0.26 → pylodstorage-0.0.28}/setup.cfg +0 -0
|
@@ -9,26 +9,31 @@ import datetime
|
|
|
9
9
|
import sys
|
|
10
10
|
import re
|
|
11
11
|
|
|
12
|
-
class
|
|
13
|
-
'''
|
|
14
|
-
mixin to allow classes to be JSON serializable see
|
|
15
|
-
|
|
16
|
-
- https://stackoverflow.com/questions/3768895/how-to-make-a-class-json-serializable
|
|
17
|
-
|
|
18
|
-
'''
|
|
12
|
+
class JSONAbleSettings():
|
|
19
13
|
indent=4
|
|
20
|
-
|
|
21
14
|
'''
|
|
22
15
|
regular expression to be used for conversion from singleQuote to doubleQuote
|
|
23
16
|
see https://stackoverflow.com/a/50257217/1497139
|
|
24
17
|
'''
|
|
25
18
|
singleQuoteRegex = re.compile('(?<!\\\\)\'')
|
|
19
|
+
|
|
20
|
+
class JSONAble(object):
|
|
21
|
+
'''
|
|
22
|
+
mixin to allow classes to be JSON serializable see
|
|
23
|
+
|
|
24
|
+
- https://stackoverflow.com/questions/3768895/how-to-make-a-class-json-serializable
|
|
25
|
+
|
|
26
|
+
'''
|
|
26
27
|
|
|
27
28
|
def __init__(self):
|
|
28
29
|
'''
|
|
29
30
|
Constructor
|
|
30
31
|
'''
|
|
31
32
|
|
|
33
|
+
@classmethod
|
|
34
|
+
def getPluralname(cls):
|
|
35
|
+
return "%ss" % cls.__name__
|
|
36
|
+
|
|
32
37
|
@staticmethod
|
|
33
38
|
def singleQuoteToDoubleQuote(singleQuoted,useRegex=False):
|
|
34
39
|
'''
|
|
@@ -70,7 +75,7 @@ class JSONAble(object):
|
|
|
70
75
|
Note:
|
|
71
76
|
see https://stackoverflow.com/a/50257217/1497139
|
|
72
77
|
"""
|
|
73
|
-
doubleQuoted=
|
|
78
|
+
doubleQuoted=JSONAbleSettings.singleQuoteRegex.sub('\"', singleQuoted)
|
|
74
79
|
return doubleQuoted
|
|
75
80
|
|
|
76
81
|
@staticmethod
|
|
@@ -102,30 +107,17 @@ class JSONAble(object):
|
|
|
102
107
|
doubleQuoted="".join(cList)
|
|
103
108
|
return doubleQuoted
|
|
104
109
|
|
|
105
|
-
def
|
|
110
|
+
def getJsonTypeSamples(self):
|
|
106
111
|
'''
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
Args:
|
|
110
|
-
storeFilePrefix(string): the prefix for the JSON file name
|
|
111
|
-
tableName(string): the name of the attribute for which to store the type information
|
|
112
|
+
does my class provide a "getSamples" method?
|
|
112
113
|
'''
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
Args:
|
|
122
|
-
storeFilePrefix(string): the prefix for the JSON file name
|
|
123
|
-
'''
|
|
124
|
-
jsonStr=JSONAble.readJsonFromFile("%s.json" % storeFilePrefix)
|
|
125
|
-
typesJson=JSONAble.readJsonFromFile("%s-types.json" % storeFilePrefix)
|
|
126
|
-
types=Types(type(self).__name__)
|
|
127
|
-
types.fromJson(typesJson)
|
|
128
|
-
self.fromJson(jsonStr, types)
|
|
114
|
+
if hasattr(self, '__class__'):
|
|
115
|
+
cls=self.__class__
|
|
116
|
+
if hasattr(cls, 'getSamples'):
|
|
117
|
+
getSamples=getattr(cls,'getSamples');
|
|
118
|
+
if callable(getSamples):
|
|
119
|
+
return getSamples()
|
|
120
|
+
return None
|
|
129
121
|
|
|
130
122
|
@staticmethod
|
|
131
123
|
def readJsonFromFile(jsonFilePath):
|
|
@@ -163,9 +155,31 @@ class JSONAble(object):
|
|
|
163
155
|
jsonStr(str): the JSON string
|
|
164
156
|
fixType(Types): the types to be fixed
|
|
165
157
|
'''
|
|
166
|
-
|
|
158
|
+
lod=self.getLoDfromJson(jsonStr, types)
|
|
159
|
+
self.fromDict(lod)
|
|
160
|
+
|
|
161
|
+
def getLoDfromJson(self,jsonStr,types=None):
|
|
162
|
+
'''
|
|
163
|
+
get a list of Dicts form the given JSON String
|
|
164
|
+
|
|
165
|
+
Args:
|
|
166
|
+
jsonStr(str): the JSON string
|
|
167
|
+
fixType(Types): the types to be fixed
|
|
168
|
+
Returns:
|
|
169
|
+
list: a list of dicts
|
|
170
|
+
'''
|
|
171
|
+
lod=json.loads(jsonStr)
|
|
167
172
|
if types is not None:
|
|
168
|
-
types.fixTypes(
|
|
173
|
+
types.fixTypes(lod)
|
|
174
|
+
return lod
|
|
175
|
+
|
|
176
|
+
def fromDict(self,data):
|
|
177
|
+
'''
|
|
178
|
+
initialize me from the given data
|
|
179
|
+
|
|
180
|
+
Args:
|
|
181
|
+
data: the dictionary to initalize me from
|
|
182
|
+
'''
|
|
169
183
|
# https://stackoverflow.com/questions/38987/how-do-i-merge-two-dictionaries-in-a-single-expression-in-python-taking-union-o
|
|
170
184
|
self.__dict__=data
|
|
171
185
|
|
|
@@ -191,7 +205,7 @@ class JSONAble(object):
|
|
|
191
205
|
a recursive JSON dump of the dicts of my objects
|
|
192
206
|
'''
|
|
193
207
|
jsonStr=json.dumps(self, default=lambda v: self.toJsonAbleValue(v),
|
|
194
|
-
sort_keys=True, indent=
|
|
208
|
+
sort_keys=True, indent=JSONAbleSettings.indent)
|
|
195
209
|
return jsonStr
|
|
196
210
|
|
|
197
211
|
def getJSONValue(self,v):
|
|
@@ -238,20 +252,113 @@ class JSONAble(object):
|
|
|
238
252
|
d[a]=self.getJSONValue(v)
|
|
239
253
|
return d
|
|
240
254
|
|
|
241
|
-
def asJSON(self,asString=True):
|
|
255
|
+
def asJSON(self,asString=True,data=None):
|
|
242
256
|
'''
|
|
243
257
|
recursively return my dict elements
|
|
244
258
|
|
|
245
259
|
Args:
|
|
246
260
|
asString(boolean): if True return my result as a string
|
|
247
261
|
'''
|
|
248
|
-
|
|
262
|
+
if data is None:
|
|
263
|
+
data=self.__dict__
|
|
264
|
+
jsonDict=self.reprDict(data)
|
|
249
265
|
if asString:
|
|
250
266
|
jsonStr=str(jsonDict)
|
|
251
267
|
jsonStr = JSONAble.singleQuoteToDoubleQuote(jsonStr)
|
|
252
268
|
return jsonStr
|
|
253
269
|
return jsonDict
|
|
254
270
|
|
|
271
|
+
class JSONAbleList(JSONAble):
|
|
272
|
+
'''
|
|
273
|
+
Container class
|
|
274
|
+
'''
|
|
275
|
+
|
|
276
|
+
def __init__(self,listName:str=None,clazz=None,tableName:str=None,):
|
|
277
|
+
'''
|
|
278
|
+
Constructor
|
|
279
|
+
|
|
280
|
+
Args:
|
|
281
|
+
listName(str): the name of the list attribute to be used for storing the List
|
|
282
|
+
clazz(class): a class to be used for Object relational mapping (if any)
|
|
283
|
+
tableName(str): the name of the "table" to be used
|
|
284
|
+
'''
|
|
285
|
+
self.clazz=clazz
|
|
286
|
+
if listName is None:
|
|
287
|
+
if self.clazz is not None:
|
|
288
|
+
listName=self.clazz.getPluralname()
|
|
289
|
+
else:
|
|
290
|
+
listName=self.__class__.name.lower()
|
|
291
|
+
self.listName=listName
|
|
292
|
+
if tableName is None:
|
|
293
|
+
self.tableName=listName
|
|
294
|
+
else:
|
|
295
|
+
self.tableName=tableName
|
|
296
|
+
|
|
297
|
+
def getJsonData(self):
|
|
298
|
+
'''
|
|
299
|
+
get my Jsondata
|
|
300
|
+
'''
|
|
301
|
+
jsonData={
|
|
302
|
+
self.listName:self.__dict__[self.listName]
|
|
303
|
+
}
|
|
304
|
+
return jsonData
|
|
305
|
+
|
|
306
|
+
def toJsonAbleValue(self,v):
|
|
307
|
+
'''
|
|
308
|
+
make sure we don't store our meta information
|
|
309
|
+
clazz, tableName and listName but just the list we are holding
|
|
310
|
+
'''
|
|
311
|
+
if v==self:
|
|
312
|
+
|
|
313
|
+
return self.getJsonData()
|
|
314
|
+
else:
|
|
315
|
+
return super().toJsonAbleValue(v)
|
|
316
|
+
|
|
317
|
+
def asJSON(self,asString=True):
|
|
318
|
+
jsonData=self.getJsonData()
|
|
319
|
+
return super().asJSON(asString, data=jsonData)
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
def storeToJsonFile(self,storeFilePrefix):
|
|
323
|
+
'''
|
|
324
|
+
store me with the given storeFilePrefix
|
|
325
|
+
|
|
326
|
+
Args:
|
|
327
|
+
storeFilePrefix(string): the prefix for the JSON file name
|
|
328
|
+
'''
|
|
329
|
+
JSONAble.storeJsonToFile(self.toJSON(), "%s.json" % storeFilePrefix)
|
|
330
|
+
|
|
331
|
+
def restoreFromJsonFile(self,storeFilePrefix):
|
|
332
|
+
'''
|
|
333
|
+
restore me from the given storeFilePrefix
|
|
334
|
+
|
|
335
|
+
Args:
|
|
336
|
+
storeFilePrefix(string): the prefix for the JSON file name
|
|
337
|
+
'''
|
|
338
|
+
jsonStr=JSONAble.readJsonFromFile("%s.json" % storeFilePrefix)
|
|
339
|
+
if self.clazz is None:
|
|
340
|
+
typeSamples=self.getJsonTypeSamples()
|
|
341
|
+
else:
|
|
342
|
+
typeSamples=self.clazz.getSamples()
|
|
343
|
+
if typeSamples is None:
|
|
344
|
+
types=None
|
|
345
|
+
else:
|
|
346
|
+
types=Types(self.listName)
|
|
347
|
+
types.getTypes(self.listName, typeSamples, len(typeSamples))
|
|
348
|
+
lod=self.getLoDfromJson(jsonStr, types)
|
|
349
|
+
|
|
350
|
+
if self.clazz is None:
|
|
351
|
+
result=lod
|
|
352
|
+
else:
|
|
353
|
+
instanceList=[]
|
|
354
|
+
for record in lod[self.listName]:
|
|
355
|
+
instance=self.clazz()
|
|
356
|
+
instance.fromDict(record)
|
|
357
|
+
instanceList.append(instance)
|
|
358
|
+
result=instanceList
|
|
359
|
+
self.__dict__[self.listName]=result
|
|
360
|
+
return result
|
|
361
|
+
|
|
255
362
|
class Types(JSONAble):
|
|
256
363
|
'''
|
|
257
364
|
Types
|
|
@@ -320,10 +427,14 @@ class Types(JSONAble):
|
|
|
320
427
|
determine the types for the given sample records
|
|
321
428
|
'''
|
|
322
429
|
for sampleRecord in sampleRecords[:limit]:
|
|
323
|
-
|
|
430
|
+
items=sampleRecord.items()
|
|
431
|
+
self.getTypesForItems(listName,items,warnOnNone=len(sampleRecords)==1)
|
|
432
|
+
|
|
433
|
+
def getTypesForItems(self,listName,items,warnOnNone=False):
|
|
434
|
+
for key,value in items:
|
|
324
435
|
valueType=None
|
|
325
436
|
if value is None:
|
|
326
|
-
if
|
|
437
|
+
if warnOnNone:
|
|
327
438
|
print("Warning sampleRecord field %s is None - using string as type" % key)
|
|
328
439
|
valueType=str
|
|
329
440
|
else:
|
|
@@ -5,7 +5,7 @@ Created on 2020-08-24
|
|
|
5
5
|
'''
|
|
6
6
|
import urllib.request
|
|
7
7
|
import json
|
|
8
|
-
from lodstorage.jsonable import JSONAble
|
|
8
|
+
from lodstorage.jsonable import JSONAble, JSONAbleList
|
|
9
9
|
from datetime import date, datetime
|
|
10
10
|
|
|
11
11
|
class Sample(object):
|
|
@@ -55,6 +55,41 @@ class Sample(object):
|
|
|
55
55
|
|
|
56
56
|
@staticmethod
|
|
57
57
|
def getRoyals():
|
|
58
|
+
return Royal.getSamples()
|
|
59
|
+
|
|
60
|
+
@staticmethod
|
|
61
|
+
def getRoyalsInstances():
|
|
62
|
+
lod=Royal.getSamples()
|
|
63
|
+
royals=[]
|
|
64
|
+
for record in lod:
|
|
65
|
+
royal=Royal()
|
|
66
|
+
royal.fromDict(record)
|
|
67
|
+
royals.append(royal)
|
|
68
|
+
return royals
|
|
69
|
+
|
|
70
|
+
class Royals(JSONAbleList):
|
|
71
|
+
def __init__(self,load=False):
|
|
72
|
+
super(Royals, self).__init__("royals",clazz=None)
|
|
73
|
+
if load:
|
|
74
|
+
self.royals=Royal.getSamples()
|
|
75
|
+
else:
|
|
76
|
+
self.royals=None
|
|
77
|
+
|
|
78
|
+
class RoyalsORMList(JSONAbleList):
|
|
79
|
+
def __init__(self,load=False):
|
|
80
|
+
super(RoyalsORMList, self).__init__("royals",Royal)
|
|
81
|
+
if load:
|
|
82
|
+
self.royals=Sample.getRoyalsInstances()
|
|
83
|
+
else:
|
|
84
|
+
self.royals=None
|
|
85
|
+
|
|
86
|
+
class Royal(JSONAble):
|
|
87
|
+
'''
|
|
88
|
+
i am a single Royal
|
|
89
|
+
'''
|
|
90
|
+
|
|
91
|
+
@classmethod
|
|
92
|
+
def getSamples(cls):
|
|
58
93
|
listOfDicts=[
|
|
59
94
|
{'name': 'Elizabeth Alexandra Mary Windsor', 'born': Sample.dob('1926-04-21'), 'numberInLine': 0, 'wikidataurl': 'https://www.wikidata.org/wiki/Q9682' },
|
|
60
95
|
{'name': 'Charles, Prince of Wales', 'born': Sample.dob('1948-11-14'), 'numberInLine': 1, 'wikidataurl': 'https://www.wikidata.org/wiki/Q43274' },
|
|
@@ -69,16 +104,10 @@ class Sample(object):
|
|
|
69
104
|
person['ofAge']=age>=18
|
|
70
105
|
person['lastmodified']=datetime.now()
|
|
71
106
|
return listOfDicts
|
|
72
|
-
|
|
73
|
-
class
|
|
74
|
-
def __init__(self,load=False):
|
|
75
|
-
if load:
|
|
76
|
-
self.royals=Sample.getRoyals()
|
|
77
|
-
else:
|
|
78
|
-
self.royals=None
|
|
79
|
-
|
|
80
|
-
class Cities(JSONAble):
|
|
107
|
+
|
|
108
|
+
class Cities(JSONAbleList):
|
|
81
109
|
def __init__(self,load=False):
|
|
110
|
+
super(Cities, self).__init__("cities",clazz=None)
|
|
82
111
|
if load:
|
|
83
112
|
self.cities=Sample.getCities()
|
|
84
113
|
else:
|
|
@@ -131,7 +131,7 @@ class SQLDB(object):
|
|
|
131
131
|
for record in listOfRecords:
|
|
132
132
|
index+=1
|
|
133
133
|
if fixNone:
|
|
134
|
-
|
|
134
|
+
LOD.setNone(record, entityInfo.typeMap.keys())
|
|
135
135
|
self.c.execute(insertCmd,record)
|
|
136
136
|
self.c.commit()
|
|
137
137
|
except sqlite3.ProgrammingError as pe:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|