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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pylodstorage
3
- Version: 0.0.26
3
+ Version: 0.0.28
4
4
  Summary: python List of Dict (Table) Storage library
5
5
  Home-page: https://github.com/WolfgangFahl/pyLodStorage
6
6
  Author: Wolfgang Fahl
@@ -9,26 +9,31 @@ import datetime
9
9
  import sys
10
10
  import re
11
11
 
12
- class JSONAble(object):
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=JSONAble.singleQuoteRegex.sub('\"', singleQuoted)
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 storeToJsonFile(self,storeFilePrefix,tableName):
110
+ def getJsonTypeSamples(self):
106
111
  '''
107
- store me with the given storeFilePrefix
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
- JSONAble.storeJsonToFile(self.toJSON(), "%s.json" % storeFilePrefix)
114
- types=Types.forTable(self, tableName)
115
- JSONAble.storeJsonToFile(types.toJSON(), "%s-types.json" % storeFilePrefix)
116
-
117
- def restoreFromJsonFile(self,storeFilePrefix):
118
- '''
119
- restore me from the given storeFilePrefix
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
- data=json.loads(jsonStr)
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(data)
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=JSONAble.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
- jsonDict=self.reprDict(self.__dict__)
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
- for key,value in sampleRecord.items():
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 len(sampleRecords)==1:
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 Royals(JSONAble):
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
- SQLDB.setNone(record, entityInfo.typeMap.keys())
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:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pylodstorage
3
- Version: 0.0.26
3
+ Version: 0.0.28
4
4
  Summary: python List of Dict (Table) Storage library
5
5
  Home-page: https://github.com/WolfgangFahl/pyLodStorage
6
6
  Author: Wolfgang Fahl
@@ -11,7 +11,7 @@ with open(path.join(this_directory, 'README.md'), encoding='utf-8') as f:
11
11
 
12
12
  setup(
13
13
  name='pylodstorage',
14
- version='0.0.26',
14
+ version='0.0.28',
15
15
 
16
16
  packages=['lodstorage',],
17
17
  author='Wolfgang Fahl',
File without changes
File without changes