From 6566c8c7454c63e8155240c383a17a8e230e3719 Mon Sep 17 00:00:00 2001 From: Jordi Saludes Date: Mon, 18 Jul 2011 11:03:54 +0200 Subject: [PATCH 1/6] More hierachical access to objects --- .gitignore | 1 + PObjects.py | 158 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 159 insertions(+) create mode 100644 .gitignore create mode 100644 PObjects.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0d20b64 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.pyc diff --git a/PObjects.py b/PObjects.py new file mode 100644 index 0000000..c0441cd --- /dev/null +++ b/PObjects.py @@ -0,0 +1,158 @@ +class PObject(object): + def __init__(self,client,**kw): + self.client = client + self.kw = kw + + ptype = '' + + def __repr__(self): + return '' % (self.ptype, self.id) + + @property + def id(self): + return self.kw[self.ptype + '_id'] + + #def get(self): + # url = '/%s/%r' %(self.ptype,self.id) + # return self.client.transport.GET(url=url) + + #def post(self,extra): + # self.client.transport.POST( + # url='/%s/%r/%s' % (self.ptype, + # self.id, + # extra)) + + + def add_comment(self, text): + """ + Add a comment to object + """ + return PComment.add_to(self, text) + + @property + def comments(self): + """ + Get all comments to this object. + (Shadows the 'comments' field) + """ + cs = self.client.transport.GET( + url='/comment/%s/%r/' % (self.ptype, self.id)) + return [PComment(self.client,**useAsciiKeys(c)) for c in cs] + + + def create(self,**kw): + import json + attrs = json.dumps(kw) + return self.client.transport.POST( + url = '/%s/'%self.ptype, + body= attrs, + type='application/json') + + def destroy(self): + self.client.transport.DELETE( + url='/%s/%r'%(self.ptype,self.id)) + +class PComment(PObject): + ptype = 'comment' + + @property + def text(self): + return self.kw['value'] + + def __str__(self): + return self.text + + @classmethod + def add_to(klass,pobj,text): + import json + tp = pobj.ptype + attrs = dict(value=text) + response = pobj.client.transport.POST( + url= '/comment/%s/%r/' % (tp,pobj.id), + body= json.dumps(attrs), + type= 'application/json') + return PComment(pobj.client, **useAsciiKeys(response)) + + +class PSpace(PObject): + ptype = 'space' + + +class Notification(PObject): + ptype = 'notification' + + star = lambda s: s.post('star') + + +class PApplication(PObject): + ptype ='app' + + activate = lambda s: s.post('activate') + deactivate = lambda s: s.post('deactivate') + + @classmethod + def fromPodio(klass,client,app_id): + app = client.Application.find(app_id) + return PApplication(client, **useAsciiKeys(app)) + + @property + def items(self): + items = self.client.Application.get_items(self.id)['items'] + return [PItem.fromPodio(self.client,i) for i in items] + + +class PItem(PObject): + ptype = 'item' + + def __iter__(self): + return self + + @classmethod + def fromPodio(klass,client,kw): + return PItem(client,**useAsciiKeys(kw)) + + def __getattr__(self,k): + if self.kw.has_key(k): + return self.kw[k] + else: + raise AttributeError + + def __getitem__(self,k): + fd = self.get_field(k) + if fd: + return fd + else: + raise KeyError + + + def get_field(self,k): + for f in self.kw['fields']: + if k == f['external_id']: return f['values'] + return None + + @property + def keys(self): + return [f['external_id'] for f in self.kw['fields']] + + def next(self): + try: + PItem(self.transport,**self.get('next')) + except: + raise StopIteration + + +# Utils + +def useAsciiKeys(d): + return dict([(str(k),v) for k,v in d.items()]) + + +if __name__ == '__main__': + from mydata import client_data + from pypodio2 import api + c = api.OAuthClient(*client_data) + + app = PApplication.fromPodio(c,) + for i in app.items: + print i.title, i.get_field('date') + i.add_comment("No comment") From 42ebd1a78ab337ff46460fb43398724bf69fd4fb Mon Sep 17 00:00:00 2001 From: Jordi Saludes Date: Mon, 18 Jul 2011 11:15:39 +0200 Subject: [PATCH 2/6] Changed class names --- PObjects.py | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/PObjects.py b/PObjects.py index c0441cd..70190d0 100644 --- a/PObjects.py +++ b/PObjects.py @@ -1,4 +1,4 @@ -class PObject(object): +class Object(object): def __init__(self,client,**kw): self.client = client self.kw = kw @@ -27,7 +27,7 @@ def add_comment(self, text): """ Add a comment to object """ - return PComment.add_to(self, text) + return Comment.add_to(self, text) @property def comments(self): @@ -37,7 +37,7 @@ def comments(self): """ cs = self.client.transport.GET( url='/comment/%s/%r/' % (self.ptype, self.id)) - return [PComment(self.client,**useAsciiKeys(c)) for c in cs] + return [Comment(self.client,**useAsciiKeys(c)) for c in cs] def create(self,**kw): @@ -52,7 +52,7 @@ def destroy(self): self.client.transport.DELETE( url='/%s/%r'%(self.ptype,self.id)) -class PComment(PObject): +class Comment(Object): ptype = 'comment' @property @@ -71,20 +71,20 @@ def add_to(klass,pobj,text): url= '/comment/%s/%r/' % (tp,pobj.id), body= json.dumps(attrs), type= 'application/json') - return PComment(pobj.client, **useAsciiKeys(response)) + return Comment(pobj.client, **useAsciiKeys(response)) -class PSpace(PObject): +class Space(Object): ptype = 'space' -class Notification(PObject): +class Notification(Object): ptype = 'notification' star = lambda s: s.post('star') -class PApplication(PObject): +class Application(Object): ptype ='app' activate = lambda s: s.post('activate') @@ -93,15 +93,15 @@ class PApplication(PObject): @classmethod def fromPodio(klass,client,app_id): app = client.Application.find(app_id) - return PApplication(client, **useAsciiKeys(app)) + return Application(client, **useAsciiKeys(app)) @property def items(self): items = self.client.Application.get_items(self.id)['items'] - return [PItem.fromPodio(self.client,i) for i in items] + return [Item.fromPodio(self.client,i) for i in items] -class PItem(PObject): +class Item(Object): ptype = 'item' def __iter__(self): @@ -109,7 +109,7 @@ def __iter__(self): @classmethod def fromPodio(klass,client,kw): - return PItem(client,**useAsciiKeys(kw)) + return Item(client,**useAsciiKeys(kw)) def __getattr__(self,k): if self.kw.has_key(k): @@ -136,7 +136,7 @@ def keys(self): def next(self): try: - PItem(self.transport,**self.get('next')) + Item(self.transport,**self.get('next')) except: raise StopIteration @@ -148,11 +148,14 @@ def useAsciiKeys(d): if __name__ == '__main__': - from mydata import client_data + from mydata import config from pypodio2 import api + client_data = [config[k] for k in 'client_id client_secret username password'.split()] c = api.OAuthClient(*client_data) - app = PApplication.fromPodio(c,) + app = Application.fromPodio(c, config['app_id']) for i in app.items: print i.title, i.get_field('date') i.add_comment("No comment") + for c in i.comments: + print "Comment:", c From faf8500aa92082f4e29e1cf35b98d9991c668f44 Mon Sep 17 00:00:00 2001 From: Jordi Saludes Date: Mon, 18 Jul 2011 11:26:39 +0200 Subject: [PATCH 3/6] Changed module name to 'Objects' --- .gitignore | 1 + PObjects.py => Objects.py | 15 +-------------- 2 files changed, 2 insertions(+), 14 deletions(-) rename PObjects.py => Objects.py (92%) diff --git a/.gitignore b/.gitignore index 0d20b64..95e1a9c 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ *.pyc +mydata* \ No newline at end of file diff --git a/PObjects.py b/Objects.py similarity index 92% rename from PObjects.py rename to Objects.py index 70190d0..be20661 100644 --- a/PObjects.py +++ b/Objects.py @@ -11,17 +11,6 @@ def __repr__(self): @property def id(self): return self.kw[self.ptype + '_id'] - - #def get(self): - # url = '/%s/%r' %(self.ptype,self.id) - # return self.client.transport.GET(url=url) - - #def post(self,extra): - # self.client.transport.POST( - # url='/%s/%r/%s' % (self.ptype, - # self.id, - # extra)) - def add_comment(self, text): """ @@ -76,8 +65,7 @@ def add_to(klass,pobj,text): class Space(Object): ptype = 'space' - - + class Notification(Object): ptype = 'notification' @@ -124,7 +112,6 @@ def __getitem__(self,k): else: raise KeyError - def get_field(self,k): for f in self.kw['fields']: if k == f['external_id']: return f['values'] From fcf2f28bdcda9eaa77f16a0bdb4347b7c6e7901b Mon Sep 17 00:00:00 2001 From: Jordi Saludes Date: Mon, 18 Jul 2011 13:31:18 +0200 Subject: [PATCH 4/6] Added 'add_item' to Application --- Objects.py | 63 +++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 46 insertions(+), 17 deletions(-) diff --git a/Objects.py b/Objects.py index be20661..9b90522 100644 --- a/Objects.py +++ b/Objects.py @@ -72,22 +72,7 @@ class Notification(Object): star = lambda s: s.post('star') -class Application(Object): - ptype ='app' - - activate = lambda s: s.post('activate') - deactivate = lambda s: s.post('deactivate') - - @classmethod - def fromPodio(klass,client,app_id): - app = client.Application.find(app_id) - return Application(client, **useAsciiKeys(app)) - - @property - def items(self): - items = self.client.Application.get_items(self.id)['items'] - return [Item.fromPodio(self.client,i) for i in items] - + class Item(Object): ptype = 'item' @@ -95,8 +80,18 @@ class Item(Object): def __iter__(self): return self + def check(self): + """ + Is it conformant? + """ + if self.kw.has_key('fields'): + return bool(self.kw['fields']) + else: + return False + @classmethod - def fromPodio(klass,client,kw): + def fromPodio(klass,client,item_id): + kw = client.Item.find(item_id) return Item(client,**useAsciiKeys(kw)) def __getattr__(self,k): @@ -127,11 +122,43 @@ def next(self): except: raise StopIteration + +class Application(Object): + ptype ='app' + itemclass = Item + + activate = lambda s: s.post('activate') + deactivate = lambda s: s.post('deactivate') + + @classmethod + def fromPodio(klass,client,app_id): + app = client.Application.find(app_id) + return Application(client, **useAsciiKeys(app)) + + @property + def items(self): + items = self.client.Application.get_items(self.id)['items'] + return [Item.fromPodio(self.client,i['item_id']) for i in items] + + + def add_item(self,**fields): + pfields = {'fields': [simpleField(k,v) for k,v in fields.items()]} + item = self.client.Item.create(self.id, pfields) + #nitem = super(Item, self.itemclass).__new__(self.itemclass, self.client,item) + #return Item(self.client,**item['fields']) + return item + # Utils def useAsciiKeys(d): return dict([(str(k),v) for k,v in d.items()]) + +def simpleField(k,v): + """ + Just 1 value (v) for key k + """ + return {"external_id":k, "values":[{"value":v}]} if __name__ == '__main__': @@ -146,3 +173,5 @@ def useAsciiKeys(d): i.add_comment("No comment") for c in i.comments: print "Comment:", c + + From 93a87fbb6e91324112d0755ba5911ed0b4384538 Mon Sep 17 00:00:00 2001 From: Jordi Saludes Date: Mon, 18 Jul 2011 14:48:16 +0200 Subject: [PATCH 5/6] Added User class --- Objects.py | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/Objects.py b/Objects.py index 9b90522..8fe07df 100644 --- a/Objects.py +++ b/Objects.py @@ -41,6 +41,21 @@ def destroy(self): self.client.transport.DELETE( url='/%s/%r'%(self.ptype,self.id)) +class User(Object): + ptype = 'user' + + @classmethod + def current(klass,client): + profile = client.transport.GET(url='/%s/profile/' % klass.ptype) + return User(client,**useAsciiKeys(profile)) + + def __getattr__(self,k): + if self.kw.has_key(k): + return self.kw[k] + else: + raise AttributeError, "Not found in Podio dict: %s" % k + + class Comment(Object): ptype = 'comment' @@ -165,13 +180,15 @@ def simpleField(k,v): from mydata import config from pypodio2 import api client_data = [config[k] for k in 'client_id client_secret username password'.split()] - c = api.OAuthClient(*client_data) + client = api.OAuthClient(*client_data) - app = Application.fromPodio(c, config['app_id']) + app = Application.fromPodio(client, config['app_id']) for i in app.items: print i.title, i.get_field('date') i.add_comment("No comment") - for c in i.comments: - print "Comment:", c + for cm in i.comments: + print "Comment:", cm + import pdb + user = User.current(client) From 3005b18405e2d2626d590ab05d293c0f6b4d905d Mon Sep 17 00:00:00 2001 From: Jordi Saludes Date: Mon, 25 Jul 2011 13:02:22 +0200 Subject: [PATCH 6/6] Using itemclass Applications use now 'itemclass' to instantiate their items --- Objects.py | 38 ++++++++++++++++++++++++++++---------- stditems.py | 22 ++++++++++++++++++++++ 2 files changed, 50 insertions(+), 10 deletions(-) create mode 100644 stditems.py diff --git a/Objects.py b/Objects.py index 8fe07df..5cdf7cf 100644 --- a/Objects.py +++ b/Objects.py @@ -1,3 +1,4 @@ +import json class Object(object): def __init__(self,client,**kw): self.client = client @@ -27,10 +28,19 @@ def comments(self): cs = self.client.transport.GET( url='/comment/%s/%r/' % (self.ptype, self.id)) return [Comment(self.client,**useAsciiKeys(c)) for c in cs] + + def add_tags(self,*texts): + """ + Add tags to the object + """ + attrs = json.dumps([s.encode('utf8') for s in texts]) + self.client.transport.POST( + url='/tag/%s/%r/' % (self.ptype,self.id), + body=attrs, + type='application/json') def create(self,**kw): - import json attrs = json.dumps(kw) return self.client.transport.POST( url = '/%s/'%self.ptype, @@ -44,6 +54,9 @@ def destroy(self): class User(Object): ptype = 'user' + def __str__(self): + return self.kw['name'] + @classmethod def current(klass,client): profile = client.transport.GET(url='/%s/profile/' % klass.ptype) @@ -68,7 +81,6 @@ def __str__(self): @classmethod def add_to(klass,pobj,text): - import json tp = pobj.ptype attrs = dict(value=text) response = pobj.client.transport.POST( @@ -107,7 +119,7 @@ def check(self): @classmethod def fromPodio(klass,client,item_id): kw = client.Item.find(item_id) - return Item(client,**useAsciiKeys(kw)) + return klass(client,**useAsciiKeys(kw)) def __getattr__(self,k): if self.kw.has_key(k): @@ -127,6 +139,9 @@ def get_field(self,k): if k == f['external_id']: return f['values'] return None + def set_field(self,k,v): + self.kw['fields'][k] = [aValue(v)] + @property def keys(self): return [f['external_id'] for f in self.kw['fields']] @@ -148,20 +163,20 @@ class Application(Object): @classmethod def fromPodio(klass,client,app_id): app = client.Application.find(app_id) - return Application(client, **useAsciiKeys(app)) + return klass(client, **useAsciiKeys(app)) @property def items(self): items = self.client.Application.get_items(self.id)['items'] - return [Item.fromPodio(self.client,i['item_id']) for i in items] + return [self.itemclass.fromPodio(self.client,i['item_id']) for i in items] def add_item(self,**fields): pfields = {'fields': [simpleField(k,v) for k,v in fields.items()]} - item = self.client.Item.create(self.id, pfields) + fields = self.client.Item.create(self.id, pfields) #nitem = super(Item, self.itemclass).__new__(self.itemclass, self.client,item) #return Item(self.client,**item['fields']) - return item + return Item(self.client,**useAsciiKeys(fields)) # Utils @@ -169,15 +184,18 @@ def add_item(self,**fields): def useAsciiKeys(d): return dict([(str(k),v) for k,v in d.items()]) +def aValue(v): + return {'value': v} + def simpleField(k,v): """ Just 1 value (v) for key k """ - return {"external_id":k, "values":[{"value":v}]} + return {"external_id":k, "values":[aValue(v)]} if __name__ == '__main__': - from mydata import config + from mydata import config from pypodio2 import api client_data = [config[k] for k in 'client_id client_secret username password'.split()] client = api.OAuthClient(*client_data) @@ -185,7 +203,7 @@ def simpleField(k,v): app = Application.fromPodio(client, config['app_id']) for i in app.items: print i.title, i.get_field('date') - i.add_comment("No comment") + #i.add_comment("No comment") for cm in i.comments: print "Comment:", cm import pdb diff --git a/stditems.py b/stditems.py new file mode 100644 index 0000000..2aab88f --- /dev/null +++ b/stditems.py @@ -0,0 +1,22 @@ +import objects +from objects import useAsciiKeys + +class Timesheet(objects.Item): + @property + def deliverable(self): + field = self['deliverable-worked-on'] + assert len(field) == 1 + return Deliverable(self.client,**useAsciiKeys(field[0]['value'])) + + @property + def employee(self): + field = self['employee'] + assert len(field) == 1 + return objects.User(self.client,**useAsciiKeys(field[0]['value'])) + + +class Deliverable(objects.Item): + pass + +class Timesheets(objects.Application): + itemclass = Timesheet