Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # ===========================================================#
- # Project Management System. #
- # Written by Tyler Beaver, 2012. #
- # Feel free to use, but don't remove my name please? :) #
- # ===========================================================#
- import os,json,copy
- from time import time # For unix time-stamp. Potential problem for threading?
- class Cache:
- objects = {}#Share objects!
- def __init__(self,load): self.loader = load
- @staticmethod
- def needsUpdate(fn):
- if fn not in Cache.objects:
- return True
- if os.path.getmtime(fn) > Cache.objects[fn][1]:
- return True
- return False
- @staticmethod
- def update(fn,ent):
- if fn in Cache.objects:
- Cache.objects[fn][0] = ent
- Cache.objects[fn][1] = time()
- def load(self,fn):
- if Cache.needsUpdate(fn):
- o,m = self.loader(fn),os.path.getmtime(fn)
- Cache.objects[fn] = (o,m)
- return o
- return Cache.objects[fn][0]
- class JSONAdapter:
- extension=".json"
- @staticmethod
- def save(dat,fn):json.dump(dat,open(fn,'w'))
- @staticmethod
- def load(fn):return json.load(open(fn))
- class DataStore:
- @staticmethod
- def base(et):
- return os.path.join(os.environ.get("FMDataStore",os.getcwd()),et.__name__)
- @staticmethod
- def getKeys(et):
- for fn in os.listdir(DataStore.base(et)):
- yield DataStore.getKey(fn)
- @staticmethod
- def store(adapter,entity):
- fn = os.path.join(DataStore.base(type(entity)),entity.key+adapter.extension)
- Cache.update(fn,entity)
- adapter.save(entity.dat,fn)
- @staticmethod
- def connect(et,*a,**b):
- c = DataStore.activeConnections.get(et,None)
- if c is None:
- c = DataStore.Connection(et,*a,**b)
- DataStore.activeConnections[et] = c
- return c
- @staticmethod
- def getKey(fn):
- s,e=os.path.sep,os.extsep
- a,b=fn.rfind(s),fn.rfind(e)
- if a<0 and b<0:return fn[:]
- elif a<0:return fn[:b]
- elif b<0:return fn[a+len(s):]
- else:return fn[a+len(s):b]
- class MetaEntity(type):
- def __init__(self,*args):
- self.cache = Cache(self.fromData)
- d=DataStore.base(self)
- if not os.path.exists(d):
- os.makedirs(d)
- print("Constructing type:",self.__name__)
- return super(MetaEntity,self).__init__(*args)
- def __iter__(self):
- for key in DataStore.getKeys(self):
- yield self.fetch(key)
- def fromData(self,fn):
- return self(key=DataStore.getKey(fn),data=self.adapter.load(fn))
- def fetch(self,key):
- return self.cache.load(os.path.join(DataStore.base(self),key+self.adapter.extension))
- def load(self,k):return self.fetch(k)
- class ReferenceListInterface(list):
- def __init__(self,original,rType):
- self.o,self.et = original,rType
- list.__init__(self,original)
- def __getitem__(self,k):
- if isinstance(k,slice):
- return [self.et.load(ent) for ent in self.o[k]]
- return self.et.load(self.o[k])
- def __setitem__(self,k,val):
- if isinstance(k,slice):
- for i in range(0,len(val)):
- val[i] = val[i].key if isinstance(val[i],Entity) else val[i]
- else:val = val.key if isinstance(val,Entity) else val
- self.o.__setitem__(k,val)
- def __iter__(self):
- for k in self.o:yield self.et.load(k)
- class Entity(metaclass=MetaEntity):
- foreignKeys = {}
- foreignLists = {}
- template = {}
- adapter = JSONAdapter
- def __init__(self,key=int(time()),data=None):
- self.key = str(key)
- self.dat = copy.copy(self.template)
- if data:self.update(data)
- def save(self):DataStore.store(self.adapter,self)
- def update(self,o):
- if o:
- self.dat.update(o)
- self.save()
- def delete(self):DataStore.delete(self)
- def __getattr__(self,attr):
- if attr in self.dat:
- v=self.dat[attr]
- if attr in self.foreignKeys:
- if v is not None:
- return self.foreignKeys[attr].load(v)
- elif attr in self.foreignLists:
- if v is not None:
- return ReferenceListInterface(v,self.foreignLists[attr])
- return v
- t="{} entity has no attribute '{}'"
- raise AttributeError(t.format(type(self).__name__, attr))
- class Query:
- def __init__(self,et,*filters):
- self.entities = et
- self.filters = list(filters)
- def fetchAll(self):return [r for r in self]
- def __iter__(self):
- for entity in self.entities:
- if all(filter(entity) for filter in self.filters):
- yield entity
- if __name__ == "__main__":
- import difflib
- class Location(Entity):
- template={'name':"Red Robins"}
- class Person(Entity):
- foreignLists = {
- 'location':Location
- }
- template={
- 'name':"",
- 'age':0,
- 'location':[]
- }
- while "yes" in input("Create a new person? >"):
- name = input("Name> ")
- age = input("Age> ")
- location = input("Location [ or 'no']> ")
- location = location if location.lower()!='no' else None
- if location:
- nameCompare = difflib.SequenceMatcher(b=location)
- def similarLocation(loc):
- if loc.key==location:return True
- nameCompare.set_seq1(loc.name or "???")
- return nameCompare.ratio() >= .8#Require a 80% match.
- results = Query(Location,similarLocation).fetchAll()
- def makeNewLocation(locName):
- newLocation = Location(data={"name":locName})
- newLocation.save()
- return newLocation.key
- if len(results)>0:
- print("We've found some similar locations that we might think you're referring to.")
- for i in range(0,len(results)):
- print(i+1,results[i].name)
- print("Are you talking about one of these places? Enter the corresponding number, or 0 if your place isn't here.")
- i = int(input("> "))
- if i<1:location = makeNewLocation(location) if i < 1 else results[i-1].key
- else:location=makeNewLocation(location)
- Person(data={"name":name,"age":age,"location":[location] if location else []}).save()
- for person in Person:
- name = person.name
- age = person.age
- location = person.location
- intro = "This is {}.".format(name)
- b = "He is {}.".format(age) if age else "We don't know how old he is."
- c = "He would rather you didn't know where he lives."
- if location:
- c="He's known to live in "+ str(len(location)) + " places."
- for area in location:
- c+="\nHe lives in: "+area.name or "???"
- print(intro,b,c)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement