github
Advanced Search
  • Home
  • Pricing and Signup
  • Explore GitHub
  • Blog
  • Login

tav / plexnet

  • Admin
  • Watch Unwatch
  • Fork
  • Your Fork
  • Pull Request
  • Download Source
    • 20
    • 2
  • Source
  • Commits
  • Network (2)
  • Downloads (101)
  • Graphs
  • Branch: master

click here to add a description

click here to add a homepage

  • Branches (1)
    • master ✓
  • Tags (0)
Sending Request…
Enable Donations

Pledgie Donations

Once activated, we'll place the following badge in your repository's detail box:
Pledgie_example
This service is courtesy of Pledgie.

An Open Web Platform — Read more

  cancel

http://www.plexnet.org

  cancel
  • Private
  • Read-Only
  • HTTP Read-Only

This URL has Read+Write access

Updating Git intro article on oierw's recommendation. 
tav (author)
Sat Jan 23 12:02:27 -0800 2010
commit  a6eddd18a2b26afcfe1ddcedaf95ffcebca4b706
tree    e5f1c89bf950808df2f389a455ada2297902314c
parent  0a60c5cbe66e0459b02e7d87528e9fcbca08e073
plexnet / source / plexnet / core / data.py source/plexnet/core/data.py
100644 304 lines (241 sloc) 8.598 kb
edit raw blame history
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
#!/usr/bin/env python
"""
data.py - Object Datatype
Author: Sean B. Palmer, inamidst.com
 
This module defines an Object class whose attributes can be set to
dynamic values which get calculated when accessed or assigned. You
can assign static attributes just by setting them:
 
>>> task1 = Object()
>>> task1.name = 'task1'
>>> task1.start = 1
>>> task1.length = 2
 
To add a dynamic attribute, you have to create getter and setter
functions, which will be called when the attribute is accessed or
assigned respectively, and then wrap them up in a Dynamic object to
be assigned to an object attribute:
 
>>> end = Dynamic()
>>> end.getter = Sum(local.start, local.length)
>>> end.setter = { local.start: Difference(local.end, local.length) }
>>> task1.end = end
>>> task1
Object{name: 'task1', start: 1, length: 2, end: 3}
 
Here we've made it so that the end attribute computes the value of
start and length added together. When we change start, end is
automatically updated:
 
>>> task1.start = 2
>>> task1
Object{name: 'task1', start: 2, length: 2, end: 4}
 
You can also derive a new object from an old object, making a kind of
copy of the object. This will automatically copy over any old values,
but if you want to refer to a value on the old object you can use an
Attribute to do so:
 
>>> task2 = task1()
>>> task2.name = 'task2'
>>> task2.start = Attribute(task1, 'end')
>>> task2
Object{name: 'task2', start: 4, length: 2, end: 6}
 
So that, putting this all together, the fields are interdependent in
interesting ways:
 
>>> task2.end = 5
>>> task2
Object{name: 'task2', start: 3, length: 2, end: 5}
>>> task1
Object{name: 'task1', start: 1, length: 2, end: 3}
>>> task2.length = 3
>>> task2.end
6
 
Although seemingly non-sensical, the fact that you set a value does
not require it to be the value actually set
 
>>> task3 = Object()
>>> task3.name = 'task3'
>>> task3.task1 = Attribute(task1, 'end')
>>> task3.task2 = Attribute(task2, 'end')
>>> total = Dynamic()
>>> total.getter = Sum(local.task1, local.task2)
>>> total.setter = { local.task1: Difference(local.total, local.task2) }
>>> task3.total = total
>>> task3
Object{name: 'task3', task1: 3, task2: 6, total: 9}
>>> task3.total = 10
>>> task3
Object{name: 'task3', task1: 4, task2: 7, total: 11}
 
We also will error if we have a dependency chain which loops back onto itself.
 
>>> cycle = Object()
>>> cycle.name = 'cycle'
>>> first = Dynamic()
>>> first.getter = Sum(local.zero, local.second)
>>> first.setter = { local.second: Difference(local.first, local.zero) }
>>> cycle.first = first
>>> second = Dynamic()
>>> second.getter = Sum(local.zero, local.first)
>>> second.setter = { local.first: Difference(local.second, local.zero) }
>>> cycle.second = second
>>> cycle.zero = 0
>>> cycle.first
Traceback (most recent call last):
...
CycleError: Cycle detected: cycle.first
 
>>> cycle.first = 1
Traceback (most recent call last):
...
CycleError: Cycle detected: cycle.first
 
>>> cycle2 = Object()
>>> cycle2.name = 'cycle2'
>>> cycle2.loop = Attribute(cycle2, 'loop')
>>> cycle2.loop
Traceback (most recent call last):
...
CycleError: Cycle detected: cycle2.loop
 
>>> cycle2.loop = 1
Traceback (most recent call last):
...
CycleError: Cycle detected: cycle2.loop
 
"""
 
import fieldtree
 
class Object(object):
   def __init__(self, fields=None):
      self.__fields = fieldtree.FieldTree()
 
   def __repr__(self):
      items = ((attr, getattr(self, attr)) for attr in self.__fields.labels())
      return 'Object{%s}' % ', '.join('%s: %r' % item for item in items)
 
   def __getattr__(self, attr):
      if attr.startswith('_'):
         return object.__getattr__(self, attr)
 
      value, special = self.__fields.get(attr)
      if special is not None:
         value = special.get_value(self, attr)
         self.__fields[attr] = (value, special)
      return value
 
   def __setattr__(self, attr, value):
      if attr.startswith('_'):
         return object.__setattr__(self, attr, value)
 
      current = self.__fields.get(attr, (None, None))[1]
      if isinstance(value, Special):
         self.__fields[attr] = (None, value)
      elif isinstance(current, Special):
         self.__fields[attr] = (value, None)
         current.set_value(self, attr, value)
         self.__fields[attr] = (value, current)
      else: self.__fields[attr] = (value, None)
 
   def __getitem__(self, item):
      return self.__fields[item]
 
   def __setitem__(self, item, value):
      self.__fields[item] = value
 
   def __call__(self):
      import copy
      obj = Object()
      for label, value in self.__fields.fields():
         obj[label] = value
      return obj
 
class Special(object):
   getted = set()
   originals = {}
   unknown = None
 
   def get_value(self, obj, attr):
      myhash = str(hash(obj)) + '.' + str(hash(attr))
 
      first = True if Special.unknown == None else False
      if first:
         Special.unknown = set()
 
      if myhash in Special.unknown:
         #if first: do unrolling, somehow
         raise CycleError("Cycle detected: %s.%s" % (obj.name, attr))
 
      Special.unknown.add(myhash)
 
      value = self._get_value(obj, attr) # do specific operations
 
      Special.unknown.discard(myhash)
      Special.getted.add(myhash)
 
      if first:
         getted = set()
         originals = {}
         unknown = None
 
      return value
 
   def set_value(self, obj, attr, value):
      myhash = str(hash(obj)) + '.' + str(hash(attr))
 
      was = None if myhash not in Special.getted else getattr(obj, attr)
      first = True if Special.unknown == None else False
      if first:
         was = None # we don't have a value if we are starting
         Special.unknown = set()
 
      if myhash in Special.unknown:
         #if first: do unrolling, somehow
         raise CycleError("Cycle detected: %s.%s" % (obj.name, attr))
 
      self._set_value(obj, attr, value)
      value = getattr(obj, attr) # do specific operations
 
      if was != None and was != value:
         #if first: do unrolling, somehow
         raise CycleError("Cycle detected: %s.%s. was: %s, now: %s" %
                 (obj.name, attr, was, value))
 
      if first:
         getted = set()
         originals = {}
         unknown = None
 
class Dynamic(Special):
   def __init__(self):
      self.getter = None
      self.setter = None
 
   def _get_value(self, obj, attr):
      self.getter.objects.append(obj)
      value = self.getter()
      self.getter.objects.pop()
 
      return value
 
   def _set_value(self, obj, attr, value):
      for output, calculate in self.setter.iteritems():
         calculate.objects.append(obj)
         setattr(obj, output, calculate())
         calculate.objects.pop()
 
class Attribute(Special):
   def __init__(self, obj, attr):
      self.obj = obj
      self.attr = attr
 
   def _get_value(self, obj, attr):
      return getattr(self.obj, self.attr)
 
   def _set_value(self, obj, attr, value):
      setattr(self.obj, self.attr, value)
 
class Local(str):
   pass
 
class LocalNamespace(object):
   def __getattr__(self, attr):
      return Local(attr)
local = LocalNamespace()
 
def Computation(original):
   def define(*args):
      def compute():
         def evaluate(arg):
            if isinstance(arg, Local):
               return getattr(compute.objects[-1], arg)
            else: return arg
         return compute.original(*[evaluate(arg) for arg in compute.args])
      compute.original = define.original
      compute.args = args
      compute.objects = []
      return compute
   define.original = original
   return define
 
@Computation
def Sum(a, b):
   return a + b
 
@Computation
def Difference(a, b):
   return a - b
 
class CycleError(Exception):
   "Circular call structure was detected."
 
def test():
   import doctest
   Documentation = type('Documentation', (object,), {'__doc__': __doc__})
   doctest.run_docstring_examples(Documentation, globals(), verbose=True)
 
def summary():
   import sys, StringIO
 
   stdout = sys.stdout
   sys.stdout = StringIO.StringIO()
   test()
   buffer = sys.stdout
   sys.stdout = stdout
   buffer.seek(0)
 
   success, failure = 0, 0
   for line in buffer:
      success += int(line.startswith('ok'))
      failure += int(line.startswith('Fail'))
   print "%s/%s Tests Passed" % (success, success + failure)
 
def main():
   summary()
 
if __name__ == '__main__':
   main()
 
Blog | Support | Training | Contact | API | Status | Twitter | Help | Security
© 2010 GitHub Inc. All rights reserved. | Terms of Service | Privacy Policy
Powered by the Dedicated Servers and
Cloud Computing of Rackspace Hosting®
Dedicated Server