comparison env/lib/python3.9/site-packages/boto/sdb/db/sequence.py @ 0:4f3585e2f14b draft default tip

"planemo upload commit 60cee0fc7c0cda8592644e1aad72851dec82c959"
author shellac
date Mon, 22 Mar 2021 18:12:50 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:4f3585e2f14b
1 # Copyright (c) 2010 Chris Moyer http://coredumped.org/
2 #
3 # Permission is hereby granted, free of charge, to any person obtaining a
4 # copy of this software and associated documentation files (the
5 # "Software"), to deal in the Software without restriction, including
6 # without limitation the rights to use, copy, modify, merge, publish, dis-
7 # tribute, sublicense, and/or sell copies of the Software, and to permit
8 # persons to whom the Software is furnished to do so, subject to the fol-
9 # lowing conditions:
10 #
11 # The above copyright notice and this permission notice shall be included
12 # in all copies or substantial portions of the Software.
13 #
14 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
16 # ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
17 # SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18 # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20 # IN THE SOFTWARE.
21
22 from boto.exception import SDBResponseError
23 from boto.compat import six
24
25 class SequenceGenerator(object):
26 """Generic Sequence Generator object, this takes a single
27 string as the "sequence" and uses that to figure out
28 what the next value in a string is. For example
29 if you give "ABC" and pass in "A" it will give you "B",
30 and if you give it "C" it will give you "AA".
31
32 If you set "rollover" to True in the above example, passing
33 in "C" would give you "A" again.
34
35 The Sequence string can be a string or any iterable
36 that has the "index" function and is indexable.
37 """
38 __name__ = "SequenceGenerator"
39
40 def __init__(self, sequence_string, rollover=False):
41 """Create a new SequenceGenerator using the sequence_string
42 as how to generate the next item.
43
44 :param sequence_string: The string or list that explains
45 how to generate the next item in the sequence
46 :type sequence_string: str,iterable
47
48 :param rollover: Rollover instead of incrementing when
49 we hit the end of the sequence
50 :type rollover: bool
51 """
52 self.sequence_string = sequence_string
53 self.sequence_length = len(sequence_string[0])
54 self.rollover = rollover
55 self.last_item = sequence_string[-1]
56 self.__name__ = "%s('%s')" % (self.__class__.__name__, sequence_string)
57
58 def __call__(self, val, last=None):
59 """Get the next value in the sequence"""
60 # If they pass us in a string that's not at least
61 # the lenght of our sequence, then return the
62 # first element in our sequence
63 if val is None or len(val) < self.sequence_length:
64 return self.sequence_string[0]
65 last_value = val[-self.sequence_length:]
66 if (not self.rollover) and (last_value == self.last_item):
67 val = "%s%s" % (self(val[:-self.sequence_length]), self._inc(last_value))
68 else:
69 val = "%s%s" % (val[:-self.sequence_length], self._inc(last_value))
70 return val
71
72 def _inc(self, val):
73 """Increment a single value"""
74 assert(len(val) == self.sequence_length)
75 return self.sequence_string[(self.sequence_string.index(val) + 1) % len(self.sequence_string)]
76
77
78 #
79 # Simple Sequence Functions
80 #
81 def increment_by_one(cv=None, lv=None):
82 if cv is None:
83 return 0
84 return cv + 1
85
86 def double(cv=None, lv=None):
87 if cv is None:
88 return 1
89 return cv * 2
90
91 def fib(cv=1, lv=0):
92 """The fibonacci sequence, this incrementer uses the
93 last value"""
94 if cv is None:
95 cv = 1
96 if lv is None:
97 lv = 0
98 return cv + lv
99
100 increment_string = SequenceGenerator("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
101
102
103 class Sequence(object):
104 """A simple Sequence using the new SDB "Consistent" features
105 Based largly off of the "Counter" example from mitch garnaat:
106 http://bitbucket.org/mitch/stupidbototricks/src/tip/counter.py"""
107
108 def __init__(self, id=None, domain_name=None, fnc=increment_by_one, init_val=None):
109 """Create a new Sequence, using an optional function to
110 increment to the next number, by default we just increment by one.
111 Every parameter here is optional, if you don't specify any options
112 then you'll get a new SequenceGenerator with a random ID stored in the
113 default domain that increments by one and uses the default botoweb
114 environment
115
116 :param id: Optional ID (name) for this counter
117 :type id: str
118
119 :param domain_name: Optional domain name to use, by default we get this out of the
120 environment configuration
121 :type domain_name:str
122
123 :param fnc: Optional function to use for the incrementation, by default we just increment by one
124 There are several functions defined in this module.
125 Your function must accept "None" to get the initial value
126 :type fnc: function, str
127
128 :param init_val: Initial value, by default this is the first element in your sequence,
129 but you can pass in any value, even a string if you pass in a function that uses
130 strings instead of ints to increment
131 """
132 self._db = None
133 self._value = None
134 self.last_value = None
135 self.domain_name = domain_name
136 self.id = id
137 if init_val is None:
138 init_val = fnc(init_val)
139
140 if self.id is None:
141 import uuid
142 self.id = str(uuid.uuid4())
143
144 self.item_type = type(fnc(None))
145 self.timestamp = None
146 # Allow us to pass in a full name to a function
147 if isinstance(fnc, six.string_types):
148 from boto.utils import find_class
149 fnc = find_class(fnc)
150 self.fnc = fnc
151
152 # Bootstrap the value last
153 if not self.val:
154 self.val = init_val
155
156 def set(self, val):
157 """Set the value"""
158 import time
159 now = time.time()
160 expected_value = []
161 new_val = {}
162 new_val['timestamp'] = now
163 if self._value is not None:
164 new_val['last_value'] = self._value
165 expected_value = ['current_value', str(self._value)]
166 new_val['current_value'] = val
167 try:
168 self.db.put_attributes(self.id, new_val, expected_value=expected_value)
169 self.timestamp = new_val['timestamp']
170 except SDBResponseError as e:
171 if e.status == 409:
172 raise ValueError("Sequence out of sync")
173 else:
174 raise
175
176
177 def get(self):
178 """Get the value"""
179 val = self.db.get_attributes(self.id, consistent_read=True)
180 if val:
181 if 'timestamp' in val:
182 self.timestamp = val['timestamp']
183 if 'current_value' in val:
184 self._value = self.item_type(val['current_value'])
185 if "last_value" in val and val['last_value'] is not None:
186 self.last_value = self.item_type(val['last_value'])
187 return self._value
188
189 val = property(get, set)
190
191 def __repr__(self):
192 return "%s('%s', '%s', '%s.%s', '%s')" % (
193 self.__class__.__name__,
194 self.id,
195 self.domain_name,
196 self.fnc.__module__, self.fnc.__name__,
197 self.val)
198
199
200 def _connect(self):
201 """Connect to our domain"""
202 if not self._db:
203 import boto
204 sdb = boto.connect_sdb()
205 if not self.domain_name:
206 self.domain_name = boto.config.get("DB", "sequence_db", boto.config.get("DB", "db_name", "default"))
207 try:
208 self._db = sdb.get_domain(self.domain_name)
209 except SDBResponseError as e:
210 if e.status == 400:
211 self._db = sdb.create_domain(self.domain_name)
212 else:
213 raise
214 return self._db
215
216 db = property(_connect)
217
218 def next(self):
219 self.val = self.fnc(self.val, self.last_value)
220 return self.val
221
222 def delete(self):
223 """Remove this sequence"""
224 self.db.delete_attributes(self.id)