Showing
20 changed files
with
1040 additions
and
823 deletions
1 | -"""SNAKES is the Net Algebra Kit for Editors and Simulators | 1 | +"""SNAKES library is organised into three parts: |
2 | - | 2 | + |
3 | -SNAKES is a Python library allowing to model all sorts of Petri nets | 3 | + * the core library is package `snakes` and its modules, among which |
4 | -and to execute them. It is very general as most Petri nets annotations | 4 | + `snakes.nets` is the one to work with Petri nets while the others |
5 | -can be arbitrary Python expressions while most values can be arbitrary | 5 | + can be seen as auxiliary modules |
6 | -Python objects. | 6 | + * the plugin system and the plugins themselves reside into package |
7 | - | 7 | + `snakes.plugins` |
8 | -SNAKES can be further extended with plugins, several ones being | 8 | + * auxiliary tools are kept into other sub-packages: `snakes.lang` |
9 | -already provided, in particular two plugins implement the Petri nets | 9 | + for all the material related to parsing Python and other |
10 | -compositions defined for the Petri Box Calculus and its successors. | 10 | + languages, `snakes.utils` for various utilities like the ABCD |
11 | + compiler | ||
11 | 12 | ||
12 | @author: Franck Pommereau | 13 | @author: Franck Pommereau |
13 | @organization: University of Evry/Paris-Saclay | 14 | @organization: University of Evry/Paris-Saclay |
14 | @copyright: (C) 2005-2013 Franck Pommereau | 15 | @copyright: (C) 2005-2013 Franck Pommereau |
15 | @license: GNU Lesser General Public Licence (aka. GNU LGPL), see the | 16 | @license: GNU Lesser General Public Licence (aka. GNU LGPL), see the |
16 | - file `doc/COPYING` in the distribution or visit [the GNU web | 17 | + file `doc/COPYING` in the distribution or visit the [GNU web |
17 | site](http://www.gnu.org/licenses/licenses.html#LGPL) | 18 | site](http://www.gnu.org/licenses/licenses.html#LGPL) |
18 | @contact: franck.pommereau@ibisc.univ-evry.fr | 19 | @contact: franck.pommereau@ibisc.univ-evry.fr |
19 | """ | 20 | """ |
... | @@ -21,8 +22,13 @@ compositions defined for the Petri Box Calculus and its successors. | ... | @@ -21,8 +22,13 @@ compositions defined for the Petri Box Calculus and its successors. |
21 | version = "0.9.16" | 22 | version = "0.9.16" |
22 | defaultencoding = "utf-8" | 23 | defaultencoding = "utf-8" |
23 | 24 | ||
25 | +"""## Module `snakes` | ||
26 | + | ||
27 | +This module only provides the exceptions used throughout SNAKES. | ||
28 | +""" | ||
29 | + | ||
24 | class SnakesError (Exception) : | 30 | class SnakesError (Exception) : |
25 | - "An error in SNAKES" | 31 | + "Generic error in SNAKES" |
26 | pass | 32 | pass |
27 | 33 | ||
28 | class ConstraintError (SnakesError) : | 34 | class ConstraintError (SnakesError) : | ... | ... |
1 | -"""Basic data types and functions used in SNAKES | 1 | +"""Basic data types and related functions used in SNAKES |
2 | """ | 2 | """ |
3 | 3 | ||
4 | import operator, inspect | 4 | import operator, inspect |
... | @@ -8,8 +8,9 @@ from snakes.hashables import hdict | ... | @@ -8,8 +8,9 @@ from snakes.hashables import hdict |
8 | from snakes.pnml import Tree | 8 | from snakes.pnml import Tree |
9 | 9 | ||
10 | def cross (sets) : | 10 | def cross (sets) : |
11 | - """Cross-product. | 11 | + """Cross-product of some iterable collections (typically, `list` |
12 | - | 12 | + or `set`). |
13 | + | ||
13 | >>> list(cross([[1, 2], [3, 4, 5]])) | 14 | >>> list(cross([[1, 2], [3, 4, 5]])) |
14 | [(1, 3), (1, 4), (1, 5), (2, 3), (2, 4), (2, 5)] | 15 | [(1, 3), (1, 4), (1, 5), (2, 3), (2, 4), (2, 5)] |
15 | >>> list(cross([[1, 2], [3, 4, 5], [6, 7, 8, 9]])) | 16 | >>> list(cross([[1, 2], [3, 4, 5], [6, 7, 8, 9]])) |
... | @@ -19,12 +20,11 @@ def cross (sets) : | ... | @@ -19,12 +20,11 @@ def cross (sets) : |
19 | (2, 4, 8), (2, 4, 9), (2, 5, 6), (2, 5, 7), (2, 5, 8), (2, 5, 9)] | 20 | (2, 4, 8), (2, 4, 9), (2, 5, 6), (2, 5, 7), (2, 5, 8), (2, 5, 9)] |
20 | >>> list(cross([[], [1]])) | 21 | >>> list(cross([[], [1]])) |
21 | [] | 22 | [] |
22 | - | 23 | + |
23 | @param sets: the sets of values to use | 24 | @param sets: the sets of values to use |
24 | - @type sets: `iterable(iterable(object))` | 25 | + @type sets: `iterable` |
25 | - @return: the `list` of obtained tuples (lists are used to allow | 26 | + @return: an iterator over the tuples in the cross-product |
26 | - unhashable objects) | 27 | + @rtype: `generator` |
27 | - @rtype: `generator(tuple(object))` | ||
28 | """ | 28 | """ |
29 | if len(sets) == 0 : | 29 | if len(sets) == 0 : |
30 | pass | 30 | pass |
... | @@ -38,7 +38,7 @@ def cross (sets) : | ... | @@ -38,7 +38,7 @@ def cross (sets) : |
38 | 38 | ||
39 | def iterate (value) : | 39 | def iterate (value) : |
40 | """Like Python's builtin `iter` but consider strings as atomic. | 40 | """Like Python's builtin `iter` but consider strings as atomic. |
41 | - | 41 | + |
42 | >>> list(iter([1, 2, 3])) | 42 | >>> list(iter([1, 2, 3])) |
43 | [1, 2, 3] | 43 | [1, 2, 3] |
44 | >>> list(iterate([1, 2, 3])) | 44 | >>> list(iterate([1, 2, 3])) |
... | @@ -47,7 +47,7 @@ def iterate (value) : | ... | @@ -47,7 +47,7 @@ def iterate (value) : |
47 | ['f', 'o', 'o'] | 47 | ['f', 'o', 'o'] |
48 | >>> list(iterate('foo')) | 48 | >>> list(iterate('foo')) |
49 | ['foo'] | 49 | ['foo'] |
50 | - | 50 | + |
51 | @param value: any object | 51 | @param value: any object |
52 | @type value: `object` | 52 | @type value: `object` |
53 | @return: an iterator on the elements of `value` if is is iterable | 53 | @return: an iterator on the elements of `value` if is is iterable |
... | @@ -65,10 +65,10 @@ def iterate (value) : | ... | @@ -65,10 +65,10 @@ def iterate (value) : |
65 | class WordSet (set) : | 65 | class WordSet (set) : |
66 | """A set of words being able to generate fresh words. | 66 | """A set of words being able to generate fresh words. |
67 | """ | 67 | """ |
68 | - def fresh (self, add=False, min=1, allowed="abcdefghijklmnopqrstuvwxyz", | 68 | + def fresh (self, add=False, min=1, base="", |
69 | - base="") : | 69 | + allowed="abcdefghijklmnopqrstuvwxyz") : |
70 | """Create a fresh word (ie, which is not in the set). | 70 | """Create a fresh word (ie, which is not in the set). |
71 | - | 71 | + |
72 | >>> w = WordSet(['foo', 'bar']) | 72 | >>> w = WordSet(['foo', 'bar']) |
73 | >>> list(sorted(w)) | 73 | >>> list(sorted(w)) |
74 | ['bar', 'foo'] | 74 | ['bar', 'foo'] |
... | @@ -80,13 +80,15 @@ class WordSet (set) : | ... | @@ -80,13 +80,15 @@ class WordSet (set) : |
80 | 'baa' | 80 | 'baa' |
81 | >>> list(sorted(w)) | 81 | >>> list(sorted(w)) |
82 | ['aaa', 'baa', 'bar', 'foo'] | 82 | ['aaa', 'baa', 'bar', 'foo'] |
83 | - | 83 | + |
84 | @param add: add the created word to the set if `add=True` | 84 | @param add: add the created word to the set if `add=True` |
85 | @type add: `bool` | 85 | @type add: `bool` |
86 | @param min: minimal length of the new word | 86 | @param min: minimal length of the new word |
87 | @type min: `int` | 87 | @type min: `int` |
88 | @param allowed: characters allowed in the new word | 88 | @param allowed: characters allowed in the new word |
89 | @type allowed: `str` | 89 | @type allowed: `str` |
90 | + @param base: prefix of generated words | ||
91 | + @type base: `str` | ||
90 | """ | 92 | """ |
91 | if base : | 93 | if base : |
92 | result = [base] + [allowed[0]] * max(0, min - len(base)) | 94 | result = [base] + [allowed[0]] * max(0, min - len(base)) |
... | @@ -115,31 +117,32 @@ class WordSet (set) : | ... | @@ -115,31 +117,32 @@ class WordSet (set) : |
115 | 117 | ||
116 | class MultiSet (hdict) : | 118 | class MultiSet (hdict) : |
117 | """Set with repetitions, ie, function from values to integers. | 119 | """Set with repetitions, ie, function from values to integers. |
118 | - | 120 | + |
119 | MultiSets support various operations, in particular: addition | 121 | MultiSets support various operations, in particular: addition |
120 | (`+`), substraction (`-`), multiplication by a non negative | 122 | (`+`), substraction (`-`), multiplication by a non negative |
121 | - integer (`*k`), comparisons (`<`, `>`, etc.), length (`len`) | 123 | + integer (`*k`), comparisons (`<`, `>`, etc.), length (`len`). |
122 | """ | 124 | """ |
123 | def __init__ (self, values=[]) : | 125 | def __init__ (self, values=[]) : |
124 | """Initialise the multiset, adding values to it. | 126 | """Initialise the multiset, adding values to it. |
125 | - | 127 | + |
126 | >>> MultiSet([1, 2, 3, 1, 2]) | 128 | >>> MultiSet([1, 2, 3, 1, 2]) |
127 | MultiSet([...]) | 129 | MultiSet([...]) |
128 | >>> MultiSet() | 130 | >>> MultiSet() |
129 | MultiSet([]) | 131 | MultiSet([]) |
130 | - | 132 | + |
131 | - @param values: a single value or an iterable object holding | 133 | + @param values: a single value or an iterable collection of |
132 | values (strings are not iterated) | 134 | values (strings are not iterated) |
133 | - @type values: any atomic object (`str` included) or an | 135 | + @type values: `object` |
134 | - iterable object | ||
135 | """ | 136 | """ |
136 | self.add(values) | 137 | self.add(values) |
137 | def copy (self) : | 138 | def copy (self) : |
138 | """Copy a `MultiSet` | 139 | """Copy a `MultiSet` |
139 | - | 140 | + |
140 | - >>> MultiSet([1, 2, 3, 1, 2]).copy() | 141 | + >>> m1 = MultiSet([1, 2, 3, 1, 2]) |
141 | - MultiSet([...]) | 142 | + >>> m2 = m1.copy() |
142 | - | 143 | + >>> m1 == m2 and m1 is not m2 |
144 | + True | ||
145 | + | ||
143 | @return: a copy of the multiset | 146 | @return: a copy of the multiset |
144 | @rtype: `MultiSet` | 147 | @rtype: `MultiSet` |
145 | """ | 148 | """ |
... | @@ -147,6 +150,7 @@ class MultiSet (hdict) : | ... | @@ -147,6 +150,7 @@ class MultiSet (hdict) : |
147 | result.update(self) | 150 | result.update(self) |
148 | return result | 151 | return result |
149 | __pnmltag__ = "multiset" | 152 | __pnmltag__ = "multiset" |
153 | + # apidoc skip | ||
150 | def __pnmldump__ (self) : | 154 | def __pnmldump__ (self) : |
151 | """ | 155 | """ |
152 | >>> MultiSet([1, 2, 3, 4, 1, 2]).__pnmldump__() | 156 | >>> MultiSet([1, 2, 3, 4, 1, 2]).__pnmldump__() |
... | @@ -202,10 +206,11 @@ class MultiSet (hdict) : | ... | @@ -202,10 +206,11 @@ class MultiSet (hdict) : |
202 | Tree("value", None, Tree.from_obj(value)), | 206 | Tree("value", None, Tree.from_obj(value)), |
203 | Tree("multiplicity", str(self[value])))) | 207 | Tree("multiplicity", str(self[value])))) |
204 | return Tree(self.__pnmltag__, None, *nodes) | 208 | return Tree(self.__pnmltag__, None, *nodes) |
209 | + # apidoc skip | ||
205 | @classmethod | 210 | @classmethod |
206 | def __pnmlload__ (cls, tree) : | 211 | def __pnmlload__ (cls, tree) : |
207 | """Load a multiset from its PNML representation | 212 | """Load a multiset from its PNML representation |
208 | - | 213 | + |
209 | >>> t = MultiSet([1, 2, 3, 4, 1, 2]).__pnmldump__() | 214 | >>> t = MultiSet([1, 2, 3, 4, 1, 2]).__pnmldump__() |
210 | >>> MultiSet.__pnmlload__(t) | 215 | >>> MultiSet.__pnmlload__(t) |
211 | MultiSet([...]) | 216 | MultiSet([...]) |
... | @@ -218,11 +223,12 @@ class MultiSet (hdict) : | ... | @@ -218,11 +223,12 @@ class MultiSet (hdict) : |
218 | return result | 223 | return result |
219 | def _add (self, value, times=1) : | 224 | def _add (self, value, times=1) : |
220 | """Add a single value `times` times. | 225 | """Add a single value `times` times. |
221 | - | 226 | + |
222 | @param value: the value to add | 227 | @param value: the value to add |
223 | - @type value: any object | 228 | + @type value: `object` |
224 | @param times: the number of times that `value` has to be added | 229 | @param times: the number of times that `value` has to be added |
225 | @type times: non negative `int` | 230 | @type times: non negative `int` |
231 | + @raise ValueError: when `times` is negative | ||
226 | """ | 232 | """ |
227 | if times < 0 : | 233 | if times < 0 : |
228 | raise ValueError("negative values are forbidden") | 234 | raise ValueError("negative values are forbidden") |
... | @@ -232,7 +238,7 @@ class MultiSet (hdict) : | ... | @@ -232,7 +238,7 @@ class MultiSet (hdict) : |
232 | self[value] = times | 238 | self[value] = times |
233 | def add (self, values, times=1) : | 239 | def add (self, values, times=1) : |
234 | """Add values to the multiset. | 240 | """Add values to the multiset. |
235 | - | 241 | + |
236 | >>> m = MultiSet() | 242 | >>> m = MultiSet() |
237 | >>> m.add([1, 2, 2, 3], 2) | 243 | >>> m.add([1, 2, 2, 3], 2) |
238 | >>> list(sorted(m.items())) | 244 | >>> list(sorted(m.items())) |
... | @@ -240,24 +246,26 @@ class MultiSet (hdict) : | ... | @@ -240,24 +246,26 @@ class MultiSet (hdict) : |
240 | >>> m.add(5, 3) | 246 | >>> m.add(5, 3) |
241 | >>> list(sorted(m.items())) | 247 | >>> list(sorted(m.items())) |
242 | [1, 1, 2, 2, 2, 2, 3, 3, 5, 5, 5] | 248 | [1, 1, 2, 2, 2, 2, 3, 3, 5, 5, 5] |
243 | - | 249 | + |
244 | @param values: the values to add or a single value to add | 250 | @param values: the values to add or a single value to add |
245 | - @type values: any atomic object (`str` included) or an | 251 | + @type values: `object` |
246 | - iterable object | ||
247 | @param times: the number of times each value should be added | 252 | @param times: the number of times each value should be added |
248 | - @type times: non negative `int` | 253 | + (must be non-negative) |
254 | + @type times: `int` | ||
255 | + @raise ValueError: when `times` is negative | ||
249 | """ | 256 | """ |
250 | self.__mutable__() | 257 | self.__mutable__() |
251 | for value in iterate(values) : | 258 | for value in iterate(values) : |
252 | self._add(value, times) | 259 | self._add(value, times) |
253 | def _remove (self, value, times=1) : | 260 | def _remove (self, value, times=1) : |
254 | """Remove a single value `times` times. | 261 | """Remove a single value `times` times. |
255 | - | 262 | + |
256 | @param value: the value to remove | 263 | @param value: the value to remove |
257 | @type value: any object | 264 | @type value: any object |
258 | @param times: the number of times that `value` has to be | 265 | @param times: the number of times that `value` has to be |
259 | removed | 266 | removed |
260 | @type times: non negative `int` | 267 | @type times: non negative `int` |
268 | + @raise ValueError: when `times` is negative | ||
261 | """ | 269 | """ |
262 | if times < 0 : | 270 | if times < 0 : |
263 | raise ValueError("negative values are forbidden") | 271 | raise ValueError("negative values are forbidden") |
... | @@ -268,9 +276,8 @@ class MultiSet (hdict) : | ... | @@ -268,9 +276,8 @@ class MultiSet (hdict) : |
268 | del self[value] | 276 | del self[value] |
269 | def remove (self, values, times=1) : | 277 | def remove (self, values, times=1) : |
270 | """Remove values to the multiset. | 278 | """Remove values to the multiset. |
271 | - | 279 | + |
272 | - >>> m = MultiSet() | 280 | + >>> m = MultiSet([1, 2, 2, 3] * 2) |
273 | - >>> m.add([1, 2, 2, 3], 2) | ||
274 | >>> list(sorted(m.items())) | 281 | >>> list(sorted(m.items())) |
275 | [1, 1, 2, 2, 2, 2, 3, 3] | 282 | [1, 1, 2, 2, 2, 2, 3, 3] |
276 | >>> m.remove(2, 3) | 283 | >>> m.remove(2, 3) |
... | @@ -279,63 +286,63 @@ class MultiSet (hdict) : | ... | @@ -279,63 +286,63 @@ class MultiSet (hdict) : |
279 | >>> m.remove([1, 3], 2) | 286 | >>> m.remove([1, 3], 2) |
280 | >>> list(sorted(m.items())) | 287 | >>> list(sorted(m.items())) |
281 | [2] | 288 | [2] |
282 | - | 289 | + |
283 | @param values: the values to remove or a single value to | 290 | @param values: the values to remove or a single value to |
284 | remove | 291 | remove |
285 | - @type values: any atomic object (`str` included) or an | 292 | + @type values: `object` |
286 | - iterable object | ||
287 | @param times: the number of times each value should be removed | 293 | @param times: the number of times each value should be removed |
288 | - @type times: non negative `int` | 294 | + (must be non negative) |
295 | + @type times: `int` | ||
296 | + @raise ValueError: when `times` is negative | ||
289 | """ | 297 | """ |
290 | self.__mutable__() | 298 | self.__mutable__() |
291 | for value in iterate(values) : | 299 | for value in iterate(values) : |
292 | self._remove(value, times) | 300 | self._remove(value, times) |
293 | def __call__ (self, value) : | 301 | def __call__ (self, value) : |
294 | """Number of occurrences of `value`. | 302 | """Number of occurrences of `value`. |
295 | - | 303 | + |
296 | >>> m = MultiSet([1, 1, 2, 3, 3, 3]) | 304 | >>> m = MultiSet([1, 1, 2, 3, 3, 3]) |
297 | >>> m(1), m(2), m(3), m(4) | 305 | >>> m(1), m(2), m(3), m(4) |
298 | (2, 1, 3, 0) | 306 | (2, 1, 3, 0) |
299 | - | 307 | + |
300 | @param value: the value the count | 308 | @param value: the value the count |
301 | @type value: `object` | 309 | @type value: `object` |
302 | @rtype: `int` | 310 | @rtype: `int` |
303 | """ | 311 | """ |
304 | return self.get(value, 0) | 312 | return self.get(value, 0) |
305 | def __iter__ (self) : | 313 | def __iter__ (self) : |
306 | - """Iterate over the values (with repetitions). | 314 | + """Iterate over the values, _including repetitions_. Use |
307 | - | 315 | + `MultiSet.keys` to ignore repetitions. |
308 | - Use `MultiSet.keys` to ignore repetitions. | 316 | + |
309 | - | ||
310 | >>> list(sorted(iter(MultiSet([1, 2, 3, 1, 2])))) | 317 | >>> list(sorted(iter(MultiSet([1, 2, 3, 1, 2])))) |
311 | [1, 1, 2, 2, 3] | 318 | [1, 1, 2, 2, 3] |
312 | - | 319 | + |
313 | @return: an iterator on the elements | 320 | @return: an iterator on the elements |
314 | - @rtype: `iterator` | 321 | + @rtype: `generator` |
315 | """ | 322 | """ |
316 | for value in dict.__iter__(self) : | 323 | for value in dict.__iter__(self) : |
317 | for count in range(self[value]) : | 324 | for count in range(self[value]) : |
318 | yield value | 325 | yield value |
319 | def items (self) : | 326 | def items (self) : |
320 | """Return the list of items with repetitions. The list without | 327 | """Return the list of items with repetitions. The list without |
321 | - repetitions can be retrieved with the `key` method. | 328 | + repetitions can be retrieved with `MultiSet.key`. |
322 | - | 329 | + |
323 | >>> m = MultiSet([1, 2, 2, 3]) | 330 | >>> m = MultiSet([1, 2, 2, 3]) |
324 | >>> list(sorted(m.items())) | 331 | >>> list(sorted(m.items())) |
325 | [1, 2, 2, 3] | 332 | [1, 2, 2, 3] |
326 | >>> list(sorted(m.keys())) | 333 | >>> list(sorted(m.keys())) |
327 | [1, 2, 3] | 334 | [1, 2, 3] |
328 | - | 335 | + |
329 | - @return: list of items with repetitions | 336 | + @return: list of items including repetitions |
330 | @rtype: `list` | 337 | @rtype: `list` |
331 | """ | 338 | """ |
332 | return list(iter(self)) | 339 | return list(iter(self)) |
333 | def __str__ (self) : | 340 | def __str__ (self) : |
334 | """Return a simple string representation of the multiset | 341 | """Return a simple string representation of the multiset |
335 | - | 342 | + |
336 | >>> str(MultiSet([1, 2, 2, 3])) | 343 | >>> str(MultiSet([1, 2, 2, 3])) |
337 | '{...}' | 344 | '{...}' |
338 | - | 345 | + |
339 | @return: simple string representation of the multiset | 346 | @return: simple string representation of the multiset |
340 | @rtype: `str` | 347 | @rtype: `str` |
341 | """ | 348 | """ |
... | @@ -343,20 +350,20 @@ class MultiSet (hdict) : | ... | @@ -343,20 +350,20 @@ class MultiSet (hdict) : |
343 | def __repr__ (self) : | 350 | def __repr__ (self) : |
344 | """Return a string representation of the multiset that is | 351 | """Return a string representation of the multiset that is |
345 | suitable for `eval` | 352 | suitable for `eval` |
346 | - | 353 | + |
347 | >>> repr(MultiSet([1, 2, 2, 3])) | 354 | >>> repr(MultiSet([1, 2, 2, 3])) |
348 | 'MultiSet([...])' | 355 | 'MultiSet([...])' |
349 | - | 356 | + |
350 | @return: precise string representation of the multiset | 357 | @return: precise string representation of the multiset |
351 | @rtype: `str` | 358 | @rtype: `str` |
352 | """ | 359 | """ |
353 | return "MultiSet([%s])" % ", ".join(repr(x) for x in self) | 360 | return "MultiSet([%s])" % ", ".join(repr(x) for x in self) |
354 | def __len__ (self) : | 361 | def __len__ (self) : |
355 | - """Return the number of elements, including repetitions. | 362 | + """Return the number of elements, _including repetitions_. |
356 | - | 363 | + |
357 | >>> len(MultiSet([1, 2] * 3)) | 364 | >>> len(MultiSet([1, 2] * 3)) |
358 | 6 | 365 | 6 |
359 | - | 366 | + |
360 | @rtype: `int` | 367 | @rtype: `int` |
361 | """ | 368 | """ |
362 | if self.size() == 0 : | 369 | if self.size() == 0 : |
... | @@ -364,20 +371,20 @@ class MultiSet (hdict) : | ... | @@ -364,20 +371,20 @@ class MultiSet (hdict) : |
364 | else : | 371 | else : |
365 | return reduce(operator.add, self.values()) | 372 | return reduce(operator.add, self.values()) |
366 | def size (self) : | 373 | def size (self) : |
367 | - """Return the number of elements, excluding repetitions. | 374 | + """Return the number of elements, _excluding repetitions_. |
368 | - | 375 | + |
369 | >>> MultiSet([1, 2] * 3).size() | 376 | >>> MultiSet([1, 2] * 3).size() |
370 | 2 | 377 | 2 |
371 | - | 378 | + |
372 | @rtype: `int` | 379 | @rtype: `int` |
373 | """ | 380 | """ |
374 | return dict.__len__(self) | 381 | return dict.__len__(self) |
375 | def __add__ (self, other) : | 382 | def __add__ (self, other) : |
376 | """Adds two multisets. | 383 | """Adds two multisets. |
377 | - | 384 | + |
378 | >>> MultiSet([1, 2, 3]) + MultiSet([2, 3, 4]) | 385 | >>> MultiSet([1, 2, 3]) + MultiSet([2, 3, 4]) |
379 | MultiSet([...]) | 386 | MultiSet([...]) |
380 | - | 387 | + |
381 | @param other: the multiset to add | 388 | @param other: the multiset to add |
382 | @type other: `MultiSet` | 389 | @type other: `MultiSet` |
383 | @rtype: `MultiSet` | 390 | @rtype: `MultiSet` |
... | @@ -387,18 +394,20 @@ class MultiSet (hdict) : | ... | @@ -387,18 +394,20 @@ class MultiSet (hdict) : |
387 | result._add(value, times) | 394 | result._add(value, times) |
388 | return result | 395 | return result |
389 | def __sub__ (self, other) : | 396 | def __sub__ (self, other) : |
390 | - """Substract two multisets. | 397 | + """Substract two multisets. The second multiset must be |
391 | - | 398 | + smaller than the first one. |
399 | + | ||
392 | >>> MultiSet([1, 2, 3]) - MultiSet([2, 3]) | 400 | >>> MultiSet([1, 2, 3]) - MultiSet([2, 3]) |
393 | MultiSet([1]) | 401 | MultiSet([1]) |
394 | >>> MultiSet([1, 2, 3]) - MultiSet([2, 3, 4]) | 402 | >>> MultiSet([1, 2, 3]) - MultiSet([2, 3, 4]) |
395 | Traceback (most recent call last): | 403 | Traceback (most recent call last): |
396 | ... | 404 | ... |
397 | ValueError: not enough occurrences | 405 | ValueError: not enough occurrences |
398 | - | 406 | + |
399 | @param other: the multiset to substract | 407 | @param other: the multiset to substract |
400 | @type other: `MultiSet` | 408 | @type other: `MultiSet` |
401 | @rtype: `MultiSet` | 409 | @rtype: `MultiSet` |
410 | + @raise ValueError: when the second multiset is not smaller | ||
402 | """ | 411 | """ |
403 | result = self.copy() | 412 | result = self.copy() |
404 | for value, times in dict.items(other) : | 413 | for value, times in dict.items(other) : |
... | @@ -406,13 +415,14 @@ class MultiSet (hdict) : | ... | @@ -406,13 +415,14 @@ class MultiSet (hdict) : |
406 | return result | 415 | return result |
407 | def __mul__ (self, other) : | 416 | def __mul__ (self, other) : |
408 | """Multiplication by a non-negative integer. | 417 | """Multiplication by a non-negative integer. |
409 | - | 418 | + |
410 | - >>> MultiSet([1, 2]) * 3 | 419 | + >>> MultiSet([1, 2]) * 3 == MultiSet([1, 2] * 3) |
411 | - MultiSet([...]) | 420 | + True |
412 | - | 421 | + |
413 | @param other: the integer to multiply | 422 | @param other: the integer to multiply |
414 | @type other: non-negative `int` | 423 | @type other: non-negative `int` |
415 | @rtype: `MultiSet` | 424 | @rtype: `MultiSet` |
425 | + @raise ValueError: when `other` is negative | ||
416 | """ | 426 | """ |
417 | if other < 0 : | 427 | if other < 0 : |
418 | raise ValueError("negative values are forbidden") | 428 | raise ValueError("negative values are forbidden") |
... | @@ -426,12 +436,12 @@ class MultiSet (hdict) : | ... | @@ -426,12 +436,12 @@ class MultiSet (hdict) : |
426 | __hash__ = hdict.__hash__ | 436 | __hash__ = hdict.__hash__ |
427 | def __eq__ (self, other) : | 437 | def __eq__ (self, other) : |
428 | """Test for equality. | 438 | """Test for equality. |
429 | - | 439 | + |
430 | >>> MultiSet([1, 2, 3]*2) == MultiSet([1, 2, 3]*2) | 440 | >>> MultiSet([1, 2, 3]*2) == MultiSet([1, 2, 3]*2) |
431 | True | 441 | True |
432 | >>> MultiSet([1, 2, 3]) == MultiSet([1, 2, 3, 3]) | 442 | >>> MultiSet([1, 2, 3]) == MultiSet([1, 2, 3, 3]) |
433 | False | 443 | False |
434 | - | 444 | + |
435 | @param other: the multiset to compare with | 445 | @param other: the multiset to compare with |
436 | @type other: `MultiSet` | 446 | @type other: `MultiSet` |
437 | @rtype: `bool` | 447 | @rtype: `bool` |
... | @@ -448,20 +458,22 @@ class MultiSet (hdict) : | ... | @@ -448,20 +458,22 @@ class MultiSet (hdict) : |
448 | return True | 458 | return True |
449 | def __ne__ (self, other) : | 459 | def __ne__ (self, other) : |
450 | """Test for difference. | 460 | """Test for difference. |
451 | - | 461 | + |
452 | >>> MultiSet([1, 2, 3]*2) != MultiSet([1, 2, 3]*2) | 462 | >>> MultiSet([1, 2, 3]*2) != MultiSet([1, 2, 3]*2) |
453 | False | 463 | False |
454 | >>> MultiSet([1, 2, 3]) != MultiSet([1, 2, 3, 3]) | 464 | >>> MultiSet([1, 2, 3]) != MultiSet([1, 2, 3, 3]) |
455 | True | 465 | True |
456 | - | 466 | + |
457 | @param other: the multiset to compare with | 467 | @param other: the multiset to compare with |
458 | @type other: `MultiSet` | 468 | @type other: `MultiSet` |
459 | @rtype: `bool` | 469 | @rtype: `bool` |
460 | """ | 470 | """ |
461 | return not(self == other) | 471 | return not(self == other) |
462 | def __lt__ (self, other) : | 472 | def __lt__ (self, other) : |
463 | - """Test for strict inclusion. | 473 | + """Test for strict inclusion. A multiset `A` is strictly |
464 | - | 474 | + included in a multiset `B` iff every element in `A` is also in |
475 | + `B` but less repetitions `A` than in `B`. | ||
476 | + | ||
465 | >>> MultiSet([1, 2, 3]) < MultiSet([1, 2, 3, 4]) | 477 | >>> MultiSet([1, 2, 3]) < MultiSet([1, 2, 3, 4]) |
466 | True | 478 | True |
467 | >>> MultiSet([1, 2, 3]) < MultiSet([1, 2, 3, 3]) | 479 | >>> MultiSet([1, 2, 3]) < MultiSet([1, 2, 3, 3]) |
... | @@ -472,7 +484,7 @@ class MultiSet (hdict) : | ... | @@ -472,7 +484,7 @@ class MultiSet (hdict) : |
472 | False | 484 | False |
473 | >>> MultiSet([1, 2, 2]) < MultiSet([1, 2, 3, 4]) | 485 | >>> MultiSet([1, 2, 2]) < MultiSet([1, 2, 3, 4]) |
474 | False | 486 | False |
475 | - | 487 | + |
476 | @param other: the multiset to compare with | 488 | @param other: the multiset to compare with |
477 | @type other: `MultiSet` | 489 | @type other: `MultiSet` |
478 | @rtype: `bool` | 490 | @rtype: `bool` |
... | @@ -488,8 +500,8 @@ class MultiSet (hdict) : | ... | @@ -488,8 +500,8 @@ class MultiSet (hdict) : |
488 | result = True | 500 | result = True |
489 | return result or (dict.__len__(self) < dict.__len__(other)) | 501 | return result or (dict.__len__(self) < dict.__len__(other)) |
490 | def __le__ (self, other) : | 502 | def __le__ (self, other) : |
491 | - """Test for inclusion inclusion. | 503 | + """Test for inclusion. |
492 | - | 504 | + |
493 | >>> MultiSet([1, 2, 3]) <= MultiSet([1, 2, 3, 4]) | 505 | >>> MultiSet([1, 2, 3]) <= MultiSet([1, 2, 3, 4]) |
494 | True | 506 | True |
495 | >>> MultiSet([1, 2, 3]) <= MultiSet([1, 2, 3, 3]) | 507 | >>> MultiSet([1, 2, 3]) <= MultiSet([1, 2, 3, 3]) |
... | @@ -500,7 +512,7 @@ class MultiSet (hdict) : | ... | @@ -500,7 +512,7 @@ class MultiSet (hdict) : |
500 | False | 512 | False |
501 | >>> MultiSet([1, 2, 2]) <= MultiSet([1, 2, 3, 4]) | 513 | >>> MultiSet([1, 2, 2]) <= MultiSet([1, 2, 3, 4]) |
502 | False | 514 | False |
503 | - | 515 | + |
504 | @param other: the multiset to compare with | 516 | @param other: the multiset to compare with |
505 | @type other: `MultiSet` | 517 | @type other: `MultiSet` |
506 | @rtype: `bool` | 518 | @rtype: `bool` |
... | @@ -514,7 +526,7 @@ class MultiSet (hdict) : | ... | @@ -514,7 +526,7 @@ class MultiSet (hdict) : |
514 | return True | 526 | return True |
515 | def __gt__ (self, other) : | 527 | def __gt__ (self, other) : |
516 | """Test for strict inclusion. | 528 | """Test for strict inclusion. |
517 | - | 529 | + |
518 | >>> MultiSet([1, 2, 3, 4]) > MultiSet([1, 2, 3]) | 530 | >>> MultiSet([1, 2, 3, 4]) > MultiSet([1, 2, 3]) |
519 | True | 531 | True |
520 | >>> MultiSet([1, 2, 3, 3]) > MultiSet([1, 2, 3]) | 532 | >>> MultiSet([1, 2, 3, 3]) > MultiSet([1, 2, 3]) |
... | @@ -525,7 +537,7 @@ class MultiSet (hdict) : | ... | @@ -525,7 +537,7 @@ class MultiSet (hdict) : |
525 | False | 537 | False |
526 | >>> MultiSet([1, 2, 3, 4]) > MultiSet([1, 2, 2]) | 538 | >>> MultiSet([1, 2, 3, 4]) > MultiSet([1, 2, 2]) |
527 | False | 539 | False |
528 | - | 540 | + |
529 | @param other: the multiset to compare with | 541 | @param other: the multiset to compare with |
530 | @type other: `MultiSet` | 542 | @type other: `MultiSet` |
531 | @rtype: `bool` | 543 | @rtype: `bool` |
... | @@ -533,7 +545,7 @@ class MultiSet (hdict) : | ... | @@ -533,7 +545,7 @@ class MultiSet (hdict) : |
533 | return other.__lt__(self) | 545 | return other.__lt__(self) |
534 | def __ge__ (self, other) : | 546 | def __ge__ (self, other) : |
535 | """Test for inclusion. | 547 | """Test for inclusion. |
536 | - | 548 | + |
537 | >>> MultiSet([1, 2, 3, 4]) >= MultiSet([1, 2, 3]) | 549 | >>> MultiSet([1, 2, 3, 4]) >= MultiSet([1, 2, 3]) |
538 | True | 550 | True |
539 | >>> MultiSet([1, 2, 3, 3]) >= MultiSet([1, 2, 3]) | 551 | >>> MultiSet([1, 2, 3, 3]) >= MultiSet([1, 2, 3]) |
... | @@ -544,18 +556,19 @@ class MultiSet (hdict) : | ... | @@ -544,18 +556,19 @@ class MultiSet (hdict) : |
544 | False | 556 | False |
545 | >>> MultiSet([1, 2, 3, 4]) >= MultiSet([1, 2, 2]) | 557 | >>> MultiSet([1, 2, 3, 4]) >= MultiSet([1, 2, 2]) |
546 | False | 558 | False |
547 | - | 559 | + |
548 | @param other: the multiset to compare with | 560 | @param other: the multiset to compare with |
549 | @type other: `MultiSet` | 561 | @type other: `MultiSet` |
550 | @rtype: `bool` | 562 | @rtype: `bool` |
551 | """ | 563 | """ |
552 | return other.__le__(self) | 564 | return other.__le__(self) |
553 | def domain (self) : | 565 | def domain (self) : |
554 | - """Return the domain of the multiset | 566 | + """Return the domain of the multiset, that is, the set of |
555 | - | 567 | + elements that occurr at least once in the multiset. |
568 | + | ||
556 | >>> list(sorted((MultiSet([1, 2, 3, 4]) + MultiSet([1, 2, 3])).domain())) | 569 | >>> list(sorted((MultiSet([1, 2, 3, 4]) + MultiSet([1, 2, 3])).domain())) |
557 | [1, 2, 3, 4] | 570 | [1, 2, 3, 4] |
558 | - | 571 | + |
559 | @return: the set of values in the domain | 572 | @return: the set of values in the domain |
560 | @rtype: `set` | 573 | @rtype: `set` |
561 | """ | 574 | """ |
... | @@ -564,21 +577,21 @@ class MultiSet (hdict) : | ... | @@ -564,21 +577,21 @@ class MultiSet (hdict) : |
564 | class Substitution (object) : | 577 | class Substitution (object) : |
565 | """Map names to values or names, equals the identity where not | 578 | """Map names to values or names, equals the identity where not |
566 | defined. | 579 | defined. |
567 | - | 580 | + |
568 | Substitutions support the `+` operation (union with consistency | 581 | Substitutions support the `+` operation (union with consistency |
569 | check between the two operands) and the `*` operation which is the | 582 | check between the two operands) and the `*` operation which is the |
570 | composition of functions (`(f*g)(x)` is `f(g(x))`). | 583 | composition of functions (`(f*g)(x)` is `f(g(x))`). |
571 | - | 584 | + |
572 | Several methods (eg, `image`) return lists instead of sets, this | 585 | Several methods (eg, `image`) return lists instead of sets, this |
573 | avoids the restriction of having only hashable values in a | 586 | avoids the restriction of having only hashable values in a |
574 | substitution image. | 587 | substitution image. |
575 | """ | 588 | """ |
576 | def __init__ (self, *largs, **dargs) : | 589 | def __init__ (self, *largs, **dargs) : |
577 | """Initialise using a dictionnary as a mapping. | 590 | """Initialise using a dictionnary as a mapping. |
578 | - | 591 | + |
579 | The expected arguments are any ones acceptables for | 592 | The expected arguments are any ones acceptables for |
580 | initializing a dictionnary. | 593 | initializing a dictionnary. |
581 | - | 594 | + |
582 | >>> Substitution() | 595 | >>> Substitution() |
583 | Substitution() | 596 | Substitution() |
584 | >>> Substitution(x=1, y=2) | 597 | >>> Substitution(x=1, y=2) |
... | @@ -589,6 +602,7 @@ class Substitution (object) : | ... | @@ -589,6 +602,7 @@ class Substitution (object) : |
589 | Substitution(...) | 602 | Substitution(...) |
590 | """ | 603 | """ |
591 | self._dict = dict(*largs, **dargs) | 604 | self._dict = dict(*largs, **dargs) |
605 | + # apidoc skip | ||
592 | def __hash__ (self) : | 606 | def __hash__ (self) : |
593 | """ | 607 | """ |
594 | >>> hash(Substitution(x=1, y=2)) == hash(Substitution(y=2, x=1)) | 608 | >>> hash(Substitution(x=1, y=2)) == hash(Substitution(y=2, x=1)) |
... | @@ -599,7 +613,8 @@ class Substitution (object) : | ... | @@ -599,7 +613,8 @@ class Substitution (object) : |
599 | (hash(i) for i in self._dict.items()), | 613 | (hash(i) for i in self._dict.items()), |
600 | 153913524) | 614 | 153913524) |
601 | def __eq__ (self, other) : | 615 | def __eq__ (self, other) : |
602 | - """ | 616 | + """Test for equality. |
617 | + | ||
603 | >>> Substitution(x=1, y=2) == Substitution(y=2, x=1) | 618 | >>> Substitution(x=1, y=2) == Substitution(y=2, x=1) |
604 | True | 619 | True |
605 | >>> Substitution(x=1, y=2) == Substitution(y=1, x=1) | 620 | >>> Substitution(x=1, y=2) == Substitution(y=1, x=1) |
... | @@ -610,7 +625,8 @@ class Substitution (object) : | ... | @@ -610,7 +625,8 @@ class Substitution (object) : |
610 | except : | 625 | except : |
611 | return False | 626 | return False |
612 | def __ne__ (self, other) : | 627 | def __ne__ (self, other) : |
613 | - """ | 628 | + """Test for inequality. |
629 | + | ||
614 | >>> Substitution(x=1, y=2) != Substitution(y=2, x=1) | 630 | >>> Substitution(x=1, y=2) != Substitution(y=2, x=1) |
615 | False | 631 | False |
616 | >>> Substitution(x=1, y=2) != Substitution(y=1, x=1) | 632 | >>> Substitution(x=1, y=2) != Substitution(y=1, x=1) |
... | @@ -618,9 +634,10 @@ class Substitution (object) : | ... | @@ -618,9 +634,10 @@ class Substitution (object) : |
618 | """ | 634 | """ |
619 | return not self.__eq__(other) | 635 | return not self.__eq__(other) |
620 | __pnmltag__ = "substitution" | 636 | __pnmltag__ = "substitution" |
637 | + # apidoc skip | ||
621 | def __pnmldump__ (self) : | 638 | def __pnmldump__ (self) : |
622 | """Dumps a substitution to a PNML tree | 639 | """Dumps a substitution to a PNML tree |
623 | - | 640 | + |
624 | >>> Substitution(x=1, y=2).__pnmldump__() | 641 | >>> Substitution(x=1, y=2).__pnmldump__() |
625 | <?xml version="1.0" encoding="utf-8"?> | 642 | <?xml version="1.0" encoding="utf-8"?> |
626 | <pnml> | 643 | <pnml> |
... | @@ -647,7 +664,7 @@ class Substitution (object) : | ... | @@ -647,7 +664,7 @@ class Substitution (object) : |
647 | </item> | 664 | </item> |
648 | </substitution> | 665 | </substitution> |
649 | </pnml> | 666 | </pnml> |
650 | - | 667 | + |
651 | @return: PNML representation | 668 | @return: PNML representation |
652 | @rtype: `snakes.pnml.Tree` | 669 | @rtype: `snakes.pnml.Tree` |
653 | """ | 670 | """ |
... | @@ -658,14 +675,15 @@ class Substitution (object) : | ... | @@ -658,14 +675,15 @@ class Substitution (object) : |
658 | Tree("value", None, | 675 | Tree("value", None, |
659 | Tree.from_obj(value)))) | 676 | Tree.from_obj(value)))) |
660 | return Tree(self.__pnmltag__, None, *nodes) | 677 | return Tree(self.__pnmltag__, None, *nodes) |
678 | + # apidoc skip | ||
661 | @classmethod | 679 | @classmethod |
662 | def __pnmlload__ (cls, tree) : | 680 | def __pnmlload__ (cls, tree) : |
663 | """Load a substitution from its PNML representation | 681 | """Load a substitution from its PNML representation |
664 | - | 682 | + |
665 | >>> t = Substitution(x=1, y=2).__pnmldump__() | 683 | >>> t = Substitution(x=1, y=2).__pnmldump__() |
666 | >>> Substitution.__pnmlload__(t) | 684 | >>> Substitution.__pnmlload__(t) |
667 | Substitution(...) | 685 | Substitution(...) |
668 | - | 686 | + |
669 | @param tree: the PNML tree to load | 687 | @param tree: the PNML tree to load |
670 | @type tree: `snakes.pnml.Tree` | 688 | @type tree: `snakes.pnml.Tree` |
671 | @return: the substitution loaded | 689 | @return: the substitution loaded |
... | @@ -678,43 +696,44 @@ class Substitution (object) : | ... | @@ -678,43 +696,44 @@ class Substitution (object) : |
678 | result._dict[name] = value | 696 | result._dict[name] = value |
679 | return result | 697 | return result |
680 | def items (self) : | 698 | def items (self) : |
681 | - """Return the list of pairs (name, value). | 699 | + """Return the list of pairs `(name, value)` such that the |
682 | - | 700 | + substitution maps each `name` to the correspondign `value`. |
701 | + | ||
683 | >>> Substitution(x=1, y=2).items() | 702 | >>> Substitution(x=1, y=2).items() |
684 | [('...', ...), ('...', ...)] | 703 | [('...', ...), ('...', ...)] |
685 | - | 704 | + |
686 | @return: a list of pairs (name, value) for each mapped name | 705 | @return: a list of pairs (name, value) for each mapped name |
687 | @rtype: `list` | 706 | @rtype: `list` |
688 | """ | 707 | """ |
689 | return list(self._dict.items()) | 708 | return list(self._dict.items()) |
690 | def domain (self) : | 709 | def domain (self) : |
691 | """Return the set of mapped names. | 710 | """Return the set of mapped names. |
692 | - | 711 | + |
693 | >>> list(sorted(Substitution(x=1, y=2).domain())) | 712 | >>> list(sorted(Substitution(x=1, y=2).domain())) |
694 | ['x', 'y'] | 713 | ['x', 'y'] |
695 | - | 714 | + |
696 | @return: the set of mapped names | 715 | @return: the set of mapped names |
697 | @rtype: `set` | 716 | @rtype: `set` |
698 | """ | 717 | """ |
699 | return set(self._dict.keys()) | 718 | return set(self._dict.keys()) |
700 | def image (self) : | 719 | def image (self) : |
701 | - """Return the set of values associated to the names. | 720 | + """Return the list of values associated to the names. |
702 | - | 721 | + |
703 | >>> list(sorted(Substitution(x=1, y=2).image())) | 722 | >>> list(sorted(Substitution(x=1, y=2).image())) |
704 | [1, 2] | 723 | [1, 2] |
705 | - | 724 | + |
706 | - @return: the set of values associated to names | 725 | + @return: the list of values associated to names |
707 | - @rtype: `set` | 726 | + @rtype: `list` |
708 | """ | 727 | """ |
709 | - return set(self._dict.values()) | 728 | + return list(self._dict.values()) |
710 | def __contains__ (self, name) : | 729 | def __contains__ (self, name) : |
711 | - """Test if a name is mapped. | 730 | + """Test if a name is mapped by the substitution. |
712 | - | 731 | + |
713 | >>> 'x' in Substitution(x=1, y=2) | 732 | >>> 'x' in Substitution(x=1, y=2) |
714 | True | 733 | True |
715 | >>> 'z' in Substitution(x=1, y=2) | 734 | >>> 'z' in Substitution(x=1, y=2) |
716 | False | 735 | False |
717 | - | 736 | + |
718 | @param name: the name to test | 737 | @param name: the name to test |
719 | @type name: `str` (usually) | 738 | @type name: `str` (usually) |
720 | @return: a Boolean indicating whether this name is in the | 739 | @return: a Boolean indicating whether this name is in the |
... | @@ -724,20 +743,20 @@ class Substitution (object) : | ... | @@ -724,20 +743,20 @@ class Substitution (object) : |
724 | return name in self._dict | 743 | return name in self._dict |
725 | def __iter__ (self) : | 744 | def __iter__ (self) : |
726 | """Iterate over the mapped names. | 745 | """Iterate over the mapped names. |
727 | - | 746 | + |
728 | >>> list(sorted(iter(Substitution(x=1, y=2)))) | 747 | >>> list(sorted(iter(Substitution(x=1, y=2)))) |
729 | ['x', 'y'] | 748 | ['x', 'y'] |
730 | - | 749 | + |
731 | @return: an iterator over the domain of the substitution | 750 | @return: an iterator over the domain of the substitution |
732 | @rtype: `generator` | 751 | @rtype: `generator` |
733 | """ | 752 | """ |
734 | return iter(self._dict) | 753 | return iter(self._dict) |
735 | def __str__ (self) : | 754 | def __str__ (self) : |
736 | """Return a compact string representation. | 755 | """Return a compact string representation. |
737 | - | 756 | + |
738 | >>> str(Substitution(x=1, y=2)) | 757 | >>> str(Substitution(x=1, y=2)) |
739 | '{... -> ..., ... -> ...}' | 758 | '{... -> ..., ... -> ...}' |
740 | - | 759 | + |
741 | @return: a simple string representation | 760 | @return: a simple string representation |
742 | @rtype: `str` | 761 | @rtype: `str` |
743 | """ | 762 | """ |
... | @@ -745,10 +764,10 @@ class Substitution (object) : | ... | @@ -745,10 +764,10 @@ class Substitution (object) : |
745 | for var, val in self.items()]) | 764 | for var, val in self.items()]) |
746 | def __repr__ (self) : | 765 | def __repr__ (self) : |
747 | """Return a string representation suitable for `eval`. | 766 | """Return a string representation suitable for `eval`. |
748 | - | 767 | + |
749 | >>> repr(Substitution(x=1, y=2)) | 768 | >>> repr(Substitution(x=1, y=2)) |
750 | 'Substitution(...)' | 769 | 'Substitution(...)' |
751 | - | 770 | + |
752 | @return: a precise string representation | 771 | @return: a precise string representation |
753 | @rtype: `str` | 772 | @rtype: `str` |
754 | """ | 773 | """ |
... | @@ -757,33 +776,35 @@ class Substitution (object) : | ... | @@ -757,33 +776,35 @@ class Substitution (object) : |
757 | for var, val in self.items()))) | 776 | for var, val in self.items()))) |
758 | def dict (self) : | 777 | def dict (self) : |
759 | """Return the mapping as a dictionnary. | 778 | """Return the mapping as a dictionnary. |
760 | - | 779 | + |
761 | - >>> Substitution(x=1, y=2).dict() | 780 | + >>> Substitution(x=1, y=2).dict() == {'x': 1, 'y': 2} |
762 | - {'...': ..., '...': ...} | 781 | + True |
763 | - | 782 | + |
764 | @return: a dictionnary that does the same mapping as the | 783 | @return: a dictionnary that does the same mapping as the |
765 | substitution | 784 | substitution |
766 | @rtype: `dict` | 785 | @rtype: `dict` |
767 | """ | 786 | """ |
768 | return self._dict.copy() | 787 | return self._dict.copy() |
769 | def copy (self) : | 788 | def copy (self) : |
770 | - """Copy the mapping. | 789 | + """Return a distinct copy of the mapping. |
771 | - | 790 | + |
772 | - >>> Substitution(x=1, y=2).copy() | 791 | + >>> s1 = Substitution(x=1, y=2) |
773 | - Substitution(...) | 792 | + >>> s2 = s1.copy() |
774 | - | 793 | + >>> s1 == s2 and s1 is not s2 |
794 | + True | ||
795 | + | ||
775 | @return: a copy of the substitution | 796 | @return: a copy of the substitution |
776 | @rtype: `Substitution` | 797 | @rtype: `Substitution` |
777 | """ | 798 | """ |
778 | return Substitution(self.dict()) | 799 | return Substitution(self.dict()) |
779 | def __setitem__ (self, var, value) : | 800 | def __setitem__ (self, var, value) : |
780 | """Assign an entry to the substitution | 801 | """Assign an entry to the substitution |
781 | - | 802 | + |
782 | >>> s = Substitution() | 803 | >>> s = Substitution() |
783 | >>> s['x'] = 42 | 804 | >>> s['x'] = 42 |
784 | >>> s | 805 | >>> s |
785 | Substitution(x=42) | 806 | Substitution(x=42) |
786 | - | 807 | + |
787 | @param var: the name of the variable | 808 | @param var: the name of the variable |
788 | @type var: `str` | 809 | @type var: `str` |
789 | @param value: the value to which `var` is bound | 810 | @param value: the value to which `var` is bound |
... | @@ -792,16 +813,14 @@ class Substitution (object) : | ... | @@ -792,16 +813,14 @@ class Substitution (object) : |
792 | self._dict[var] = value | 813 | self._dict[var] = value |
793 | def __getitem__ (self, var) : | 814 | def __getitem__ (self, var) : |
794 | """Return the mapped value. | 815 | """Return the mapped value. |
795 | - | 816 | + |
796 | - Fails with `DomainError` if `var` is not mapped. | ||
797 | - | ||
798 | >>> s = Substitution(x=1, y=2) | 817 | >>> s = Substitution(x=1, y=2) |
799 | >>> s['x'] | 818 | >>> s['x'] |
800 | 1 | 819 | 1 |
801 | >>> try : s['z'] | 820 | >>> try : s['z'] |
802 | ... except DomainError : print(sys.exc_info()[1]) | 821 | ... except DomainError : print(sys.exc_info()[1]) |
803 | unbound variable 'z' | 822 | unbound variable 'z' |
804 | - | 823 | + |
805 | @param var: the name of the variable | 824 | @param var: the name of the variable |
806 | @type var: `str` (usually) | 825 | @type var: `str` (usually) |
807 | @return: the value that `var` maps to | 826 | @return: the value that `var` maps to |
... | @@ -813,16 +832,15 @@ class Substitution (object) : | ... | @@ -813,16 +832,15 @@ class Substitution (object) : |
813 | except KeyError : | 832 | except KeyError : |
814 | raise DomainError("unbound variable '%s'" % var) | 833 | raise DomainError("unbound variable '%s'" % var) |
815 | def __call__ (self, var) : | 834 | def __call__ (self, var) : |
816 | - """Return the mapped value. | 835 | + """Return the mapped value or `var` itself if it is not |
817 | - | 836 | + mapped. |
818 | - Never fails but return `var` if it is not mapped. | 837 | + |
819 | - | ||
820 | >>> s = Substitution(x=1, y=2) | 838 | >>> s = Substitution(x=1, y=2) |
821 | >>> s('x') | 839 | >>> s('x') |
822 | 1 | 840 | 1 |
823 | >>> s('z') | 841 | >>> s('z') |
824 | 'z' | 842 | 'z' |
825 | - | 843 | + |
826 | @param var: the name of the variable | 844 | @param var: the name of the variable |
827 | @type var: `str` (usually) | 845 | @type var: `str` (usually) |
828 | @return: the value that `var` maps to or `var` itself if it | 846 | @return: the value that `var` maps to or `var` itself if it |
... | @@ -835,22 +853,21 @@ class Substitution (object) : | ... | @@ -835,22 +853,21 @@ class Substitution (object) : |
835 | return var | 853 | return var |
836 | def __add__ (self, other) : | 854 | def __add__ (self, other) : |
837 | """Add two substitution. | 855 | """Add two substitution. |
838 | - | ||
839 | Fails with `DomainError` if the two substitutions map a same | 856 | Fails with `DomainError` if the two substitutions map a same |
840 | name to different values. | 857 | name to different values. |
841 | - | 858 | + |
842 | >>> s = Substitution(x=1, y=2) + Substitution(y=2, z=3) | 859 | >>> s = Substitution(x=1, y=2) + Substitution(y=2, z=3) |
843 | >>> s('x'), s('y'), s('z') | 860 | >>> s('x'), s('y'), s('z') |
844 | (1, 2, 3) | 861 | (1, 2, 3) |
845 | >>> try : Substitution(x=1, y=2) + Substitution(y=4, z=3) | 862 | >>> try : Substitution(x=1, y=2) + Substitution(y=4, z=3) |
846 | ... except DomainError : print(sys.exc_info()[1]) | 863 | ... except DomainError : print(sys.exc_info()[1]) |
847 | conflict on 'y' | 864 | conflict on 'y' |
848 | - | 865 | + |
849 | @param other: another substitution | 866 | @param other: another substitution |
850 | @type other: `Substitution` | 867 | @type other: `Substitution` |
851 | @return: the union of the substitutions | 868 | @return: the union of the substitutions |
852 | @rtype: `Substitution` | 869 | @rtype: `Substitution` |
853 | - @raise DomainError: when one name is mapped to distinct values | 870 | + @raise DomainError: when a name is inconsistently mapped |
854 | """ | 871 | """ |
855 | for var in self : | 872 | for var in self : |
856 | if var in other and (self[var] != other[var]) : | 873 | if var in other and (self[var] != other[var]) : |
... | @@ -860,15 +877,15 @@ class Substitution (object) : | ... | @@ -860,15 +877,15 @@ class Substitution (object) : |
860 | return s | 877 | return s |
861 | def __mul__ (self, other) : | 878 | def __mul__ (self, other) : |
862 | """Compose two substitutions. | 879 | """Compose two substitutions. |
863 | - | 880 | + The composition of `f` and `g` is such that `(f*g)(x)` is |
864 | - The composition of f and g is such that (f*g)(x) = f(g(x)). | 881 | + `f(g(x))`. |
865 | - | 882 | + |
866 | >>> f = Substitution(a=1, d=3, y=5) | 883 | >>> f = Substitution(a=1, d=3, y=5) |
867 | >>> g = Substitution(b='d', c=2, e=4, y=6) | 884 | >>> g = Substitution(b='d', c=2, e=4, y=6) |
868 | >>> h = f*g | 885 | >>> h = f*g |
869 | >>> h('a'), h('b'), h('c'), h('d'), h('e'), h('y'), h('x') | 886 | >>> h('a'), h('b'), h('c'), h('d'), h('e'), h('y'), h('x') |
870 | (1, 3, 2, 3, 4, 6, 'x') | 887 | (1, 3, 2, 3, 4, 6, 'x') |
871 | - | 888 | + |
872 | @param other: another substitution | 889 | @param other: another substitution |
873 | @type other: `Substitution` | 890 | @type other: `Substitution` |
874 | @return: the composition of the substitutions | 891 | @return: the composition of the substitutions |
... | @@ -886,13 +903,14 @@ class Symbol (object) : | ... | @@ -886,13 +903,14 @@ class Symbol (object) : |
886 | """If `export` is `True`, the created symbol is exported under | 903 | """If `export` is `True`, the created symbol is exported under |
887 | its name. If `export` is `False`, no export is made. Finally, | 904 | its name. If `export` is `False`, no export is made. Finally, |
888 | if `export` is a string, it specifies the name of the exported | 905 | if `export` is a string, it specifies the name of the exported |
889 | - symbol. | 906 | + symbol. Exporting the name is made by adding it to the |
890 | - | 907 | + caller's global dict. |
908 | + | ||
891 | @param name: the name (or value of the symbol) | 909 | @param name: the name (or value of the symbol) |
892 | @type name: `str` | 910 | @type name: `str` |
893 | @param export: the name under which the symbol is exported | 911 | @param export: the name under which the symbol is exported |
894 | @type export: `str` or `bool` or `None` | 912 | @type export: `str` or `bool` or `None` |
895 | - | 913 | + |
896 | >>> Symbol('foo') | 914 | >>> Symbol('foo') |
897 | Symbol('foo') | 915 | Symbol('foo') |
898 | >>> foo | 916 | >>> foo |
... | @@ -915,6 +933,7 @@ class Symbol (object) : | ... | @@ -915,6 +933,7 @@ class Symbol (object) : |
915 | if export : | 933 | if export : |
916 | inspect.stack()[1][0].f_globals[export] = self | 934 | inspect.stack()[1][0].f_globals[export] = self |
917 | __pnmltag__ = "symbol" | 935 | __pnmltag__ = "symbol" |
936 | + # apidoc skip | ||
918 | def __pnmldump__ (self) : | 937 | def __pnmldump__ (self) : |
919 | """ | 938 | """ |
920 | >>> Symbol('egg', 'spam').__pnmldump__() | 939 | >>> Symbol('egg', 'spam').__pnmldump__() |
... | @@ -946,6 +965,7 @@ class Symbol (object) : | ... | @@ -946,6 +965,7 @@ class Symbol (object) : |
946 | else : | 965 | else : |
947 | children = [Tree.from_obj(self._export)] | 966 | children = [Tree.from_obj(self._export)] |
948 | return Tree(self.__pnmltag__, None, *children, **dict(name=self.name)) | 967 | return Tree(self.__pnmltag__, None, *children, **dict(name=self.name)) |
968 | + # apidoc skip | ||
949 | @classmethod | 969 | @classmethod |
950 | def __pnmlload__ (cls, tree) : | 970 | def __pnmlload__ (cls, tree) : |
951 | """ | 971 | """ |
... | @@ -963,7 +983,9 @@ class Symbol (object) : | ... | @@ -963,7 +983,9 @@ class Symbol (object) : |
963 | export = name | 983 | export = name |
964 | return cls(name, export) | 984 | return cls(name, export) |
965 | def __eq__ (self, other) : | 985 | def __eq__ (self, other) : |
966 | - """ | 986 | + """Test for equality of two symbols, which is the equality of |
987 | + their names. | ||
988 | + | ||
967 | >>> Symbol('foo', 'bar') == Symbol('foo') | 989 | >>> Symbol('foo', 'bar') == Symbol('foo') |
968 | True | 990 | True |
969 | >>> Symbol('egg') == Symbol('spam') | 991 | >>> Symbol('egg') == Symbol('spam') |
... | @@ -975,13 +997,15 @@ class Symbol (object) : | ... | @@ -975,13 +997,15 @@ class Symbol (object) : |
975 | except AttributeError : | 997 | except AttributeError : |
976 | return False | 998 | return False |
977 | def __ne__ (self, other) : | 999 | def __ne__ (self, other) : |
978 | - """ | 1000 | + """Test for inequality. |
1001 | + | ||
979 | >>> Symbol('foo', 'bar') != Symbol('foo') | 1002 | >>> Symbol('foo', 'bar') != Symbol('foo') |
980 | False | 1003 | False |
981 | >>> Symbol('egg') != Symbol('spam') | 1004 | >>> Symbol('egg') != Symbol('spam') |
982 | True | 1005 | True |
983 | """ | 1006 | """ |
984 | return not (self == other) | 1007 | return not (self == other) |
1008 | + # apidoc skip | ||
985 | def __hash__ (self) : | 1009 | def __hash__ (self) : |
986 | """ | 1010 | """ |
987 | >>> hash(Symbol('foo', 'bar')) == hash(Symbol('foo')) | 1011 | >>> hash(Symbol('foo', 'bar')) == hash(Symbol('foo')) |
... | @@ -989,13 +1013,15 @@ class Symbol (object) : | ... | @@ -989,13 +1013,15 @@ class Symbol (object) : |
989 | """ | 1013 | """ |
990 | return hash((self.__class__.__name__, self.name)) | 1014 | return hash((self.__class__.__name__, self.name)) |
991 | def __str__ (self) : | 1015 | def __str__ (self) : |
992 | - """ | 1016 | + """Short string representation |
1017 | + | ||
993 | >>> str(Symbol('foo')) | 1018 | >>> str(Symbol('foo')) |
994 | 'foo' | 1019 | 'foo' |
995 | """ | 1020 | """ |
996 | return self.name | 1021 | return self.name |
997 | def __repr__ (self) : | 1022 | def __repr__ (self) : |
998 | - """ | 1023 | + """String representation suitable for `eval` |
1024 | + | ||
999 | >>> Symbol('foo') | 1025 | >>> Symbol('foo') |
1000 | Symbol('foo') | 1026 | Symbol('foo') |
1001 | >>> Symbol('egg', 'spam') | 1027 | >>> Symbol('egg', 'spam') | ... | ... |
1 | -"""Hashable mutable objets. | 1 | +"""This module proposes hashable version of the mutable containers |
2 | - | ||
3 | -This module proposes hashable version of the mutable containers | ||
4 | `list`, `dict` and `set`, called respectively `hlist`, `hdict` and | 2 | `list`, `dict` and `set`, called respectively `hlist`, `hdict` and |
5 | -`hset`. After one object has been hashed, it becomes not mutable and | 3 | +`hset`. |
6 | -raises a ValueError if a method which changes the object (let call a | 4 | + |
7 | -_mutation_ such a method) is invoqued. The object can be then un- | 5 | +After one object has been hashed, it becomes not mutable and raises a |
8 | -hashed by calling `unhash` on it so that it becomes mutable again. | 6 | +`ValueError` if a method which changes the object (let call a |
7 | +_mutation_ such a method) is invoqued. The object can be then | ||
8 | +un-hashed by calling `unhash` on it so that it becomes mutable again. | ||
9 | Notice that this may cause troubles if the object is stored in a set | 9 | Notice that this may cause troubles if the object is stored in a set |
10 | or dict which uses its hashcode to locate it. Notice also that | 10 | or dict which uses its hashcode to locate it. Notice also that |
11 | hashable containers cannot be hashed if they contain non hashable | 11 | hashable containers cannot be hashed if they contain non hashable |
... | @@ -53,8 +53,9 @@ from operator import xor | ... | @@ -53,8 +53,9 @@ from operator import xor |
53 | from snakes.compat import * | 53 | from snakes.compat import * |
54 | 54 | ||
55 | def unhash (obj) : | 55 | def unhash (obj) : |
56 | - """Make the object hashable again. | 56 | + """Make the object mutable again. This should be used with |
57 | - | 57 | + caution, especially if the object is stored in a dict or a set. |
58 | + | ||
58 | >>> l = hlist(range(3)) | 59 | >>> l = hlist(range(3)) |
59 | >>> _ = hash(l) | 60 | >>> _ = hash(l) |
60 | >>> l.append(3) | 61 | >>> l.append(3) |
... | @@ -63,7 +64,7 @@ def unhash (obj) : | ... | @@ -63,7 +64,7 @@ def unhash (obj) : |
63 | ValueError: hashed 'hlist' object is not mutable | 64 | ValueError: hashed 'hlist' object is not mutable |
64 | >>> unhash(l) | 65 | >>> unhash(l) |
65 | >>> l.append(3) | 66 | >>> l.append(3) |
66 | - | 67 | + |
67 | @param obj: any object | 68 | @param obj: any object |
68 | @type obj: `object` | 69 | @type obj: `object` |
69 | """ | 70 | """ |
... | @@ -72,6 +73,7 @@ def unhash (obj) : | ... | @@ -72,6 +73,7 @@ def unhash (obj) : |
72 | except : | 73 | except : |
73 | pass | 74 | pass |
74 | 75 | ||
76 | +# apidoc skip | ||
75 | def hashable (cls) : | 77 | def hashable (cls) : |
76 | """Wrap methods in a class in order to make it hashable. | 78 | """Wrap methods in a class in order to make it hashable. |
77 | """ | 79 | """ |
... | @@ -122,8 +124,8 @@ def hashable (cls) : | ... | @@ -122,8 +124,8 @@ def hashable (cls) : |
122 | return cls | 124 | return cls |
123 | 125 | ||
124 | class hlist (list) : | 126 | class hlist (list) : |
125 | - """Hashable lists. | 127 | + """Hashable lists. They support all standard methods from `list`. |
126 | - | 128 | + |
127 | >>> l = hlist(range(5)) | 129 | >>> l = hlist(range(5)) |
128 | >>> l | 130 | >>> l |
129 | hlist([0, 1, 2, 3, 4]) | 131 | hlist([0, 1, 2, 3, 4]) |
... | @@ -138,6 +140,7 @@ class hlist (list) : | ... | @@ -138,6 +140,7 @@ class hlist (list) : |
138 | >>> unhash(l) | 140 | >>> unhash(l) |
139 | >>> l.append(6) | 141 | >>> l.append(6) |
140 | """ | 142 | """ |
143 | + # apidoc stop | ||
141 | def __add__ (self, other) : | 144 | def __add__ (self, other) : |
142 | return self.__class__(list.__add__(self, other)) | 145 | return self.__class__(list.__add__(self, other)) |
143 | def __delitem__ (self, item) : | 146 | def __delitem__ (self, item) : |
... | @@ -200,8 +203,9 @@ class hlist (list) : | ... | @@ -200,8 +203,9 @@ class hlist (list) : |
200 | hlist = hashable(hlist) | 203 | hlist = hashable(hlist) |
201 | 204 | ||
202 | class hdict (dict) : | 205 | class hdict (dict) : |
203 | - """Hashable dictionnaries. | 206 | + """Hashable dictionnaries. They support all standard methods from |
204 | - | 207 | + `dict`. |
208 | + | ||
205 | >>> l = hlist(range(5)) | 209 | >>> l = hlist(range(5)) |
206 | >>> d = hdict([(l, 0)]) | 210 | >>> d = hdict([(l, 0)]) |
207 | >>> d | 211 | >>> d |
... | @@ -229,6 +233,7 @@ class hdict (dict) : | ... | @@ -229,6 +233,7 @@ class hdict (dict) : |
229 | >>> d.pop(l) | 233 | >>> d.pop(l) |
230 | 0 | 234 | 0 |
231 | """ | 235 | """ |
236 | + # apidoc stop | ||
232 | def __delitem__ (self, key) : | 237 | def __delitem__ (self, key) : |
233 | self.__mutable__() | 238 | self.__mutable__() |
234 | dict.__delitem__(self, key) | 239 | dict.__delitem__(self, key) |
... | @@ -271,8 +276,8 @@ class hdict (dict) : | ... | @@ -271,8 +276,8 @@ class hdict (dict) : |
271 | hdict = hashable(hdict) | 276 | hdict = hashable(hdict) |
272 | 277 | ||
273 | class hset (set) : | 278 | class hset (set) : |
274 | - """Hashable sets. | 279 | + """Hashable sets. They support all standard methods from `set`. |
275 | - | 280 | + |
276 | >>> s = hset() | 281 | >>> s = hset() |
277 | >>> l = hlist(range(5)) | 282 | >>> l = hlist(range(5)) |
278 | >>> s.add(l) | 283 | >>> s.add(l) |
... | @@ -298,6 +303,7 @@ class hset (set) : | ... | @@ -298,6 +303,7 @@ class hset (set) : |
298 | >>> unhash(s) | 303 | >>> unhash(s) |
299 | >>> s.discard(l) | 304 | >>> s.discard(l) |
300 | """ | 305 | """ |
306 | + # apidoc stop | ||
301 | def __and__ (self, other) : | 307 | def __and__ (self, other) : |
302 | return self.__class__(set.__and__(self, other)) | 308 | return self.__class__(set.__and__(self, other)) |
303 | def __hash__ (self) : | 309 | def __hash__ (self) : | ... | ... |
1 | +"""This package is dedicated to parse and work with various languages, | ||
2 | +in particular Python itself and ABCD. These are mainly utilities for | ||
3 | +internal use in SNAKES, however, they may be of general interest | ||
4 | +independently of SNAKES. | ||
5 | + | ||
6 | +@todo: add documentation about how to use parsing and similar services | ||
7 | +""" | ||
8 | + | ||
1 | import sys | 9 | import sys |
2 | if sys.version_info[:2] in ((2, 6), (2, 7)) : | 10 | if sys.version_info[:2] in ((2, 6), (2, 7)) : |
3 | import ast | 11 | import ast |
... | @@ -14,9 +22,34 @@ else : | ... | @@ -14,9 +22,34 @@ else : |
14 | 22 | ||
15 | sys.modules["snkast"] = ast | 23 | sys.modules["snkast"] = ast |
16 | 24 | ||
25 | +"""### Module `ast` ### | ||
26 | + | ||
27 | +The module `ast` exported by `snakes.lang` is similar to Python's | ||
28 | +standard `ast` module (starting from version 2.6) but is available and | ||
29 | +uniform on every implementation of Python supported by SNAKES: CPython | ||
30 | +from 2.5, Jython and PyPy. (In general, these modules are available in | ||
31 | +these implementation - except CPython 2.5 - but with slight | ||
32 | +differences, so using `snakes.lang.ast` can be seen as a portable | ||
33 | +implementation.) | ||
34 | + | ||
35 | +Notice that this module is _not_ available for direct import but is | ||
36 | +exposed as a member of `snakes.lang`. Moreover, when `snakes.lang` is | ||
37 | +loaded, this module `ast` is also loaded as `snkast` in `sys.modules`, | ||
38 | +this allows to have both versions from Python and SNAKES | ||
39 | +simultaneously. | ||
40 | + | ||
41 | +>>> import snakes.lang.ast as ast | ||
42 | +ImportError ... | ||
43 | + ... | ||
44 | +ImportError: No module named ast | ||
45 | +>>> from snakes.lang import ast | ||
46 | +>>> import snkast | ||
47 | +""" | ||
48 | + | ||
17 | from . import unparse as _unparse | 49 | from . import unparse as _unparse |
18 | from snakes.compat import * | 50 | from snakes.compat import * |
19 | 51 | ||
52 | +# apidoc skip | ||
20 | class Names (ast.NodeVisitor) : | 53 | class Names (ast.NodeVisitor) : |
21 | def __init__ (self) : | 54 | def __init__ (self) : |
22 | ast.NodeVisitor.__init__(self) | 55 | ast.NodeVisitor.__init__(self) |
... | @@ -25,16 +58,24 @@ class Names (ast.NodeVisitor) : | ... | @@ -25,16 +58,24 @@ class Names (ast.NodeVisitor) : |
25 | self.names.add(node.id) | 58 | self.names.add(node.id) |
26 | 59 | ||
27 | def getvars (expr) : | 60 | def getvars (expr) : |
28 | - """ | 61 | + """Return the set of variables (or names in general) involved in a |
62 | + Python expression. | ||
63 | + | ||
29 | >>> list(sorted(getvars('x+y<z'))) | 64 | >>> list(sorted(getvars('x+y<z'))) |
30 | ['x', 'y', 'z'] | 65 | ['x', 'y', 'z'] |
31 | >>> list(sorted(getvars('x+y<z+f(3,t)'))) | 66 | >>> list(sorted(getvars('x+y<z+f(3,t)'))) |
32 | ['f', 't', 'x', 'y', 'z'] | 67 | ['f', 't', 'x', 'y', 'z'] |
68 | + | ||
69 | + @param expr: a Python expression | ||
70 | + @type expr: `str` | ||
71 | + @return: the set of variable names as strings | ||
72 | + @rtype: `set` | ||
33 | """ | 73 | """ |
34 | names = Names() | 74 | names = Names() |
35 | names.visit(ast.parse(expr)) | 75 | names.visit(ast.parse(expr)) |
36 | return names.names - set(['None', 'True', 'False']) | 76 | return names.names - set(['None', 'True', 'False']) |
37 | 77 | ||
78 | +# apidoc skip | ||
38 | class Unparser(_unparse.Unparser) : | 79 | class Unparser(_unparse.Unparser) : |
39 | boolops = {"And": 'and', "Or": 'or'} | 80 | boolops = {"And": 'and', "Or": 'or'} |
40 | def _Interactive (self, tree) : | 81 | def _Interactive (self, tree) : |
... | @@ -58,11 +99,13 @@ class Unparser(_unparse.Unparser) : | ... | @@ -58,11 +99,13 @@ class Unparser(_unparse.Unparser) : |
58 | self.dispatch(tree.body) | 99 | self.dispatch(tree.body) |
59 | self.leave() | 100 | self.leave() |
60 | 101 | ||
102 | +# apidoc skip | ||
61 | def unparse (st) : | 103 | def unparse (st) : |
62 | output = io.StringIO() | 104 | output = io.StringIO() |
63 | Unparser(st, output) | 105 | Unparser(st, output) |
64 | return output.getvalue().strip() | 106 | return output.getvalue().strip() |
65 | 107 | ||
108 | +# apidoc skip | ||
66 | class Renamer (ast.NodeTransformer) : | 109 | class Renamer (ast.NodeTransformer) : |
67 | def __init__ (self, map_names) : | 110 | def __init__ (self, map_names) : |
68 | ast.NodeTransformer.__init__(self) | 111 | ast.NodeTransformer.__init__(self) |
... | @@ -96,7 +139,8 @@ class Renamer (ast.NodeTransformer) : | ... | @@ -96,7 +139,8 @@ class Renamer (ast.NodeTransformer) : |
96 | ctx=ast.Load()), node) | 139 | ctx=ast.Load()), node) |
97 | 140 | ||
98 | def rename (expr, map={}, **ren) : | 141 | def rename (expr, map={}, **ren) : |
99 | - """ | 142 | + """Rename variables (ie, names) in a Python expression |
143 | + | ||
100 | >>> rename('x+y<z', x='t') | 144 | >>> rename('x+y<z', x='t') |
101 | '((t + y) < z)' | 145 | '((t + y) < z)' |
102 | >>> rename('x+y<z+f(3,t)', f='g', t='z', z='t') | 146 | >>> rename('x+y<z+f(3,t)', f='g', t='z', z='t') |
... | @@ -105,12 +149,22 @@ def rename (expr, map={}, **ren) : | ... | @@ -105,12 +149,22 @@ def rename (expr, map={}, **ren) : |
105 | '[(x + y) for x in range(3)]' | 149 | '[(x + y) for x in range(3)]' |
106 | >>> rename('[x+y for x in range(3)]', y='z') | 150 | >>> rename('[x+y for x in range(3)]', y='z') |
107 | '[(x + z) for x in range(3)]' | 151 | '[(x + z) for x in range(3)]' |
152 | + | ||
153 | + @param expr: a Python expression | ||
154 | + @type expr: `str` | ||
155 | + @param map: a mapping from old to new names (`str` to `str`) | ||
156 | + @type map: `dict` | ||
157 | + @param ren: additional mapping of old to new names | ||
158 | + @type ren: `str` | ||
159 | + @return: the new expression | ||
160 | + @rtype: `str` | ||
108 | """ | 161 | """ |
109 | map_names = dict(map) | 162 | map_names = dict(map) |
110 | map_names.update(ren) | 163 | map_names.update(ren) |
111 | transf = Renamer(map_names) | 164 | transf = Renamer(map_names) |
112 | return unparse(transf.visit(ast.parse(expr))) | 165 | return unparse(transf.visit(ast.parse(expr))) |
113 | 166 | ||
167 | +# apidoc skip | ||
114 | class Binder (Renamer) : | 168 | class Binder (Renamer) : |
115 | def visit_Name (self, node) : | 169 | def visit_Name (self, node) : |
116 | if node.id in self.map[-1] : | 170 | if node.id in self.map[-1] : |
... | @@ -119,7 +173,10 @@ class Binder (Renamer) : | ... | @@ -119,7 +173,10 @@ class Binder (Renamer) : |
119 | return node | 173 | return node |
120 | 174 | ||
121 | def bind (expr, map={}, **ren) : | 175 | def bind (expr, map={}, **ren) : |
122 | - """ | 176 | + """Replace variables (ie, names) in an expression with other |
177 | + expressions. The replacements should be provided as `ast` nodes, | ||
178 | + and so could be arbitrary expression. | ||
179 | + | ||
123 | >>> bind('x+y<z', x=ast.Num(n=2)) | 180 | >>> bind('x+y<z', x=ast.Num(n=2)) |
124 | '((2 + y) < z)' | 181 | '((2 + y) < z)' |
125 | >>> bind('x+y<z', y=ast.Num(n=2)) | 182 | >>> bind('x+y<z', y=ast.Num(n=2)) |
... | @@ -128,6 +185,15 @@ def bind (expr, map={}, **ren) : | ... | @@ -128,6 +185,15 @@ def bind (expr, map={}, **ren) : |
128 | '[(x + y) for x in range(3)]' | 185 | '[(x + y) for x in range(3)]' |
129 | >>> bind('[x+y for x in range(3)]', y=ast.Num(n=2)) | 186 | >>> bind('[x+y for x in range(3)]', y=ast.Num(n=2)) |
130 | '[(x + 2) for x in range(3)]' | 187 | '[(x + 2) for x in range(3)]' |
188 | + | ||
189 | + @param expr: a Python expression | ||
190 | + @type expr: `str` | ||
191 | + @param map: a mapping from old to new names (`str` to `ast.AST`) | ||
192 | + @type map: `dict` | ||
193 | + @param ren: additional mapping of old to new names | ||
194 | + @type ren: `ast.AST` | ||
195 | + @return: the new expression | ||
196 | + @rtype: `str` | ||
131 | """ | 197 | """ |
132 | map_names = dict(map) | 198 | map_names = dict(map) |
133 | map_names.update(ren) | 199 | map_names.update(ren) | ... | ... |
... | @@ -2,6 +2,8 @@ | ... | @@ -2,6 +2,8 @@ |
2 | 2 | ||
3 | This module holds the various Petri net elements: arcs, places, | 3 | This module holds the various Petri net elements: arcs, places, |
4 | transitions, markings, nets themselves and marking graphs. | 4 | transitions, markings, nets themselves and marking graphs. |
5 | + | ||
6 | +@todo: revise documentation | ||
5 | """ | 7 | """ |
6 | 8 | ||
7 | import re, operator, inspect | 9 | import re, operator, inspect |
... | @@ -35,7 +37,7 @@ class Evaluator (object) : | ... | @@ -35,7 +37,7 @@ class Evaluator (object) : |
35 | exec(stmt, self._env, locals) | 37 | exec(stmt, self._env, locals) |
36 | def attach (self, other) : | 38 | def attach (self, other) : |
37 | """Make this instance use the namespaces of another | 39 | """Make this instance use the namespaces of another |
38 | - | 40 | + |
39 | All the instances attached to this will also share the same | 41 | All the instances attached to this will also share the same |
40 | namespace. | 42 | namespace. |
41 | """ | 43 | """ |
... | @@ -88,20 +90,20 @@ class Evaluator (object) : | ... | @@ -88,20 +90,20 @@ class Evaluator (object) : |
88 | 90 | ||
89 | class NetElement (object) : | 91 | class NetElement (object) : |
90 | """The base class for Petri net elements. | 92 | """The base class for Petri net elements. |
91 | - | 93 | + |
92 | Attributes can be locked, forbidding their assignment or deletion. | 94 | Attributes can be locked, forbidding their assignment or deletion. |
93 | For instance, a PetriNet object may lock the 'name' field of its | 95 | For instance, a PetriNet object may lock the 'name' field of its |
94 | nodes in order to force the renaming through the method | 96 | nodes in order to force the renaming through the method |
95 | 'PetriNet.rename'. | 97 | 'PetriNet.rename'. |
96 | - | 98 | + |
97 | FIXME: attribute locking is an unnecessarry complication, this | 99 | FIXME: attribute locking is an unnecessarry complication, this |
98 | will be progressively removed. | 100 | will be progressively removed. |
99 | - | 101 | + |
100 | This class is abstract and should not be instanciated. | 102 | This class is abstract and should not be instanciated. |
101 | """ | 103 | """ |
102 | def __init__ (self) : | 104 | def __init__ (self) : |
103 | """Abstract method | 105 | """Abstract method |
104 | - | 106 | + |
105 | >>> try : NetElement() | 107 | >>> try : NetElement() |
106 | ... except NotImplementedError : print(sys.exc_info()[1]) | 108 | ... except NotImplementedError : print(sys.exc_info()[1]) |
107 | abstract class | 109 | abstract class |
... | @@ -110,7 +112,7 @@ class NetElement (object) : | ... | @@ -110,7 +112,7 @@ class NetElement (object) : |
110 | def lock (self, name, owner, value=None) : | 112 | def lock (self, name, owner, value=None) : |
111 | """Lock the attribute `name` that becomes writeable only by | 113 | """Lock the attribute `name` that becomes writeable only by |
112 | `owner`, set its value if `value` is not `None`. | 114 | `owner`, set its value if `value` is not `None`. |
113 | - | 115 | + |
114 | @param name: the name of the attribute | 116 | @param name: the name of the attribute |
115 | @type name: `str` | 117 | @type name: `str` |
116 | @param owner: any value, usually the object instance that | 118 | @param owner: any value, usually the object instance that |
... | @@ -131,7 +133,7 @@ class NetElement (object) : | ... | @@ -131,7 +133,7 @@ class NetElement (object) : |
131 | def unlock (self, name, owner, remove=False, value=None) : | 133 | def unlock (self, name, owner, remove=False, value=None) : |
132 | """Release a locked attribute, making it assignable or deletable | 134 | """Release a locked attribute, making it assignable or deletable |
133 | from everywhere. | 135 | from everywhere. |
134 | - | 136 | + |
135 | @param name: the name of the attribute | 137 | @param name: the name of the attribute |
136 | @type name: `str` | 138 | @type name: `str` |
137 | @param owner: the value that was used to lock the attribute | 139 | @param owner: the value that was used to lock the attribute |
... | @@ -158,11 +160,11 @@ class NetElement (object) : | ... | @@ -158,11 +160,11 @@ class NetElement (object) : |
158 | # raise ConstraintError, "'%s' not locked" % name | 160 | # raise ConstraintError, "'%s' not locked" % name |
159 | def __setattr__ (self, name, value) : | 161 | def __setattr__ (self, name, value) : |
160 | """Assign attribute, taking care of locks | 162 | """Assign attribute, taking care of locks |
161 | - | 163 | + |
162 | Check whether the assignment is allowed or not, the owner may | 164 | Check whether the assignment is allowed or not, the owner may |
163 | re-assign the attribute by using `lock` with its parameter | 165 | re-assign the attribute by using `lock` with its parameter |
164 | `value` instead of a direct assignment. | 166 | `value` instead of a direct assignment. |
165 | - | 167 | + |
166 | @param name: name of the attribute | 168 | @param name: name of the attribute |
167 | @type name: `str` | 169 | @type name: `str` |
168 | @param value: value of the attribute | 170 | @param value: value of the attribute |
... | @@ -174,11 +176,11 @@ class NetElement (object) : | ... | @@ -174,11 +176,11 @@ class NetElement (object) : |
174 | self.__dict__[name] = value | 176 | self.__dict__[name] = value |
175 | def __delattr__ (self, name) : | 177 | def __delattr__ (self, name) : |
176 | """Delete attribute, taking care of locks | 178 | """Delete attribute, taking care of locks |
177 | - | 179 | + |
178 | Check whether the deletion is allowed or not, the owner may | 180 | Check whether the deletion is allowed or not, the owner may |
179 | delete the attribute by using `unlock` with its parameter | 181 | delete the attribute by using `unlock` with its parameter |
180 | `remove` set to `True` instead of a direct deletion. | 182 | `remove` set to `True` instead of a direct deletion. |
181 | - | 183 | + |
182 | @param name: name of the attribute | 184 | @param name: name of the attribute |
183 | @type name: `str` | 185 | @type name: `str` |
184 | """ | 186 | """ |
... | @@ -193,49 +195,49 @@ class NetElement (object) : | ... | @@ -193,49 +195,49 @@ class NetElement (object) : |
193 | 195 | ||
194 | class Token (NetElement) : | 196 | class Token (NetElement) : |
195 | """A container for one token value | 197 | """A container for one token value |
196 | - | 198 | + |
197 | This class is intended for internal use only in order to avoid | 199 | This class is intended for internal use only in order to avoid |
198 | some confusion when inserting arbitrary values in a place. End | 200 | some confusion when inserting arbitrary values in a place. End |
199 | users will probably never need to use it. | 201 | users will probably never need to use it. |
200 | """ | 202 | """ |
201 | def __init__ (self, value) : | 203 | def __init__ (self, value) : |
202 | """Initialise the token | 204 | """Initialise the token |
203 | - | 205 | + |
204 | >>> Token(42) | 206 | >>> Token(42) |
205 | Token(42) | 207 | Token(42) |
206 | - | 208 | + |
207 | @param value: value of the token | 209 | @param value: value of the token |
208 | @type value: `object` | 210 | @type value: `object` |
209 | """ | 211 | """ |
210 | self.value = value | 212 | self.value = value |
211 | def __str__ (self) : | 213 | def __str__ (self) : |
212 | """Simple string representation (that of the value) | 214 | """Simple string representation (that of the value) |
213 | - | 215 | + |
214 | >>> str(Token(42)) | 216 | >>> str(Token(42)) |
215 | '42' | 217 | '42' |
216 | - | 218 | + |
217 | @return: simple string representation | 219 | @return: simple string representation |
218 | @rtype: `str` | 220 | @rtype: `str` |
219 | """ | 221 | """ |
220 | return str(self.value) | 222 | return str(self.value) |
221 | def __repr__ (self) : | 223 | def __repr__ (self) : |
222 | """String representation suitable for `eval` | 224 | """String representation suitable for `eval` |
223 | - | 225 | + |
224 | >>> repr(Token(42)) | 226 | >>> repr(Token(42)) |
225 | 'Token(42)' | 227 | 'Token(42)' |
226 | - | 228 | + |
227 | @return: precise string representation | 229 | @return: precise string representation |
228 | @rtype: `str` | 230 | @rtype: `str` |
229 | """ | 231 | """ |
230 | return "%s(%s)" % (self.__class__.__name__, repr(self.value)) | 232 | return "%s(%s)" % (self.__class__.__name__, repr(self.value)) |
231 | def __eq__ (self, other) : | 233 | def __eq__ (self, other) : |
232 | """Test token equality | 234 | """Test token equality |
233 | - | 235 | + |
234 | >>> Token(42) == Token(10) | 236 | >>> Token(42) == Token(10) |
235 | False | 237 | False |
236 | >>> Token(42) == Token(42) | 238 | >>> Token(42) == Token(42) |
237 | True | 239 | True |
238 | - | 240 | + |
239 | @param other: second argument of equality | 241 | @param other: second argument of equality |
240 | @type other: `Token` | 242 | @type other: `Token` |
241 | @return: `True` if token values are equal, `False` otherwise | 243 | @return: `True` if token values are equal, `False` otherwise |
... | @@ -247,12 +249,12 @@ class Token (NetElement) : | ... | @@ -247,12 +249,12 @@ class Token (NetElement) : |
247 | return False | 249 | return False |
248 | def __ne__ (self, other) : | 250 | def __ne__ (self, other) : |
249 | """Test token inequality | 251 | """Test token inequality |
250 | - | 252 | + |
251 | >>> Token(42) != Token(10) | 253 | >>> Token(42) != Token(10) |
252 | True | 254 | True |
253 | >>> Token(42) != Token(42) | 255 | >>> Token(42) != Token(42) |
254 | False | 256 | False |
255 | - | 257 | + |
256 | @param other: second argument of inequality | 258 | @param other: second argument of inequality |
257 | @type other: `Token` | 259 | @type other: `Token` |
258 | @return: `True` if token values differ, `False` otherwise | 260 | @return: `True` if token values differ, `False` otherwise |
... | @@ -261,12 +263,12 @@ class Token (NetElement) : | ... | @@ -261,12 +263,12 @@ class Token (NetElement) : |
261 | return not self.__eq__(other) | 263 | return not self.__eq__(other) |
262 | def __hash__ (self) : | 264 | def __hash__ (self) : |
263 | """Hash a token | 265 | """Hash a token |
264 | - | 266 | + |
265 | This is done by hashing the value stored in the token | 267 | This is done by hashing the value stored in the token |
266 | - | 268 | + |
267 | >>> hash(Token(42)) == hash(42) | 269 | >>> hash(Token(42)) == hash(42) |
268 | True | 270 | True |
269 | - | 271 | + |
270 | @return: hash value for the token | 272 | @return: hash value for the token |
271 | @rtype: `int` | 273 | @rtype: `int` |
272 | """ | 274 | """ |
... | @@ -274,39 +276,39 @@ class Token (NetElement) : | ... | @@ -274,39 +276,39 @@ class Token (NetElement) : |
274 | 276 | ||
275 | class BlackToken (Token) : | 277 | class BlackToken (Token) : |
276 | """The usual black token | 278 | """The usual black token |
277 | - | 279 | + |
278 | >>> BlackToken() | 280 | >>> BlackToken() |
279 | dot | 281 | dot |
280 | """ | 282 | """ |
281 | def __init__ (self) : | 283 | def __init__ (self) : |
282 | """Initialise the token | 284 | """Initialise the token |
283 | - | 285 | + |
284 | >>> BlackToken() | 286 | >>> BlackToken() |
285 | dot | 287 | dot |
286 | """ | 288 | """ |
287 | self.value = None | 289 | self.value = None |
288 | def __repr__ (self) : | 290 | def __repr__ (self) : |
289 | """String representation suitable for `eval` | 291 | """String representation suitable for `eval` |
290 | - | 292 | + |
291 | Since `snakes.nets` sets `dot = BlackToken()`, the string | 293 | Since `snakes.nets` sets `dot = BlackToken()`, the string |
292 | representation is `'dot'`. | 294 | representation is `'dot'`. |
293 | - | 295 | + |
294 | >>> repr(BlackToken()) | 296 | >>> repr(BlackToken()) |
295 | 'dot' | 297 | 'dot' |
296 | - | 298 | + |
297 | @return: precise string representation | 299 | @return: precise string representation |
298 | @rtype: `str` | 300 | @rtype: `str` |
299 | """ | 301 | """ |
300 | return "dot" | 302 | return "dot" |
301 | def __str__ (self) : | 303 | def __str__ (self) : |
302 | """Simple string representation (that of the value) | 304 | """Simple string representation (that of the value) |
303 | - | 305 | + |
304 | Since `snakes.nets` sets `dot = BlackToken()`, the string | 306 | Since `snakes.nets` sets `dot = BlackToken()`, the string |
305 | representation is `'dot'`. | 307 | representation is `'dot'`. |
306 | - | 308 | + |
307 | >>> str(BlackToken()) | 309 | >>> str(BlackToken()) |
308 | 'dot' | 310 | 'dot' |
309 | - | 311 | + |
310 | @return: simple string representation | 312 | @return: simple string representation |
311 | @rtype: `str` | 313 | @rtype: `str` |
312 | """ | 314 | """ |
... | @@ -314,7 +316,7 @@ class BlackToken (Token) : | ... | @@ -314,7 +316,7 @@ class BlackToken (Token) : |
314 | __pnmltag__ = "token" | 316 | __pnmltag__ = "token" |
315 | def __pnmldump__ (self) : | 317 | def __pnmldump__ (self) : |
316 | """Dumps value to PNML tree | 318 | """Dumps value to PNML tree |
317 | - | 319 | + |
318 | >>> BlackToken().__pnmldump__() | 320 | >>> BlackToken().__pnmldump__() |
319 | <?xml version="1.0" encoding="utf-8"?> | 321 | <?xml version="1.0" encoding="utf-8"?> |
320 | <pnml> | 322 | <pnml> |
... | @@ -325,7 +327,7 @@ class BlackToken (Token) : | ... | @@ -325,7 +327,7 @@ class BlackToken (Token) : |
325 | @classmethod | 327 | @classmethod |
326 | def __pnmlload__ (cls, tree) : | 328 | def __pnmlload__ (cls, tree) : |
327 | """Load from a PNML tree | 329 | """Load from a PNML tree |
328 | - | 330 | + |
329 | >>> t = BlackToken().__pnmldump__() | 331 | >>> t = BlackToken().__pnmldump__() |
330 | >>> BlackToken.__pnmlload__(t) | 332 | >>> BlackToken.__pnmlload__(t) |
331 | dot | 333 | dot |
... | @@ -341,12 +343,12 @@ tBlackToken = Instance(BlackToken) | ... | @@ -341,12 +343,12 @@ tBlackToken = Instance(BlackToken) |
341 | 343 | ||
342 | class ArcAnnotation (NetElement) : | 344 | class ArcAnnotation (NetElement) : |
343 | """An annotation on an arc. | 345 | """An annotation on an arc. |
344 | - | 346 | + |
345 | On input arcs (from a place to a transition) annotations may be | 347 | On input arcs (from a place to a transition) annotations may be |
346 | values or variables, potentially nested in tuples. On output arcs | 348 | values or variables, potentially nested in tuples. On output arcs |
347 | (from a transition to a place), expressions are allowed, which | 349 | (from a transition to a place), expressions are allowed, which |
348 | corresponds to a computation. | 350 | corresponds to a computation. |
349 | - | 351 | + |
350 | A class attribute `input_allowed` is set to `True` or `False` | 352 | A class attribute `input_allowed` is set to `True` or `False` |
351 | according to whether an annotation is allowed on input arcs. | 353 | according to whether an annotation is allowed on input arcs. |
352 | """ | 354 | """ |
... | @@ -356,7 +358,7 @@ class ArcAnnotation (NetElement) : | ... | @@ -356,7 +358,7 @@ class ArcAnnotation (NetElement) : |
356 | raise NotImplementedError("abstract method") | 358 | raise NotImplementedError("abstract method") |
357 | def substitute (self, binding) : | 359 | def substitute (self, binding) : |
358 | """Substitutes the variables in the annotation. | 360 | """Substitutes the variables in the annotation. |
359 | - | 361 | + |
360 | @param binding: the substitution to apply | 362 | @param binding: the substitution to apply |
361 | @type binding: `snakes.data.Substitution` | 363 | @type binding: `snakes.data.Substitution` |
362 | """ | 364 | """ |
... | @@ -364,11 +366,11 @@ class ArcAnnotation (NetElement) : | ... | @@ -364,11 +366,11 @@ class ArcAnnotation (NetElement) : |
364 | def replace (self, old, new) : | 366 | def replace (self, old, new) : |
365 | """Returns a copy of the annotation in which the `old` annotation | 367 | """Returns a copy of the annotation in which the `old` annotation |
366 | has been replaced by the `new` one. | 368 | has been replaced by the `new` one. |
367 | - | 369 | + |
368 | With non composite annotation, this will return a copy of the | 370 | With non composite annotation, this will return a copy of the |
369 | annotation if it is not the same as `old` otherwise it returns | 371 | annotation if it is not the same as `old` otherwise it returns |
370 | `new`. Composite annotations will replace there components. | 372 | `new`. Composite annotations will replace there components. |
371 | - | 373 | + |
372 | >>> Value(2).replace(Variable('x'), Value(5)) | 374 | >>> Value(2).replace(Variable('x'), Value(5)) |
373 | Value(2) | 375 | Value(2) |
374 | >>> Variable('x').replace(Variable('x'), Value(5)) | 376 | >>> Variable('x').replace(Variable('x'), Value(5)) |
... | @@ -379,7 +381,7 @@ class ArcAnnotation (NetElement) : | ... | @@ -379,7 +381,7 @@ class ArcAnnotation (NetElement) : |
379 | Test(Value(2)) | 381 | Test(Value(2)) |
380 | >>> Test(Variable('x')).replace(Variable('x'), Value(5)) | 382 | >>> Test(Variable('x')).replace(Variable('x'), Value(5)) |
381 | Test(Value(5)) | 383 | Test(Value(5)) |
382 | - | 384 | + |
383 | @param old: the annotation to be replaced | 385 | @param old: the annotation to be replaced |
384 | @type old: `ArcAnnotation` | 386 | @type old: `ArcAnnotation` |
385 | @param new: the annotation to use instead of `old` | 387 | @param new: the annotation to use instead of `old` |
... | @@ -394,21 +396,21 @@ class ArcAnnotation (NetElement) : | ... | @@ -394,21 +396,21 @@ class ArcAnnotation (NetElement) : |
394 | raise NotImplementedError("abstract method") | 396 | raise NotImplementedError("abstract method") |
395 | def __eq__ (self, other) : | 397 | def __eq__ (self, other) : |
396 | """Check for equality. | 398 | """Check for equality. |
397 | - | 399 | + |
398 | @param other: the other object to compare with | 400 | @param other: the other object to compare with |
399 | @type other: `ArcAnnotation` | 401 | @type other: `ArcAnnotation` |
400 | """ | 402 | """ |
401 | raise NotImplementedError("abstract method") | 403 | raise NotImplementedError("abstract method") |
402 | def __hash__ (self) : | 404 | def __hash__ (self) : |
403 | """Computes a hash of the annotation | 405 | """Computes a hash of the annotation |
404 | - | 406 | + |
405 | Warning: must be consistent with equality, ie, two equal | 407 | Warning: must be consistent with equality, ie, two equal |
406 | values must have the same hash. | 408 | values must have the same hash. |
407 | """ | 409 | """ |
408 | raise NotImplementedError("abstract method") | 410 | raise NotImplementedError("abstract method") |
409 | def __ne__ (self, other) : | 411 | def __ne__ (self, other) : |
410 | """Check for difference. | 412 | """Check for difference. |
411 | - | 413 | + |
412 | @param other: the other object to compare with | 414 | @param other: the other object to compare with |
413 | @type other: `ArcAnnotation` | 415 | @type other: `ArcAnnotation` |
414 | """ | 416 | """ |
... | @@ -416,10 +418,10 @@ class ArcAnnotation (NetElement) : | ... | @@ -416,10 +418,10 @@ class ArcAnnotation (NetElement) : |
416 | def bind (self, binding) : | 418 | def bind (self, binding) : |
417 | """Return the value of the annotation evaluated through | 419 | """Return the value of the annotation evaluated through |
418 | `binding`. | 420 | `binding`. |
419 | - | 421 | + |
420 | >>> Expression('x+1').bind(Substitution(x=2)) | 422 | >>> Expression('x+1').bind(Substitution(x=2)) |
421 | Token(3) | 423 | Token(3) |
422 | - | 424 | + |
423 | @param binding: a substitution | 425 | @param binding: a substitution |
424 | @type binding: `snakes.data.Substitution` | 426 | @type binding: `snakes.data.Substitution` |
425 | @return: a value | 427 | @return: a value |
... | @@ -428,10 +430,10 @@ class ArcAnnotation (NetElement) : | ... | @@ -428,10 +430,10 @@ class ArcAnnotation (NetElement) : |
428 | def flow (self, binding) : | 430 | def flow (self, binding) : |
429 | """Return the flow of tokens implied by the annotation evaluated | 431 | """Return the flow of tokens implied by the annotation evaluated |
430 | through `binding`. | 432 | through `binding`. |
431 | - | 433 | + |
432 | >>> Value(1).flow(Substitution(x=2)) | 434 | >>> Value(1).flow(Substitution(x=2)) |
433 | MultiSet([1]) | 435 | MultiSet([1]) |
434 | - | 436 | + |
435 | @param binding: a substitution | 437 | @param binding: a substitution |
436 | @type binding: `snakes.data.Substitution` | 438 | @type binding: `snakes.data.Substitution` |
437 | @return: a multiset of values | 439 | @return: a multiset of values |
... | @@ -441,10 +443,10 @@ class ArcAnnotation (NetElement) : | ... | @@ -441,10 +443,10 @@ class ArcAnnotation (NetElement) : |
441 | """Return the list of modes under which an arc with the | 443 | """Return the list of modes under which an arc with the |
442 | annotation may flow the tokens in `values`. Each mode is a | 444 | annotation may flow the tokens in `values`. Each mode is a |
443 | substitution indicating how to bind the annotation. | 445 | substitution indicating how to bind the annotation. |
444 | - | 446 | + |
445 | >>> Variable('x').modes([1, 2, 3]) | 447 | >>> Variable('x').modes([1, 2, 3]) |
446 | [Substitution(x=1), Substitution(x=2), Substitution(x=3)] | 448 | [Substitution(x=1), Substitution(x=2), Substitution(x=3)] |
447 | - | 449 | + |
448 | @param values: a collection of values | 450 | @param values: a collection of values |
449 | @type values: any collection like `set`, `list`, `tuple`, ... | 451 | @type values: any collection like `set`, `list`, `tuple`, ... |
450 | @return: a list of substitutions | 452 | @return: a list of substitutions |
... | @@ -457,17 +459,17 @@ class Value (ArcAnnotation) : | ... | @@ -457,17 +459,17 @@ class Value (ArcAnnotation) : |
457 | input_allowed = True | 459 | input_allowed = True |
458 | def __init__ (self, value) : | 460 | def __init__ (self, value) : |
459 | """Initialise with the encapsulated value. | 461 | """Initialise with the encapsulated value. |
460 | - | 462 | + |
461 | @param value: the value of the token. | 463 | @param value: the value of the token. |
462 | @type value: any object | 464 | @type value: any object |
463 | """ | 465 | """ |
464 | self.value = value | 466 | self.value = value |
465 | def copy (self) : | 467 | def copy (self) : |
466 | """Return a copy of the value. | 468 | """Return a copy of the value. |
467 | - | 469 | + |
468 | >>> Value(5).copy() | 470 | >>> Value(5).copy() |
469 | Value(5) | 471 | Value(5) |
470 | - | 472 | + |
471 | @return: a copy of the value | 473 | @return: a copy of the value |
472 | @rtype: `Value` | 474 | @rtype: `Value` |
473 | """ | 475 | """ |
... | @@ -475,7 +477,7 @@ class Value (ArcAnnotation) : | ... | @@ -475,7 +477,7 @@ class Value (ArcAnnotation) : |
475 | __pnmltag__ = "value" | 477 | __pnmltag__ = "value" |
476 | def __pnmldump__ (self) : | 478 | def __pnmldump__ (self) : |
477 | """Dump a `Value` as a PNML tree | 479 | """Dump a `Value` as a PNML tree |
478 | - | 480 | + |
479 | >>> Value(3).__pnmldump__() | 481 | >>> Value(3).__pnmldump__() |
480 | <?xml version="1.0" encoding="utf-8"?> | 482 | <?xml version="1.0" encoding="utf-8"?> |
481 | <pnml> | 483 | <pnml> |
... | @@ -485,7 +487,7 @@ class Value (ArcAnnotation) : | ... | @@ -485,7 +487,7 @@ class Value (ArcAnnotation) : |
485 | </object> | 487 | </object> |
486 | </value> | 488 | </value> |
487 | </pnml> | 489 | </pnml> |
488 | - | 490 | + |
489 | @return: PNML tree | 491 | @return: PNML tree |
490 | @rtype: `pnml.Tree` | 492 | @rtype: `pnml.Tree` |
491 | """ | 493 | """ |
... | @@ -493,11 +495,11 @@ class Value (ArcAnnotation) : | ... | @@ -493,11 +495,11 @@ class Value (ArcAnnotation) : |
493 | @classmethod | 495 | @classmethod |
494 | def __pnmlload__ (cls, tree) : | 496 | def __pnmlload__ (cls, tree) : |
495 | """Create a `Value` from a PNML tree | 497 | """Create a `Value` from a PNML tree |
496 | - | 498 | + |
497 | >>> t = Value(3).__pnmldump__() | 499 | >>> t = Value(3).__pnmldump__() |
498 | >>> Value.__pnmlload__(t) | 500 | >>> Value.__pnmlload__(t) |
499 | Value(3) | 501 | Value(3) |
500 | - | 502 | + |
501 | @param tree: the tree to convert | 503 | @param tree: the tree to convert |
502 | @type tree: `pnml.Tree` | 504 | @type tree: `pnml.Tree` |
503 | @return: the value built | 505 | @return: the value built |
... | @@ -506,14 +508,14 @@ class Value (ArcAnnotation) : | ... | @@ -506,14 +508,14 @@ class Value (ArcAnnotation) : |
506 | return cls(tree.child().to_obj()) | 508 | return cls(tree.child().to_obj()) |
507 | def __str__ (self) : | 509 | def __str__ (self) : |
508 | """Concise string representation | 510 | """Concise string representation |
509 | - | 511 | + |
510 | This is the string representation of the encapsulated value. | 512 | This is the string representation of the encapsulated value. |
511 | - | 513 | + |
512 | >>> print(str(Value(42))) | 514 | >>> print(str(Value(42))) |
513 | 42 | 515 | 42 |
514 | >>> print(str(Value('hello'))) | 516 | >>> print(str(Value('hello'))) |
515 | 'hello' | 517 | 'hello' |
516 | - | 518 | + |
517 | @return: concise string representation | 519 | @return: concise string representation |
518 | @rtype: `str` | 520 | @rtype: `str` |
519 | """ | 521 | """ |
... | @@ -523,36 +525,36 @@ class Value (ArcAnnotation) : | ... | @@ -523,36 +525,36 @@ class Value (ArcAnnotation) : |
523 | return str(self.value) | 525 | return str(self.value) |
524 | def __repr__ (self) : | 526 | def __repr__ (self) : |
525 | """String representation suitable for `eval` | 527 | """String representation suitable for `eval` |
526 | - | 528 | + |
527 | >>> print(repr(Value(42))) | 529 | >>> print(repr(Value(42))) |
528 | Value(42) | 530 | Value(42) |
529 | >>> print(repr(Value('hello'))) | 531 | >>> print(repr(Value('hello'))) |
530 | Value('hello') | 532 | Value('hello') |
531 | - | 533 | + |
532 | @return: precise string representation | 534 | @return: precise string representation |
533 | @rtype: `str` | 535 | @rtype: `str` |
534 | """ | 536 | """ |
535 | return "%s(%s)" % (self.__class__.__name__, repr(self.value)) | 537 | return "%s(%s)" % (self.__class__.__name__, repr(self.value)) |
536 | def vars (self) : | 538 | def vars (self) : |
537 | """Return the list of variables involved in the value (empty). | 539 | """Return the list of variables involved in the value (empty). |
538 | - | 540 | + |
539 | >>> Value(42).vars() | 541 | >>> Value(42).vars() |
540 | [] | 542 | [] |
541 | - | 543 | + |
542 | @return: empty list | 544 | @return: empty list |
543 | @rtype: `list` | 545 | @rtype: `list` |
544 | """ | 546 | """ |
545 | return [] | 547 | return [] |
546 | def __eq__ (self, other) : | 548 | def __eq__ (self, other) : |
547 | """Test for equality | 549 | """Test for equality |
548 | - | 550 | + |
549 | This tests the equality of encapsulated values | 551 | This tests the equality of encapsulated values |
550 | - | 552 | + |
551 | >>> Value(42) == Value(42) | 553 | >>> Value(42) == Value(42) |
552 | True | 554 | True |
553 | >>> Value(42) == Value(4) | 555 | >>> Value(42) == Value(4) |
554 | False | 556 | False |
555 | - | 557 | + |
556 | @param other: second operand of the equality | 558 | @param other: second operand of the equality |
557 | @type other: `Value` | 559 | @type other: `Value` |
558 | @return: `True` if encapsulated values are equal, `False` | 560 | @return: `True` if encapsulated values are equal, `False` |
... | @@ -568,10 +570,10 @@ class Value (ArcAnnotation) : | ... | @@ -568,10 +570,10 @@ class Value (ArcAnnotation) : |
568 | def bind (self, binding) : | 570 | def bind (self, binding) : |
569 | """Return the value evaluated through `binding` (which is the | 571 | """Return the value evaluated through `binding` (which is the |
570 | value itself). | 572 | value itself). |
571 | - | 573 | + |
572 | >>> Value(1).bind(Substitution(x=2)) | 574 | >>> Value(1).bind(Substitution(x=2)) |
573 | Token(1) | 575 | Token(1) |
574 | - | 576 | + |
575 | @param binding: a substitution | 577 | @param binding: a substitution |
576 | @type binding: `snakes.data.Substitution` | 578 | @type binding: `snakes.data.Substitution` |
577 | @return: a value | 579 | @return: a value |
... | @@ -580,13 +582,13 @@ class Value (ArcAnnotation) : | ... | @@ -580,13 +582,13 @@ class Value (ArcAnnotation) : |
580 | def modes (self, values) : | 582 | def modes (self, values) : |
581 | """Return an empty binding (no binding needed for values) iff the | 583 | """Return an empty binding (no binding needed for values) iff the |
582 | value is in `values`, raise ModeError otherwise. | 584 | value is in `values`, raise ModeError otherwise. |
583 | - | 585 | + |
584 | >>> Value(1).modes([1, 2, 3]) | 586 | >>> Value(1).modes([1, 2, 3]) |
585 | [Substitution()] | 587 | [Substitution()] |
586 | >>> try : Value(1).modes([2, 3, 4]) | 588 | >>> try : Value(1).modes([2, 3, 4]) |
587 | ... except ModeError : print(sys.exc_info()[1]) | 589 | ... except ModeError : print(sys.exc_info()[1]) |
588 | no match for value | 590 | no match for value |
589 | - | 591 | + |
590 | @param values: a collection of values | 592 | @param values: a collection of values |
591 | @type values: any collection like `set`, `list`, `tuple`, ... | 593 | @type values: any collection like `set`, `list`, `tuple`, ... |
592 | @return: a list of substitutions | 594 | @return: a list of substitutions |
... | @@ -597,12 +599,12 @@ class Value (ArcAnnotation) : | ... | @@ -597,12 +599,12 @@ class Value (ArcAnnotation) : |
597 | raise ModeError("no match for value") | 599 | raise ModeError("no match for value") |
598 | def substitute (self, binding) : | 600 | def substitute (self, binding) : |
599 | """Bind the value (nothing to do). | 601 | """Bind the value (nothing to do). |
600 | - | 602 | + |
601 | >>> v = Value(5) | 603 | >>> v = Value(5) |
602 | >>> v.substitute(Substitution(x=5)) | 604 | >>> v.substitute(Substitution(x=5)) |
603 | >>> v | 605 | >>> v |
604 | Value(5) | 606 | Value(5) |
605 | - | 607 | + |
606 | @param binding: a substitution | 608 | @param binding: a substitution |
607 | @type binding: `snakes.data.Substitution` | 609 | @type binding: `snakes.data.Substitution` |
608 | """ | 610 | """ |
... | @@ -615,13 +617,13 @@ class Variable (ArcAnnotation) : | ... | @@ -615,13 +617,13 @@ class Variable (ArcAnnotation) : |
615 | def __init__ (self, name) : | 617 | def __init__ (self, name) : |
616 | """Variable names must start with a letter and may continue with | 618 | """Variable names must start with a letter and may continue with |
617 | any alphanumeric character. | 619 | any alphanumeric character. |
618 | - | 620 | + |
619 | >>> Variable('x') | 621 | >>> Variable('x') |
620 | Variable('x') | 622 | Variable('x') |
621 | >>> try : Variable('_test') | 623 | >>> try : Variable('_test') |
622 | ... except ValueError: print(sys.exc_info()[1]) | 624 | ... except ValueError: print(sys.exc_info()[1]) |
623 | not a variable name '_test' | 625 | not a variable name '_test' |
624 | - | 626 | + |
625 | @param name: the name of the variable | 627 | @param name: the name of the variable |
626 | @type name: `str` | 628 | @type name: `str` |
627 | """ | 629 | """ |
... | @@ -630,10 +632,10 @@ class Variable (ArcAnnotation) : | ... | @@ -630,10 +632,10 @@ class Variable (ArcAnnotation) : |
630 | self.name = name | 632 | self.name = name |
631 | def copy (self) : | 633 | def copy (self) : |
632 | """Return a copy of the variable. | 634 | """Return a copy of the variable. |
633 | - | 635 | + |
634 | >>> Variable('x').copy() | 636 | >>> Variable('x').copy() |
635 | Variable('x') | 637 | Variable('x') |
636 | - | 638 | + |
637 | @return: a copy of the variable | 639 | @return: a copy of the variable |
638 | @rtype: `Variable` | 640 | @rtype: `Variable` |
639 | """ | 641 | """ |
... | @@ -641,7 +643,7 @@ class Variable (ArcAnnotation) : | ... | @@ -641,7 +643,7 @@ class Variable (ArcAnnotation) : |
641 | __pnmltag__ = "variable" | 643 | __pnmltag__ = "variable" |
642 | def __pnmldump__ (self) : | 644 | def __pnmldump__ (self) : |
643 | """Dump a `Variable` as a PNML tree | 645 | """Dump a `Variable` as a PNML tree |
644 | - | 646 | + |
645 | >>> Variable('x').__pnmldump__() | 647 | >>> Variable('x').__pnmldump__() |
646 | <?xml version="1.0" encoding="utf-8"?> | 648 | <?xml version="1.0" encoding="utf-8"?> |
647 | <pnml> | 649 | <pnml> |
... | @@ -649,7 +651,7 @@ class Variable (ArcAnnotation) : | ... | @@ -649,7 +651,7 @@ class Variable (ArcAnnotation) : |
649 | x | 651 | x |
650 | </variable> | 652 | </variable> |
651 | </pnml> | 653 | </pnml> |
652 | - | 654 | + |
653 | @return: PNML tree | 655 | @return: PNML tree |
654 | @rtype: `pnml.Tree` | 656 | @rtype: `pnml.Tree` |
655 | """ | 657 | """ |
... | @@ -657,11 +659,11 @@ class Variable (ArcAnnotation) : | ... | @@ -657,11 +659,11 @@ class Variable (ArcAnnotation) : |
657 | @classmethod | 659 | @classmethod |
658 | def __pnmlload__ (cls, tree) : | 660 | def __pnmlload__ (cls, tree) : |
659 | """Create a `Variable` from a PNML tree | 661 | """Create a `Variable` from a PNML tree |
660 | - | 662 | + |
661 | >>> t = Variable('x').__pnmldump__() | 663 | >>> t = Variable('x').__pnmldump__() |
662 | >>> Variable.__pnmlload__(t) | 664 | >>> Variable.__pnmlload__(t) |
663 | Variable('x') | 665 | Variable('x') |
664 | - | 666 | + |
665 | @param tree: the tree to convert | 667 | @param tree: the tree to convert |
666 | @type tree: `pnml.Tree` | 668 | @type tree: `pnml.Tree` |
667 | @return: the variable built | 669 | @return: the variable built |
... | @@ -670,34 +672,34 @@ class Variable (ArcAnnotation) : | ... | @@ -670,34 +672,34 @@ class Variable (ArcAnnotation) : |
670 | return cls(tree.data) | 672 | return cls(tree.data) |
671 | def rename (self, name) : | 673 | def rename (self, name) : |
672 | """Change the name of the variable. | 674 | """Change the name of the variable. |
673 | - | 675 | + |
674 | >>> v = Variable('x') | 676 | >>> v = Variable('x') |
675 | >>> v.rename('y') | 677 | >>> v.rename('y') |
676 | >>> v | 678 | >>> v |
677 | Variable('y') | 679 | Variable('y') |
678 | - | 680 | + |
679 | @param name: the new name of the variable | 681 | @param name: the new name of the variable |
680 | @type name: `str` | 682 | @type name: `str` |
681 | """ | 683 | """ |
682 | self.__init__(name) | 684 | self.__init__(name) |
683 | def __str__ (self) : | 685 | def __str__ (self) : |
684 | """Concise string representation | 686 | """Concise string representation |
685 | - | 687 | + |
686 | This is the name of the variable | 688 | This is the name of the variable |
687 | - | 689 | + |
688 | >>> str(Variable('x')) | 690 | >>> str(Variable('x')) |
689 | 'x' | 691 | 'x' |
690 | - | 692 | + |
691 | @return: concise string representation | 693 | @return: concise string representation |
692 | @rtype: `str` | 694 | @rtype: `str` |
693 | """ | 695 | """ |
694 | return self.name | 696 | return self.name |
695 | def __repr__ (self) : | 697 | def __repr__ (self) : |
696 | """String representation suitable for `eval` | 698 | """String representation suitable for `eval` |
697 | - | 699 | + |
698 | >>> Variable('x') | 700 | >>> Variable('x') |
699 | Variable('x') | 701 | Variable('x') |
700 | - | 702 | + |
701 | @return: precise string representation | 703 | @return: precise string representation |
702 | @rtype: `str` | 704 | @rtype: `str` |
703 | """ | 705 | """ |
... | @@ -705,10 +707,10 @@ class Variable (ArcAnnotation) : | ... | @@ -705,10 +707,10 @@ class Variable (ArcAnnotation) : |
705 | def modes (self, values) : | 707 | def modes (self, values) : |
706 | """Return the the list of substitutions mapping the name of the | 708 | """Return the the list of substitutions mapping the name of the |
707 | variable to each value in `values`. | 709 | variable to each value in `values`. |
708 | - | 710 | + |
709 | >>> Variable('x').modes(range(3)) | 711 | >>> Variable('x').modes(range(3)) |
710 | [Substitution(x=0), Substitution(x=1), Substitution(x=2)] | 712 | [Substitution(x=0), Substitution(x=1), Substitution(x=2)] |
711 | - | 713 | + |
712 | @param values: a collection of values | 714 | @param values: a collection of values |
713 | @type values: any collection like `set`, `list`, `tuple`, ... | 715 | @type values: any collection like `set`, `list`, `tuple`, ... |
714 | @return: a list of substitutions | 716 | @return: a list of substitutions |
... | @@ -719,13 +721,13 @@ class Variable (ArcAnnotation) : | ... | @@ -719,13 +721,13 @@ class Variable (ArcAnnotation) : |
719 | return result | 721 | return result |
720 | def bind (self, binding) : | 722 | def bind (self, binding) : |
721 | """Return the value of the variable evaluated through `binding`. | 723 | """Return the value of the variable evaluated through `binding`. |
722 | - | 724 | + |
723 | >>> Variable('x').bind(Substitution(x=3)) | 725 | >>> Variable('x').bind(Substitution(x=3)) |
724 | Token(3) | 726 | Token(3) |
725 | >>> try : Variable('x').bind(Substitution(z=3)) | 727 | >>> try : Variable('x').bind(Substitution(z=3)) |
726 | ... except DomainError : print(sys.exc_info()[1]) | 728 | ... except DomainError : print(sys.exc_info()[1]) |
727 | unbound variable 'x' | 729 | unbound variable 'x' |
728 | - | 730 | + |
729 | @param binding: a substitution | 731 | @param binding: a substitution |
730 | @type binding: `snakes.data.Substitution` | 732 | @type binding: `snakes.data.Substitution` |
731 | @return: a value | 733 | @return: a value |
... | @@ -733,7 +735,7 @@ class Variable (ArcAnnotation) : | ... | @@ -733,7 +735,7 @@ class Variable (ArcAnnotation) : |
733 | return Token(binding[self.name]) | 735 | return Token(binding[self.name]) |
734 | def substitute (self, binding) : | 736 | def substitute (self, binding) : |
735 | """Change the name according to `binding`. | 737 | """Change the name according to `binding`. |
736 | - | 738 | + |
737 | >>> v = Variable('x') | 739 | >>> v = Variable('x') |
738 | >>> v.substitute(Substitution(x='y')) | 740 | >>> v.substitute(Substitution(x='y')) |
739 | >>> v | 741 | >>> v |
... | @@ -744,29 +746,29 @@ class Variable (ArcAnnotation) : | ... | @@ -744,29 +746,29 @@ class Variable (ArcAnnotation) : |
744 | >>> v.rename('z') | 746 | >>> v.rename('z') |
745 | >>> v | 747 | >>> v |
746 | Variable('z') | 748 | Variable('z') |
747 | - | 749 | + |
748 | @param binding: a substitution | 750 | @param binding: a substitution |
749 | @type binding: `snakes.data.Substitution` | 751 | @type binding: `snakes.data.Substitution` |
750 | """ | 752 | """ |
751 | self.rename(binding(self.name)) | 753 | self.rename(binding(self.name)) |
752 | def vars (self) : | 754 | def vars (self) : |
753 | """Return variable name in a list. | 755 | """Return variable name in a list. |
754 | - | 756 | + |
755 | >>> Variable('x').vars() | 757 | >>> Variable('x').vars() |
756 | ['x'] | 758 | ['x'] |
757 | - | 759 | + |
758 | @return: a list holding the name of the variable | 760 | @return: a list holding the name of the variable |
759 | @rtype: `list` holding a single `str` | 761 | @rtype: `list` holding a single `str` |
760 | """ | 762 | """ |
761 | return [self.name] | 763 | return [self.name] |
762 | def __eq__ (self, other) : | 764 | def __eq__ (self, other) : |
763 | """Test for equality | 765 | """Test for equality |
764 | - | 766 | + |
765 | >>> Variable('x') == Variable('x') | 767 | >>> Variable('x') == Variable('x') |
766 | True | 768 | True |
767 | >>> Variable('x') == Variable('y') | 769 | >>> Variable('x') == Variable('y') |
768 | False | 770 | False |
769 | - | 771 | + |
770 | @param other: right operand of equality | 772 | @param other: right operand of equality |
771 | @type other: `Variable` | 773 | @type other: `Variable` |
772 | @return: `True` if variables have the same name, `False` | 774 | @return: `True` if variables have the same name, `False` |
... | @@ -782,14 +784,14 @@ class Variable (ArcAnnotation) : | ... | @@ -782,14 +784,14 @@ class Variable (ArcAnnotation) : |
782 | 784 | ||
783 | class Expression (ArcAnnotation) : | 785 | class Expression (ArcAnnotation) : |
784 | """An arbitrary Python expression which may be evaluated. | 786 | """An arbitrary Python expression which may be evaluated. |
785 | - | 787 | + |
786 | Each expression has its private namespace which can be extended or | 788 | Each expression has its private namespace which can be extended or |
787 | changed. | 789 | changed. |
788 | """ | 790 | """ |
789 | input_allowed = False | 791 | input_allowed = False |
790 | def __init__ (self, expr) : | 792 | def __init__ (self, expr) : |
791 | """The expression is compiled so its syntax is checked. | 793 | """The expression is compiled so its syntax is checked. |
792 | - | 794 | + |
793 | @param expr: a Python expression suitable for `eval` | 795 | @param expr: a Python expression suitable for `eval` |
794 | @type expr: `str` | 796 | @type expr: `str` |
795 | """ | 797 | """ |
... | @@ -803,10 +805,10 @@ class Expression (ArcAnnotation) : | ... | @@ -803,10 +805,10 @@ class Expression (ArcAnnotation) : |
803 | __pnmltag__ = "expression" | 805 | __pnmltag__ = "expression" |
804 | def __pnmldump__ (self) : | 806 | def __pnmldump__ (self) : |
805 | """Dump an `Expression` as a PNML tree | 807 | """Dump an `Expression` as a PNML tree |
806 | - | 808 | + |
807 | @return: PNML tree | 809 | @return: PNML tree |
808 | @rtype: `pnml.Tree` | 810 | @rtype: `pnml.Tree` |
809 | - | 811 | + |
810 | >>> Expression('x+1').__pnmldump__() | 812 | >>> Expression('x+1').__pnmldump__() |
811 | <?xml version="1.0" encoding="utf-8"?> | 813 | <?xml version="1.0" encoding="utf-8"?> |
812 | <pnml> | 814 | <pnml> |
... | @@ -819,12 +821,12 @@ class Expression (ArcAnnotation) : | ... | @@ -819,12 +821,12 @@ class Expression (ArcAnnotation) : |
819 | @classmethod | 821 | @classmethod |
820 | def __pnmlload__ (cls, tree) : | 822 | def __pnmlload__ (cls, tree) : |
821 | """Create an `Expression` from a PNML tree | 823 | """Create an `Expression` from a PNML tree |
822 | - | 824 | + |
823 | @param tree: the tree to convert | 825 | @param tree: the tree to convert |
824 | @type tree: `pnml.Tree` | 826 | @type tree: `pnml.Tree` |
825 | @return: the expression built | 827 | @return: the expression built |
826 | @rtype: `Expression` | 828 | @rtype: `Expression` |
827 | - | 829 | + |
828 | >>> t = Expression('x+1').__pnmldump__() | 830 | >>> t = Expression('x+1').__pnmldump__() |
829 | >>> Expression.__pnmlload__(t) | 831 | >>> Expression.__pnmlload__(t) |
830 | Expression('x+1') | 832 | Expression('x+1') |
... | @@ -836,7 +838,7 @@ class Expression (ArcAnnotation) : | ... | @@ -836,7 +838,7 @@ class Expression (ArcAnnotation) : |
836 | return "%s(%s)" % (self.__class__.__name__, repr(self._str)) | 838 | return "%s(%s)" % (self.__class__.__name__, repr(self._str)) |
837 | def bind (self, binding) : | 839 | def bind (self, binding) : |
838 | """Evaluate the expression through `binding`. | 840 | """Evaluate the expression through `binding`. |
839 | - | 841 | + |
840 | >>> e = Expression('x*(y-1)') | 842 | >>> e = Expression('x*(y-1)') |
841 | >>> e.bind(Substitution(x=2, y=3)) | 843 | >>> e.bind(Substitution(x=2, y=3)) |
842 | Token(4) | 844 | Token(4) |
... | @@ -845,7 +847,7 @@ class Expression (ArcAnnotation) : | ... | @@ -845,7 +847,7 @@ class Expression (ArcAnnotation) : |
845 | ... raise Exception() | 847 | ... raise Exception() |
846 | ... except NameError: | 848 | ... except NameError: |
847 | ... pass | 849 | ... pass |
848 | - | 850 | + |
849 | @param binding: a substitution | 851 | @param binding: a substitution |
850 | @type binding: `snakes.data.Substitution` | 852 | @type binding: `snakes.data.Substitution` |
851 | @return: a value | 853 | @return: a value |
... | @@ -861,15 +863,15 @@ class Expression (ArcAnnotation) : | ... | @@ -861,15 +863,15 @@ class Expression (ArcAnnotation) : |
861 | return self.bind(binding).value | 863 | return self.bind(binding).value |
862 | def substitute (self, binding) : | 864 | def substitute (self, binding) : |
863 | """Substitute the variables according to 'binding'. | 865 | """Substitute the variables according to 'binding'. |
864 | - | 866 | + |
865 | >>> e = Expression('x+1*xy') | 867 | >>> e = Expression('x+1*xy') |
866 | >>> e.substitute(Substitution(x='y')) | 868 | >>> e.substitute(Substitution(x='y')) |
867 | >>> e | 869 | >>> e |
868 | Expression('(y + (1 * xy))') | 870 | Expression('(y + (1 * xy))') |
869 | - | 871 | + |
870 | As one can see, the substitution adds a lot of parentheses and | 872 | As one can see, the substitution adds a lot of parentheses and |
871 | spaces to the expression. | 873 | spaces to the expression. |
872 | - | 874 | + |
873 | @param binding: a substitution | 875 | @param binding: a substitution |
874 | @type binding: `snakes.data.Substitution` | 876 | @type binding: `snakes.data.Substitution` |
875 | """ | 877 | """ |
... | @@ -879,30 +881,30 @@ class Expression (ArcAnnotation) : | ... | @@ -879,30 +881,30 @@ class Expression (ArcAnnotation) : |
879 | self._str = expr.strip() | 881 | self._str = expr.strip() |
880 | def vars (self) : | 882 | def vars (self) : |
881 | """Return the list of variable names involved in the expression. | 883 | """Return the list of variable names involved in the expression. |
882 | - | 884 | + |
883 | >>> list(sorted(Expression('x+y').vars())) | 885 | >>> list(sorted(Expression('x+y').vars())) |
884 | ['x', 'y'] | 886 | ['x', 'y'] |
885 | - | 887 | + |
886 | @return: a list holding the names of the variables | 888 | @return: a list holding the names of the variables |
887 | @rtype: `list` of `str` | 889 | @rtype: `list` of `str` |
888 | """ | 890 | """ |
889 | return list(n for n in getvars(self._str) if n not in self.globals) | 891 | return list(n for n in getvars(self._str) if n not in self.globals) |
890 | def __and__ (self, other) : | 892 | def __and__ (self, other) : |
891 | """Implement `&` to perform `and` between two expressions. | 893 | """Implement `&` to perform `and` between two expressions. |
892 | - | 894 | + |
893 | It is not checked whether we combine boolean expressions or | 895 | It is not checked whether we combine boolean expressions or |
894 | not. | 896 | not. |
895 | - | 897 | + |
896 | >>> Expression('x==1') & Expression('y==2') | 898 | >>> Expression('x==1') & Expression('y==2') |
897 | Expression('(x==1) and (y==2)') | 899 | Expression('(x==1) and (y==2)') |
898 | - | 900 | + |
899 | Minor optimisation are implemented: | 901 | Minor optimisation are implemented: |
900 | - | 902 | + |
901 | >>> Expression('True') & Expression('x==y') | 903 | >>> Expression('True') & Expression('x==y') |
902 | Expression('x==y') | 904 | Expression('x==y') |
903 | >>> Expression('x==y') & Expression('True') | 905 | >>> Expression('x==y') & Expression('True') |
904 | Expression('x==y') | 906 | Expression('x==y') |
905 | - | 907 | + |
906 | @param other: an expression | 908 | @param other: an expression |
907 | @type other: `snakes.nets.Expression` | 909 | @type other: `snakes.nets.Expression` |
908 | @return: an expression | 910 | @return: an expression |
... | @@ -919,20 +921,20 @@ class Expression (ArcAnnotation) : | ... | @@ -919,20 +921,20 @@ class Expression (ArcAnnotation) : |
919 | return result | 921 | return result |
920 | def __or__ (self, other) : | 922 | def __or__ (self, other) : |
921 | """Implement `|` to perform `or` between two expressions. | 923 | """Implement `|` to perform `or` between two expressions. |
922 | - | 924 | + |
923 | It is not checked whether we combine boolean expressions or | 925 | It is not checked whether we combine boolean expressions or |
924 | not. | 926 | not. |
925 | - | 927 | + |
926 | >>> Expression('x==1') | Expression('y==2') | 928 | >>> Expression('x==1') | Expression('y==2') |
927 | Expression('(x==1) or (y==2)') | 929 | Expression('(x==1) or (y==2)') |
928 | - | 930 | + |
929 | Minor optimisation are implemented: | 931 | Minor optimisation are implemented: |
930 | - | 932 | + |
931 | >>> Expression('True') | Expression('x==y') | 933 | >>> Expression('True') | Expression('x==y') |
932 | Expression('True') | 934 | Expression('True') |
933 | >>> Expression('x==y') | Expression('True') | 935 | >>> Expression('x==y') | Expression('True') |
934 | Expression('True') | 936 | Expression('True') |
935 | - | 937 | + |
936 | @param other: an expression | 938 | @param other: an expression |
937 | @type other: `snakes.nets.Expression` | 939 | @type other: `snakes.nets.Expression` |
938 | @return: an expression | 940 | @return: an expression |
... | @@ -947,20 +949,20 @@ class Expression (ArcAnnotation) : | ... | @@ -947,20 +949,20 @@ class Expression (ArcAnnotation) : |
947 | return result | 949 | return result |
948 | def __invert__ (self) : | 950 | def __invert__ (self) : |
949 | """Implement `~` to perform `not`. | 951 | """Implement `~` to perform `not`. |
950 | - | 952 | + |
951 | It is not checked whether we negate a boolean expression or | 953 | It is not checked whether we negate a boolean expression or |
952 | not. | 954 | not. |
953 | - | 955 | + |
954 | >>> ~Expression('x==1') | 956 | >>> ~Expression('x==1') |
955 | Expression('not (x==1)') | 957 | Expression('not (x==1)') |
956 | - | 958 | + |
957 | Minor optimisation are implemented: | 959 | Minor optimisation are implemented: |
958 | - | 960 | + |
959 | >>> ~Expression('True') | 961 | >>> ~Expression('True') |
960 | Expression('False') | 962 | Expression('False') |
961 | >>> ~Expression('False') | 963 | >>> ~Expression('False') |
962 | Expression('True') | 964 | Expression('True') |
963 | - | 965 | + |
964 | @return: an expression | 966 | @return: an expression |
965 | @rtype: `snakes.nets.Expression` | 967 | @rtype: `snakes.nets.Expression` |
966 | """ | 968 | """ |
... | @@ -980,14 +982,14 @@ class Expression (ArcAnnotation) : | ... | @@ -980,14 +982,14 @@ class Expression (ArcAnnotation) : |
980 | 982 | ||
981 | def let (**args) : | 983 | def let (**args) : |
982 | """A dirty trick to allow side effects in expressions | 984 | """A dirty trick to allow side effects in expressions |
983 | - | 985 | + |
984 | Assignement takes place when method `bind` of the expression is | 986 | Assignement takes place when method `bind` of the expression is |
985 | called. Assigned variables are then stored in the `Substitution` | 987 | called. Assigned variables are then stored in the `Substitution` |
986 | passed to `bind`. | 988 | passed to `bind`. |
987 | - | 989 | + |
988 | Use with care: sides effects are nasty tricks, you may get | 990 | Use with care: sides effects are nasty tricks, you may get |
989 | unexpected results while playing with `let`. | 991 | unexpected results while playing with `let`. |
990 | - | 992 | + |
991 | >>> n = PetriNet('n') | 993 | >>> n = PetriNet('n') |
992 | >>> n.globals['let'] = let | 994 | >>> n.globals['let'] = let |
993 | >>> t = Transition('t', Expression('x is not None and let(foo=42)')) | 995 | >>> t = Transition('t', Expression('x is not None and let(foo=42)')) |
... | @@ -996,7 +998,7 @@ def let (**args) : | ... | @@ -996,7 +998,7 @@ def let (**args) : |
996 | >>> n.add_input('p', 't', Variable('x')) | 998 | >>> n.add_input('p', 't', Variable('x')) |
997 | >>> t.modes() == [Substitution(x=dot, foo=42)] | 999 | >>> t.modes() == [Substitution(x=dot, foo=42)] |
998 | True | 1000 | True |
999 | - | 1001 | + |
1000 | @param args: a list of `name=value` to assign | 1002 | @param args: a list of `name=value` to assign |
1001 | @return: `True` if assignment could be made, `False` otherwise | 1003 | @return: `True` if assignment could be made, `False` otherwise |
1002 | @rtype: `bool` | 1004 | @rtype: `bool` |
... | @@ -1012,21 +1014,21 @@ def let (**args) : | ... | @@ -1012,21 +1014,21 @@ def let (**args) : |
1012 | class MultiArc (ArcAnnotation) : | 1014 | class MultiArc (ArcAnnotation) : |
1013 | """A collection of other annotations, allowing to consume or produce | 1015 | """A collection of other annotations, allowing to consume or produce |
1014 | several tokens at once. | 1016 | several tokens at once. |
1015 | - | 1017 | + |
1016 | Such a collection is allowed on input arcs only if so are all its | 1018 | Such a collection is allowed on input arcs only if so are all its |
1017 | components. | 1019 | components. |
1018 | """ | 1020 | """ |
1019 | input_allowed = False | 1021 | input_allowed = False |
1020 | def __init__ (self, components) : | 1022 | def __init__ (self, components) : |
1021 | """Initialise with the components of the tuple. | 1023 | """Initialise with the components of the tuple. |
1022 | - | 1024 | + |
1023 | >>> MultiArc((Value(1), Expression('x+1'))) | 1025 | >>> MultiArc((Value(1), Expression('x+1'))) |
1024 | MultiArc((Value(1), Expression('x+1'))) | 1026 | MultiArc((Value(1), Expression('x+1'))) |
1025 | >>> MultiArc((Value(1), Expression('x+1'))).input_allowed | 1027 | >>> MultiArc((Value(1), Expression('x+1'))).input_allowed |
1026 | False | 1028 | False |
1027 | >>> MultiArc((Value(1), Variable('x'))).input_allowed | 1029 | >>> MultiArc((Value(1), Variable('x'))).input_allowed |
1028 | True | 1030 | True |
1029 | - | 1031 | + |
1030 | @param components: a list of components | 1032 | @param components: a list of components |
1031 | @type components: an iterable collection of `ArcAnnotation` | 1033 | @type components: an iterable collection of `ArcAnnotation` |
1032 | """ | 1034 | """ |
... | @@ -1046,10 +1048,10 @@ class MultiArc (ArcAnnotation) : | ... | @@ -1046,10 +1048,10 @@ class MultiArc (ArcAnnotation) : |
1046 | __pnmltag__ = "multiarc" | 1048 | __pnmltag__ = "multiarc" |
1047 | def __pnmldump__ (self) : | 1049 | def __pnmldump__ (self) : |
1048 | """Dump a `MultiArc` as a PNML tree | 1050 | """Dump a `MultiArc` as a PNML tree |
1049 | - | 1051 | + |
1050 | @return: PNML tree | 1052 | @return: PNML tree |
1051 | @rtype: `pnml.Tree` | 1053 | @rtype: `pnml.Tree` |
1052 | - | 1054 | + |
1053 | >>> MultiArc([Value(3), Expression('x+1')]).__pnmldump__() | 1055 | >>> MultiArc([Value(3), Expression('x+1')]).__pnmldump__() |
1054 | <?xml version="1.0" encoding="utf-8"?> | 1056 | <?xml version="1.0" encoding="utf-8"?> |
1055 | <pnml> | 1057 | <pnml> |
... | @@ -1070,12 +1072,12 @@ class MultiArc (ArcAnnotation) : | ... | @@ -1070,12 +1072,12 @@ class MultiArc (ArcAnnotation) : |
1070 | @classmethod | 1072 | @classmethod |
1071 | def __pnmlload__ (cls, tree) : | 1073 | def __pnmlload__ (cls, tree) : |
1072 | """Create a `MultiArc` from a PNML tree | 1074 | """Create a `MultiArc` from a PNML tree |
1073 | - | 1075 | + |
1074 | @param tree: the tree to convert | 1076 | @param tree: the tree to convert |
1075 | @type tree: `pnml.Tree` | 1077 | @type tree: `pnml.Tree` |
1076 | @return: the multiarc built | 1078 | @return: the multiarc built |
1077 | @rtype: `MultiArc` | 1079 | @rtype: `MultiArc` |
1078 | - | 1080 | + |
1079 | >>> t = MultiArc((Value(3), Expression('x+1'))).__pnmldump__() | 1081 | >>> t = MultiArc((Value(3), Expression('x+1'))).__pnmldump__() |
1080 | >>> MultiArc.__pnmlload__(t) | 1082 | >>> MultiArc.__pnmlload__(t) |
1081 | MultiArc((Value(3), Expression('x+1'))) | 1083 | MultiArc((Value(3), Expression('x+1'))) |
... | @@ -1133,11 +1135,11 @@ class MultiArc (ArcAnnotation) : | ... | @@ -1133,11 +1135,11 @@ class MultiArc (ArcAnnotation) : |
1133 | def bind (self, binding) : | 1135 | def bind (self, binding) : |
1134 | """Return the value of the annotation evaluated through | 1136 | """Return the value of the annotation evaluated through |
1135 | `binding`. | 1137 | `binding`. |
1136 | - | 1138 | + |
1137 | >>> t = MultiArc((Value(1), Variable('x'), Variable('y'))) | 1139 | >>> t = MultiArc((Value(1), Variable('x'), Variable('y'))) |
1138 | >>> t.bind(Substitution(x=2, y=3)) | 1140 | >>> t.bind(Substitution(x=2, y=3)) |
1139 | (Token(1), Token(2), Token(3)) | 1141 | (Token(1), Token(2), Token(3)) |
1140 | - | 1142 | + |
1141 | @param binding: a substitution | 1143 | @param binding: a substitution |
1142 | @type binding: `snakes.data.Substitution` | 1144 | @type binding: `snakes.data.Substitution` |
1143 | @return: a tuple of value | 1145 | @return: a tuple of value |
... | @@ -1147,7 +1149,7 @@ class MultiArc (ArcAnnotation) : | ... | @@ -1147,7 +1149,7 @@ class MultiArc (ArcAnnotation) : |
1147 | """Return the list of modes under which an arc with the | 1149 | """Return the list of modes under which an arc with the |
1148 | annotation may flow the tokens in `values`. Each mode is a | 1150 | annotation may flow the tokens in `values`. Each mode is a |
1149 | substitution indicating how to bind the annotation. | 1151 | substitution indicating how to bind the annotation. |
1150 | - | 1152 | + |
1151 | >>> t = MultiArc((Value(1), Variable('x'), Variable('y'))) | 1153 | >>> t = MultiArc((Value(1), Variable('x'), Variable('y'))) |
1152 | >>> m = t.modes([1, 2, 3]) | 1154 | >>> m = t.modes([1, 2, 3]) |
1153 | >>> len(m) | 1155 | >>> len(m) |
... | @@ -1156,7 +1158,7 @@ class MultiArc (ArcAnnotation) : | ... | @@ -1156,7 +1158,7 @@ class MultiArc (ArcAnnotation) : |
1156 | True | 1158 | True |
1157 | >>> Substitution(y=2, x=3) in m | 1159 | >>> Substitution(y=2, x=3) in m |
1158 | True | 1160 | True |
1159 | - | 1161 | + |
1160 | @param values: a collection of values | 1162 | @param values: a collection of values |
1161 | @type values: any collection like `set`, `list`, `tuple`, ... | 1163 | @type values: any collection like `set`, `list`, `tuple`, ... |
1162 | @return: a list of substitutions | 1164 | @return: a list of substitutions |
... | @@ -1179,12 +1181,12 @@ class MultiArc (ArcAnnotation) : | ... | @@ -1179,12 +1181,12 @@ class MultiArc (ArcAnnotation) : |
1179 | return result | 1181 | return result |
1180 | def substitute (self, binding) : | 1182 | def substitute (self, binding) : |
1181 | """Substitute each component according to 'binding'. | 1183 | """Substitute each component according to 'binding'. |
1182 | - | 1184 | + |
1183 | >>> t = MultiArc((Value(1), Variable('x'), Variable('y'))) | 1185 | >>> t = MultiArc((Value(1), Variable('x'), Variable('y'))) |
1184 | >>> t.substitute(Substitution(x='z')) | 1186 | >>> t.substitute(Substitution(x='z')) |
1185 | >>> t | 1187 | >>> t |
1186 | MultiArc((Value(1), Variable('z'), Variable('y'))) | 1188 | MultiArc((Value(1), Variable('z'), Variable('y'))) |
1187 | - | 1189 | + |
1188 | @param binding: a substitution | 1190 | @param binding: a substitution |
1189 | @type binding: `snakes.data.Substitution` | 1191 | @type binding: `snakes.data.Substitution` |
1190 | """ | 1192 | """ |
... | @@ -1192,11 +1194,11 @@ class MultiArc (ArcAnnotation) : | ... | @@ -1192,11 +1194,11 @@ class MultiArc (ArcAnnotation) : |
1192 | x.substitute(binding) | 1194 | x.substitute(binding) |
1193 | def vars (self) : | 1195 | def vars (self) : |
1194 | """Return the list of variables involved in the components. | 1196 | """Return the list of variables involved in the components. |
1195 | - | 1197 | + |
1196 | >>> t = MultiArc((Value(1), Variable('x'), Variable('y'))) | 1198 | >>> t = MultiArc((Value(1), Variable('x'), Variable('y'))) |
1197 | >>> list(sorted(t.vars())) | 1199 | >>> list(sorted(t.vars())) |
1198 | ['x', 'y'] | 1200 | ['x', 'y'] |
1199 | - | 1201 | + |
1200 | @return: the set of variables | 1202 | @return: the set of variables |
1201 | @rtype: `set` | 1203 | @rtype: `set` |
1202 | """ | 1204 | """ |
... | @@ -1207,9 +1209,9 @@ class MultiArc (ArcAnnotation) : | ... | @@ -1207,9 +1209,9 @@ class MultiArc (ArcAnnotation) : |
1207 | def replace (self, old, new) : | 1209 | def replace (self, old, new) : |
1208 | """Returns a copy of the annotation in which the `old` annotation | 1210 | """Returns a copy of the annotation in which the `old` annotation |
1209 | has been replaced by the `new` one. | 1211 | has been replaced by the `new` one. |
1210 | - | 1212 | + |
1211 | With `MultiArc`, replaces each occurrence of `old` by `new` | 1213 | With `MultiArc`, replaces each occurrence of `old` by `new` |
1212 | - | 1214 | + |
1213 | @param old: the annotation to be replaced | 1215 | @param old: the annotation to be replaced |
1214 | @type old: `ArcAnnotation` | 1216 | @type old: `ArcAnnotation` |
1215 | @param new: the annotation to use instead of `old` | 1217 | @param new: the annotation to use instead of `old` |
... | @@ -1276,11 +1278,11 @@ class Tuple (MultiArc) : | ... | @@ -1276,11 +1278,11 @@ class Tuple (MultiArc) : |
1276 | def bind (self, binding) : | 1278 | def bind (self, binding) : |
1277 | """Return the value of the annotation evaluated through | 1279 | """Return the value of the annotation evaluated through |
1278 | `binding`. | 1280 | `binding`. |
1279 | - | 1281 | + |
1280 | >>> t = Tuple((Value(1), Variable('x'), Variable('y'))) | 1282 | >>> t = Tuple((Value(1), Variable('x'), Variable('y'))) |
1281 | >>> t.bind(Substitution(x=2, y=3)) | 1283 | >>> t.bind(Substitution(x=2, y=3)) |
1282 | Token((1, 2, 3)) | 1284 | Token((1, 2, 3)) |
1283 | - | 1285 | + |
1284 | @param binding: a substitution | 1286 | @param binding: a substitution |
1285 | @type binding: `snakes.data.Substitution` | 1287 | @type binding: `snakes.data.Substitution` |
1286 | @return: a tuple of value | 1288 | @return: a tuple of value |
... | @@ -1312,10 +1314,10 @@ class Test (ArcAnnotation) : | ... | @@ -1312,10 +1314,10 @@ class Test (ArcAnnotation) : |
1312 | __pnmltag__ = "test" | 1314 | __pnmltag__ = "test" |
1313 | def __pnmldump__ (self) : | 1315 | def __pnmldump__ (self) : |
1314 | """Dump a `Test` as a PNML tree | 1316 | """Dump a `Test` as a PNML tree |
1315 | - | 1317 | + |
1316 | @return: PNML tree | 1318 | @return: PNML tree |
1317 | @rtype: `pnml.Tree` | 1319 | @rtype: `pnml.Tree` |
1318 | - | 1320 | + |
1319 | >>> Test(Value(3)).__pnmldump__() | 1321 | >>> Test(Value(3)).__pnmldump__() |
1320 | <?xml version="1.0" encoding="utf-8"?> | 1322 | <?xml version="1.0" encoding="utf-8"?> |
1321 | <pnml> | 1323 | <pnml> |
... | @@ -1332,12 +1334,12 @@ class Test (ArcAnnotation) : | ... | @@ -1332,12 +1334,12 @@ class Test (ArcAnnotation) : |
1332 | @classmethod | 1334 | @classmethod |
1333 | def __pnmlload__ (cls, tree) : | 1335 | def __pnmlload__ (cls, tree) : |
1334 | """Create a `Test` from a PNML tree | 1336 | """Create a `Test` from a PNML tree |
1335 | - | 1337 | + |
1336 | @param tree: the tree to convert | 1338 | @param tree: the tree to convert |
1337 | @type tree: `pnml.Tree` | 1339 | @type tree: `pnml.Tree` |
1338 | @return: the test arc built | 1340 | @return: the test arc built |
1339 | @rtype: `Test` | 1341 | @rtype: `Test` |
1340 | - | 1342 | + |
1341 | >>> t = Test(Value(3)).__pnmldump__() | 1343 | >>> t = Test(Value(3)).__pnmldump__() |
1342 | >>> Test.__pnmlload__(t) | 1344 | >>> Test.__pnmlload__(t) |
1343 | Test(Value(3)) | 1345 | Test(Value(3)) |
... | @@ -1369,7 +1371,7 @@ class Test (ArcAnnotation) : | ... | @@ -1369,7 +1371,7 @@ class Test (ArcAnnotation) : |
1369 | return "%s(%s)" % (self.__class__.__name__, repr(self._annotation)) | 1371 | return "%s(%s)" % (self.__class__.__name__, repr(self._annotation)) |
1370 | def substitute (self, binding) : | 1372 | def substitute (self, binding) : |
1371 | """Substitutes the variables in the annotation. | 1373 | """Substitutes the variables in the annotation. |
1372 | - | 1374 | + |
1373 | @param binding: the substitution to apply | 1375 | @param binding: the substitution to apply |
1374 | @type binding: `snakes.data.Substitution` | 1376 | @type binding: `snakes.data.Substitution` |
1375 | """ | 1377 | """ |
... | @@ -1388,10 +1390,10 @@ class Test (ArcAnnotation) : | ... | @@ -1388,10 +1390,10 @@ class Test (ArcAnnotation) : |
1388 | def bind (self, binding) : | 1390 | def bind (self, binding) : |
1389 | """Return the value of the annotation evaluated through | 1391 | """Return the value of the annotation evaluated through |
1390 | `binding`. | 1392 | `binding`. |
1391 | - | 1393 | + |
1392 | >>> Test(Expression('x+1')).bind(Substitution(x=2)) | 1394 | >>> Test(Expression('x+1')).bind(Substitution(x=2)) |
1393 | Token(3) | 1395 | Token(3) |
1394 | - | 1396 | + |
1395 | @param binding: a substitution | 1397 | @param binding: a substitution |
1396 | @type binding: `snakes.data.Substitution` | 1398 | @type binding: `snakes.data.Substitution` |
1397 | @return: a value | 1399 | @return: a value |
... | @@ -1400,10 +1402,10 @@ class Test (ArcAnnotation) : | ... | @@ -1400,10 +1402,10 @@ class Test (ArcAnnotation) : |
1400 | def flow (self, binding) : | 1402 | def flow (self, binding) : |
1401 | """Return the flow of tokens implied by the annotation evaluated | 1403 | """Return the flow of tokens implied by the annotation evaluated |
1402 | through `binding`. | 1404 | through `binding`. |
1403 | - | 1405 | + |
1404 | >>> Test(Value(1)).flow(Substitution()) | 1406 | >>> Test(Value(1)).flow(Substitution()) |
1405 | MultiSet([]) | 1407 | MultiSet([]) |
1406 | - | 1408 | + |
1407 | @param binding: a substitution | 1409 | @param binding: a substitution |
1408 | @type binding: `snakes.data.Substitution` | 1410 | @type binding: `snakes.data.Substitution` |
1409 | @return: an empty multiset | 1411 | @return: an empty multiset |
... | @@ -1413,10 +1415,10 @@ class Test (ArcAnnotation) : | ... | @@ -1413,10 +1415,10 @@ class Test (ArcAnnotation) : |
1413 | """Return the list of modes under which an arc with the | 1415 | """Return the list of modes under which an arc with the |
1414 | annotation may flow the tokens in `values`. Each mode is a | 1416 | annotation may flow the tokens in `values`. Each mode is a |
1415 | substitution indicating how to bind the annotation. | 1417 | substitution indicating how to bind the annotation. |
1416 | - | 1418 | + |
1417 | >>> Test(Variable('x')).modes([1, 2, 3]) | 1419 | >>> Test(Variable('x')).modes([1, 2, 3]) |
1418 | [Substitution(x=1), Substitution(x=2), Substitution(x=3)] | 1420 | [Substitution(x=1), Substitution(x=2), Substitution(x=3)] |
1419 | - | 1421 | + |
1420 | @param values: a collection of values | 1422 | @param values: a collection of values |
1421 | @type values: any collection like `set`, `list`, `tuple`, ... | 1423 | @type values: any collection like `set`, `list`, `tuple`, ... |
1422 | @return: a list of substitutions | 1424 | @return: a list of substitutions |
... | @@ -1425,9 +1427,9 @@ class Test (ArcAnnotation) : | ... | @@ -1425,9 +1427,9 @@ class Test (ArcAnnotation) : |
1425 | def replace (self, old, new) : | 1427 | def replace (self, old, new) : |
1426 | """Returns a copy of the annotation in which the `old` annotation | 1428 | """Returns a copy of the annotation in which the `old` annotation |
1427 | has been replaced by the `new` one. | 1429 | has been replaced by the `new` one. |
1428 | - | 1430 | + |
1429 | With `Test`, always returns `Test(new)` | 1431 | With `Test`, always returns `Test(new)` |
1430 | - | 1432 | + |
1431 | @param old: the annotation to be replaced | 1433 | @param old: the annotation to be replaced |
1432 | @type old: `ArcAnnotation` | 1434 | @type old: `ArcAnnotation` |
1433 | @param new: the annotation to use instead of `old` | 1435 | @param new: the annotation to use instead of `old` |
... | @@ -1451,10 +1453,10 @@ class Inhibitor (Test) : | ... | @@ -1451,10 +1453,10 @@ class Inhibitor (Test) : |
1451 | __pnmltag__ = "inhibitor" | 1453 | __pnmltag__ = "inhibitor" |
1452 | def __pnmldump__ (self) : | 1454 | def __pnmldump__ (self) : |
1453 | """Dump a `Inhibitor` as a PNML tree | 1455 | """Dump a `Inhibitor` as a PNML tree |
1454 | - | 1456 | + |
1455 | @return: PNML tree | 1457 | @return: PNML tree |
1456 | @rtype: `pnml.Tree` | 1458 | @rtype: `pnml.Tree` |
1457 | - | 1459 | + |
1458 | >>> Inhibitor(Value(3)).__pnmldump__() | 1460 | >>> Inhibitor(Value(3)).__pnmldump__() |
1459 | <?xml version="1.0" encoding="utf-8"?> | 1461 | <?xml version="1.0" encoding="utf-8"?> |
1460 | <pnml> | 1462 | <pnml> |
... | @@ -1480,12 +1482,12 @@ class Inhibitor (Test) : | ... | @@ -1480,12 +1482,12 @@ class Inhibitor (Test) : |
1480 | @classmethod | 1482 | @classmethod |
1481 | def __pnmlload__ (cls, tree) : | 1483 | def __pnmlload__ (cls, tree) : |
1482 | """Create a `Inhibitor` from a PNML tree | 1484 | """Create a `Inhibitor` from a PNML tree |
1483 | - | 1485 | + |
1484 | @param tree: the tree to convert | 1486 | @param tree: the tree to convert |
1485 | @type tree: `pnml.Tree` | 1487 | @type tree: `pnml.Tree` |
1486 | @return: the inhibitor arc built | 1488 | @return: the inhibitor arc built |
1487 | @rtype: `Inhibitor` | 1489 | @rtype: `Inhibitor` |
1488 | - | 1490 | + |
1489 | >>> t = Inhibitor(Value(3)).__pnmldump__() | 1491 | >>> t = Inhibitor(Value(3)).__pnmldump__() |
1490 | >>> Inhibitor.__pnmlload__(t) | 1492 | >>> Inhibitor.__pnmlload__(t) |
1491 | Inhibitor(Value(3)) | 1493 | Inhibitor(Value(3)) |
... | @@ -1520,7 +1522,7 @@ class Inhibitor (Test) : | ... | @@ -1520,7 +1522,7 @@ class Inhibitor (Test) : |
1520 | self._annotation, self._condition) | 1522 | self._annotation, self._condition) |
1521 | def substitute (self, binding) : | 1523 | def substitute (self, binding) : |
1522 | """Substitutes the variables in the annotation. | 1524 | """Substitutes the variables in the annotation. |
1523 | - | 1525 | + |
1524 | @param binding: the substitution to apply | 1526 | @param binding: the substitution to apply |
1525 | @type binding: `snakes.data.Substitution` | 1527 | @type binding: `snakes.data.Substitution` |
1526 | """ | 1528 | """ |
... | @@ -1542,13 +1544,13 @@ class Inhibitor (Test) : | ... | @@ -1542,13 +1544,13 @@ class Inhibitor (Test) : |
1542 | """Return the value of the annotation evaluated through | 1544 | """Return the value of the annotation evaluated through |
1543 | `binding`, or raise `ValueError` of this binding does not | 1545 | `binding`, or raise `ValueError` of this binding does not |
1544 | validate the condition. | 1546 | validate the condition. |
1545 | - | 1547 | + |
1546 | >>> Inhibitor(Expression('x+1'), Expression('x>0')).bind(Substitution(x=2)) | 1548 | >>> Inhibitor(Expression('x+1'), Expression('x>0')).bind(Substitution(x=2)) |
1547 | Token(3) | 1549 | Token(3) |
1548 | >>> try : Inhibitor(Expression('x+1'), Expression('x<0')).bind(Substitution(x=2)) | 1550 | >>> try : Inhibitor(Expression('x+1'), Expression('x<0')).bind(Substitution(x=2)) |
1549 | ... except ValueError : print(sys.exc_info()[1]) | 1551 | ... except ValueError : print(sys.exc_info()[1]) |
1550 | condition not True for {x -> 2} | 1552 | condition not True for {x -> 2} |
1551 | - | 1553 | + |
1552 | @param binding: a substitution | 1554 | @param binding: a substitution |
1553 | @type binding: `snakes.data.Substitution` | 1555 | @type binding: `snakes.data.Substitution` |
1554 | @return: a value | 1556 | @return: a value |
... | @@ -1561,7 +1563,7 @@ class Inhibitor (Test) : | ... | @@ -1561,7 +1563,7 @@ class Inhibitor (Test) : |
1561 | """Return the list of modes under which an arc with the | 1563 | """Return the list of modes under which an arc with the |
1562 | annotation may flow the tokens in `values`. Each mode is a | 1564 | annotation may flow the tokens in `values`. Each mode is a |
1563 | substitution indicating how to bind the annotation. | 1565 | substitution indicating how to bind the annotation. |
1564 | - | 1566 | + |
1565 | >>> try : Inhibitor(Value(1)).modes([1, 2, 3]) | 1567 | >>> try : Inhibitor(Value(1)).modes([1, 2, 3]) |
1566 | ... except ModeError : print(sys.exc_info()[1]) | 1568 | ... except ModeError : print(sys.exc_info()[1]) |
1567 | inhibited by {} | 1569 | inhibited by {} |
... | @@ -1579,7 +1581,7 @@ class Inhibitor (Test) : | ... | @@ -1579,7 +1581,7 @@ class Inhibitor (Test) : |
1579 | >>> Inhibitor(MultiArc([Variable('x'), Variable('y')]), | 1581 | >>> Inhibitor(MultiArc([Variable('x'), Variable('y')]), |
1580 | ... Expression('x==y')).modes([1, 2, 3]) | 1582 | ... Expression('x==y')).modes([1, 2, 3]) |
1581 | [Substitution()] | 1583 | [Substitution()] |
1582 | - | 1584 | + |
1583 | @param values: a collection of values | 1585 | @param values: a collection of values |
1584 | @type values: any collection like `set`, `list`, `tuple`, ... | 1586 | @type values: any collection like `set`, `list`, `tuple`, ... |
1585 | @return: a list of substitutions | 1587 | @return: a list of substitutions |
... | @@ -1595,7 +1597,7 @@ class Inhibitor (Test) : | ... | @@ -1595,7 +1597,7 @@ class Inhibitor (Test) : |
1595 | def replace (self, old, new) : | 1597 | def replace (self, old, new) : |
1596 | """Returns a copy of the annotation in which the `old` annotation | 1598 | """Returns a copy of the annotation in which the `old` annotation |
1597 | has been replaced by the `new` one. | 1599 | has been replaced by the `new` one. |
1598 | - | 1600 | + |
1599 | @param old: the annotation to be replaced | 1601 | @param old: the annotation to be replaced |
1600 | @type old: `ArcAnnotation` | 1602 | @type old: `ArcAnnotation` |
1601 | @param new: the annotation to use instead of `old` | 1603 | @param new: the annotation to use instead of `old` |
... | @@ -1666,13 +1668,13 @@ class Flush (ArcAnnotation) : | ... | @@ -1666,13 +1668,13 @@ class Flush (ArcAnnotation) : |
1666 | """Return the list of modes under which an arc with the | 1668 | """Return the list of modes under which an arc with the |
1667 | annotation may flow the tokens in `values`. Each mode is a | 1669 | annotation may flow the tokens in `values`. Each mode is a |
1668 | substitution indicating how to bind the annotation. | 1670 | substitution indicating how to bind the annotation. |
1669 | - | 1671 | + |
1670 | >>> m = Flush('x').modes([1, 2, 3]) | 1672 | >>> m = Flush('x').modes([1, 2, 3]) |
1671 | >>> m | 1673 | >>> m |
1672 | [Substitution(x=MultiSet([...]))] | 1674 | [Substitution(x=MultiSet([...]))] |
1673 | >>> m[0]['x'] == MultiSet([1, 2, 3]) | 1675 | >>> m[0]['x'] == MultiSet([1, 2, 3]) |
1674 | True | 1676 | True |
1675 | - | 1677 | + |
1676 | @param values: a collection of values | 1678 | @param values: a collection of values |
1677 | @type values: any collection like `set`, `list`, `tuple`, ... | 1679 | @type values: any collection like `set`, `list`, `tuple`, ... |
1678 | @return: a list of substitutions | 1680 | @return: a list of substitutions |
... | @@ -1681,10 +1683,10 @@ class Flush (ArcAnnotation) : | ... | @@ -1681,10 +1683,10 @@ class Flush (ArcAnnotation) : |
1681 | def flow (self, binding) : | 1683 | def flow (self, binding) : |
1682 | """Return the flow of tokens implied by the annotation evaluated | 1684 | """Return the flow of tokens implied by the annotation evaluated |
1683 | through `binding`. | 1685 | through `binding`. |
1684 | - | 1686 | + |
1685 | >>> Flush('x').flow(Substitution(x=MultiSet([1, 2, 3]))) == MultiSet([1, 2, 3]) | 1687 | >>> Flush('x').flow(Substitution(x=MultiSet([1, 2, 3]))) == MultiSet([1, 2, 3]) |
1686 | True | 1688 | True |
1687 | - | 1689 | + |
1688 | @param binding: a substitution | 1690 | @param binding: a substitution |
1689 | @type binding: `snakes.data.Substitution` | 1691 | @type binding: `snakes.data.Substitution` |
1690 | @return: a multiset | 1692 | @return: a multiset |
... | @@ -1693,10 +1695,10 @@ class Flush (ArcAnnotation) : | ... | @@ -1693,10 +1695,10 @@ class Flush (ArcAnnotation) : |
1693 | def bind (self, binding) : | 1695 | def bind (self, binding) : |
1694 | """Return the value of the annotation evaluated through | 1696 | """Return the value of the annotation evaluated through |
1695 | `binding`. | 1697 | `binding`. |
1696 | - | 1698 | + |
1697 | >>> set(Flush('x').bind(Substitution(x=MultiSet([1, 2, 3])))) == set([Token(1), Token(2), Token(3)]) | 1699 | >>> set(Flush('x').bind(Substitution(x=MultiSet([1, 2, 3])))) == set([Token(1), Token(2), Token(3)]) |
1698 | True | 1700 | True |
1699 | - | 1701 | + |
1700 | @param binding: a substitution | 1702 | @param binding: a substitution |
1701 | @type binding: `snakes.data.Substitution` | 1703 | @type binding: `snakes.data.Substitution` |
1702 | @return: a value | 1704 | @return: a value |
... | @@ -1704,10 +1706,10 @@ class Flush (ArcAnnotation) : | ... | @@ -1704,10 +1706,10 @@ class Flush (ArcAnnotation) : |
1704 | return tuple(Token(v) for v in self._annotation.bind(binding).value) | 1706 | return tuple(Token(v) for v in self._annotation.bind(binding).value) |
1705 | def vars (self) : | 1707 | def vars (self) : |
1706 | """Return the list of variable names involved in the arc. | 1708 | """Return the list of variable names involved in the arc. |
1707 | - | 1709 | + |
1708 | >>> Flush('x').vars() | 1710 | >>> Flush('x').vars() |
1709 | ['x'] | 1711 | ['x'] |
1710 | - | 1712 | + |
1711 | @return: list of variable names | 1713 | @return: list of variable names |
1712 | @rtype: `list` of `str` | 1714 | @rtype: `list` of `str` |
1713 | """ | 1715 | """ |
... | @@ -1719,13 +1721,13 @@ class Flush (ArcAnnotation) : | ... | @@ -1719,13 +1721,13 @@ class Flush (ArcAnnotation) : |
1719 | 1721 | ||
1720 | class Node (NetElement) : | 1722 | class Node (NetElement) : |
1721 | """A node in a Petri net. | 1723 | """A node in a Petri net. |
1722 | - | 1724 | + |
1723 | This class is abstract and should not be instanciated, use `Place` | 1725 | This class is abstract and should not be instanciated, use `Place` |
1724 | or `Transition` as concrete nodes. | 1726 | or `Transition` as concrete nodes. |
1725 | """ | 1727 | """ |
1726 | def rename (self, name) : | 1728 | def rename (self, name) : |
1727 | """Change the name of the node. | 1729 | """Change the name of the node. |
1728 | - | 1730 | + |
1729 | >>> p = Place('p', range(3)) | 1731 | >>> p = Place('p', range(3)) |
1730 | >>> p.rename('egg') | 1732 | >>> p.rename('egg') |
1731 | >>> p | 1733 | >>> p |
... | @@ -1734,7 +1736,7 @@ class Node (NetElement) : | ... | @@ -1734,7 +1736,7 @@ class Node (NetElement) : |
1734 | >>> t.rename('spam') | 1736 | >>> t.rename('spam') |
1735 | >>> t | 1737 | >>> t |
1736 | Transition('spam', Expression('x==1')) | 1738 | Transition('spam', Expression('x==1')) |
1737 | - | 1739 | + |
1738 | @param name: the new name of the node | 1740 | @param name: the new name of the node |
1739 | @type name: `str` | 1741 | @type name: `str` |
1740 | """ | 1742 | """ |
... | @@ -1744,14 +1746,14 @@ class Place (Node) : | ... | @@ -1744,14 +1746,14 @@ class Place (Node) : |
1744 | "A place of a Petri net." | 1746 | "A place of a Petri net." |
1745 | def __init__ (self, name, tokens=[], check=None) : | 1747 | def __init__ (self, name, tokens=[], check=None) : |
1746 | """Initialise with name, tokens and typecheck. | 1748 | """Initialise with name, tokens and typecheck. |
1747 | - | 1749 | + |
1748 | `tokens` may be a single value or an iterable object. `check` | 1750 | `tokens` may be a single value or an iterable object. `check` |
1749 | may be `None` (any token allowed) or a type from the module | 1751 | may be `None` (any token allowed) or a type from the module |
1750 | typing. | 1752 | typing. |
1751 | - | 1753 | + |
1752 | >>> Place('p', range(3), tInteger) | 1754 | >>> Place('p', range(3), tInteger) |
1753 | Place('p', MultiSet([...]), Instance(int)) | 1755 | Place('p', MultiSet([...]), Instance(int)) |
1754 | - | 1756 | + |
1755 | @param name: the name of the place | 1757 | @param name: the name of the place |
1756 | @type name: `str` | 1758 | @type name: `str` |
1757 | @param tokens: a collection of tokens that mark the place | 1759 | @param tokens: a collection of tokens that mark the place |
... | @@ -1770,7 +1772,7 @@ class Place (Node) : | ... | @@ -1770,7 +1772,7 @@ class Place (Node) : |
1770 | self.add(tokens) | 1772 | self.add(tokens) |
1771 | def copy (self, name=None) : | 1773 | def copy (self, name=None) : |
1772 | """Return a copy of the place, with no arc attached. | 1774 | """Return a copy of the place, with no arc attached. |
1773 | - | 1775 | + |
1774 | >>> p = Place('p', range(3), tInteger) | 1776 | >>> p = Place('p', range(3), tInteger) |
1775 | >>> n = p.copy() | 1777 | >>> n = p.copy() |
1776 | >>> n.name == 'p' | 1778 | >>> n.name == 'p' |
... | @@ -1786,7 +1788,7 @@ class Place (Node) : | ... | @@ -1786,7 +1788,7 @@ class Place (Node) : |
1786 | True | 1788 | True |
1787 | >>> n.checker() | 1789 | >>> n.checker() |
1788 | Instance(int) | 1790 | Instance(int) |
1789 | - | 1791 | + |
1790 | @param name: if not `None`, the name of the copy | 1792 | @param name: if not `None`, the name of the copy |
1791 | @type name: `str` | 1793 | @type name: `str` |
1792 | @return: a copy of the place. | 1794 | @return: a copy of the place. |
... | @@ -1798,10 +1800,10 @@ class Place (Node) : | ... | @@ -1798,10 +1800,10 @@ class Place (Node) : |
1798 | __pnmltag__ = "place" | 1800 | __pnmltag__ = "place" |
1799 | def __pnmldump__ (self) : | 1801 | def __pnmldump__ (self) : |
1800 | """Dump a `Place` as a PNML tree | 1802 | """Dump a `Place` as a PNML tree |
1801 | - | 1803 | + |
1802 | @return: PNML tree | 1804 | @return: PNML tree |
1803 | @rtype: `pnml.Tree` | 1805 | @rtype: `pnml.Tree` |
1804 | - | 1806 | + |
1805 | >>> Place('p', [dot, dot], tBlackToken).__pnmldump__() | 1807 | >>> Place('p', [dot, dot], tBlackToken).__pnmldump__() |
1806 | <?xml version="1.0" encoding="utf-8"?> | 1808 | <?xml version="1.0" encoding="utf-8"?> |
1807 | <pnml> | 1809 | <pnml> |
... | @@ -1873,14 +1875,14 @@ class Place (Node) : | ... | @@ -1873,14 +1875,14 @@ class Place (Node) : |
1873 | return cls(tree["id"], [dot] * toks, tBlackToken) | 1875 | return cls(tree["id"], [dot] * toks, tBlackToken) |
1874 | def checker (self, check=None) : | 1876 | def checker (self, check=None) : |
1875 | """Change or return the type of the place. | 1877 | """Change or return the type of the place. |
1876 | - | 1878 | + |
1877 | >>> p = Place('p', range(3), tInteger) | 1879 | >>> p = Place('p', range(3), tInteger) |
1878 | >>> p.checker() | 1880 | >>> p.checker() |
1879 | Instance(int) | 1881 | Instance(int) |
1880 | >>> p.checker(tAll) | 1882 | >>> p.checker(tAll) |
1881 | >>> p.checker() | 1883 | >>> p.checker() |
1882 | tAll | 1884 | tAll |
1883 | - | 1885 | + |
1884 | @param check: the new constraint for the place or `None` to | 1886 | @param check: the new constraint for the place or `None` to |
1885 | retreive the current constraint | 1887 | retreive the current constraint |
1886 | @type check: `None` or a type from the module `typing` | 1888 | @type check: `None` or a type from the module `typing` |
... | @@ -1894,13 +1896,13 @@ class Place (Node) : | ... | @@ -1894,13 +1896,13 @@ class Place (Node) : |
1894 | self._check = check | 1896 | self._check = check |
1895 | def __contains__ (self, token) : | 1897 | def __contains__ (self, token) : |
1896 | """Check if a token is in the place. | 1898 | """Check if a token is in the place. |
1897 | - | 1899 | + |
1898 | >>> p = Place('p', range(3)) | 1900 | >>> p = Place('p', range(3)) |
1899 | >>> 1 in p | 1901 | >>> 1 in p |
1900 | True | 1902 | True |
1901 | >>> 5 in p | 1903 | >>> 5 in p |
1902 | False | 1904 | False |
1903 | - | 1905 | + |
1904 | @param token: a token value | 1906 | @param token: a token value |
1905 | @type token: any type | 1907 | @type token: any type |
1906 | @return: `True` if `token` is held by the place, `False` | 1908 | @return: `True` if `token` is held by the place, `False` |
... | @@ -1910,17 +1912,17 @@ class Place (Node) : | ... | @@ -1910,17 +1912,17 @@ class Place (Node) : |
1910 | return token in self.tokens | 1912 | return token in self.tokens |
1911 | def __iter__ (self) : | 1913 | def __iter__ (self) : |
1912 | """Iterate over the tokens in the place. | 1914 | """Iterate over the tokens in the place. |
1913 | - | 1915 | + |
1914 | >>> p = Place('p', range(3)) | 1916 | >>> p = Place('p', range(3)) |
1915 | >>> list(sorted([tok for tok in p])) | 1917 | >>> list(sorted([tok for tok in p])) |
1916 | [0, 1, 2] | 1918 | [0, 1, 2] |
1917 | - | 1919 | + |
1918 | @return: an iterator object | 1920 | @return: an iterator object |
1919 | """ | 1921 | """ |
1920 | return iter(self.tokens) | 1922 | return iter(self.tokens) |
1921 | def is_empty (self) : | 1923 | def is_empty (self) : |
1922 | """Check is the place is empty. | 1924 | """Check is the place is empty. |
1923 | - | 1925 | + |
1924 | >>> p = Place('p', range(3)) | 1926 | >>> p = Place('p', range(3)) |
1925 | >>> p.tokens == MultiSet([0, 1, 2]) | 1927 | >>> p.tokens == MultiSet([0, 1, 2]) |
1926 | True | 1928 | True |
... | @@ -1929,7 +1931,7 @@ class Place (Node) : | ... | @@ -1929,7 +1931,7 @@ class Place (Node) : |
1929 | >>> p.tokens = MultiSet() | 1931 | >>> p.tokens = MultiSet() |
1930 | >>> p.is_empty() | 1932 | >>> p.is_empty() |
1931 | True | 1933 | True |
1932 | - | 1934 | + |
1933 | @return: `True` if the place is empty, `False` otherwise | 1935 | @return: `True` if the place is empty, `False` otherwise |
1934 | @rtype: `bool` | 1936 | @rtype: `bool` |
1935 | """ | 1937 | """ |
... | @@ -1938,13 +1940,13 @@ class Place (Node) : | ... | @@ -1938,13 +1940,13 @@ class Place (Node) : |
1938 | """Check if the 'tokens' are allowed in the place. An exception | 1940 | """Check if the 'tokens' are allowed in the place. An exception |
1939 | `ValueError` is raised whenever a forbidden token is | 1941 | `ValueError` is raised whenever a forbidden token is |
1940 | encountered. | 1942 | encountered. |
1941 | - | 1943 | + |
1942 | >>> p = Place('p', [], tInteger) | 1944 | >>> p = Place('p', [], tInteger) |
1943 | >>> p.check([1, 2, 3]) | 1945 | >>> p.check([1, 2, 3]) |
1944 | >>> try : p.check(['forbidden!']) | 1946 | >>> try : p.check(['forbidden!']) |
1945 | ... except ValueError : print(sys.exc_info()[1]) | 1947 | ... except ValueError : print(sys.exc_info()[1]) |
1946 | forbidden token 'forbidden!' | 1948 | forbidden token 'forbidden!' |
1947 | - | 1949 | + |
1948 | @param tokens: an iterable collection of tokens or a single | 1950 | @param tokens: an iterable collection of tokens or a single |
1949 | value | 1951 | value |
1950 | @type tokens: any type, iterable types (except `str`) will be | 1952 | @type tokens: any type, iterable types (except `str`) will be |
... | @@ -1955,21 +1957,21 @@ class Place (Node) : | ... | @@ -1955,21 +1957,21 @@ class Place (Node) : |
1955 | raise ValueError("forbidden token '%s'" % (t,)) | 1957 | raise ValueError("forbidden token '%s'" % (t,)) |
1956 | def __str__ (self) : | 1958 | def __str__ (self) : |
1957 | """Return the name of the place. | 1959 | """Return the name of the place. |
1958 | - | 1960 | + |
1959 | >>> p = Place('Great place!') | 1961 | >>> p = Place('Great place!') |
1960 | >>> str(p) | 1962 | >>> str(p) |
1961 | 'Great place!' | 1963 | 'Great place!' |
1962 | - | 1964 | + |
1963 | @return: the name of the place | 1965 | @return: the name of the place |
1964 | @rtype: `str` | 1966 | @rtype: `str` |
1965 | """ | 1967 | """ |
1966 | return self.name | 1968 | return self.name |
1967 | def __repr__ (self) : | 1969 | def __repr__ (self) : |
1968 | """Return a textual representation of the place. | 1970 | """Return a textual representation of the place. |
1969 | - | 1971 | + |
1970 | >>> repr(Place('p', range(3), tInteger)) | 1972 | >>> repr(Place('p', range(3), tInteger)) |
1971 | "Place('p', MultiSet([...]), Instance(int))" | 1973 | "Place('p', MultiSet([...]), Instance(int))" |
1972 | - | 1974 | + |
1973 | @return: a string suitable to `eval` representing the place | 1975 | @return: a string suitable to `eval` representing the place |
1974 | @rtype: `str` | 1976 | @rtype: `str` |
1975 | """ | 1977 | """ |
... | @@ -1979,14 +1981,14 @@ class Place (Node) : | ... | @@ -1979,14 +1981,14 @@ class Place (Node) : |
1979 | repr(self._check)) | 1981 | repr(self._check)) |
1980 | def add (self, tokens) : | 1982 | def add (self, tokens) : |
1981 | """Add tokens to the place. | 1983 | """Add tokens to the place. |
1982 | - | 1984 | + |
1983 | >>> p = Place('p') | 1985 | >>> p = Place('p') |
1984 | >>> p.tokens == MultiSet([]) | 1986 | >>> p.tokens == MultiSet([]) |
1985 | True | 1987 | True |
1986 | >>> p.add(range(3)) | 1988 | >>> p.add(range(3)) |
1987 | >>> p.tokens == MultiSet([0, 1, 2]) | 1989 | >>> p.tokens == MultiSet([0, 1, 2]) |
1988 | True | 1990 | True |
1989 | - | 1991 | + |
1990 | @param tokens: a collection of tokens to be added to the place | 1992 | @param tokens: a collection of tokens to be added to the place |
1991 | @type tokens: any type, iterable types (except `str`) will be | 1993 | @type tokens: any type, iterable types (except `str`) will be |
1992 | considered as collections of values | 1994 | considered as collections of values |
... | @@ -1995,14 +1997,14 @@ class Place (Node) : | ... | @@ -1995,14 +1997,14 @@ class Place (Node) : |
1995 | self.tokens.add(iterate(tokens)) | 1997 | self.tokens.add(iterate(tokens)) |
1996 | def remove (self, tokens) : | 1998 | def remove (self, tokens) : |
1997 | """Remove tokens from the place. | 1999 | """Remove tokens from the place. |
1998 | - | 2000 | + |
1999 | >>> p = Place('p', list(range(3)) * 2) | 2001 | >>> p = Place('p', list(range(3)) * 2) |
2000 | >>> p.tokens == MultiSet([0, 0, 1, 1, 2, 2]) | 2002 | >>> p.tokens == MultiSet([0, 0, 1, 1, 2, 2]) |
2001 | True | 2003 | True |
2002 | >>> p.remove(range(3)) | 2004 | >>> p.remove(range(3)) |
2003 | >>> p.tokens == MultiSet([0, 1, 2]) | 2005 | >>> p.tokens == MultiSet([0, 1, 2]) |
2004 | True | 2006 | True |
2005 | - | 2007 | + |
2006 | @param tokens: a collection of tokens to be removed from the | 2008 | @param tokens: a collection of tokens to be removed from the |
2007 | place | 2009 | place |
2008 | @type tokens: any type, iterable types (except `str`) will be | 2010 | @type tokens: any type, iterable types (except `str`) will be |
... | @@ -2011,7 +2013,7 @@ class Place (Node) : | ... | @@ -2011,7 +2013,7 @@ class Place (Node) : |
2011 | self.tokens.remove(tokens) | 2013 | self.tokens.remove(tokens) |
2012 | def empty (self) : | 2014 | def empty (self) : |
2013 | """Remove all the tokens. | 2015 | """Remove all the tokens. |
2014 | - | 2016 | + |
2015 | >>> p = Place('p', list(range(3)) * 2) | 2017 | >>> p = Place('p', list(range(3)) * 2) |
2016 | >>> p.tokens == MultiSet([0, 0, 1, 1, 2, 2]) | 2018 | >>> p.tokens == MultiSet([0, 0, 1, 1, 2, 2]) |
2017 | True | 2019 | True |
... | @@ -2022,7 +2024,7 @@ class Place (Node) : | ... | @@ -2022,7 +2024,7 @@ class Place (Node) : |
2022 | self.tokens = MultiSet() | 2024 | self.tokens = MultiSet() |
2023 | def reset (self, tokens) : | 2025 | def reset (self, tokens) : |
2024 | """Replace the marking with 'tokens'. | 2026 | """Replace the marking with 'tokens'. |
2025 | - | 2027 | + |
2026 | >>> p = Place('p', list(range(3)) * 2) | 2028 | >>> p = Place('p', list(range(3)) * 2) |
2027 | >>> p.tokens == MultiSet([0, 0, 1, 1, 2, 2]) | 2029 | >>> p.tokens == MultiSet([0, 0, 1, 1, 2, 2]) |
2028 | True | 2030 | True |
... | @@ -2037,12 +2039,12 @@ class Transition (Node) : | ... | @@ -2037,12 +2039,12 @@ class Transition (Node) : |
2037 | "A transition in a Petri net." | 2039 | "A transition in a Petri net." |
2038 | def __init__ (self, name, guard=None) : | 2040 | def __init__ (self, name, guard=None) : |
2039 | """Initialise with the name and the guard. | 2041 | """Initialise with the name and the guard. |
2040 | - | 2042 | + |
2041 | If `guard` is `None`, `True` is assumed instead. | 2043 | If `guard` is `None`, `True` is assumed instead. |
2042 | - | 2044 | + |
2043 | >>> Transition('t') | 2045 | >>> Transition('t') |
2044 | Transition('t', Expression('True')) | 2046 | Transition('t', Expression('True')) |
2045 | - | 2047 | + |
2046 | @param name: the name of the transition | 2048 | @param name: the name of the transition |
2047 | @type name: `str` | 2049 | @type name: `str` |
2048 | @param guard: the guard of the transition | 2050 | @param guard: the guard of the transition |
... | @@ -2057,13 +2059,13 @@ class Transition (Node) : | ... | @@ -2057,13 +2059,13 @@ class Transition (Node) : |
2057 | self.name = name | 2059 | self.name = name |
2058 | def copy (self, name=None) : | 2060 | def copy (self, name=None) : |
2059 | """Return a copy of the transition, with no arc attached. | 2061 | """Return a copy of the transition, with no arc attached. |
2060 | - | 2062 | + |
2061 | >>> t = Transition('t', Expression('x==1')) | 2063 | >>> t = Transition('t', Expression('x==1')) |
2062 | >>> t.copy() | 2064 | >>> t.copy() |
2063 | Transition('t', Expression('x==1')) | 2065 | Transition('t', Expression('x==1')) |
2064 | >>> t.copy('x') | 2066 | >>> t.copy('x') |
2065 | Transition('x', Expression('x==1')) | 2067 | Transition('x', Expression('x==1')) |
2066 | - | 2068 | + |
2067 | @param name: if not `None`, the name if of the copy | 2069 | @param name: if not `None`, the name if of the copy |
2068 | @type name: `str` | 2070 | @type name: `str` |
2069 | @return: a copy of the transition. | 2071 | @return: a copy of the transition. |
... | @@ -2114,21 +2116,21 @@ class Transition (Node) : | ... | @@ -2114,21 +2116,21 @@ class Transition (Node) : |
2114 | return cls(tree["id"]) | 2116 | return cls(tree["id"]) |
2115 | def __str__ (self) : | 2117 | def __str__ (self) : |
2116 | """Return the name of the transition. | 2118 | """Return the name of the transition. |
2117 | - | 2119 | + |
2118 | >>> t = Transition('What a transition!') | 2120 | >>> t = Transition('What a transition!') |
2119 | >>> str(t) | 2121 | >>> str(t) |
2120 | 'What a transition!' | 2122 | 'What a transition!' |
2121 | - | 2123 | + |
2122 | @return: the name of the transition | 2124 | @return: the name of the transition |
2123 | @rtype: `str` | 2125 | @rtype: `str` |
2124 | """ | 2126 | """ |
2125 | return self.name | 2127 | return self.name |
2126 | def __repr__ (self) : | 2128 | def __repr__ (self) : |
2127 | """Return a textual representation of the transition. | 2129 | """Return a textual representation of the transition. |
2128 | - | 2130 | + |
2129 | >>> repr(Transition('t', Expression('x==1'))) | 2131 | >>> repr(Transition('t', Expression('x==1'))) |
2130 | "Transition('t', Expression('x==1'))" | 2132 | "Transition('t', Expression('x==1'))" |
2131 | - | 2133 | + |
2132 | @return: a string suitable to `eval` representing the | 2134 | @return: a string suitable to `eval` representing the |
2133 | transition | 2135 | transition |
2134 | @rtype: `str` | 2136 | @rtype: `str` |
... | @@ -2138,7 +2140,7 @@ class Transition (Node) : | ... | @@ -2138,7 +2140,7 @@ class Transition (Node) : |
2138 | repr(self.guard)) | 2140 | repr(self.guard)) |
2139 | def add_input (self, place, label) : | 2141 | def add_input (self, place, label) : |
2140 | """Add an input arc from `place` labelled by `label`. | 2142 | """Add an input arc from `place` labelled by `label`. |
2141 | - | 2143 | + |
2142 | >>> t = Transition('t') | 2144 | >>> t = Transition('t') |
2143 | >>> t.add_input(Place('p'), Variable('x')) | 2145 | >>> t.add_input(Place('p'), Variable('x')) |
2144 | >>> t.input() | 2146 | >>> t.input() |
... | @@ -2146,7 +2148,7 @@ class Transition (Node) : | ... | @@ -2146,7 +2148,7 @@ class Transition (Node) : |
2146 | >>> try : t.add_input(Place('x'), Expression('x+y')) | 2148 | >>> try : t.add_input(Place('x'), Expression('x+y')) |
2147 | ... except ConstraintError : print(sys.exc_info()[1]) | 2149 | ... except ConstraintError : print(sys.exc_info()[1]) |
2148 | 'Expression' objects not allowed on input arcs | 2150 | 'Expression' objects not allowed on input arcs |
2149 | - | 2151 | + |
2150 | @param place: the input place | 2152 | @param place: the input place |
2151 | @type place: `Place` | 2153 | @type place: `Place` |
2152 | @param label: the arc label | 2154 | @param label: the arc label |
... | @@ -2161,7 +2163,7 @@ class Transition (Node) : | ... | @@ -2161,7 +2163,7 @@ class Transition (Node) : |
2161 | self._input[place] = label | 2163 | self._input[place] = label |
2162 | def remove_input (self, place) : | 2164 | def remove_input (self, place) : |
2163 | """Remove the input arc from `place`. | 2165 | """Remove the input arc from `place`. |
2164 | - | 2166 | + |
2165 | >>> t = Transition('t') | 2167 | >>> t = Transition('t') |
2166 | >>> p = Place('p') | 2168 | >>> p = Place('p') |
2167 | >>> t.add_input(p, Variable('x')) | 2169 | >>> t.add_input(p, Variable('x')) |
... | @@ -2170,7 +2172,7 @@ class Transition (Node) : | ... | @@ -2170,7 +2172,7 @@ class Transition (Node) : |
2170 | >>> t.remove_input(p) | 2172 | >>> t.remove_input(p) |
2171 | >>> t.input() | 2173 | >>> t.input() |
2172 | [] | 2174 | [] |
2173 | - | 2175 | + |
2174 | @param place: the input place | 2176 | @param place: the input place |
2175 | @type place: `Place` | 2177 | @type place: `Place` |
2176 | """ | 2178 | """ |
... | @@ -2180,24 +2182,24 @@ class Transition (Node) : | ... | @@ -2180,24 +2182,24 @@ class Transition (Node) : |
2180 | raise ConstraintError("not connected to '%s'" % place.name) | 2182 | raise ConstraintError("not connected to '%s'" % place.name) |
2181 | def input (self) : | 2183 | def input (self) : |
2182 | """Return the list of input arcs. | 2184 | """Return the list of input arcs. |
2183 | - | 2185 | + |
2184 | >>> t = Transition('t') | 2186 | >>> t = Transition('t') |
2185 | >>> t.add_input(Place('p'), Variable('x')) | 2187 | >>> t.add_input(Place('p'), Variable('x')) |
2186 | >>> t.input() | 2188 | >>> t.input() |
2187 | [(Place('p', MultiSet([]), tAll), Variable('x'))] | 2189 | [(Place('p', MultiSet([]), tAll), Variable('x'))] |
2188 | - | 2190 | + |
2189 | @return: a list of pairs (place, label). | 2191 | @return: a list of pairs (place, label). |
2190 | @rtype: `[(Place, ArcAnnotation)]` | 2192 | @rtype: `[(Place, ArcAnnotation)]` |
2191 | """ | 2193 | """ |
2192 | return list(self._input.items()) | 2194 | return list(self._input.items()) |
2193 | def add_output (self, place, label) : | 2195 | def add_output (self, place, label) : |
2194 | """Add an output arc from `place` labelled by `label`. | 2196 | """Add an output arc from `place` labelled by `label`. |
2195 | - | 2197 | + |
2196 | >>> t = Transition('t') | 2198 | >>> t = Transition('t') |
2197 | >>> t.add_output(Place('p'), Expression('x+1')) | 2199 | >>> t.add_output(Place('p'), Expression('x+1')) |
2198 | >>> t.output() | 2200 | >>> t.output() |
2199 | [(Place('p', MultiSet([]), tAll), Expression('x+1'))] | 2201 | [(Place('p', MultiSet([]), tAll), Expression('x+1'))] |
2200 | - | 2202 | + |
2201 | @param place: the output place | 2203 | @param place: the output place |
2202 | @type place: `Place` | 2204 | @type place: `Place` |
2203 | @param label: the arc label | 2205 | @param label: the arc label |
... | @@ -2209,7 +2211,7 @@ class Transition (Node) : | ... | @@ -2209,7 +2211,7 @@ class Transition (Node) : |
2209 | self._output[place] = label | 2211 | self._output[place] = label |
2210 | def remove_output (self, place) : | 2212 | def remove_output (self, place) : |
2211 | """Remove the output arc to `place`. | 2213 | """Remove the output arc to `place`. |
2212 | - | 2214 | + |
2213 | >>> t = Transition('t') | 2215 | >>> t = Transition('t') |
2214 | >>> p = Place('p') | 2216 | >>> p = Place('p') |
2215 | >>> t.add_output(p, Variable('x')) | 2217 | >>> t.add_output(p, Variable('x')) |
... | @@ -2218,7 +2220,7 @@ class Transition (Node) : | ... | @@ -2218,7 +2220,7 @@ class Transition (Node) : |
2218 | >>> t.remove_output(p) | 2220 | >>> t.remove_output(p) |
2219 | >>> t.output() | 2221 | >>> t.output() |
2220 | [] | 2222 | [] |
2221 | - | 2223 | + |
2222 | @param place: the output place | 2224 | @param place: the output place |
2223 | @type place: `Place` | 2225 | @type place: `Place` |
2224 | """ | 2226 | """ |
... | @@ -2228,25 +2230,25 @@ class Transition (Node) : | ... | @@ -2228,25 +2230,25 @@ class Transition (Node) : |
2228 | raise ConstraintError("not connected to '%s'" % place.name) | 2230 | raise ConstraintError("not connected to '%s'" % place.name) |
2229 | def output (self) : | 2231 | def output (self) : |
2230 | """Return the list of output arcs. | 2232 | """Return the list of output arcs. |
2231 | - | 2233 | + |
2232 | >>> t = Transition('t') | 2234 | >>> t = Transition('t') |
2233 | >>> t.add_output(Place('p'), Expression('x+1')) | 2235 | >>> t.add_output(Place('p'), Expression('x+1')) |
2234 | >>> t.output() | 2236 | >>> t.output() |
2235 | [(Place('p', MultiSet([]), tAll), Expression('x+1'))] | 2237 | [(Place('p', MultiSet([]), tAll), Expression('x+1'))] |
2236 | - | 2238 | + |
2237 | @return: a list of pairs (place, label). | 2239 | @return: a list of pairs (place, label). |
2238 | @rtype: `[(Place, ArcAnnotation)]` | 2240 | @rtype: `[(Place, ArcAnnotation)]` |
2239 | """ | 2241 | """ |
2240 | return list(self._output.items()) | 2242 | return list(self._output.items()) |
2241 | def _check (self, binding, tokens, input) : | 2243 | def _check (self, binding, tokens, input) : |
2242 | """Check `binding` against the guard and tokens flow. | 2244 | """Check `binding` against the guard and tokens flow. |
2243 | - | 2245 | + |
2244 | If `tokens` is `True`, check whether the flow of tokens can be | 2246 | If `tokens` is `True`, check whether the flow of tokens can be |
2245 | provided by the input places. If `input` is `True`, check if | 2247 | provided by the input places. If `input` is `True`, check if |
2246 | the evaluation of the inputs arcs respect the types of the | 2248 | the evaluation of the inputs arcs respect the types of the |
2247 | input places. In any case, this is checked for the output | 2249 | input places. In any case, this is checked for the output |
2248 | places. | 2250 | places. |
2249 | - | 2251 | + |
2250 | >>> t = Transition('t', Expression('x>0')) | 2252 | >>> t = Transition('t', Expression('x>0')) |
2251 | >>> p = Place('p', [], tInteger) | 2253 | >>> p = Place('p', [], tInteger) |
2252 | >>> t.add_input(p, Variable('x')) | 2254 | >>> t.add_input(p, Variable('x')) |
... | @@ -2268,7 +2270,7 @@ class Transition (Node) : | ... | @@ -2268,7 +2270,7 @@ class Transition (Node) : |
2268 | False | 2270 | False |
2269 | >>> t._check(s, True, True) | 2271 | >>> t._check(s, True, True) |
2270 | False | 2272 | False |
2271 | - | 2273 | + |
2272 | @param binding: a valuation of the variables on the transition | 2274 | @param binding: a valuation of the variables on the transition |
2273 | @type binding: `data.Substitution` | 2275 | @type binding: `data.Substitution` |
2274 | @param tokens: whether it should be checked that input places | 2276 | @param tokens: whether it should be checked that input places |
... | @@ -2299,11 +2301,11 @@ class Transition (Node) : | ... | @@ -2299,11 +2301,11 @@ class Transition (Node) : |
2299 | return True | 2301 | return True |
2300 | def activated (self, binding) : | 2302 | def activated (self, binding) : |
2301 | """Check if `binding` activates the transition. | 2303 | """Check if `binding` activates the transition. |
2302 | - | 2304 | + |
2303 | This is the case if the guard evaluates to `True` and if the | 2305 | This is the case if the guard evaluates to `True` and if the |
2304 | types of the places are respected. Note that the presence of | 2306 | types of the places are respected. Note that the presence of |
2305 | enough tokens is not required. | 2307 | enough tokens is not required. |
2306 | - | 2308 | + |
2307 | >>> t = Transition('t', Expression('x>0')) | 2309 | >>> t = Transition('t', Expression('x>0')) |
2308 | >>> p = Place('p', [], tInteger) | 2310 | >>> p = Place('p', [], tInteger) |
2309 | >>> t.add_input(p, Variable('x')) | 2311 | >>> t.add_input(p, Variable('x')) |
... | @@ -2313,17 +2315,17 @@ class Transition (Node) : | ... | @@ -2313,17 +2315,17 @@ class Transition (Node) : |
2313 | False | 2315 | False |
2314 | >>> t.activated(Substitution(x=3.14)) | 2316 | >>> t.activated(Substitution(x=3.14)) |
2315 | False | 2317 | False |
2316 | - | 2318 | + |
2317 | @param binding: a valuation of the variables on the transition | 2319 | @param binding: a valuation of the variables on the transition |
2318 | @type binding: `Substitution` | 2320 | @type binding: `Substitution` |
2319 | """ | 2321 | """ |
2320 | return self._check(binding, False, True) | 2322 | return self._check(binding, False, True) |
2321 | def enabled (self, binding) : | 2323 | def enabled (self, binding) : |
2322 | """Check if `binding` enables the transition. | 2324 | """Check if `binding` enables the transition. |
2323 | - | 2325 | + |
2324 | This is the case if the transition is activated and if the | 2326 | This is the case if the transition is activated and if the |
2325 | input places hold enough tokens to allow the firing. | 2327 | input places hold enough tokens to allow the firing. |
2326 | - | 2328 | + |
2327 | >>> t = Transition('t', Expression('x>0')) | 2329 | >>> t = Transition('t', Expression('x>0')) |
2328 | >>> p = Place('p', [0], tInteger) | 2330 | >>> p = Place('p', [0], tInteger) |
2329 | >>> t.add_input(p, Variable('x')) | 2331 | >>> t.add_input(p, Variable('x')) |
... | @@ -2332,7 +2334,7 @@ class Transition (Node) : | ... | @@ -2332,7 +2334,7 @@ class Transition (Node) : |
2332 | >>> p.add(1) | 2334 | >>> p.add(1) |
2333 | >>> t.enabled(Substitution(x=1)) | 2335 | >>> t.enabled(Substitution(x=1)) |
2334 | True | 2336 | True |
2335 | - | 2337 | + |
2336 | @param binding: a valuation of the variables on the transition | 2338 | @param binding: a valuation of the variables on the transition |
2337 | @type binding: `Substitution` | 2339 | @type binding: `Substitution` |
2338 | """ | 2340 | """ |
... | @@ -2340,7 +2342,7 @@ class Transition (Node) : | ... | @@ -2340,7 +2342,7 @@ class Transition (Node) : |
2340 | def vars (self) : | 2342 | def vars (self) : |
2341 | """Return the set of variables involved in the guard, input and | 2343 | """Return the set of variables involved in the guard, input and |
2342 | output arcs of the transition. | 2344 | output arcs of the transition. |
2343 | - | 2345 | + |
2344 | >>> t = Transition('t', Expression('z is not None')) | 2346 | >>> t = Transition('t', Expression('z is not None')) |
2345 | >>> px = Place('px') | 2347 | >>> px = Place('px') |
2346 | >>> t.add_input(px, Variable('x')) | 2348 | >>> t.add_input(px, Variable('x')) |
... | @@ -2348,7 +2350,7 @@ class Transition (Node) : | ... | @@ -2348,7 +2350,7 @@ class Transition (Node) : |
2348 | >>> t.add_output(py, Variable('y')) | 2350 | >>> t.add_output(py, Variable('y')) |
2349 | >>> list(sorted(t.vars())) | 2351 | >>> list(sorted(t.vars())) |
2350 | ['x', 'y', 'z'] | 2352 | ['x', 'y', 'z'] |
2351 | - | 2353 | + |
2352 | @return: the set of variables names | 2354 | @return: the set of variables names |
2353 | @rtype: a `set` of `str` | 2355 | @rtype: a `set` of `str` |
2354 | """ | 2356 | """ |
... | @@ -2360,10 +2362,10 @@ class Transition (Node) : | ... | @@ -2360,10 +2362,10 @@ class Transition (Node) : |
2360 | return v | 2362 | return v |
2361 | def substitute (self, binding) : | 2363 | def substitute (self, binding) : |
2362 | """Substite all the annotations arround the transition. | 2364 | """Substite all the annotations arround the transition. |
2363 | - | 2365 | + |
2364 | `binding` is used to substitute the guard and all the labels | 2366 | `binding` is used to substitute the guard and all the labels |
2365 | on the arcs attached to the transition. | 2367 | on the arcs attached to the transition. |
2366 | - | 2368 | + |
2367 | >>> t = Transition('t', Expression('z is not None')) | 2369 | >>> t = Transition('t', Expression('z is not None')) |
2368 | >>> px = Place('px') | 2370 | >>> px = Place('px') |
2369 | >>> t.add_input(px, Variable('x')) | 2371 | >>> t.add_input(px, Variable('x')) |
... | @@ -2376,7 +2378,7 @@ class Transition (Node) : | ... | @@ -2376,7 +2378,7 @@ class Transition (Node) : |
2376 | [(Place('px', MultiSet([]), tAll), Variable('a'))] | 2378 | [(Place('px', MultiSet([]), tAll), Variable('a'))] |
2377 | >>> t.output() | 2379 | >>> t.output() |
2378 | [(Place('py', MultiSet([]), tAll), Variable('b'))] | 2380 | [(Place('py', MultiSet([]), tAll), Variable('b'))] |
2379 | - | 2381 | + |
2380 | @param binding: a substitution from variables to variables | 2382 | @param binding: a substitution from variables to variables |
2381 | (not values) | 2383 | (not values) |
2382 | @type binding: `Substitution` | 2384 | @type binding: `Substitution` |
... | @@ -2388,12 +2390,12 @@ class Transition (Node) : | ... | @@ -2388,12 +2390,12 @@ class Transition (Node) : |
2388 | label.substitute(binding) | 2390 | label.substitute(binding) |
2389 | def modes (self) : | 2391 | def modes (self) : |
2390 | """Return the list of bindings which enable the transition. | 2392 | """Return the list of bindings which enable the transition. |
2391 | - | 2393 | + |
2392 | Note that the modes are usually considered to be the list of | 2394 | Note that the modes are usually considered to be the list of |
2393 | bindings that _activate_ a transitions. However, this list is | 2395 | bindings that _activate_ a transitions. However, this list is |
2394 | generally infinite so we retricted ourselves to _actual | 2396 | generally infinite so we retricted ourselves to _actual |
2395 | modes_, taking into account the present tokens. | 2397 | modes_, taking into account the present tokens. |
2396 | - | 2398 | + |
2397 | >>> t = Transition('t', Expression('x!=y')) | 2399 | >>> t = Transition('t', Expression('x!=y')) |
2398 | >>> px = Place('px', range(2)) | 2400 | >>> px = Place('px', range(2)) |
2399 | >>> t.add_input(px, Variable('x')) | 2401 | >>> t.add_input(px, Variable('x')) |
... | @@ -2406,12 +2408,12 @@ class Transition (Node) : | ... | @@ -2406,12 +2408,12 @@ class Transition (Node) : |
2406 | True | 2408 | True |
2407 | >>> Substitution(y=1, x=0) in m | 2409 | >>> Substitution(y=1, x=0) in m |
2408 | True | 2410 | True |
2409 | - | 2411 | + |
2410 | Note also that modes cannot be computed with respect to output | 2412 | Note also that modes cannot be computed with respect to output |
2411 | arcs: indeed, only input arcs allow for concretely associate | 2413 | arcs: indeed, only input arcs allow for concretely associate |
2412 | values to variables; on the other hand, binding an output arc | 2414 | values to variables; on the other hand, binding an output arc |
2413 | would require to solve the equation provided by the guard. | 2415 | would require to solve the equation provided by the guard. |
2414 | - | 2416 | + |
2415 | >>> t = Transition('t', Expression('x!=y')) | 2417 | >>> t = Transition('t', Expression('x!=y')) |
2416 | >>> px = Place('px', range(2)) | 2418 | >>> px = Place('px', range(2)) |
2417 | >>> t.add_input(px, Variable('x')) | 2419 | >>> t.add_input(px, Variable('x')) |
... | @@ -2422,7 +2424,7 @@ class Transition (Node) : | ... | @@ -2422,7 +2424,7 @@ class Transition (Node) : |
2422 | ... raise Exception() | 2424 | ... raise Exception() |
2423 | ... except NameError : | 2425 | ... except NameError : |
2424 | ... pass | 2426 | ... pass |
2425 | - | 2427 | + |
2426 | @return: a list of substitutions usable to fire the transition | 2428 | @return: a list of substitutions usable to fire the transition |
2427 | @rtype: a `list` of `Substitution` | 2429 | @rtype: a `list` of `Substitution` |
2428 | """ | 2430 | """ |
... | @@ -2447,10 +2449,10 @@ class Transition (Node) : | ... | @@ -2447,10 +2449,10 @@ class Transition (Node) : |
2447 | return result | 2449 | return result |
2448 | def flow (self, binding) : | 2450 | def flow (self, binding) : |
2449 | """Return the token flow for a firing with `binding`. | 2451 | """Return the token flow for a firing with `binding`. |
2450 | - | 2452 | + |
2451 | The flow is represented by a pair `(in, out)`, both being | 2453 | The flow is represented by a pair `(in, out)`, both being |
2452 | instances of the class `Marking`. | 2454 | instances of the class `Marking`. |
2453 | - | 2455 | + |
2454 | >>> t = Transition('t', Expression('x!=1')) | 2456 | >>> t = Transition('t', Expression('x!=1')) |
2455 | >>> px = Place('px', range(3)) | 2457 | >>> px = Place('px', range(3)) |
2456 | >>> t.add_input(px, Variable('x')) | 2458 | >>> t.add_input(px, Variable('x')) |
... | @@ -2463,7 +2465,7 @@ class Transition (Node) : | ... | @@ -2463,7 +2465,7 @@ class Transition (Node) : |
2463 | transition not enabled for {x -> 1} | 2465 | transition not enabled for {x -> 1} |
2464 | >>> t.flow(Substitution(x=2)) | 2466 | >>> t.flow(Substitution(x=2)) |
2465 | (Marking({'px': MultiSet([2])}), Marking({'py': MultiSet([3])})) | 2467 | (Marking({'px': MultiSet([2])}), Marking({'py': MultiSet([3])})) |
2466 | - | 2468 | + |
2467 | @param binding: a substitution from variables to values (not | 2469 | @param binding: a substitution from variables to values (not |
2468 | variables) | 2470 | variables) |
2469 | @type binding: `Substitution` | 2471 | @type binding: `Substitution` |
... | @@ -2480,7 +2482,7 @@ class Transition (Node) : | ... | @@ -2480,7 +2482,7 @@ class Transition (Node) : |
2480 | raise ValueError("transition not enabled for %s" % binding) | 2482 | raise ValueError("transition not enabled for %s" % binding) |
2481 | def fire (self, binding) : | 2483 | def fire (self, binding) : |
2482 | """Fire the transition with `binding`. | 2484 | """Fire the transition with `binding`. |
2483 | - | 2485 | + |
2484 | >>> t = Transition('t', Expression('x!=1')) | 2486 | >>> t = Transition('t', Expression('x!=1')) |
2485 | >>> px = Place('px', range(3)) | 2487 | >>> px = Place('px', range(3)) |
2486 | >>> t.add_input(px, Variable('x')) | 2488 | >>> t.add_input(px, Variable('x')) |
... | @@ -2499,7 +2501,7 @@ class Transition (Node) : | ... | @@ -2499,7 +2501,7 @@ class Transition (Node) : |
2499 | True | 2501 | True |
2500 | >>> py.tokens == MultiSet([1, 3]) | 2502 | >>> py.tokens == MultiSet([1, 3]) |
2501 | True | 2503 | True |
2502 | - | 2504 | + |
2503 | @param binding: a substitution from variables to values (not | 2505 | @param binding: a substitution from variables to values (not |
2504 | variables) | 2506 | variables) |
2505 | @type binding: `Substitution` | 2507 | @type binding: `Substitution` |
... | @@ -2518,10 +2520,10 @@ class Transition (Node) : | ... | @@ -2518,10 +2520,10 @@ class Transition (Node) : |
2518 | 2520 | ||
2519 | class Marking (hdict) : | 2521 | class Marking (hdict) : |
2520 | """A marking of a Petri net. | 2522 | """A marking of a Petri net. |
2521 | - | 2523 | + |
2522 | This is basically a `snakes.hashables.hdict` mapping place names | 2524 | This is basically a `snakes.hashables.hdict` mapping place names |
2523 | to multisets of tokens. | 2525 | to multisets of tokens. |
2524 | - | 2526 | + |
2525 | The parameters for the constructor must be given in a form | 2527 | The parameters for the constructor must be given in a form |
2526 | suitable for initialising a `hdict` with place names as keys and | 2528 | suitable for initialising a `hdict` with place names as keys and |
2527 | multisets as values. Places not given in the marking are assumed | 2529 | multisets as values. Places not given in the marking are assumed |
... | @@ -2587,16 +2589,16 @@ class Marking (hdict) : | ... | @@ -2587,16 +2589,16 @@ class Marking (hdict) : |
2587 | for child in tree.get_children("place"))) | 2589 | for child in tree.get_children("place"))) |
2588 | def __call__ (self, place) : | 2590 | def __call__ (self, place) : |
2589 | """Return the marking of `place`. | 2591 | """Return the marking of `place`. |
2590 | - | 2592 | + |
2591 | The empty multiset is returned if `place` is not explicitely | 2593 | The empty multiset is returned if `place` is not explicitely |
2592 | given in the marking. | 2594 | given in the marking. |
2593 | - | 2595 | + |
2594 | >>> m = Marking(p1=MultiSet([1]), p2=MultiSet([2])) | 2596 | >>> m = Marking(p1=MultiSet([1]), p2=MultiSet([2])) |
2595 | >>> m('p1') | 2597 | >>> m('p1') |
2596 | MultiSet([1]) | 2598 | MultiSet([1]) |
2597 | >>> m('p') | 2599 | >>> m('p') |
2598 | MultiSet([]) | 2600 | MultiSet([]) |
2599 | - | 2601 | + |
2600 | @param place: a place name | 2602 | @param place: a place name |
2601 | @type place: `str` | 2603 | @type place: `str` |
2602 | @return: the marking of `place` | 2604 | @return: the marking of `place` |
... | @@ -2608,7 +2610,7 @@ class Marking (hdict) : | ... | @@ -2608,7 +2610,7 @@ class Marking (hdict) : |
2608 | return MultiSet() | 2610 | return MultiSet() |
2609 | def copy (self) : | 2611 | def copy (self) : |
2610 | """Copy a marking | 2612 | """Copy a marking |
2611 | - | 2613 | + |
2612 | >>> m = Marking(p1=MultiSet([1]), p2=MultiSet([2])) | 2614 | >>> m = Marking(p1=MultiSet([1]), p2=MultiSet([2])) |
2613 | >>> m.copy() == Marking({'p2': MultiSet([2]), 'p1': MultiSet([1])}) | 2615 | >>> m.copy() == Marking({'p2': MultiSet([2]), 'p1': MultiSet([1])}) |
2614 | True | 2616 | True |
... | @@ -2619,10 +2621,10 @@ class Marking (hdict) : | ... | @@ -2619,10 +2621,10 @@ class Marking (hdict) : |
2619 | return result | 2621 | return result |
2620 | def __add__ (self, other) : | 2622 | def __add__ (self, other) : |
2621 | """Addition of markings. | 2623 | """Addition of markings. |
2622 | - | 2624 | + |
2623 | >>> Marking(p1=MultiSet([1]), p2=MultiSet([2])) + Marking(p2=MultiSet([2]), p3=MultiSet([3])) == Marking({'p2': MultiSet([2, 2]), 'p3': MultiSet([3]), 'p1': MultiSet([1])}) | 2625 | >>> Marking(p1=MultiSet([1]), p2=MultiSet([2])) + Marking(p2=MultiSet([2]), p3=MultiSet([3])) == Marking({'p2': MultiSet([2, 2]), 'p3': MultiSet([3]), 'p1': MultiSet([1])}) |
2624 | True | 2626 | True |
2625 | - | 2627 | + |
2626 | @param other: another marking | 2628 | @param other: another marking |
2627 | @type other: `Marking` | 2629 | @type other: `Marking` |
2628 | @return: the addition of the two markings | 2630 | @return: the addition of the two markings |
... | @@ -2637,7 +2639,7 @@ class Marking (hdict) : | ... | @@ -2637,7 +2639,7 @@ class Marking (hdict) : |
2637 | return result | 2639 | return result |
2638 | def __sub__ (self, other) : | 2640 | def __sub__ (self, other) : |
2639 | """Substraction of markings. | 2641 | """Substraction of markings. |
2640 | - | 2642 | + |
2641 | >>> Marking(p1=MultiSet([1]), p2=MultiSet([2, 2])) - Marking(p2=MultiSet([2])) | 2643 | >>> Marking(p1=MultiSet([1]), p2=MultiSet([2, 2])) - Marking(p2=MultiSet([2])) |
2642 | Marking({'p2': MultiSet([2]), 'p1': MultiSet([1])}) | 2644 | Marking({'p2': MultiSet([2]), 'p1': MultiSet([1])}) |
2643 | >>> try : Marking(p1=MultiSet([1]), p2=MultiSet([2])) - Marking(p2=MultiSet([2, 2])) | 2645 | >>> try : Marking(p1=MultiSet([1]), p2=MultiSet([2])) - Marking(p2=MultiSet([2, 2])) |
... | @@ -2646,7 +2648,7 @@ class Marking (hdict) : | ... | @@ -2646,7 +2648,7 @@ class Marking (hdict) : |
2646 | >>> try : Marking(p1=MultiSet([1]), p2=MultiSet([2])) - Marking(p3=MultiSet([3])) | 2648 | >>> try : Marking(p1=MultiSet([1]), p2=MultiSet([2])) - Marking(p3=MultiSet([3])) |
2647 | ... except DomainError : print(sys.exc_info()[1]) | 2649 | ... except DomainError : print(sys.exc_info()[1]) |
2648 | 'p3' absent from the marking | 2650 | 'p3' absent from the marking |
2649 | - | 2651 | + |
2650 | @param other: another marking | 2652 | @param other: another marking |
2651 | @type other: `Marking` | 2653 | @type other: `Marking` |
2652 | @return: the difference of the two markings | 2654 | @return: the difference of the two markings |
... | @@ -2664,14 +2666,14 @@ class Marking (hdict) : | ... | @@ -2664,14 +2666,14 @@ class Marking (hdict) : |
2664 | __hash__ = hdict.__hash__ | 2666 | __hash__ = hdict.__hash__ |
2665 | def __eq__ (self, other) : | 2667 | def __eq__ (self, other) : |
2666 | """Test for equality (same places with the same tokens). | 2668 | """Test for equality (same places with the same tokens). |
2667 | - | 2669 | + |
2668 | >>> Marking(p=MultiSet([1])) == Marking(p=MultiSet([1])) | 2670 | >>> Marking(p=MultiSet([1])) == Marking(p=MultiSet([1])) |
2669 | True | 2671 | True |
2670 | >>> Marking(p=MultiSet([1])) == Marking(p=MultiSet([1, 1])) | 2672 | >>> Marking(p=MultiSet([1])) == Marking(p=MultiSet([1, 1])) |
2671 | False | 2673 | False |
2672 | >>> Marking(p1=MultiSet([1])) == Marking(p2=MultiSet([1])) | 2674 | >>> Marking(p1=MultiSet([1])) == Marking(p2=MultiSet([1])) |
2673 | False | 2675 | False |
2674 | - | 2676 | + |
2675 | @param other: another marking | 2677 | @param other: another marking |
2676 | @type other: `Marking` | 2678 | @type other: `Marking` |
2677 | @return: `True` if the markings are equal, `False` otherwise | 2679 | @return: `True` if the markings are equal, `False` otherwise |
... | @@ -2688,14 +2690,14 @@ class Marking (hdict) : | ... | @@ -2688,14 +2690,14 @@ class Marking (hdict) : |
2688 | return True | 2690 | return True |
2689 | def __ne__ (self, other) : | 2691 | def __ne__ (self, other) : |
2690 | """Test if two markings differ. | 2692 | """Test if two markings differ. |
2691 | - | 2693 | + |
2692 | >>> Marking(p=MultiSet([1])) != Marking(p=MultiSet([1])) | 2694 | >>> Marking(p=MultiSet([1])) != Marking(p=MultiSet([1])) |
2693 | False | 2695 | False |
2694 | >>> Marking(p=MultiSet([1])) != Marking(p=MultiSet([1, 1])) | 2696 | >>> Marking(p=MultiSet([1])) != Marking(p=MultiSet([1, 1])) |
2695 | True | 2697 | True |
2696 | >>> Marking(p1=MultiSet([1])) != Marking(p2=MultiSet([1])) | 2698 | >>> Marking(p1=MultiSet([1])) != Marking(p2=MultiSet([1])) |
2697 | True | 2699 | True |
2698 | - | 2700 | + |
2699 | @param other: another marking | 2701 | @param other: another marking |
2700 | @type other: `Marking` | 2702 | @type other: `Marking` |
2701 | @return: `True` if the markings differ, `False` otherwise | 2703 | @return: `True` if the markings differ, `False` otherwise |
... | @@ -2705,10 +2707,10 @@ class Marking (hdict) : | ... | @@ -2705,10 +2707,10 @@ class Marking (hdict) : |
2705 | def __ge__ (self, other) : | 2707 | def __ge__ (self, other) : |
2706 | """Test if the marking `self` is greater than or equal to | 2708 | """Test if the marking `self` is greater than or equal to |
2707 | `other`. | 2709 | `other`. |
2708 | - | 2710 | + |
2709 | This is the case when any place in `other` is also in `self` | 2711 | This is the case when any place in `other` is also in `self` |
2710 | and is marked with a smaller or equal multiset of tokens. | 2712 | and is marked with a smaller or equal multiset of tokens. |
2711 | - | 2713 | + |
2712 | >>> Marking(p=MultiSet([1])) >= Marking(p=MultiSet([1])) | 2714 | >>> Marking(p=MultiSet([1])) >= Marking(p=MultiSet([1])) |
2713 | True | 2715 | True |
2714 | >>> Marking(p=MultiSet([1, 1])) >= Marking(p=MultiSet([1])) | 2716 | >>> Marking(p=MultiSet([1, 1])) >= Marking(p=MultiSet([1])) |
... | @@ -2719,7 +2721,7 @@ class Marking (hdict) : | ... | @@ -2719,7 +2721,7 @@ class Marking (hdict) : |
2719 | False | 2721 | False |
2720 | >>> Marking(p=MultiSet([1]), r=MultiSet([2])) >= Marking(p=MultiSet([1, 1])) | 2722 | >>> Marking(p=MultiSet([1]), r=MultiSet([2])) >= Marking(p=MultiSet([1, 1])) |
2721 | False | 2723 | False |
2722 | - | 2724 | + |
2723 | @param other: another marking | 2725 | @param other: another marking |
2724 | @type other: `Marking` | 2726 | @type other: `Marking` |
2725 | @return: `True` if `self >= other`, `False` otherwise | 2727 | @return: `True` if `self >= other`, `False` otherwise |
... | @@ -2733,11 +2735,11 @@ class Marking (hdict) : | ... | @@ -2733,11 +2735,11 @@ class Marking (hdict) : |
2733 | return True | 2735 | return True |
2734 | def __gt__ (self, other) : | 2736 | def __gt__ (self, other) : |
2735 | """Test if the marking `self` is strictly greater than `other`. | 2737 | """Test if the marking `self` is strictly greater than `other`. |
2736 | - | 2738 | + |
2737 | This is the case when any place in `other` is also in `self` | 2739 | This is the case when any place in `other` is also in `self` |
2738 | and either one place in `other` is marked with a smaller | 2740 | and either one place in `other` is marked with a smaller |
2739 | multiset of tokens or `slef` has more places than `other`. | 2741 | multiset of tokens or `slef` has more places than `other`. |
2740 | - | 2742 | + |
2741 | >>> Marking(p=MultiSet([1])) > Marking(p=MultiSet([1])) | 2743 | >>> Marking(p=MultiSet([1])) > Marking(p=MultiSet([1])) |
2742 | False | 2744 | False |
2743 | >>> Marking(p=MultiSet([1, 1])) > Marking(p=MultiSet([1])) | 2745 | >>> Marking(p=MultiSet([1, 1])) > Marking(p=MultiSet([1])) |
... | @@ -2748,7 +2750,7 @@ class Marking (hdict) : | ... | @@ -2748,7 +2750,7 @@ class Marking (hdict) : |
2748 | False | 2750 | False |
2749 | >>> Marking(p=MultiSet([1]), r=MultiSet([2])) > Marking(p=MultiSet([1, 1])) | 2751 | >>> Marking(p=MultiSet([1]), r=MultiSet([2])) > Marking(p=MultiSet([1, 1])) |
2750 | False | 2752 | False |
2751 | - | 2753 | + |
2752 | @param other: another marking | 2754 | @param other: another marking |
2753 | @type other: `Marking` | 2755 | @type other: `Marking` |
2754 | @return: `True` if `self > other`, `False` otherwise | 2756 | @return: `True` if `self > other`, `False` otherwise |
... | @@ -2766,10 +2768,10 @@ class Marking (hdict) : | ... | @@ -2766,10 +2768,10 @@ class Marking (hdict) : |
2766 | def __le__ (self, other) : | 2768 | def __le__ (self, other) : |
2767 | """Test if the marking `self` is smaller than or equal to | 2769 | """Test if the marking `self` is smaller than or equal to |
2768 | `other`. | 2770 | `other`. |
2769 | - | 2771 | + |
2770 | This is the case when any place in `self` is also in `other` | 2772 | This is the case when any place in `self` is also in `other` |
2771 | and is marked with a smaller or equal multiset of tokens. | 2773 | and is marked with a smaller or equal multiset of tokens. |
2772 | - | 2774 | + |
2773 | >>> Marking(p=MultiSet([1])) <= Marking(p=MultiSet([1])) | 2775 | >>> Marking(p=MultiSet([1])) <= Marking(p=MultiSet([1])) |
2774 | True | 2776 | True |
2775 | >>> Marking(p=MultiSet([1])) <= Marking(p=MultiSet([1, 1])) | 2777 | >>> Marking(p=MultiSet([1])) <= Marking(p=MultiSet([1, 1])) |
... | @@ -2780,7 +2782,7 @@ class Marking (hdict) : | ... | @@ -2780,7 +2782,7 @@ class Marking (hdict) : |
2780 | False | 2782 | False |
2781 | >>> Marking(p=MultiSet([1, 1])) <= Marking(p=MultiSet([1]), r=MultiSet([2])) | 2783 | >>> Marking(p=MultiSet([1, 1])) <= Marking(p=MultiSet([1]), r=MultiSet([2])) |
2782 | False | 2784 | False |
2783 | - | 2785 | + |
2784 | @param other: another marking | 2786 | @param other: another marking |
2785 | @type other: `Marking` | 2787 | @type other: `Marking` |
2786 | @return: `True` if `self <= other`, `False` otherwise | 2788 | @return: `True` if `self <= other`, `False` otherwise |
... | @@ -2794,12 +2796,12 @@ class Marking (hdict) : | ... | @@ -2794,12 +2796,12 @@ class Marking (hdict) : |
2794 | return True | 2796 | return True |
2795 | def __lt__ (self, other) : | 2797 | def __lt__ (self, other) : |
2796 | """Test if the marking `self` is strictly smaller than `other`. | 2798 | """Test if the marking `self` is strictly smaller than `other`. |
2797 | - | 2799 | + |
2798 | This is the case when any place in `self` is also in `other` | 2800 | This is the case when any place in `self` is also in `other` |
2799 | and either one place in `self` marked in self with a strictly | 2801 | and either one place in `self` marked in self with a strictly |
2800 | smaller multiset of tokens or `other` has more places than | 2802 | smaller multiset of tokens or `other` has more places than |
2801 | `self`. | 2803 | `self`. |
2802 | - | 2804 | + |
2803 | >>> Marking(p=MultiSet([1])) < Marking(p=MultiSet([1])) | 2805 | >>> Marking(p=MultiSet([1])) < Marking(p=MultiSet([1])) |
2804 | False | 2806 | False |
2805 | >>> Marking(p=MultiSet([1])) < Marking(p=MultiSet([1, 1])) | 2807 | >>> Marking(p=MultiSet([1])) < Marking(p=MultiSet([1, 1])) |
... | @@ -2810,7 +2812,7 @@ class Marking (hdict) : | ... | @@ -2810,7 +2812,7 @@ class Marking (hdict) : |
2810 | False | 2812 | False |
2811 | >>> Marking(p=MultiSet([1, 1])) < Marking(p=MultiSet([1]), r=MultiSet([2])) | 2813 | >>> Marking(p=MultiSet([1, 1])) < Marking(p=MultiSet([1]), r=MultiSet([2])) |
2812 | False | 2814 | False |
2813 | - | 2815 | + |
2814 | @param other: another marking | 2816 | @param other: another marking |
2815 | @type other: `Marking` | 2817 | @type other: `Marking` |
2816 | @return: `True` if `self < other`, `False` otherwise | 2818 | @return: `True` if `self < other`, `False` otherwise |
... | @@ -2832,20 +2834,20 @@ class Marking (hdict) : | ... | @@ -2832,20 +2834,20 @@ class Marking (hdict) : |
2832 | 2834 | ||
2833 | class PetriNet (object) : | 2835 | class PetriNet (object) : |
2834 | """A Petri net. | 2836 | """A Petri net. |
2835 | - | 2837 | + |
2836 | As soon as nodes are added to a `PetriNet`, they are handled by | 2838 | As soon as nodes are added to a `PetriNet`, they are handled by |
2837 | name instead of by the `Place` or `Transition` instance. For | 2839 | name instead of by the `Place` or `Transition` instance. For |
2838 | instance: | 2840 | instance: |
2839 | - | 2841 | + |
2840 | >>> n = PetriNet('N') | 2842 | >>> n = PetriNet('N') |
2841 | >>> t = Transition('t') | 2843 | >>> t = Transition('t') |
2842 | >>> n.add_transition(t) | 2844 | >>> n.add_transition(t) |
2843 | >>> n.has_transition('t') # use 't' and not t | 2845 | >>> n.has_transition('t') # use 't' and not t |
2844 | True | 2846 | True |
2845 | - | 2847 | + |
2846 | Because nodes can be retreived through their name, this allows to | 2848 | Because nodes can be retreived through their name, this allows to |
2847 | rewrite the above code as: | 2849 | rewrite the above code as: |
2848 | - | 2850 | + |
2849 | >>> n = PetriNet('N') | 2851 | >>> n = PetriNet('N') |
2850 | >>> n.add_transition(Transition('t')) | 2852 | >>> n.add_transition(Transition('t')) |
2851 | >>> n.has_transition('t') # use 't' and not t | 2853 | >>> n.has_transition('t') # use 't' and not t |
... | @@ -2855,10 +2857,10 @@ class PetriNet (object) : | ... | @@ -2855,10 +2857,10 @@ class PetriNet (object) : |
2855 | """ | 2857 | """ |
2856 | def __init__ (self, name) : | 2858 | def __init__ (self, name) : |
2857 | """Initialise with the name. | 2859 | """Initialise with the name. |
2858 | - | 2860 | + |
2859 | >>> PetriNet('N') | 2861 | >>> PetriNet('N') |
2860 | PetriNet('N') | 2862 | PetriNet('N') |
2861 | - | 2863 | + |
2862 | @param name: the name of the net | 2864 | @param name: the name of the net |
2863 | @type name: `str` | 2865 | @type name: `str` |
2864 | """ | 2866 | """ |
... | @@ -2876,12 +2878,12 @@ class PetriNet (object) : | ... | @@ -2876,12 +2878,12 @@ class PetriNet (object) : |
2876 | def copy (self, name=None) : | 2878 | def copy (self, name=None) : |
2877 | """Return a complete copy of the net, including places, | 2879 | """Return a complete copy of the net, including places, |
2878 | transitions, arcs and declarations. | 2880 | transitions, arcs and declarations. |
2879 | - | 2881 | + |
2880 | >>> PetriNet('N').copy() | 2882 | >>> PetriNet('N').copy() |
2881 | PetriNet('N') | 2883 | PetriNet('N') |
2882 | >>> PetriNet('N').copy('x') | 2884 | >>> PetriNet('N').copy('x') |
2883 | PetriNet('x') | 2885 | PetriNet('x') |
2884 | - | 2886 | + |
2885 | @param name: if not `None`, the name of the copy | 2887 | @param name: if not `None`, the name of the copy |
2886 | @type name: `str` | 2888 | @type name: `str` |
2887 | @return: a copy of the net | 2889 | @return: a copy of the net |
... | @@ -2905,12 +2907,12 @@ class PetriNet (object) : | ... | @@ -2905,12 +2907,12 @@ class PetriNet (object) : |
2905 | @classmethod | 2907 | @classmethod |
2906 | def _pnml_dump_arc (cls, label) : | 2908 | def _pnml_dump_arc (cls, label) : |
2907 | """Dump an arc to PNML | 2909 | """Dump an arc to PNML |
2908 | - | 2910 | + |
2909 | @param label: the arc label to dump | 2911 | @param label: the arc label to dump |
2910 | @type label: `ArcAnnotation` | 2912 | @type label: `ArcAnnotation` |
2911 | @return: a tuple of PNML trees | 2913 | @return: a tuple of PNML trees |
2912 | @rtype: `tuple` of `pnml.Tree` | 2914 | @rtype: `tuple` of `pnml.Tree` |
2913 | - | 2915 | + |
2914 | >>> PetriNet._pnml_dump_arc(Value(dot)) | 2916 | >>> PetriNet._pnml_dump_arc(Value(dot)) |
2915 | (<?xml version="1.0" encoding="utf-8"?> | 2917 | (<?xml version="1.0" encoding="utf-8"?> |
2916 | <pnml> | 2918 | <pnml> |
... | @@ -2969,10 +2971,10 @@ class PetriNet (object) : | ... | @@ -2969,10 +2971,10 @@ class PetriNet (object) : |
2969 | return (Tree("inscription", None, Tree.from_obj(label)),) | 2971 | return (Tree("inscription", None, Tree.from_obj(label)),) |
2970 | def __pnmldump__ (self) : | 2972 | def __pnmldump__ (self) : |
2971 | """Dump a `PetriNet` as a PNML tree | 2973 | """Dump a `PetriNet` as a PNML tree |
2972 | - | 2974 | + |
2973 | @return: PNML tree | 2975 | @return: PNML tree |
2974 | @rtype: `pnml.Tree` | 2976 | @rtype: `pnml.Tree` |
2975 | - | 2977 | + |
2976 | >>> n = PetriNet('N') | 2978 | >>> n = PetriNet('N') |
2977 | >>> n.declare('x = "foo" + "bar"') | 2979 | >>> n.declare('x = "foo" + "bar"') |
2978 | >>> n.globals['y'] = 'egg' | 2980 | >>> n.globals['y'] = 'egg' |
... | @@ -3057,12 +3059,12 @@ class PetriNet (object) : | ... | @@ -3057,12 +3059,12 @@ class PetriNet (object) : |
3057 | @classmethod | 3059 | @classmethod |
3058 | def __pnmlload__ (cls, tree) : | 3060 | def __pnmlload__ (cls, tree) : |
3059 | """Create a `PetriNet` from a PNML tree | 3061 | """Create a `PetriNet` from a PNML tree |
3060 | - | 3062 | + |
3061 | @param tree: the tree to convert | 3063 | @param tree: the tree to convert |
3062 | @type tree: `pnml.Tree` | 3064 | @type tree: `pnml.Tree` |
3063 | @return: the net built | 3065 | @return: the net built |
3064 | @rtype: `PetriNet` | 3066 | @rtype: `PetriNet` |
3065 | - | 3067 | + |
3066 | >>> old = PetriNet('N') | 3068 | >>> old = PetriNet('N') |
3067 | >>> old.declare('x = "foo" + "bar"') | 3069 | >>> old.declare('x = "foo" + "bar"') |
3068 | >>> old.globals['y'] = 'egg' | 3070 | >>> old.globals['y'] = 'egg' |
... | @@ -3124,46 +3126,46 @@ class PetriNet (object) : | ... | @@ -3124,46 +3126,46 @@ class PetriNet (object) : |
3124 | return result | 3126 | return result |
3125 | def __repr__ (self) : | 3127 | def __repr__ (self) : |
3126 | """Return a string suitable for `eval` to represent the net. | 3128 | """Return a string suitable for `eval` to represent the net. |
3127 | - | 3129 | + |
3128 | >>> repr(PetriNet('N')) | 3130 | >>> repr(PetriNet('N')) |
3129 | "PetriNet('N')" | 3131 | "PetriNet('N')" |
3130 | - | 3132 | + |
3131 | @return: the textual representation of the net | 3133 | @return: the textual representation of the net |
3132 | @rtype: `str` | 3134 | @rtype: `str` |
3133 | """ | 3135 | """ |
3134 | return "%s(%s)" % (self.__class__.__name__, repr(self.name)) | 3136 | return "%s(%s)" % (self.__class__.__name__, repr(self.name)) |
3135 | def __str__ (self) : | 3137 | def __str__ (self) : |
3136 | """Return the name of the net. | 3138 | """Return the name of the net. |
3137 | - | 3139 | + |
3138 | >>> str(PetriNet('N')) | 3140 | >>> str(PetriNet('N')) |
3139 | 'N' | 3141 | 'N' |
3140 | - | 3142 | + |
3141 | @return: the name if the net | 3143 | @return: the name if the net |
3142 | @rtype: `str` | 3144 | @rtype: `str` |
3143 | """ | 3145 | """ |
3144 | return self.name | 3146 | return self.name |
3145 | def rename (self, name) : | 3147 | def rename (self, name) : |
3146 | """Change the name of the net. | 3148 | """Change the name of the net. |
3147 | - | 3149 | + |
3148 | >>> n = PetriNet('N') | 3150 | >>> n = PetriNet('N') |
3149 | >>> n.rename('Long name!') | 3151 | >>> n.rename('Long name!') |
3150 | >>> n | 3152 | >>> n |
3151 | PetriNet('Long name!') | 3153 | PetriNet('Long name!') |
3152 | - | 3154 | + |
3153 | @param name: the new name | 3155 | @param name: the new name |
3154 | @type name: `str` | 3156 | @type name: `str` |
3155 | """ | 3157 | """ |
3156 | self.name = name | 3158 | self.name = name |
3157 | def has_place (self, name) : | 3159 | def has_place (self, name) : |
3158 | """Check if there is a place called `name` in the net. | 3160 | """Check if there is a place called `name` in the net. |
3159 | - | 3161 | + |
3160 | >>> n = PetriNet('N') | 3162 | >>> n = PetriNet('N') |
3161 | >>> n.has_place('p') | 3163 | >>> n.has_place('p') |
3162 | False | 3164 | False |
3163 | >>> n.add_place(Place('p')) | 3165 | >>> n.add_place(Place('p')) |
3164 | >>> n.has_place('p') | 3166 | >>> n.has_place('p') |
3165 | True | 3167 | True |
3166 | - | 3168 | + |
3167 | @param name: the name of the searched place | 3169 | @param name: the name of the searched place |
3168 | @type name: `str` | 3170 | @type name: `str` |
3169 | @return: `True` if a place called `name` is present in the | 3171 | @return: `True` if a place called `name` is present in the |
... | @@ -3173,14 +3175,14 @@ class PetriNet (object) : | ... | @@ -3173,14 +3175,14 @@ class PetriNet (object) : |
3173 | return name in self._place | 3175 | return name in self._place |
3174 | def has_transition (self, name) : | 3176 | def has_transition (self, name) : |
3175 | """Check if there is a transition called `name` in the net. | 3177 | """Check if there is a transition called `name` in the net. |
3176 | - | 3178 | + |
3177 | >>> n = PetriNet('N') | 3179 | >>> n = PetriNet('N') |
3178 | >>> n.has_transition('t') | 3180 | >>> n.has_transition('t') |
3179 | False | 3181 | False |
3180 | >>> n.add_transition(Transition('t')) | 3182 | >>> n.add_transition(Transition('t')) |
3181 | >>> n.has_transition('t') | 3183 | >>> n.has_transition('t') |
3182 | True | 3184 | True |
3183 | - | 3185 | + |
3184 | @param name: the name of the searched transition | 3186 | @param name: the name of the searched transition |
3185 | @type name: `str` | 3187 | @type name: `str` |
3186 | @return: `True` if a transition called `name` is present in | 3188 | @return: `True` if a transition called `name` is present in |
... | @@ -3190,7 +3192,7 @@ class PetriNet (object) : | ... | @@ -3190,7 +3192,7 @@ class PetriNet (object) : |
3190 | return name in self._trans | 3192 | return name in self._trans |
3191 | def has_node (self, name) : | 3193 | def has_node (self, name) : |
3192 | """Check if there is a transition called `name` in the net. | 3194 | """Check if there is a transition called `name` in the net. |
3193 | - | 3195 | + |
3194 | >>> n = PetriNet('N') | 3196 | >>> n = PetriNet('N') |
3195 | >>> n.has_node('t') | 3197 | >>> n.has_node('t') |
3196 | False | 3198 | False |
... | @@ -3202,7 +3204,7 @@ class PetriNet (object) : | ... | @@ -3202,7 +3204,7 @@ class PetriNet (object) : |
3202 | True | 3204 | True |
3203 | >>> n.has_node('p') | 3205 | >>> n.has_node('p') |
3204 | True | 3206 | True |
3205 | - | 3207 | + |
3206 | @param name: the name of the searched node | 3208 | @param name: the name of the searched node |
3207 | @type name: `str` | 3209 | @type name: `str` |
3208 | @return: `True` if a node called `name` is present in the net, | 3210 | @return: `True` if a node called `name` is present in the net, |
... | @@ -3212,7 +3214,7 @@ class PetriNet (object) : | ... | @@ -3212,7 +3214,7 @@ class PetriNet (object) : |
3212 | return name in self._node | 3214 | return name in self._node |
3213 | def __contains__ (self, name) : | 3215 | def __contains__ (self, name) : |
3214 | """`name in net` is a shortcut for `net.has_node(name)` | 3216 | """`name in net` is a shortcut for `net.has_node(name)` |
3215 | - | 3217 | + |
3216 | >>> n = PetriNet('N') | 3218 | >>> n = PetriNet('N') |
3217 | >>> 't' in n | 3219 | >>> 't' in n |
3218 | False | 3220 | False |
... | @@ -3224,7 +3226,7 @@ class PetriNet (object) : | ... | @@ -3224,7 +3226,7 @@ class PetriNet (object) : |
3224 | True | 3226 | True |
3225 | >>> 'p' in n | 3227 | >>> 'p' in n |
3226 | True | 3228 | True |
3227 | - | 3229 | + |
3228 | @param name: the name of the searched node | 3230 | @param name: the name of the searched node |
3229 | @type name: `str` | 3231 | @type name: `str` |
3230 | @return: `True` if a node called `name` is present in the net, | 3232 | @return: `True` if a node called `name` is present in the net, |
... | @@ -3234,7 +3236,7 @@ class PetriNet (object) : | ... | @@ -3234,7 +3236,7 @@ class PetriNet (object) : |
3234 | return name in self._node | 3236 | return name in self._node |
3235 | def declare (self, statements, locals=None) : | 3237 | def declare (self, statements, locals=None) : |
3236 | """Execute `statements` in the global dictionnary of the net. | 3238 | """Execute `statements` in the global dictionnary of the net. |
3237 | - | 3239 | + |
3238 | This has also on the dictionnarie of the instances of | 3240 | This has also on the dictionnarie of the instances of |
3239 | `Expression` in the net (guards of the transitions and labels | 3241 | `Expression` in the net (guards of the transitions and labels |
3240 | on the arcs) so the declarations have an influence over the | 3242 | on the arcs) so the declarations have an influence over the |
... | @@ -3242,7 +3244,7 @@ class PetriNet (object) : | ... | @@ -3242,7 +3244,7 @@ class PetriNet (object) : |
3242 | the declared objects will be placed in it instead of the | 3244 | the declared objects will be placed in it instead of the |
3243 | global dictionnary, see the documentation of Python for more | 3245 | global dictionnary, see the documentation of Python for more |
3244 | details about local and global environments. | 3246 | details about local and global environments. |
3245 | - | 3247 | + |
3246 | >>> n = PetriNet('N') | 3248 | >>> n = PetriNet('N') |
3247 | >>> t = Transition('t', Expression('x==0')) | 3249 | >>> t = Transition('t', Expression('x==0')) |
3248 | >>> n.add_transition(t) | 3250 | >>> n.add_transition(t) |
... | @@ -3265,7 +3267,7 @@ class PetriNet (object) : | ... | @@ -3265,7 +3267,7 @@ class PetriNet (object) : |
3265 | >>> t.fire(Substitution()) | 3267 | >>> t.fire(Substitution()) |
3266 | >>> n.place('p') | 3268 | >>> n.place('p') |
3267 | Place('p', MultiSet([0...]), tAll) | 3269 | Place('p', MultiSet([0...]), tAll) |
3268 | - | 3270 | + |
3269 | @param statements: a Python instruction suitable to `exec` | 3271 | @param statements: a Python instruction suitable to `exec` |
3270 | @type statements: `str` or `code` | 3272 | @type statements: `str` or `code` |
3271 | @param locals: a `dict` used as locals when `statements` is | 3273 | @param locals: a `dict` used as locals when `statements` is |
... | @@ -3276,10 +3278,10 @@ class PetriNet (object) : | ... | @@ -3276,10 +3278,10 @@ class PetriNet (object) : |
3276 | self._declare.append(statements) | 3278 | self._declare.append(statements) |
3277 | def add_place (self, place) : | 3279 | def add_place (self, place) : |
3278 | """Add a place to the net. | 3280 | """Add a place to the net. |
3279 | - | 3281 | + |
3280 | Each node in a net must have a name unique to this net, which | 3282 | Each node in a net must have a name unique to this net, which |
3281 | is checked when it is added. | 3283 | is checked when it is added. |
3282 | - | 3284 | + |
3283 | >>> n = PetriNet('N') | 3285 | >>> n = PetriNet('N') |
3284 | >>> try : n.place('p') | 3286 | >>> try : n.place('p') |
3285 | ... except ConstraintError : print(sys.exc_info()[1]) | 3287 | ... except ConstraintError : print(sys.exc_info()[1]) |
... | @@ -3292,7 +3294,7 @@ class PetriNet (object) : | ... | @@ -3292,7 +3294,7 @@ class PetriNet (object) : |
3292 | >>> try : n.add_place(Place('p')) | 3294 | >>> try : n.add_place(Place('p')) |
3293 | ... except ConstraintError : print(sys.exc_info()[1]) | 3295 | ... except ConstraintError : print(sys.exc_info()[1]) |
3294 | place 'p' exists | 3296 | place 'p' exists |
3295 | - | 3297 | + |
3296 | @param place: the place to add | 3298 | @param place: the place to add |
3297 | @type place: `Place` | 3299 | @type place: `Place` |
3298 | """ | 3300 | """ |
... | @@ -3308,7 +3310,7 @@ class PetriNet (object) : | ... | @@ -3308,7 +3310,7 @@ class PetriNet (object) : |
3308 | place.lock("post", self, {}) | 3310 | place.lock("post", self, {}) |
3309 | def remove_place (self, name) : | 3311 | def remove_place (self, name) : |
3310 | """Remove a place (given by its name) from the net. | 3312 | """Remove a place (given by its name) from the net. |
3311 | - | 3313 | + |
3312 | >>> n = PetriNet('N') | 3314 | >>> n = PetriNet('N') |
3313 | >>> try : n.remove_place('p') | 3315 | >>> try : n.remove_place('p') |
3314 | ... except ConstraintError : print(sys.exc_info()[1]) | 3316 | ... except ConstraintError : print(sys.exc_info()[1]) |
... | @@ -3320,7 +3322,7 @@ class PetriNet (object) : | ... | @@ -3320,7 +3322,7 @@ class PetriNet (object) : |
3320 | >>> try : n.place('p') | 3322 | >>> try : n.place('p') |
3321 | ... except ConstraintError : print(sys.exc_info()[1]) | 3323 | ... except ConstraintError : print(sys.exc_info()[1]) |
3322 | place 'p' not found | 3324 | place 'p' not found |
3323 | - | 3325 | + |
3324 | @param name: the name of the place to remove | 3326 | @param name: the name of the place to remove |
3325 | @type name: `str` | 3327 | @type name: `str` |
3326 | """ | 3328 | """ |
... | @@ -3340,10 +3342,10 @@ class PetriNet (object) : | ... | @@ -3340,10 +3342,10 @@ class PetriNet (object) : |
3340 | place.unlock("net", self, remove=True) | 3342 | place.unlock("net", self, remove=True) |
3341 | def add_transition (self, trans) : | 3343 | def add_transition (self, trans) : |
3342 | """Add a transition to the net. | 3344 | """Add a transition to the net. |
3343 | - | 3345 | + |
3344 | Each node in a net must have a name unique to this net, which | 3346 | Each node in a net must have a name unique to this net, which |
3345 | is checked when it is added. | 3347 | is checked when it is added. |
3346 | - | 3348 | + |
3347 | >>> n = PetriNet('N') | 3349 | >>> n = PetriNet('N') |
3348 | >>> try : n.transition('t') | 3350 | >>> try : n.transition('t') |
3349 | ... except ConstraintError : print(sys.exc_info()[1]) | 3351 | ... except ConstraintError : print(sys.exc_info()[1]) |
... | @@ -3354,7 +3356,7 @@ class PetriNet (object) : | ... | @@ -3354,7 +3356,7 @@ class PetriNet (object) : |
3354 | >>> try : n.add_transition(Transition('t')) | 3356 | >>> try : n.add_transition(Transition('t')) |
3355 | ... except ConstraintError : print(sys.exc_info()[1]) | 3357 | ... except ConstraintError : print(sys.exc_info()[1]) |
3356 | transition 't' exists | 3358 | transition 't' exists |
3357 | - | 3359 | + |
3358 | @param trans: the transition to add | 3360 | @param trans: the transition to add |
3359 | @type trans: `Transition` | 3361 | @type trans: `Transition` |
3360 | """ | 3362 | """ |
... | @@ -3371,7 +3373,7 @@ class PetriNet (object) : | ... | @@ -3371,7 +3373,7 @@ class PetriNet (object) : |
3371 | trans.guard.globals.attach(self.globals) | 3373 | trans.guard.globals.attach(self.globals) |
3372 | def remove_transition (self, name) : | 3374 | def remove_transition (self, name) : |
3373 | """Remove a transition (given by its name) from the net. | 3375 | """Remove a transition (given by its name) from the net. |
3374 | - | 3376 | + |
3375 | >>> n = PetriNet('N') | 3377 | >>> n = PetriNet('N') |
3376 | >>> try : n.remove_transition('t') | 3378 | >>> try : n.remove_transition('t') |
3377 | ... except ConstraintError : print(sys.exc_info()[1]) | 3379 | ... except ConstraintError : print(sys.exc_info()[1]) |
... | @@ -3383,7 +3385,7 @@ class PetriNet (object) : | ... | @@ -3383,7 +3385,7 @@ class PetriNet (object) : |
3383 | >>> try : n.transition('t') | 3385 | >>> try : n.transition('t') |
3384 | ... except ConstraintError : print(sys.exc_info()[1]) | 3386 | ... except ConstraintError : print(sys.exc_info()[1]) |
3385 | transition 't' not found | 3387 | transition 't' not found |
3386 | - | 3388 | + |
3387 | @param name: the name of the transition to remove | 3389 | @param name: the name of the transition to remove |
3388 | @type name: `str` | 3390 | @type name: `str` |
3389 | """ | 3391 | """ |
... | @@ -3404,7 +3406,7 @@ class PetriNet (object) : | ... | @@ -3404,7 +3406,7 @@ class PetriNet (object) : |
3404 | trans.guard.globals.detach(self.globals) | 3406 | trans.guard.globals.detach(self.globals) |
3405 | def place (self, name=None) : | 3407 | def place (self, name=None) : |
3406 | """Return one (if `name` is not `None`) or all the places. | 3408 | """Return one (if `name` is not `None`) or all the places. |
3407 | - | 3409 | + |
3408 | >>> n = PetriNet('N') | 3410 | >>> n = PetriNet('N') |
3409 | >>> n.add_place(Place('p1')) | 3411 | >>> n.add_place(Place('p1')) |
3410 | >>> n.add_place(Place('p2')) | 3412 | >>> n.add_place(Place('p2')) |
... | @@ -3415,7 +3417,7 @@ class PetriNet (object) : | ... | @@ -3415,7 +3417,7 @@ class PetriNet (object) : |
3415 | place 'p' not found | 3417 | place 'p' not found |
3416 | >>> n.place() | 3418 | >>> n.place() |
3417 | [Place('p2', MultiSet([]), tAll), Place('p1', MultiSet([]), tAll)] | 3419 | [Place('p2', MultiSet([]), tAll), Place('p1', MultiSet([]), tAll)] |
3418 | - | 3420 | + |
3419 | @param name: the name of the place to retrieve or `None` to | 3421 | @param name: the name of the place to retrieve or `None` to |
3420 | get the list of all the places in the net | 3422 | get the list of all the places in the net |
3421 | @type name: `str` or `None` | 3423 | @type name: `str` or `None` |
... | @@ -3431,7 +3433,7 @@ class PetriNet (object) : | ... | @@ -3431,7 +3433,7 @@ class PetriNet (object) : |
3431 | raise ConstraintError("place '%s' not found" % name) | 3433 | raise ConstraintError("place '%s' not found" % name) |
3432 | def transition (self, name=None) : | 3434 | def transition (self, name=None) : |
3433 | """Return one (if `name` is not `None`) or all the transitions. | 3435 | """Return one (if `name` is not `None`) or all the transitions. |
3434 | - | 3436 | + |
3435 | >>> n = PetriNet('N') | 3437 | >>> n = PetriNet('N') |
3436 | >>> n.add_transition(Transition('t1')) | 3438 | >>> n.add_transition(Transition('t1')) |
3437 | >>> n.add_transition(Transition('t2')) | 3439 | >>> n.add_transition(Transition('t2')) |
... | @@ -3442,7 +3444,7 @@ class PetriNet (object) : | ... | @@ -3442,7 +3444,7 @@ class PetriNet (object) : |
3442 | transition 't' not found | 3444 | transition 't' not found |
3443 | >>> n.transition() | 3445 | >>> n.transition() |
3444 | [Transition('t2', Expression('True')), Transition('t1', Expression('True'))] | 3446 | [Transition('t2', Expression('True')), Transition('t1', Expression('True'))] |
3445 | - | 3447 | + |
3446 | @param name: the name of the transition to retrieve or `None` | 3448 | @param name: the name of the transition to retrieve or `None` |
3447 | to get the list of all the transitions in the net | 3449 | to get the list of all the transitions in the net |
3448 | @type name: `str` or `None` | 3450 | @type name: `str` or `None` |
... | @@ -3459,7 +3461,7 @@ class PetriNet (object) : | ... | @@ -3459,7 +3461,7 @@ class PetriNet (object) : |
3459 | raise ConstraintError("transition '%s' not found" % name) | 3461 | raise ConstraintError("transition '%s' not found" % name) |
3460 | def node (self, name=None) : | 3462 | def node (self, name=None) : |
3461 | """Return one (if `name` is not `None`) or all the nodes. | 3463 | """Return one (if `name` is not `None`) or all the nodes. |
3462 | - | 3464 | + |
3463 | >>> n = PetriNet('N') | 3465 | >>> n = PetriNet('N') |
3464 | >>> n.add_transition(Transition('t')) | 3466 | >>> n.add_transition(Transition('t')) |
3465 | >>> n.add_place(Place('p')) | 3467 | >>> n.add_place(Place('p')) |
... | @@ -3470,7 +3472,7 @@ class PetriNet (object) : | ... | @@ -3470,7 +3472,7 @@ class PetriNet (object) : |
3470 | node 'x' not found | 3472 | node 'x' not found |
3471 | >>> list(sorted(n.node(), key=str)) | 3473 | >>> list(sorted(n.node(), key=str)) |
3472 | [Place('p', MultiSet([]), tAll), Transition('t', Expression('True'))] | 3474 | [Place('p', MultiSet([]), tAll), Transition('t', Expression('True'))] |
3473 | - | 3475 | + |
3474 | @param name: the name of the node to retrieve or `None` to get | 3476 | @param name: the name of the node to retrieve or `None` to get |
3475 | the list of all the nodes in the net | 3477 | the list of all the nodes in the net |
3476 | @type name: `str` or `None` | 3478 | @type name: `str` or `None` |
... | @@ -3487,9 +3489,9 @@ class PetriNet (object) : | ... | @@ -3487,9 +3489,9 @@ class PetriNet (object) : |
3487 | raise ConstraintError("node '%s' not found" % name) | 3489 | raise ConstraintError("node '%s' not found" % name) |
3488 | def add_input (self, place, trans, label) : | 3490 | def add_input (self, place, trans, label) : |
3489 | """Add an input arc between `place` and `trans` (nodes names). | 3491 | """Add an input arc between `place` and `trans` (nodes names). |
3490 | - | 3492 | + |
3491 | An input arc is directed from a place toward a transition. | 3493 | An input arc is directed from a place toward a transition. |
3492 | - | 3494 | + |
3493 | >>> n = PetriNet('N') | 3495 | >>> n = PetriNet('N') |
3494 | >>> n.add_place(Place('p', range(3))) | 3496 | >>> n.add_place(Place('p', range(3))) |
3495 | >>> n.add_transition(Transition('t', Expression('x!=1'))) | 3497 | >>> n.add_transition(Transition('t', Expression('x!=1'))) |
... | @@ -3509,7 +3511,7 @@ class PetriNet (object) : | ... | @@ -3509,7 +3511,7 @@ class PetriNet (object) : |
3509 | >>> try : n.add_input('p', 't', Value(42)) | 3511 | >>> try : n.add_input('p', 't', Value(42)) |
3510 | ... except ConstraintError: print(sys.exc_info()[1]) | 3512 | ... except ConstraintError: print(sys.exc_info()[1]) |
3511 | already connected to 'p' | 3513 | already connected to 'p' |
3512 | - | 3514 | + |
3513 | @param place: the name of the place to connect | 3515 | @param place: the name of the place to connect |
3514 | @type place: `str` | 3516 | @type place: `str` |
3515 | @param trans: the name of the transition to connect | 3517 | @param trans: the name of the transition to connect |
... | @@ -3534,7 +3536,7 @@ class PetriNet (object) : | ... | @@ -3534,7 +3536,7 @@ class PetriNet (object) : |
3534 | label.globals.attach(self.globals) | 3536 | label.globals.attach(self.globals) |
3535 | def remove_input (self, place, trans) : | 3537 | def remove_input (self, place, trans) : |
3536 | """Remove an input arc between `place` and `trans` (nodes names). | 3538 | """Remove an input arc between `place` and `trans` (nodes names). |
3537 | - | 3539 | + |
3538 | >>> n = PetriNet('N') | 3540 | >>> n = PetriNet('N') |
3539 | >>> n.add_place(Place('p', range(3))) | 3541 | >>> n.add_place(Place('p', range(3))) |
3540 | >>> n.add_transition(Transition('t', Expression('x!=1'))) | 3542 | >>> n.add_transition(Transition('t', Expression('x!=1'))) |
... | @@ -3547,7 +3549,7 @@ class PetriNet (object) : | ... | @@ -3547,7 +3549,7 @@ class PetriNet (object) : |
3547 | >>> try : n.remove_input('p', 't') | 3549 | >>> try : n.remove_input('p', 't') |
3548 | ... except ConstraintError : print(sys.exc_info()[1]) | 3550 | ... except ConstraintError : print(sys.exc_info()[1]) |
3549 | not connected to 'p' | 3551 | not connected to 'p' |
3550 | - | 3552 | + |
3551 | @param place: the name of the place to disconnect | 3553 | @param place: the name of the place to disconnect |
3552 | @type place: `str` | 3554 | @type place: `str` |
3553 | @param trans: the name of the transition to disconnect | 3555 | @param trans: the name of the transition to disconnect |
... | @@ -3569,9 +3571,9 @@ class PetriNet (object) : | ... | @@ -3569,9 +3571,9 @@ class PetriNet (object) : |
3569 | l.globals.detach(self.globals) | 3571 | l.globals.detach(self.globals) |
3570 | def add_output (self, place, trans, label) : | 3572 | def add_output (self, place, trans, label) : |
3571 | """Add an output arc between `place` and `trans` (nodes names). | 3573 | """Add an output arc between `place` and `trans` (nodes names). |
3572 | - | 3574 | + |
3573 | An output arc is directed from a transition toward a place. | 3575 | An output arc is directed from a transition toward a place. |
3574 | - | 3576 | + |
3575 | >>> n = PetriNet('N') | 3577 | >>> n = PetriNet('N') |
3576 | >>> n.add_place(Place('p')) | 3578 | >>> n.add_place(Place('p')) |
3577 | >>> n.add_transition(Transition('t')) | 3579 | >>> n.add_transition(Transition('t')) |
... | @@ -3586,7 +3588,7 @@ class PetriNet (object) : | ... | @@ -3586,7 +3588,7 @@ class PetriNet (object) : |
3586 | >>> try : n.add_output('p', 't', Value(42)) | 3588 | >>> try : n.add_output('p', 't', Value(42)) |
3587 | ... except ConstraintError : print(sys.exc_info()[1]) | 3589 | ... except ConstraintError : print(sys.exc_info()[1]) |
3588 | already connected to 'p' | 3590 | already connected to 'p' |
3589 | - | 3591 | + |
3590 | @param place: the name of the place to connect | 3592 | @param place: the name of the place to connect |
3591 | @type place: `str` | 3593 | @type place: `str` |
3592 | @param trans: the name of the transition to connect | 3594 | @param trans: the name of the transition to connect |
... | @@ -3610,7 +3612,7 @@ class PetriNet (object) : | ... | @@ -3610,7 +3612,7 @@ class PetriNet (object) : |
3610 | def remove_output (self, place, trans) : | 3612 | def remove_output (self, place, trans) : |
3611 | """Remove an output arc between `place` and `trans` (nodes | 3613 | """Remove an output arc between `place` and `trans` (nodes |
3612 | names). | 3614 | names). |
3613 | - | 3615 | + |
3614 | >>> n = PetriNet('N') | 3616 | >>> n = PetriNet('N') |
3615 | >>> n.add_place(Place('p')) | 3617 | >>> n.add_place(Place('p')) |
3616 | >>> n.add_transition(Transition('t')) | 3618 | >>> n.add_transition(Transition('t')) |
... | @@ -3623,7 +3625,7 @@ class PetriNet (object) : | ... | @@ -3623,7 +3625,7 @@ class PetriNet (object) : |
3623 | >>> try : n.remove_output('p', 't') | 3625 | >>> try : n.remove_output('p', 't') |
3624 | ... except ConstraintError : print(sys.exc_info()[1]) | 3626 | ... except ConstraintError : print(sys.exc_info()[1]) |
3625 | not connected to 'p' | 3627 | not connected to 'p' |
3626 | - | 3628 | + |
3627 | @param place: the name of the place to disconnect | 3629 | @param place: the name of the place to disconnect |
3628 | @type place: `str` | 3630 | @type place: `str` |
3629 | @param trans: the name of the transition to disconnect | 3631 | @param trans: the name of the transition to disconnect |
... | @@ -3645,9 +3647,9 @@ class PetriNet (object) : | ... | @@ -3645,9 +3647,9 @@ class PetriNet (object) : |
3645 | l.globals.detach(self.globals) | 3647 | l.globals.detach(self.globals) |
3646 | def pre (self, nodes) : | 3648 | def pre (self, nodes) : |
3647 | """Return the set of nodes names preceeding `nodes`. | 3649 | """Return the set of nodes names preceeding `nodes`. |
3648 | - | 3650 | + |
3649 | `nodes` can be a single node name ot a list of nodes names. | 3651 | `nodes` can be a single node name ot a list of nodes names. |
3650 | - | 3652 | + |
3651 | >>> n = PetriNet('N') | 3653 | >>> n = PetriNet('N') |
3652 | >>> n.add_place(Place('p1')) | 3654 | >>> n.add_place(Place('p1')) |
3653 | >>> n.add_place(Place('p2')) | 3655 | >>> n.add_place(Place('p2')) |
... | @@ -3659,7 +3661,7 @@ class PetriNet (object) : | ... | @@ -3659,7 +3661,7 @@ class PetriNet (object) : |
3659 | True | 3661 | True |
3660 | >>> n.pre(['p1', 'p2']) == set(['t2', 't1']) | 3662 | >>> n.pre(['p1', 'p2']) == set(['t2', 't1']) |
3661 | True | 3663 | True |
3662 | - | 3664 | + |
3663 | @param nodes: a single node name or a list of node names | 3665 | @param nodes: a single node name or a list of node names |
3664 | @type nodes: `str` or a `list` of `str` | 3666 | @type nodes: `str` or a `list` of `str` |
3665 | @return: a set of node names | 3667 | @return: a set of node names |
... | @@ -3674,9 +3676,9 @@ class PetriNet (object) : | ... | @@ -3674,9 +3676,9 @@ class PetriNet (object) : |
3674 | return result | 3676 | return result |
3675 | def post (self, nodes) : | 3677 | def post (self, nodes) : |
3676 | """Return the set of nodes names succeeding `nodes`. | 3678 | """Return the set of nodes names succeeding `nodes`. |
3677 | - | 3679 | + |
3678 | `nodes` can be a single node name ot a list of nodes names. | 3680 | `nodes` can be a single node name ot a list of nodes names. |
3679 | - | 3681 | + |
3680 | >>> n = PetriNet('N') | 3682 | >>> n = PetriNet('N') |
3681 | >>> n.add_place(Place('p1')) | 3683 | >>> n.add_place(Place('p1')) |
3682 | >>> n.add_place(Place('p2')) | 3684 | >>> n.add_place(Place('p2')) |
... | @@ -3688,7 +3690,7 @@ class PetriNet (object) : | ... | @@ -3688,7 +3690,7 @@ class PetriNet (object) : |
3688 | True | 3690 | True |
3689 | >>> n.post(['t1', 't2']) == set(['p2', 'p1']) | 3691 | >>> n.post(['t1', 't2']) == set(['p2', 'p1']) |
3690 | True | 3692 | True |
3691 | - | 3693 | + |
3692 | @param nodes: a single node name or a list of node names | 3694 | @param nodes: a single node name or a list of node names |
3693 | @type nodes: `str` or a `list` of `str` | 3695 | @type nodes: `str` or a `list` of `str` |
3694 | @return: a set of node names | 3696 | @return: a set of node names |
... | @@ -3703,7 +3705,7 @@ class PetriNet (object) : | ... | @@ -3703,7 +3705,7 @@ class PetriNet (object) : |
3703 | return result | 3705 | return result |
3704 | def get_marking (self) : | 3706 | def get_marking (self) : |
3705 | """Return the current marking of the net, omitting empty places. | 3707 | """Return the current marking of the net, omitting empty places. |
3706 | - | 3708 | + |
3707 | >>> n = PetriNet('N') | 3709 | >>> n = PetriNet('N') |
3708 | >>> n.add_place(Place('p0', range(0))) | 3710 | >>> n.add_place(Place('p0', range(0))) |
3709 | >>> n.add_place(Place('p1', range(1))) | 3711 | >>> n.add_place(Place('p1', range(1))) |
... | @@ -3711,7 +3713,7 @@ class PetriNet (object) : | ... | @@ -3711,7 +3713,7 @@ class PetriNet (object) : |
3711 | >>> n.add_place(Place('p3', range(3))) | 3713 | >>> n.add_place(Place('p3', range(3))) |
3712 | >>> n.get_marking() == Marking({'p2': MultiSet([0, 1]), 'p3': MultiSet([0, 1, 2]), 'p1': MultiSet([0])}) | 3714 | >>> n.get_marking() == Marking({'p2': MultiSet([0, 1]), 'p3': MultiSet([0, 1, 2]), 'p1': MultiSet([0])}) |
3713 | True | 3715 | True |
3714 | - | 3716 | + |
3715 | @return: the current marking | 3717 | @return: the current marking |
3716 | @rtype: `Marking` | 3718 | @rtype: `Marking` |
3717 | """ | 3719 | """ |
... | @@ -3720,14 +3722,14 @@ class PetriNet (object) : | ... | @@ -3720,14 +3722,14 @@ class PetriNet (object) : |
3720 | if not place.is_empty()) | 3722 | if not place.is_empty()) |
3721 | def _set_marking (self, marking) : | 3723 | def _set_marking (self, marking) : |
3722 | """Assign a marking to the net. | 3724 | """Assign a marking to the net. |
3723 | - | 3725 | + |
3724 | Places not listed in the marking are considered empty, the | 3726 | Places not listed in the marking are considered empty, the |
3725 | corresponding place in the net is thus emptied. If the marking | 3727 | corresponding place in the net is thus emptied. If the marking |
3726 | has places that do not belong to the net, these are ignored | 3728 | has places that do not belong to the net, these are ignored |
3727 | (as in the last instruction below). If an error occurs during | 3729 | (as in the last instruction below). If an error occurs during |
3728 | the assignment, the marking is left inconsistent. You should | 3730 | the assignment, the marking is left inconsistent. You should |
3729 | thus use `set_marking` unless you will have no error. | 3731 | thus use `set_marking` unless you will have no error. |
3730 | - | 3732 | + |
3731 | >>> n = PetriNet('N') | 3733 | >>> n = PetriNet('N') |
3732 | >>> n.add_place(Place('p0', range(5))) | 3734 | >>> n.add_place(Place('p0', range(5))) |
3733 | >>> n.add_place(Place('p1')) | 3735 | >>> n.add_place(Place('p1')) |
... | @@ -3746,7 +3748,7 @@ class PetriNet (object) : | ... | @@ -3746,7 +3748,7 @@ class PetriNet (object) : |
3746 | forbidden token '3.14' | 3748 | forbidden token '3.14' |
3747 | >>> n.get_marking() # inconsistent | 3749 | >>> n.get_marking() # inconsistent |
3748 | Marking({'p2': MultiSet([1])}) | 3750 | Marking({'p2': MultiSet([1])}) |
3749 | - | 3751 | + |
3750 | @param marking: the new marking | 3752 | @param marking: the new marking |
3751 | @type marking: `Marking` | 3753 | @type marking: `Marking` |
3752 | """ | 3754 | """ |
... | @@ -3757,13 +3759,13 @@ class PetriNet (object) : | ... | @@ -3757,13 +3759,13 @@ class PetriNet (object) : |
3757 | place.empty() | 3759 | place.empty() |
3758 | def set_marking (self, marking) : | 3760 | def set_marking (self, marking) : |
3759 | """Assign a marking to the net. | 3761 | """Assign a marking to the net. |
3760 | - | 3762 | + |
3761 | Places not listed in the marking are considered empty, the | 3763 | Places not listed in the marking are considered empty, the |
3762 | corresponding place in the net is thus emptied. If the marking | 3764 | corresponding place in the net is thus emptied. If the marking |
3763 | has places that do not belong to the net, these are ignored | 3765 | has places that do not belong to the net, these are ignored |
3764 | (as in the last instruction below). If an error occurs during | 3766 | (as in the last instruction below). If an error occurs during |
3765 | the assignment, the marking is left unchanged. | 3767 | the assignment, the marking is left unchanged. |
3766 | - | 3768 | + |
3767 | >>> n = PetriNet('N') | 3769 | >>> n = PetriNet('N') |
3768 | >>> n.add_place(Place('p0', range(5), tInteger)) | 3770 | >>> n.add_place(Place('p0', range(5), tInteger)) |
3769 | >>> n.add_place(Place('p1')) | 3771 | >>> n.add_place(Place('p1')) |
... | @@ -3782,7 +3784,7 @@ class PetriNet (object) : | ... | @@ -3782,7 +3784,7 @@ class PetriNet (object) : |
3782 | forbidden token '3.14' | 3784 | forbidden token '3.14' |
3783 | >>> n.get_marking() # unchanged | 3785 | >>> n.get_marking() # unchanged |
3784 | Marking({}) | 3786 | Marking({}) |
3785 | - | 3787 | + |
3786 | @param marking: the new marking | 3788 | @param marking: the new marking |
3787 | @type marking: `Marking` | 3789 | @type marking: `Marking` |
3788 | """ | 3790 | """ |
... | @@ -3794,11 +3796,11 @@ class PetriNet (object) : | ... | @@ -3794,11 +3796,11 @@ class PetriNet (object) : |
3794 | raise | 3796 | raise |
3795 | def add_marking (self, marking) : | 3797 | def add_marking (self, marking) : |
3796 | """Add a marking to the current one. | 3798 | """Add a marking to the current one. |
3797 | - | 3799 | + |
3798 | If an error occurs during the process, the marking is left | 3800 | If an error occurs during the process, the marking is left |
3799 | unchanged. Places in the marking that do not belong to the net | 3801 | unchanged. Places in the marking that do not belong to the net |
3800 | are ignored. | 3802 | are ignored. |
3801 | - | 3803 | + |
3802 | >>> n = PetriNet('N') | 3804 | >>> n = PetriNet('N') |
3803 | >>> n.add_place(Place('p1')) | 3805 | >>> n.add_place(Place('p1')) |
3804 | >>> n.add_place(Place('p2', range(3))) | 3806 | >>> n.add_place(Place('p2', range(3))) |
... | @@ -3807,7 +3809,7 @@ class PetriNet (object) : | ... | @@ -3807,7 +3809,7 @@ class PetriNet (object) : |
3807 | >>> n.add_marking(Marking(p1=MultiSet(range(2)), p2=MultiSet([1]))) | 3809 | >>> n.add_marking(Marking(p1=MultiSet(range(2)), p2=MultiSet([1]))) |
3808 | >>> n.get_marking() == Marking({'p2': MultiSet([0, 1, 1, 2]), 'p1': MultiSet([0, 1])}) | 3810 | >>> n.get_marking() == Marking({'p2': MultiSet([0, 1, 1, 2]), 'p1': MultiSet([0, 1])}) |
3809 | True | 3811 | True |
3810 | - | 3812 | + |
3811 | @param marking: the new marking | 3813 | @param marking: the new marking |
3812 | @type marking: `Marking` | 3814 | @type marking: `Marking` |
3813 | """ | 3815 | """ |
... | @@ -3821,11 +3823,11 @@ class PetriNet (object) : | ... | @@ -3821,11 +3823,11 @@ class PetriNet (object) : |
3821 | raise | 3823 | raise |
3822 | def remove_marking (self, marking) : | 3824 | def remove_marking (self, marking) : |
3823 | """Substract a marking from the current one. | 3825 | """Substract a marking from the current one. |
3824 | - | 3826 | + |
3825 | If an error occurs during the process, the marking is left | 3827 | If an error occurs during the process, the marking is left |
3826 | unchanged. Places in the marking that do not belong to the net | 3828 | unchanged. Places in the marking that do not belong to the net |
3827 | are ignored. | 3829 | are ignored. |
3828 | - | 3830 | + |
3829 | >>> n = PetriNet('N') | 3831 | >>> n = PetriNet('N') |
3830 | >>> n.add_place(Place('p1')) | 3832 | >>> n.add_place(Place('p1')) |
3831 | >>> n.add_place(Place('p2', range(3))) | 3833 | >>> n.add_place(Place('p2', range(3))) |
... | @@ -3839,7 +3841,7 @@ class PetriNet (object) : | ... | @@ -3839,7 +3841,7 @@ class PetriNet (object) : |
3839 | >>> n.remove_marking(Marking(p2=MultiSet([1]))) | 3841 | >>> n.remove_marking(Marking(p2=MultiSet([1]))) |
3840 | >>> n.get_marking() == Marking({'p2': MultiSet([0, 2])}) | 3842 | >>> n.get_marking() == Marking({'p2': MultiSet([0, 2])}) |
3841 | True | 3843 | True |
3842 | - | 3844 | + |
3843 | @param marking: the new marking | 3845 | @param marking: the new marking |
3844 | @type marking: `Marking` | 3846 | @type marking: `Marking` |
3845 | """ | 3847 | """ |
... | @@ -3853,7 +3855,7 @@ class PetriNet (object) : | ... | @@ -3853,7 +3855,7 @@ class PetriNet (object) : |
3853 | raise | 3855 | raise |
3854 | def rename_node (self, old, new) : | 3856 | def rename_node (self, old, new) : |
3855 | """Change the name of a node. | 3857 | """Change the name of a node. |
3856 | - | 3858 | + |
3857 | >>> n = PetriNet('N') | 3859 | >>> n = PetriNet('N') |
3858 | >>> n.add_place(Place('p')) | 3860 | >>> n.add_place(Place('p')) |
3859 | >>> n.add_transition(Transition('t')) | 3861 | >>> n.add_transition(Transition('t')) |
... | @@ -3873,7 +3875,7 @@ class PetriNet (object) : | ... | @@ -3873,7 +3875,7 @@ class PetriNet (object) : |
3873 | >>> try : n.rename_node('old_t', 'new_t') | 3875 | >>> try : n.rename_node('old_t', 'new_t') |
3874 | ... except ConstraintError : print(sys.exc_info()[1]) | 3876 | ... except ConstraintError : print(sys.exc_info()[1]) |
3875 | node 'old_t' not found | 3877 | node 'old_t' not found |
3876 | - | 3878 | + |
3877 | @param old: the current name of the node | 3879 | @param old: the current name of the node |
3878 | @type old: `str` | 3880 | @type old: `str` |
3879 | @param new: the new name for the node | 3881 | @param new: the new name for the node |
... | @@ -3903,7 +3905,7 @@ class PetriNet (object) : | ... | @@ -3903,7 +3905,7 @@ class PetriNet (object) : |
3903 | del other.pre[old] | 3905 | del other.pre[old] |
3904 | def copy_place (self, source, targets) : | 3906 | def copy_place (self, source, targets) : |
3905 | """Make copies of the `source` place (use place names). | 3907 | """Make copies of the `source` place (use place names). |
3906 | - | 3908 | + |
3907 | >>> n = PetriNet('N') | 3909 | >>> n = PetriNet('N') |
3908 | >>> n.add_place(Place('p', range(3))) | 3910 | >>> n.add_place(Place('p', range(3))) |
3909 | >>> n.add_transition(Transition('t')) | 3911 | >>> n.add_transition(Transition('t')) |
... | @@ -3917,7 +3919,7 @@ class PetriNet (object) : | ... | @@ -3917,7 +3919,7 @@ class PetriNet (object) : |
3917 | Place('ter', MultiSet([...]), tAll)] | 3919 | Place('ter', MultiSet([...]), tAll)] |
3918 | >>> list(sorted(n.pre('t'), key=str)) | 3920 | >>> list(sorted(n.pre('t'), key=str)) |
3919 | ['bis', 'more', 'p', 'ter'] | 3921 | ['bis', 'more', 'p', 'ter'] |
3920 | - | 3922 | + |
3921 | @param source: the name of the place to copy | 3923 | @param source: the name of the place to copy |
3922 | @type source: `str` | 3924 | @type source: `str` |
3923 | @param targets: a name or a list of names for the copie(s) | 3925 | @param targets: a name or a list of names for the copie(s) |
... | @@ -3932,7 +3934,7 @@ class PetriNet (object) : | ... | @@ -3932,7 +3934,7 @@ class PetriNet (object) : |
3932 | self.add_output(target, trans, label.copy()) | 3934 | self.add_output(target, trans, label.copy()) |
3933 | def copy_transition (self, source, targets) : | 3935 | def copy_transition (self, source, targets) : |
3934 | """Make copies of the `source` transition (use transition names). | 3936 | """Make copies of the `source` transition (use transition names). |
3935 | - | 3937 | + |
3936 | >>> n = PetriNet('N') | 3938 | >>> n = PetriNet('N') |
3937 | >>> n.add_transition(Transition('t', Expression('x==1'))) | 3939 | >>> n.add_transition(Transition('t', Expression('x==1'))) |
3938 | >>> n.add_place(Place('p')) | 3940 | >>> n.add_place(Place('p')) |
... | @@ -3946,7 +3948,7 @@ class PetriNet (object) : | ... | @@ -3946,7 +3948,7 @@ class PetriNet (object) : |
3946 | Transition('ter', Expression('x==1'))] | 3948 | Transition('ter', Expression('x==1'))] |
3947 | >>> list(sorted(n.post('p'))) | 3949 | >>> list(sorted(n.post('p'))) |
3948 | ['bis', 'more', 't', 'ter'] | 3950 | ['bis', 'more', 't', 'ter'] |
3949 | - | 3951 | + |
3950 | @param source: the name of the transition to copy | 3952 | @param source: the name of the transition to copy |
3951 | @type source: `str` | 3953 | @type source: `str` |
3952 | @param targets: a name or a list of names for the copie(s) | 3954 | @param targets: a name or a list of names for the copie(s) |
... | @@ -3961,11 +3963,11 @@ class PetriNet (object) : | ... | @@ -3961,11 +3963,11 @@ class PetriNet (object) : |
3961 | self.add_output(place, target, label.copy()) | 3963 | self.add_output(place, target, label.copy()) |
3962 | def merge_places (self, target, sources) : | 3964 | def merge_places (self, target, sources) : |
3963 | """Create a new place by merging those in `sources`. | 3965 | """Create a new place by merging those in `sources`. |
3964 | - | 3966 | + |
3965 | Markings are added, place types are 'or'ed and arcs labels are | 3967 | Markings are added, place types are 'or'ed and arcs labels are |
3966 | joinded into multi-arcs, the sources places are not removed. | 3968 | joinded into multi-arcs, the sources places are not removed. |
3967 | Use places names. | 3969 | Use places names. |
3968 | - | 3970 | + |
3969 | >>> n = PetriNet('n') | 3971 | >>> n = PetriNet('n') |
3970 | >>> n.add_place(Place('p1', [1], tInteger)) | 3972 | >>> n.add_place(Place('p1', [1], tInteger)) |
3971 | >>> n.add_place(Place('p2', [2.0], tFloat)) | 3973 | >>> n.add_place(Place('p2', [2.0], tFloat)) |
... | @@ -3984,7 +3986,7 @@ class PetriNet (object) : | ... | @@ -3984,7 +3986,7 @@ class PetriNet (object) : |
3984 | True | 3986 | True |
3985 | >>> n.node('p').checker() | 3987 | >>> n.node('p').checker() |
3986 | (Instance(int) | Instance(float)) | 3988 | (Instance(int) | Instance(float)) |
3987 | - | 3989 | + |
3988 | @param target: the name of the created place | 3990 | @param target: the name of the created place |
3989 | @type target: `str` | 3991 | @type target: `str` |
3990 | @param sources: the list of places names to be merged (or a | 3992 | @param sources: the list of places names to be merged (or a |
... | @@ -4027,11 +4029,11 @@ class PetriNet (object) : | ... | @@ -4027,11 +4029,11 @@ class PetriNet (object) : |
4027 | self.add_output(target, trans, MultiArc(labels)) | 4029 | self.add_output(target, trans, MultiArc(labels)) |
4028 | def merge_transitions (self, target, sources) : | 4030 | def merge_transitions (self, target, sources) : |
4029 | """Create a new transition by merging those in `sources`. | 4031 | """Create a new transition by merging those in `sources`. |
4030 | - | 4032 | + |
4031 | Guards are 'and'ed and arcs labels are joinded into multi- | 4033 | Guards are 'and'ed and arcs labels are joinded into multi- |
4032 | arcs, the sources transitions are not removed. Use transitions | 4034 | arcs, the sources transitions are not removed. Use transitions |
4033 | names. | 4035 | names. |
4034 | - | 4036 | + |
4035 | >>> n = PetriNet('n') | 4037 | >>> n = PetriNet('n') |
4036 | >>> n.add_place(Place('p1')) | 4038 | >>> n.add_place(Place('p1')) |
4037 | >>> n.add_place(Place('p2')) | 4039 | >>> n.add_place(Place('p2')) |
... | @@ -4049,7 +4051,7 @@ class PetriNet (object) : | ... | @@ -4049,7 +4051,7 @@ class PetriNet (object) : |
4049 | Transition('t', Expression('(x==1) and (y==2)')) | 4051 | Transition('t', Expression('(x==1) and (y==2)')) |
4050 | >>> n.node('t').post | 4052 | >>> n.node('t').post |
4051 | {'p2': MultiArc((Value(2.0), Value(2.0))), 'p1': Value(1)} | 4053 | {'p2': MultiArc((Value(2.0), Value(2.0))), 'p1': Value(1)} |
4052 | - | 4054 | + |
4053 | @param target: the name of the created transition | 4055 | @param target: the name of the created transition |
4054 | @type target: `str` | 4056 | @type target: `str` |
4055 | @param sources: the list of transitions names to be merged (or | 4057 | @param sources: the list of transitions names to be merged (or |
... | @@ -4100,10 +4102,10 @@ class StateGraph (object) : | ... | @@ -4100,10 +4102,10 @@ class StateGraph (object) : |
4100 | "The graph of reachable markings of a net." | 4102 | "The graph of reachable markings of a net." |
4101 | def __init__ (self, net) : | 4103 | def __init__ (self, net) : |
4102 | """Initialise with the net. | 4104 | """Initialise with the net. |
4103 | - | 4105 | + |
4104 | >>> StateGraph(PetriNet('N')).net | 4106 | >>> StateGraph(PetriNet('N')).net |
4105 | PetriNet('N') | 4107 | PetriNet('N') |
4106 | - | 4108 | + |
4107 | @param net: the Petri net whose graph has to be computed | 4109 | @param net: the Petri net whose graph has to be computed |
4108 | @type net: `PetriNet` | 4110 | @type net: `PetriNet` |
4109 | """ | 4111 | """ |
... | @@ -4128,10 +4130,10 @@ class StateGraph (object) : | ... | @@ -4128,10 +4130,10 @@ class StateGraph (object) : |
4128 | return self._last | 4130 | return self._last |
4129 | def goto (self, state) : | 4131 | def goto (self, state) : |
4130 | """Change the current state to another (given by its number). | 4132 | """Change the current state to another (given by its number). |
4131 | - | 4133 | + |
4132 | This also changes the marking of the net consistently. Notice | 4134 | This also changes the marking of the net consistently. Notice |
4133 | that the state may not exist yet. | 4135 | that the state may not exist yet. |
4134 | - | 4136 | + |
4135 | >>> n = PetriNet('N') | 4137 | >>> n = PetriNet('N') |
4136 | >>> n.add_place(Place('p', [0])) | 4138 | >>> n.add_place(Place('p', [0])) |
4137 | >>> n.add_transition(Transition('t', Expression('x<5'))) | 4139 | >>> n.add_transition(Transition('t', Expression('x<5'))) |
... | @@ -4145,7 +4147,7 @@ class StateGraph (object) : | ... | @@ -4145,7 +4147,7 @@ class StateGraph (object) : |
4145 | >>> g.goto(2) | 4147 | >>> g.goto(2) |
4146 | >>> g.net.get_marking() | 4148 | >>> g.net.get_marking() |
4147 | Marking({'p': MultiSet([2])}) | 4149 | Marking({'p': MultiSet([2])}) |
4148 | - | 4150 | + |
4149 | @param state: the number of the state to go to | 4151 | @param state: the number of the state to go to |
4150 | @type state: non-negative `int` | 4152 | @type state: non-negative `int` |
4151 | """ | 4153 | """ |
... | @@ -4159,7 +4161,7 @@ class StateGraph (object) : | ... | @@ -4159,7 +4161,7 @@ class StateGraph (object) : |
4159 | raise ValueError("unknown state") | 4161 | raise ValueError("unknown state") |
4160 | def current (self) : | 4162 | def current (self) : |
4161 | """Return the number of the current state. | 4163 | """Return the number of the current state. |
4162 | - | 4164 | + |
4163 | >>> n = PetriNet('N') | 4165 | >>> n = PetriNet('N') |
4164 | >>> n.add_place(Place('p', [0])) | 4166 | >>> n.add_place(Place('p', [0])) |
4165 | >>> n.add_transition(Transition('t', Expression('x<5'))) | 4167 | >>> n.add_transition(Transition('t', Expression('x<5'))) |
... | @@ -4168,7 +4170,7 @@ class StateGraph (object) : | ... | @@ -4168,7 +4170,7 @@ class StateGraph (object) : |
4168 | >>> g = StateGraph(n) | 4170 | >>> g = StateGraph(n) |
4169 | >>> g.current() | 4171 | >>> g.current() |
4170 | 0 | 4172 | 0 |
4171 | - | 4173 | + |
4172 | @return: the number of the current state | 4174 | @return: the number of the current state |
4173 | @rtype: non-negative `int` | 4175 | @rtype: non-negative `int` |
4174 | """ | 4176 | """ |
... | @@ -4224,12 +4226,12 @@ class StateGraph (object) : | ... | @@ -4224,12 +4226,12 @@ class StateGraph (object) : |
4224 | return marking in self._state | 4226 | return marking in self._state |
4225 | def successors (self, state=None) : | 4227 | def successors (self, state=None) : |
4226 | """Return the successors of the current state. | 4228 | """Return the successors of the current state. |
4227 | - | 4229 | + |
4228 | The value returned is a dictionnary mapping the numbers of | 4230 | The value returned is a dictionnary mapping the numbers of |
4229 | successor states to pairs (trans, mode) representing the name | 4231 | successor states to pairs (trans, mode) representing the name |
4230 | of the transition and the binding needed to reach the new | 4232 | of the transition and the binding needed to reach the new |
4231 | state. | 4233 | state. |
4232 | - | 4234 | + |
4233 | >>> n = PetriNet('N') | 4235 | >>> n = PetriNet('N') |
4234 | >>> n.add_place(Place('p', [0])) | 4236 | >>> n.add_place(Place('p', [0])) |
4235 | >>> n.add_transition(Transition('t', Expression('x<5'))) | 4237 | >>> n.add_transition(Transition('t', Expression('x<5'))) |
... | @@ -4240,7 +4242,7 @@ class StateGraph (object) : | ... | @@ -4240,7 +4242,7 @@ class StateGraph (object) : |
4240 | >>> g.goto(2) | 4242 | >>> g.goto(2) |
4241 | >>> g.successors() | 4243 | >>> g.successors() |
4242 | {3: (Transition('t', Expression('x<5')), Substitution(x=2))} | 4244 | {3: (Transition('t', Expression('x<5')), Substitution(x=2))} |
4243 | - | 4245 | + |
4244 | @return: the dictionnary of successors and transitions to them | 4246 | @return: the dictionnary of successors and transitions to them |
4245 | @rtype: `dict` mapping non-negative `int` to `tuple` holding a | 4247 | @rtype: `dict` mapping non-negative `int` to `tuple` holding a |
4246 | `str` and a `Substitution` | 4248 | `str` and a `Substitution` |
... | @@ -4252,12 +4254,12 @@ class StateGraph (object) : | ... | @@ -4252,12 +4254,12 @@ class StateGraph (object) : |
4252 | for label in self._succ[state][succ]) | 4254 | for label in self._succ[state][succ]) |
4253 | def predecessors (self, state=None) : | 4255 | def predecessors (self, state=None) : |
4254 | """Return the predecessors states. | 4256 | """Return the predecessors states. |
4255 | - | 4257 | + |
4256 | The returned value is as in `successors`. Notice that if the | 4258 | The returned value is as in `successors`. Notice that if the |
4257 | graph is not complete, this value may be wrong: states | 4259 | graph is not complete, this value may be wrong: states |
4258 | computed in the future may lead to the current one thus | 4260 | computed in the future may lead to the current one thus |
4259 | becoming one of its predecessors. | 4261 | becoming one of its predecessors. |
4260 | - | 4262 | + |
4261 | >>> n = PetriNet('N') | 4263 | >>> n = PetriNet('N') |
4262 | >>> n.add_place(Place('p', [0])) | 4264 | >>> n.add_place(Place('p', [0])) |
4263 | >>> n.add_transition(Transition('t', Expression('x<5'))) | 4265 | >>> n.add_transition(Transition('t', Expression('x<5'))) |
... | @@ -4268,7 +4270,7 @@ class StateGraph (object) : | ... | @@ -4268,7 +4270,7 @@ class StateGraph (object) : |
4268 | >>> g.goto(2) | 4270 | >>> g.goto(2) |
4269 | >>> g.predecessors() | 4271 | >>> g.predecessors() |
4270 | {1: (Transition('t', Expression('x<5')), Substitution(x=1))} | 4272 | {1: (Transition('t', Expression('x<5')), Substitution(x=1))} |
4271 | - | 4273 | + |
4272 | @return: the dictionnary of predecessors and transitions to | 4274 | @return: the dictionnary of predecessors and transitions to |
4273 | them | 4275 | them |
4274 | @rtype: `dict` mapping non-negative `int` to `tuple` holding a | 4276 | @rtype: `dict` mapping non-negative `int` to `tuple` holding a |
... | @@ -4306,7 +4308,7 @@ class StateGraph (object) : | ... | @@ -4306,7 +4308,7 @@ class StateGraph (object) : |
4306 | return | 4308 | return |
4307 | def __len__ (self) : | 4309 | def __len__ (self) : |
4308 | """Return the number of states currently reached. | 4310 | """Return the number of states currently reached. |
4309 | - | 4311 | + |
4310 | >>> n = PetriNet('N') | 4312 | >>> n = PetriNet('N') |
4311 | >>> n.add_place(Place('p', [0])) | 4313 | >>> n.add_place(Place('p', [0])) |
4312 | >>> n.add_transition(Transition('t', Expression('x<5'))) | 4314 | >>> n.add_transition(Transition('t', Expression('x<5'))) |
... | @@ -4323,21 +4325,21 @@ class StateGraph (object) : | ... | @@ -4323,21 +4325,21 @@ class StateGraph (object) : |
4323 | 5 states known | 4325 | 5 states known |
4324 | 6 states known | 4326 | 6 states known |
4325 | 6 states known | 4327 | 6 states known |
4326 | - | 4328 | + |
4327 | @return: the number of states generated at call time | 4329 | @return: the number of states generated at call time |
4328 | @rtype: non-negative `int` | 4330 | @rtype: non-negative `int` |
4329 | """ | 4331 | """ |
4330 | return len(self._done) + len(self._todo) | 4332 | return len(self._done) + len(self._todo) |
4331 | def __iter__ (self) : | 4333 | def __iter__ (self) : |
4332 | """Iterate over the reachable states (numbers). | 4334 | """Iterate over the reachable states (numbers). |
4333 | - | 4335 | + |
4334 | If needed, the successors of each state are computed just | 4336 | If needed, the successors of each state are computed just |
4335 | before it is yield. So, if the graph is not complete, getting | 4337 | before it is yield. So, if the graph is not complete, getting |
4336 | the predecessors may be wrong during the iteration. | 4338 | the predecessors may be wrong during the iteration. |
4337 | - | 4339 | + |
4338 | **Warning:** the net may have an infinite state graph, which | 4340 | **Warning:** the net may have an infinite state graph, which |
4339 | is not checked. So you may enter an infinite iteration. | 4341 | is not checked. So you may enter an infinite iteration. |
4340 | - | 4342 | + |
4341 | >>> n = PetriNet('N') | 4343 | >>> n = PetriNet('N') |
4342 | >>> n.add_place(Place('p', [0])) | 4344 | >>> n.add_place(Place('p', [0])) |
4343 | >>> n.add_transition(Transition('t', Expression('x<5'))) | 4345 | >>> n.add_transition(Transition('t', Expression('x<5'))) |
... | @@ -4376,13 +4378,13 @@ class StateGraph (object) : | ... | @@ -4376,13 +4378,13 @@ class StateGraph (object) : |
4376 | self.goto(current) | 4378 | self.goto(current) |
4377 | def _build (self, stop=None) : | 4379 | def _build (self, stop=None) : |
4378 | """Build the complete reachability graph. | 4380 | """Build the complete reachability graph. |
4379 | - | 4381 | + |
4380 | The graph is build using a breadth first exploration as the | 4382 | The graph is build using a breadth first exploration as the |
4381 | newly computed states are put in a queue. | 4383 | newly computed states are put in a queue. |
4382 | - | 4384 | + |
4383 | **Warning:** this may be infinite! No check of this is | 4385 | **Warning:** this may be infinite! No check of this is |
4384 | performed. | 4386 | performed. |
4385 | - | 4387 | + |
4386 | >>> n = PetriNet('N') | 4388 | >>> n = PetriNet('N') |
4387 | >>> n.add_place(Place('p', [0])) | 4389 | >>> n.add_place(Place('p', [0])) |
4388 | >>> n.add_transition(Transition('t', Expression('x<5'))) | 4390 | >>> n.add_transition(Transition('t', Expression('x<5'))) |
... | @@ -4404,7 +4406,7 @@ class StateGraph (object) : | ... | @@ -4404,7 +4406,7 @@ class StateGraph (object) : |
4404 | pass | 4406 | pass |
4405 | def completed (self) : | 4407 | def completed (self) : |
4406 | """Check if all the reachable markings have been explored. | 4408 | """Check if all the reachable markings have been explored. |
4407 | - | 4409 | + |
4408 | >>> n = PetriNet('N') | 4410 | >>> n = PetriNet('N') |
4409 | >>> n.add_place(Place('p', [0])) | 4411 | >>> n.add_place(Place('p', [0])) |
4410 | >>> n.add_transition(Transition('t', Expression('x<5'))) | 4412 | >>> n.add_transition(Transition('t', Expression('x<5'))) |
... | @@ -4419,7 +4421,7 @@ class StateGraph (object) : | ... | @@ -4419,7 +4421,7 @@ class StateGraph (object) : |
4419 | 3 False | 4421 | 3 False |
4420 | 4 False | 4422 | 4 False |
4421 | 5 True | 4423 | 5 True |
4422 | - | 4424 | + |
4423 | @return: `True` if the graph has been completely computed, | 4425 | @return: `True` if the graph has been completely computed, |
4424 | `False` otherwise | 4426 | `False` otherwise |
4425 | @rtype: `bool` | 4427 | @rtype: `bool` |
... | @@ -4428,7 +4430,7 @@ class StateGraph (object) : | ... | @@ -4428,7 +4430,7 @@ class StateGraph (object) : |
4428 | def todo (self) : | 4430 | def todo (self) : |
4429 | """Return the number of states whose successors are not yet | 4431 | """Return the number of states whose successors are not yet |
4430 | computed. | 4432 | computed. |
4431 | - | 4433 | + |
4432 | >>> n = PetriNet('N') | 4434 | >>> n = PetriNet('N') |
4433 | >>> n.add_place(Place('p', [0])) | 4435 | >>> n.add_place(Place('p', [0])) |
4434 | >>> n.add_transition(Transition('t', Expression('x<5'))) | 4436 | >>> n.add_transition(Transition('t', Expression('x<5'))) |
... | @@ -4443,7 +4445,7 @@ class StateGraph (object) : | ... | @@ -4443,7 +4445,7 @@ class StateGraph (object) : |
4443 | 3 1 | 4445 | 3 1 |
4444 | 4 1 | 4446 | 4 1 |
4445 | 5 0 | 4447 | 5 0 |
4446 | - | 4448 | + |
4447 | @return: the number of pending states | 4449 | @return: the number of pending states |
4448 | @rtype: non-negative `int` | 4450 | @rtype: non-negative `int` |
4449 | """ | 4451 | """ | ... | ... |
1 | -"""A plugins system. | 1 | +"""This package implements SNAKES plugin system. SNAKES plugins |
2 | +themselves are available as modules within the package. | ||
3 | + | ||
4 | +Examples below are based on plugin `hello` that is distributed with | ||
5 | +SNAKES to be used as an exemple of how to build a plugin. It extends | ||
6 | +class `PetriNet` adding a method `hello` that says hello displaying | ||
7 | +the name of the net. | ||
8 | + | ||
9 | +## Loading plugins ## | ||
2 | 10 | ||
3 | The first example shows how to load a plugin: we load | 11 | The first example shows how to load a plugin: we load |
4 | `snakes.plugins.hello` and plug it into `snakes.nets`, which results | 12 | `snakes.plugins.hello` and plug it into `snakes.nets`, which results |
5 | -in a new module that actually `snakes.nets` extended by | 13 | +in a new module that is actually `snakes.nets` extended by |
6 | `snakes.plugins.hello`. | 14 | `snakes.plugins.hello`. |
7 | 15 | ||
8 | >>> import snakes.plugins as plugins | 16 | >>> import snakes.plugins as plugins |
... | @@ -18,11 +26,6 @@ The next example shows how to simulate the effect of `import module`: | ... | @@ -18,11 +26,6 @@ The next example shows how to simulate the effect of `import module`: |
18 | we give to `load` a thrid argument that is the name of the created | 26 | we give to `load` a thrid argument that is the name of the created |
19 | module, from which it becomes possible to import names or `*`. | 27 | module, from which it becomes possible to import names or `*`. |
20 | 28 | ||
21 | -**Warning:** this feature will not work `load` is not called from the | ||
22 | -module where we then do the `from ... import ...`. This is exactly the | ||
23 | -same when, from a module `foo` that you load a module `bar`: if `bar` | ||
24 | -loads other modules they will not be imported in `foo`. | ||
25 | - | ||
26 | >>> plugins.load('hello', 'snakes.nets', 'another_version') | 29 | >>> plugins.load('hello', 'snakes.nets', 'another_version') |
27 | <module ...> | 30 | <module ...> |
28 | >>> from another_version import PetriNet | 31 | >>> from another_version import PetriNet |
... | @@ -33,12 +36,23 @@ Hello from another net | ... | @@ -33,12 +36,23 @@ Hello from another net |
33 | >>> n.hello() | 36 | >>> n.hello() |
34 | Hi, this is yet another net! | 37 | Hi, this is yet another net! |
35 | 38 | ||
36 | -How to define a plugin is explained in the example `hello`. | 39 | +The last example shows how to load several plugins at once, instead of |
40 | +giving one plugin name, we just need to give a list of plugin names. | ||
41 | + | ||
42 | +>>> plugins.load(['hello', 'pos'], 'snakes.nets', 'mynets') | ||
43 | +<module ...> | ||
44 | +>>> from mynets import PetriNet | ||
45 | +>>> n = PetriNet('a net') | ||
46 | +>>> n.hello() # works thanks to plugin `hello` | ||
47 | +Hello from a net | ||
48 | +>>> n.bbox() # works thanks to plugin `pos` | ||
49 | +((0, 0), (0, 0)) | ||
37 | """ | 50 | """ |
38 | 51 | ||
39 | import imp, sys, inspect | 52 | import imp, sys, inspect |
40 | from functools import wraps | 53 | from functools import wraps |
41 | 54 | ||
55 | +# apidoc skip | ||
42 | def update (module, objects) : | 56 | def update (module, objects) : |
43 | """Update a module content | 57 | """Update a module content |
44 | """ | 58 | """ |
... | @@ -54,48 +68,17 @@ def update (module, objects) : | ... | @@ -54,48 +68,17 @@ def update (module, objects) : |
54 | else : | 68 | else : |
55 | raise ValueError("cannot plug '%r'" % obj) | 69 | raise ValueError("cannot plug '%r'" % obj) |
56 | 70 | ||
57 | -def build (name, module, *objects) : | ||
58 | - """Builds an extended module. | ||
59 | - | ||
60 | - The parameter `module` is exactly that taken by the function | ||
61 | - `extend` of a plugin. This list argument `objects` holds all the | ||
62 | - objects, constructed in `extend`, that are extensions of objects | ||
63 | - from `module`. The resulting value should be returned by `extend`. | ||
64 | - | ||
65 | - @param name: the name of the constructed module | ||
66 | - @type name: `str` | ||
67 | - @param module: the extended module | ||
68 | - @type module: `module` | ||
69 | - @param objects: the sub-objects | ||
70 | - @type objects: each is a class object | ||
71 | - @return: the new module | ||
72 | - @rtype: `module` | ||
73 | - """ | ||
74 | - result = imp.new_module(name) | ||
75 | - result.__dict__.update(module.__dict__) | ||
76 | - update(result, objects) | ||
77 | - result.__plugins__ = (module.__dict__.get("__plugins__", | ||
78 | - (module.__name__,)) | ||
79 | - + (name,)) | ||
80 | - for obj in objects : | ||
81 | - if inspect.isclass(obj) : | ||
82 | - obj.__plugins__ = result.__plugins__ | ||
83 | - return result | ||
84 | - | ||
85 | def load (plugins, base, name=None) : | 71 | def load (plugins, base, name=None) : |
86 | - """Load plugins. | 72 | + """Load plugins, `plugins` can be a single plugin name, a module |
87 | - | 73 | + or a list of such values. If `name` is not `None`, the extended |
88 | - `plugins` can be a single plugin name or module or a list of such | 74 | + module is loaded as `name` in `sys.modules` as well as in the |
89 | - values. If `name` is not `None`, the extended module is loaded ad | 75 | + global environment from which `load` was called. |
90 | - `name` in `sys.modules` as well as in the global environment from | 76 | + |
91 | - which `load` was called. | ||
92 | - | ||
93 | @param plugins: the module that implements the plugin, or its | 77 | @param plugins: the module that implements the plugin, or its |
94 | - name, or a collection of such values | 78 | + name, or a collection (eg, list, tuple) of such values |
95 | - @type plugins: `str` or `module`, or a `list`/`tuple`/... of such | 79 | + @type plugins: `object` |
96 | - values | ||
97 | @param base: the module being extended or its name | 80 | @param base: the module being extended or its name |
98 | - @type base: `str` or `module` | 81 | + @type base: `object` |
99 | @param name: the name of the created module | 82 | @param name: the name of the created module |
100 | @type name: `str` | 83 | @type name: `str` |
101 | @return: the extended module | 84 | @return: the extended module |
... | @@ -125,17 +108,45 @@ def load (plugins, base, name=None) : | ... | @@ -125,17 +108,45 @@ def load (plugins, base, name=None) : |
125 | inspect.stack()[1][0].f_globals[name] = result | 108 | inspect.stack()[1][0].f_globals[name] = result |
126 | return result | 109 | return result |
127 | 110 | ||
111 | +"""## Creating plugins ### | ||
112 | + | ||
113 | +We show now how to develop a plugin that allows instances of | ||
114 | +`PetriNet` to say hello: a new method `PetriNet.hello` is added and | ||
115 | +the constructor `PetriNet.__init__` is added a keyword argument | ||
116 | +`hello` for the message to print when calling method `hello`. | ||
117 | + | ||
118 | +Defining a plugins required to write a module with a function called | ||
119 | +`extend` that takes as its single argument the module to be extended. | ||
120 | +Inside this function, extensions of the classes in the module are | ||
121 | +defined as normal sub-classes. Function `extend` returns the extended | ||
122 | +classes. A decorator called `plugin` must be used, it also allows to | ||
123 | +resolve plugin dependencies and conflicts. | ||
124 | +""" | ||
125 | + | ||
126 | +# apidoc include "hello.py" lang="python" | ||
127 | + | ||
128 | +"""Note that, when extending an existing method like `__init__` above, | ||
129 | +we have to take care that you may be working on an already extended | ||
130 | +class, consequently, we cannot know how its arguments have been | ||
131 | +changed already. So, we must always use those from the unextended | ||
132 | +method plus `**args`. Then, we remove from the latter what your plugin | ||
133 | +needs and pass the remaining to the method of the base class if we | ||
134 | +need to call it (which is usually the case). """ | ||
135 | + | ||
128 | def plugin (base, depends=[], conflicts=[]) : | 136 | def plugin (base, depends=[], conflicts=[]) : |
129 | """Decorator for extension functions | 137 | """Decorator for extension functions |
130 | - | 138 | + |
131 | - @param base: name of base module (usually 'snakes.nets') | 139 | + @param base: name of base module (usually 'snakes.nets') that the |
132 | - @type base: str | 140 | + plugin extends |
133 | - @param depends: list of plugins on which this one depends | 141 | + @type base: `str` |
134 | - @type depends: list of str | 142 | + @param depends: list of plugin names (as `str`) this one depends |
135 | - @param conflicts: list of plugins with which this one conflicts | 143 | + on, prefix `snakes.plugins.` may be omitted |
136 | - @type conflicts: list of str | 144 | + @type depends: `list` |
145 | + @param conflicts: list of plugin names with which this one | ||
146 | + conflicts | ||
147 | + @type conflicts: `list` | ||
137 | @return: the appropriate decorator | 148 | @return: the appropriate decorator |
138 | - @rtype: function | 149 | + @rtype: `decorator` |
139 | """ | 150 | """ |
140 | def wrapper (fun) : | 151 | def wrapper (fun) : |
141 | @wraps(fun) | 152 | @wraps(fun) |
... | @@ -164,9 +175,39 @@ def plugin (base, depends=[], conflicts=[]) : | ... | @@ -164,9 +175,39 @@ def plugin (base, depends=[], conflicts=[]) : |
164 | return extend | 175 | return extend |
165 | return wrapper | 176 | return wrapper |
166 | 177 | ||
178 | +# apidoc skip | ||
167 | def new_instance (cls, obj) : | 179 | def new_instance (cls, obj) : |
168 | """Create a copy of `obj` which is an instance of `cls` | 180 | """Create a copy of `obj` which is an instance of `cls` |
169 | """ | 181 | """ |
170 | result = object.__new__(cls) | 182 | result = object.__new__(cls) |
171 | result.__dict__.update(obj.__dict__) | 183 | result.__dict__.update(obj.__dict__) |
172 | return result | 184 | return result |
185 | + | ||
186 | +# apidoc skip | ||
187 | +def build (name, module, *objects) : | ||
188 | + """Builds an extended module. | ||
189 | + | ||
190 | + The parameter `module` is exactly that taken by the function | ||
191 | + `extend` of a plugin. This list argument `objects` holds all the | ||
192 | + objects, constructed in `extend`, that are extensions of objects | ||
193 | + from `module`. The resulting value should be returned by `extend`. | ||
194 | + | ||
195 | + @param name: the name of the constructed module | ||
196 | + @type name: `str` | ||
197 | + @param module: the extended module | ||
198 | + @type module: `module` | ||
199 | + @param objects: the sub-objects | ||
200 | + @type objects: each is a class object | ||
201 | + @return: the new module | ||
202 | + @rtype: `module` | ||
203 | + """ | ||
204 | + result = imp.new_module(name) | ||
205 | + result.__dict__.update(module.__dict__) | ||
206 | + update(result, objects) | ||
207 | + result.__plugins__ = (module.__dict__.get("__plugins__", | ||
208 | + (module.__name__,)) | ||
209 | + + (name,)) | ||
210 | + for obj in objects : | ||
211 | + if inspect.isclass(obj) : | ||
212 | + obj.__plugins__ = result.__plugins__ | ||
213 | + return result | ... | ... |
... | @@ -26,6 +26,8 @@ | ... | @@ -26,6 +26,8 @@ |
26 | >>> n.layout() | 26 | >>> n.layout() |
27 | >>> any(node.pos == (-100, -100) for node in sorted(n.node(), key=str)) | 27 | >>> any(node.pos == (-100, -100) for node in sorted(n.node(), key=str)) |
28 | False | 28 | False |
29 | + | ||
30 | +@todo: revise documentation | ||
29 | """ | 31 | """ |
30 | 32 | ||
31 | import os, os.path, subprocess, collections | 33 | import os, os.path, subprocess, collections | ... | ... |
1 | -"""An example plugin that allows instances class `PetriNet` to say hello. | 1 | +"""An example plugin that allows instances of `PetriNet` to |
2 | - | 2 | +say hello. The source code can be used as a starting |
3 | -A new method `hello` is added. The constructor is added a keyword | 3 | +example.""" |
4 | -argument `hello` that must be the `str` to print when calling `hello`, | ||
5 | -with one `%s` that will be replaced by the name of the net when | ||
6 | -`hello` is called. | ||
7 | - | ||
8 | -Defining a plugins need writing a module with a single function called | ||
9 | -`extend` that takes a single argument that is the module to be | ||
10 | -extended. | ||
11 | - | ||
12 | -Inside the function, extensions of the classes in the module are | ||
13 | -defined as normal sub-classes. | ||
14 | - | ||
15 | -The function `extend` should return the extended module created by | ||
16 | -`snakes.plugins.build` that takes as arguments: the name of the | ||
17 | -extended module, the module taken as argument and the sub-classes | ||
18 | -defined (expected as a list argument `*args` in no special order). | ||
19 | - | ||
20 | -If the plugin depends on other plugins, for instance `foo` and `bar`, | ||
21 | -the function `extend` should be decorated by `@depends('foo', 'bar')`. | ||
22 | - | ||
23 | -Read the source code of this module to have an example | ||
24 | -""" | ||
25 | 4 | ||
26 | import snakes.plugins | 5 | import snakes.plugins |
27 | 6 | ||
28 | @snakes.plugins.plugin("snakes.nets") | 7 | @snakes.plugins.plugin("snakes.nets") |
29 | def extend (module) : | 8 | def extend (module) : |
30 | - """Extends `module` | 9 | + "Extends `module`" |
31 | - """ | ||
32 | class PetriNet (module.PetriNet) : | 10 | class PetriNet (module.PetriNet) : |
33 | - """Extension of the class `PetriNet` in `module` | 11 | + "Extension of the class `PetriNet` in `module`" |
34 | - """ | ||
35 | def __init__ (self, name, **args) : | 12 | def __init__ (self, name, **args) : |
36 | - """When extending an existing method, take care that you may | 13 | + """Add new keyword argument `hello` |
37 | - be working on an already extended class, so you so not | 14 | + |
38 | - know how its arguments have been changed. So, always use | ||
39 | - those from the unextended class plus `**args`, remove from | ||
40 | - it what your plugin needs and pass it to the method of the | ||
41 | - extended class if you need to call it. | ||
42 | - | ||
43 | >>> PetriNet('N').hello() | 15 | >>> PetriNet('N').hello() |
44 | Hello from N | 16 | Hello from N |
45 | >>> PetriNet('N', hello='Hi! This is %s...').hello() | 17 | >>> PetriNet('N', hello='Hi! This is %s...').hello() |
46 | Hi! This is N... | 18 | Hi! This is N... |
47 | - | 19 | + |
48 | @param args: plugin options | 20 | @param args: plugin options |
49 | - @keyword hello: the message to print, with `%s` where the | 21 | + @keyword hello: the message to print, with |
50 | - net name should appear. | 22 | + `%s` where the net name should appear. |
51 | @type hello: `str` | 23 | @type hello: `str` |
52 | """ | 24 | """ |
53 | self._hello = args.pop("hello", "Hello from %s") | 25 | self._hello = args.pop("hello", "Hello from %s") |
54 | module.PetriNet.__init__(self, name, **args) | 26 | module.PetriNet.__init__(self, name, **args) |
55 | def hello (self) : | 27 | def hello (self) : |
56 | - """A new method `hello` | 28 | + "Ask the net to say hello" |
57 | - | ||
58 | - >>> n = PetriNet('N') | ||
59 | - >>> n.hello() | ||
60 | - Hello from N | ||
61 | - """ | ||
62 | print(self._hello % self.name) | 29 | print(self._hello % self.name) |
63 | return PetriNet | 30 | return PetriNet | ... | ... |
... | @@ -42,6 +42,8 @@ Position(1, 3) | ... | @@ -42,6 +42,8 @@ Position(1, 3) |
42 | >>> n.transpose() | 42 | >>> n.transpose() |
43 | >>> n.node('t01').pos | 43 | >>> n.node('t01').pos |
44 | Position(-3, 1) | 44 | Position(-3, 1) |
45 | + | ||
46 | +@todo: revise documentation | ||
45 | """ | 47 | """ |
46 | 48 | ||
47 | from snakes import SnakesError | 49 | from snakes import SnakesError | ... | ... |
1 | +""" | ||
2 | +@todo: revise (actually make) documentation | ||
3 | +""" | ||
4 | + | ||
1 | from snakes.plugins import plugin | 5 | from snakes.plugins import plugin |
2 | from snakes.pnml import Tree, loads, dumps | 6 | from snakes.pnml import Tree, loads, dumps |
3 | import imp, sys, socket, traceback, operator | 7 | import imp, sys, socket, traceback, operator | ... | ... |
... | @@ -12,6 +12,8 @@ Several status are defined by default: `entry`, `internal`, `exit`, | ... | @@ -12,6 +12,8 @@ Several status are defined by default: `entry`, `internal`, `exit`, |
12 | >>> n.add_place(Place('p1'), status=status.entry) | 12 | >>> n.add_place(Place('p1'), status=status.entry) |
13 | >>> n.place('p1') | 13 | >>> n.place('p1') |
14 | Place('p1', MultiSet([]), tAll, status=Status('entry')) | 14 | Place('p1', MultiSet([]), tAll, status=Status('entry')) |
15 | + | ||
16 | +@todo: revise documentation | ||
15 | """ | 17 | """ |
16 | 18 | ||
17 | import operator, weakref | 19 | import operator, weakref | ... | ... |
... | @@ -6,8 +6,6 @@ The plugin proposes a generalisation of the M-nets synchronisation in | ... | @@ -6,8 +6,6 @@ The plugin proposes a generalisation of the M-nets synchronisation in |
6 | that it does not impose a fixed correspondence between action names | 6 | that it does not impose a fixed correspondence between action names |
7 | and action arities. | 7 | and action arities. |
8 | 8 | ||
9 | - | ||
10 | - | ||
11 | * class `Action` corresponds to a synchronisable action, it has a | 9 | * class `Action` corresponds to a synchronisable action, it has a |
12 | name, a send/receive flag and a list of parameters. Actions have | 10 | name, a send/receive flag and a list of parameters. Actions have |
13 | no predetermined arities, only conjugated actions with the same | 11 | no predetermined arities, only conjugated actions with the same |
... | @@ -66,6 +64,8 @@ t2 z>0 | ... | @@ -66,6 +64,8 @@ t2 z>0 |
66 | >>> [t.name for t in sorted(n.transition(), key=str)] | 64 | >>> [t.name for t in sorted(n.transition(), key=str)] |
67 | ["((t1{...}+t2{...})[a(...)]{...}+t2{...})[a(...)]", | 65 | ["((t1{...}+t2{...})[a(...)]{...}+t2{...})[a(...)]", |
68 | "((t1{...}+t2{...})[a(...)]{...}+t2{...})[a(...)]"] | 66 | "((t1{...}+t2{...})[a(...)]{...}+t2{...})[a(...)]"] |
67 | + | ||
68 | +@todo: revise documentation | ||
69 | """ | 69 | """ |
70 | 70 | ||
71 | from snakes import ConstraintError | 71 | from snakes import ConstraintError |
... | @@ -91,6 +91,7 @@ class Action (object) : | ... | @@ -91,6 +91,7 @@ class Action (object) : |
91 | self.send = send | 91 | self.send = send |
92 | self.params = list(params) | 92 | self.params = list(params) |
93 | __pnmltag__ = "action" | 93 | __pnmltag__ = "action" |
94 | + # apidoc skip | ||
94 | def __pnmldump__ (self) : | 95 | def __pnmldump__ (self) : |
95 | """ | 96 | """ |
96 | >>> Action('a', True, [Value(1), Variable('x')]).__pnmldump__() | 97 | >>> Action('a', True, [Value(1), Variable('x')]).__pnmldump__() |
... | @@ -114,6 +115,7 @@ class Action (object) : | ... | @@ -114,6 +115,7 @@ class Action (object) : |
114 | for param in self.params : | 115 | for param in self.params : |
115 | result.add_child(Tree.from_obj(param)) | 116 | result.add_child(Tree.from_obj(param)) |
116 | return result | 117 | return result |
118 | + # apidoc skip | ||
117 | @classmethod | 119 | @classmethod |
118 | def __pnmlload__ (cls, tree) : | 120 | def __pnmlload__ (cls, tree) : |
119 | """ | 121 | """ |
... | @@ -136,6 +138,7 @@ class Action (object) : | ... | @@ -136,6 +138,7 @@ class Action (object) : |
136 | return "%s!(%s)" % (self.name, ",".join([str(p) for p in self])) | 138 | return "%s!(%s)" % (self.name, ",".join([str(p) for p in self])) |
137 | else : | 139 | else : |
138 | return "%s?(%s)" % (self.name, ",".join([str(p) for p in self])) | 140 | return "%s?(%s)" % (self.name, ",".join([str(p) for p in self])) |
141 | + # apidoc stop | ||
139 | def __repr__ (self) : | 142 | def __repr__ (self) : |
140 | """ | 143 | """ |
141 | >>> a = Action('a', True, [Value(1), Variable('x')]) | 144 | >>> a = Action('a', True, [Value(1), Variable('x')]) |
... | @@ -150,17 +153,17 @@ class Action (object) : | ... | @@ -150,17 +153,17 @@ class Action (object) : |
150 | ", ".join([repr(p) for p in self])) | 153 | ", ".join([repr(p) for p in self])) |
151 | def __len__ (self) : | 154 | def __len__ (self) : |
152 | """Return the number of parameters, aka the arity of the action. | 155 | """Return the number of parameters, aka the arity of the action. |
153 | - | 156 | + |
154 | >>> len(Action('a', True, [Value(1), Variable('x')])) | 157 | >>> len(Action('a', True, [Value(1), Variable('x')])) |
155 | 2 | 158 | 2 |
156 | - | 159 | + |
157 | @return: the arity of the action | 160 | @return: the arity of the action |
158 | @rtype: non negative `int` | 161 | @rtype: non negative `int` |
159 | """ | 162 | """ |
160 | return len(self.params) | 163 | return len(self.params) |
161 | def __iter__ (self) : | 164 | def __iter__ (self) : |
162 | """Iterate on the parameters | 165 | """Iterate on the parameters |
163 | - | 166 | + |
164 | >>> list(Action('a', True, [Value(1), Variable('x')])) | 167 | >>> list(Action('a', True, [Value(1), Variable('x')])) |
165 | [Value(1), Variable('x')] | 168 | [Value(1), Variable('x')] |
166 | """ | 169 | """ |
... | @@ -169,7 +172,7 @@ class Action (object) : | ... | @@ -169,7 +172,7 @@ class Action (object) : |
169 | def __eq__ (self, other) : | 172 | def __eq__ (self, other) : |
170 | """Two actions are equal if they have the same name, same send | 173 | """Two actions are equal if they have the same name, same send |
171 | flags and same parameters. | 174 | flags and same parameters. |
172 | - | 175 | + |
173 | >>> Action('a', True, [Value(1), Variable('x')]) == Action('a', True, [Value(1), Variable('x')]) | 176 | >>> Action('a', True, [Value(1), Variable('x')]) == Action('a', True, [Value(1), Variable('x')]) |
174 | True | 177 | True |
175 | >>> Action('a', True, [Value(1), Variable('x')]) == Action('b', True, [Value(1), Variable('x')]) | 178 | >>> Action('a', True, [Value(1), Variable('x')]) == Action('b', True, [Value(1), Variable('x')]) |
... | @@ -180,7 +183,7 @@ class Action (object) : | ... | @@ -180,7 +183,7 @@ class Action (object) : |
180 | False | 183 | False |
181 | >>> Action('a', True, [Value(1), Variable('x')]) == Action('a', True, [Value(1)]) | 184 | >>> Action('a', True, [Value(1), Variable('x')]) == Action('a', True, [Value(1)]) |
182 | False | 185 | False |
183 | - | 186 | + |
184 | @param other: the action to compare | 187 | @param other: the action to compare |
185 | @type other: `Action` | 188 | @type other: `Action` |
186 | @return: `True` if the two actions are equal, `False` | 189 | @return: `True` if the two actions are equal, `False` |
... | @@ -201,14 +204,14 @@ class Action (object) : | ... | @@ -201,14 +204,14 @@ class Action (object) : |
201 | return not (self == other) | 204 | return not (self == other) |
202 | def copy (self, subst=None) : | 205 | def copy (self, subst=None) : |
203 | """Copy the action, optionally substituting its parameters. | 206 | """Copy the action, optionally substituting its parameters. |
204 | - | 207 | + |
205 | >>> a = Action('a', True, [Variable('x'), Value(2)]) | 208 | >>> a = Action('a', True, [Variable('x'), Value(2)]) |
206 | >>> a.copy() | 209 | >>> a.copy() |
207 | Action('a', True, [Variable('x'), Value(2)]) | 210 | Action('a', True, [Variable('x'), Value(2)]) |
208 | >>> a = Action('a', True, [Variable('x'), Value(2)]) | 211 | >>> a = Action('a', True, [Variable('x'), Value(2)]) |
209 | >>> a.copy(Substitution(x=Value(3))) | 212 | >>> a.copy(Substitution(x=Value(3))) |
210 | Action('a', True, [Value(3), Value(2)]) | 213 | Action('a', True, [Value(3), Value(2)]) |
211 | - | 214 | + |
212 | @param subst: if not `None`, a substitution to apply to the | 215 | @param subst: if not `None`, a substitution to apply to the |
213 | parameters of the copy | 216 | parameters of the copy |
214 | @type subst: `None` or `Substitution` mapping variables names | 217 | @type subst: `None` or `Substitution` mapping variables names |
... | @@ -224,12 +227,12 @@ class Action (object) : | ... | @@ -224,12 +227,12 @@ class Action (object) : |
224 | return result | 227 | return result |
225 | def substitute (self, subst) : | 228 | def substitute (self, subst) : |
226 | """Substitute the parameters according to `subst` | 229 | """Substitute the parameters according to `subst` |
227 | - | 230 | + |
228 | >>> a = Action('a', True, [Variable('x'), Value(2)]) | 231 | >>> a = Action('a', True, [Variable('x'), Value(2)]) |
229 | >>> a.substitute(Substitution(x=Value(3))) | 232 | >>> a.substitute(Substitution(x=Value(3))) |
230 | >>> a | 233 | >>> a |
231 | Action('a', True, [Value(3), Value(2)]) | 234 | Action('a', True, [Value(3), Value(2)]) |
232 | - | 235 | + |
233 | @param subst: a substitution to apply to the parameters | 236 | @param subst: a substitution to apply to the parameters |
234 | @type subst: `Substitution` mapping variables names to `Value` | 237 | @type subst: `Substitution` mapping variables names to `Value` |
235 | or `Variable` | 238 | or `Variable` |
... | @@ -241,7 +244,7 @@ class Action (object) : | ... | @@ -241,7 +244,7 @@ class Action (object) : |
241 | """ | 244 | """ |
242 | >>> Action('a', True, [Value(3), Variable('x'), Variable('y'), Variable('x')]).vars() == set(['x', 'y']) | 245 | >>> Action('a', True, [Value(3), Variable('x'), Variable('y'), Variable('x')]).vars() == set(['x', 'y']) |
243 | True | 246 | True |
244 | - | 247 | + |
245 | @return: the set of variable names appearing in the parameters | 248 | @return: the set of variable names appearing in the parameters |
246 | of the action | 249 | of the action |
247 | @rtype: `set` of `str` | 250 | @rtype: `set` of `str` |
... | @@ -249,13 +252,13 @@ class Action (object) : | ... | @@ -249,13 +252,13 @@ class Action (object) : |
249 | return set(p.name for p in self.params if isinstance(p, Variable)) | 252 | return set(p.name for p in self.params if isinstance(p, Variable)) |
250 | def __and__ (self, other) : | 253 | def __and__ (self, other) : |
251 | """Compute an unification of two conjugated actions. | 254 | """Compute an unification of two conjugated actions. |
252 | - | 255 | + |
253 | An unification is a `Substitution` that maps variable names to | 256 | An unification is a `Substitution` that maps variable names to |
254 | `Variable` or `Values`. If both actions are substituted by | 257 | `Variable` or `Values`. If both actions are substituted by |
255 | this unification, their parameters lists become equal. If no | 258 | this unification, their parameters lists become equal. If no |
256 | unification can be found, `ConstraintError` is raised (or, | 259 | unification can be found, `ConstraintError` is raised (or, |
257 | rarely, `DomainError` depending on the cause of the failure). | 260 | rarely, `DomainError` depending on the cause of the failure). |
258 | - | 261 | + |
259 | >>> s = Action('a', True, [Value(3), Variable('x'), Variable('y'), Variable('x')]) | 262 | >>> s = Action('a', True, [Value(3), Variable('x'), Variable('y'), Variable('x')]) |
260 | >>> r = Action('a', False, [Value(3), Value(2), Variable('t'), Variable('z')]) | 263 | >>> r = Action('a', False, [Value(3), Value(2), Variable('t'), Variable('z')]) |
261 | >>> u = s & r | 264 | >>> u = s & r |
... | @@ -284,7 +287,7 @@ class Action (object) : | ... | @@ -284,7 +287,7 @@ class Action (object) : |
284 | >>> try : s & r | 287 | >>> try : s & r |
285 | ... except ConstraintError : print(sys.exc_info()[1]) | 288 | ... except ConstraintError : print(sys.exc_info()[1]) |
286 | actions not conjugated | 289 | actions not conjugated |
287 | - | 290 | + |
288 | @param other: the other action to unify with | 291 | @param other: the other action to unify with |
289 | @type other: `Action` | 292 | @type other: `Action` |
290 | @return: a substitution that unify both actions | 293 | @return: a substitution that unify both actions |
... | @@ -323,7 +326,7 @@ class MultiAction (object) : | ... | @@ -323,7 +326,7 @@ class MultiAction (object) : |
323 | ... Action('a', False, [Value(2)])]) | 326 | ... Action('a', False, [Value(2)])]) |
324 | ... except ConstraintError : print(sys.exc_info()[1]) | 327 | ... except ConstraintError : print(sys.exc_info()[1]) |
325 | conjugated actions in the same multiaction | 328 | conjugated actions in the same multiaction |
326 | - | 329 | + |
327 | @param actions: a collection of actions with no conjugated | 330 | @param actions: a collection of actions with no conjugated |
328 | actions in it | 331 | actions in it |
329 | @type actions: `list` of `Action` | 332 | @type actions: `list` of `Action` |
... | @@ -392,10 +395,10 @@ class MultiAction (object) : | ... | @@ -392,10 +395,10 @@ class MultiAction (object) : |
392 | def send (self, name) : | 395 | def send (self, name) : |
393 | """Returns the send flag of the action `name` in this | 396 | """Returns the send flag of the action `name` in this |
394 | multiaction. | 397 | multiaction. |
395 | - | 398 | + |
396 | This value is unique as conjugated actions are forbidden in | 399 | This value is unique as conjugated actions are forbidden in |
397 | the same multiaction. | 400 | the same multiaction. |
398 | - | 401 | + |
399 | >>> m = MultiAction([Action('a', True, [Variable('x')]), | 402 | >>> m = MultiAction([Action('a', True, [Variable('x')]), |
400 | ... Action('b', False, [Variable('y'), Value(2)])]) | 403 | ... Action('b', False, [Variable('y'), Value(2)])]) |
401 | >>> m.send('a'), m.send('b') | 404 | >>> m.send('a'), m.send('b') |
... | @@ -404,10 +407,10 @@ class MultiAction (object) : | ... | @@ -404,10 +407,10 @@ class MultiAction (object) : |
404 | return self._sndrcv[name] | 407 | return self._sndrcv[name] |
405 | def add (self, action) : | 408 | def add (self, action) : |
406 | """Add an action to the multiaction. | 409 | """Add an action to the multiaction. |
407 | - | 410 | + |
408 | This may raise `ConstraintError` if the added action is | 411 | This may raise `ConstraintError` if the added action is |
409 | conjugated to one that already belongs to the multiaction. | 412 | conjugated to one that already belongs to the multiaction. |
410 | - | 413 | + |
411 | @param action: the action to add | 414 | @param action: the action to add |
412 | @type action: `Action` | 415 | @type action: `Action` |
413 | """ | 416 | """ |
... | @@ -418,10 +421,10 @@ class MultiAction (object) : | ... | @@ -418,10 +421,10 @@ class MultiAction (object) : |
418 | self._actions.append(action) | 421 | self._actions.append(action) |
419 | def remove (self, action) : | 422 | def remove (self, action) : |
420 | """Remove an action from the multiaction. | 423 | """Remove an action from the multiaction. |
421 | - | 424 | + |
422 | This may raise `ValueError` if the removed action does belongs | 425 | This may raise `ValueError` if the removed action does belongs |
423 | to the multiaction. | 426 | to the multiaction. |
424 | - | 427 | + |
425 | @param action: the action to remove | 428 | @param action: the action to remove |
426 | @type action: `Action` | 429 | @type action: `Action` |
427 | """ | 430 | """ |
... | @@ -432,7 +435,7 @@ class MultiAction (object) : | ... | @@ -432,7 +435,7 @@ class MultiAction (object) : |
432 | del self._sndrcv[action.name] | 435 | del self._sndrcv[action.name] |
433 | def __iter__ (self) : | 436 | def __iter__ (self) : |
434 | """Iterate over the actions in the multiaction. | 437 | """Iterate over the actions in the multiaction. |
435 | - | 438 | + |
436 | >>> list(MultiAction([Action('a', True, [Variable('x')]), | 439 | >>> list(MultiAction([Action('a', True, [Variable('x')]), |
437 | ... Action('b', False, [Variable('y'), Value(2)])])) | 440 | ... Action('b', False, [Variable('y'), Value(2)])])) |
438 | [Action('a', True, [Variable('x')]), | 441 | [Action('a', True, [Variable('x')]), |
... | @@ -442,18 +445,18 @@ class MultiAction (object) : | ... | @@ -442,18 +445,18 @@ class MultiAction (object) : |
442 | yield action | 445 | yield action |
443 | def __len__ (self) : | 446 | def __len__ (self) : |
444 | """Return the number of actions in a multiaction. | 447 | """Return the number of actions in a multiaction. |
445 | - | 448 | + |
446 | >>> len(MultiAction([Action('a', True, [Variable('x')]), | 449 | >>> len(MultiAction([Action('a', True, [Variable('x')]), |
447 | ... Action('b', False, [Variable('y'), Value(2)])])) | 450 | ... Action('b', False, [Variable('y'), Value(2)])])) |
448 | 2 | 451 | 2 |
449 | - | 452 | + |
450 | @return: the number of contained actions | 453 | @return: the number of contained actions |
451 | @rtype: non negative `int` | 454 | @rtype: non negative `int` |
452 | """ | 455 | """ |
453 | return len(self._actions) | 456 | return len(self._actions) |
454 | def substitute (self, subst) : | 457 | def substitute (self, subst) : |
455 | """Substitute bu `subt` all the actions in the multiaction. | 458 | """Substitute bu `subt` all the actions in the multiaction. |
456 | - | 459 | + |
457 | >>> m = MultiAction([Action('a', True, [Variable('x')]), | 460 | >>> m = MultiAction([Action('a', True, [Variable('x')]), |
458 | ... Action('b', False, [Variable('y'), Variable('x')])]) | 461 | ... Action('b', False, [Variable('y'), Variable('x')])]) |
459 | >>> m.substitute(Substitution(x=Value(4))) | 462 | >>> m.substitute(Substitution(x=Value(4))) |
... | @@ -466,7 +469,7 @@ class MultiAction (object) : | ... | @@ -466,7 +469,7 @@ class MultiAction (object) : |
466 | def copy (self, subst=None) : | 469 | def copy (self, subst=None) : |
467 | """Copy the multiaction (and the actions is contains) optionally | 470 | """Copy the multiaction (and the actions is contains) optionally |
468 | substituting it. | 471 | substituting it. |
469 | - | 472 | + |
470 | @param subst: if not `None`, the substitution to apply to the | 473 | @param subst: if not `None`, the substitution to apply to the |
471 | copy. | 474 | copy. |
472 | @type subst: `None` or `Substitution` | 475 | @type subst: `None` or `Substitution` |
... | @@ -479,10 +482,10 @@ class MultiAction (object) : | ... | @@ -479,10 +482,10 @@ class MultiAction (object) : |
479 | return result | 482 | return result |
480 | def __contains__ (self, action) : | 483 | def __contains__ (self, action) : |
481 | """Search an action in the multiaction. | 484 | """Search an action in the multiaction. |
482 | - | 485 | + |
483 | The searched action may be a complete `Action`, just an action | 486 | The searched action may be a complete `Action`, just an action |
484 | name, or a pair `(name, send_flag)`. | 487 | name, or a pair `(name, send_flag)`. |
485 | - | 488 | + |
486 | >>> m = MultiAction([Action('a', True, [Variable('x'), Value(2)]), | 489 | >>> m = MultiAction([Action('a', True, [Variable('x'), Value(2)]), |
487 | ... Action('a', True, [Value(3), Variable('y')]), | 490 | ... Action('a', True, [Value(3), Variable('y')]), |
488 | ... Action('b', False, [Variable('x'), Variable('y')])]) | 491 | ... Action('b', False, [Variable('x'), Variable('y')])]) |
... | @@ -498,7 +501,7 @@ class MultiAction (object) : | ... | @@ -498,7 +501,7 @@ class MultiAction (object) : |
498 | False | 501 | False |
499 | >>> Action('c', True, [Variable('x'), Value(2)]) in m | 502 | >>> Action('c', True, [Variable('x'), Value(2)]) in m |
500 | False | 503 | False |
501 | - | 504 | + |
502 | @param action: an complete action, or its name or its name and | 505 | @param action: an complete action, or its name or its name and |
503 | send flag | 506 | send flag |
504 | @type action: `Action` or `str` or `tuple(str, bool)` | 507 | @type action: `Action` or `str` or `tuple(str, bool)` |
... | @@ -517,7 +520,7 @@ class MultiAction (object) : | ... | @@ -517,7 +520,7 @@ class MultiAction (object) : |
517 | raise ValueError("invalid action specification") | 520 | raise ValueError("invalid action specification") |
518 | def __add__ (self, other) : | 521 | def __add__ (self, other) : |
519 | """Create a multiaction by adding the actions of two others. | 522 | """Create a multiaction by adding the actions of two others. |
520 | - | 523 | + |
521 | >>> m = MultiAction([Action('a', True, [Variable('x'), Value(2)]), | 524 | >>> m = MultiAction([Action('a', True, [Variable('x'), Value(2)]), |
522 | ... Action('a', True, [Value(3), Variable('y')]), | 525 | ... Action('a', True, [Value(3), Variable('y')]), |
523 | ... Action('b', False, [Variable('x'), Variable('y')])]) | 526 | ... Action('b', False, [Variable('x'), Variable('y')])]) |
... | @@ -533,7 +536,7 @@ class MultiAction (object) : | ... | @@ -533,7 +536,7 @@ class MultiAction (object) : |
533 | Action('a', True, [Value(3), Variable('y')]), | 536 | Action('a', True, [Value(3), Variable('y')]), |
534 | Action('b', False, [Variable('x'), Variable('y')]), | 537 | Action('b', False, [Variable('x'), Variable('y')]), |
535 | Action('c', True, [])]) | 538 | Action('c', True, [])]) |
536 | - | 539 | + |
537 | @param other: the other multiaction to combine or a single | 540 | @param other: the other multiaction to combine or a single |
538 | action | 541 | action |
539 | @type other: `MultiAction` or `Action` | 542 | @type other: `MultiAction` or `Action` |
... | @@ -549,7 +552,7 @@ class MultiAction (object) : | ... | @@ -549,7 +552,7 @@ class MultiAction (object) : |
549 | def __sub__ (self, other) : | 552 | def __sub__ (self, other) : |
550 | """Create a multiaction by substracting the actions of two | 553 | """Create a multiaction by substracting the actions of two |
551 | others. | 554 | others. |
552 | - | 555 | + |
553 | >>> m = MultiAction([Action('a', True, [Variable('x'), Value(2)]), | 556 | >>> m = MultiAction([Action('a', True, [Variable('x'), Value(2)]), |
554 | ... Action('a', True, [Value(3), Variable('y')]), | 557 | ... Action('a', True, [Value(3), Variable('y')]), |
555 | ... Action('b', False, [Variable('x'), Variable('y')])]) | 558 | ... Action('b', False, [Variable('x'), Variable('y')])]) |
... | @@ -558,7 +561,7 @@ class MultiAction (object) : | ... | @@ -558,7 +561,7 @@ class MultiAction (object) : |
558 | >>> m - Action('b', False, [Variable('x'), Variable('y')]) | 561 | >>> m - Action('b', False, [Variable('x'), Variable('y')]) |
559 | MultiAction([Action('a', True, [Variable('x'), Value(2)]), | 562 | MultiAction([Action('a', True, [Variable('x'), Value(2)]), |
560 | Action('a', True, [Value(3), Variable('y')])]) | 563 | Action('a', True, [Value(3), Variable('y')])]) |
561 | - | 564 | + |
562 | @param other: the other multiaction to combine or a single | 565 | @param other: the other multiaction to combine or a single |
563 | action | 566 | action |
564 | @type other: `MultiAction` or `Action` | 567 | @type other: `MultiAction` or `Action` |
... | @@ -574,12 +577,12 @@ class MultiAction (object) : | ... | @@ -574,12 +577,12 @@ class MultiAction (object) : |
574 | def vars (self) : | 577 | def vars (self) : |
575 | """Return the set of variable names used in all the actions of | 578 | """Return the set of variable names used in all the actions of |
576 | the multiaction. | 579 | the multiaction. |
577 | - | 580 | + |
578 | >>> MultiAction([Action('a', True, [Variable('x'), Value(2)]), | 581 | >>> MultiAction([Action('a', True, [Variable('x'), Value(2)]), |
579 | ... Action('a', True, [Value(3), Variable('y')]), | 582 | ... Action('a', True, [Value(3), Variable('y')]), |
580 | ... Action('b', False, [Variable('x'), Variable('z')])]).vars() == set(['x', 'y', 'z']) | 583 | ... Action('b', False, [Variable('x'), Variable('z')])]).vars() == set(['x', 'y', 'z']) |
581 | True | 584 | True |
582 | - | 585 | + |
583 | @return: the set of variable names | 586 | @return: the set of variable names |
584 | @rtype: `set` of `str` | 587 | @rtype: `set` of `str` |
585 | """ | 588 | """ |
... | @@ -590,12 +593,12 @@ class MultiAction (object) : | ... | @@ -590,12 +593,12 @@ class MultiAction (object) : |
590 | def synchronise (self, other, name) : | 593 | def synchronise (self, other, name) : |
591 | """Search all the possible synchronisation on an action name with | 594 | """Search all the possible synchronisation on an action name with |
592 | another multiaction. | 595 | another multiaction. |
593 | - | 596 | + |
594 | This method returns an iterator that yields for each possible | 597 | This method returns an iterator that yields for each possible |
595 | synchronisation a 4-tuple whose components are: | 598 | synchronisation a 4-tuple whose components are: |
596 | - | 599 | + |
597 | - | 600 | + |
598 | - | 601 | + |
599 | * the sending action that did synchronise, it is already | 602 | * the sending action that did synchronise, it is already |
600 | unified, so the corresponding receiving action is just | 603 | unified, so the corresponding receiving action is just |
601 | the same with the reversed send flag | 604 | the same with the reversed send flag |
... | @@ -605,7 +608,7 @@ class MultiAction (object) : | ... | @@ -605,7 +608,7 @@ class MultiAction (object) : |
605 | that provided the sending action | 608 | that provided the sending action |
606 | * the substitution that must be applied to the transition | 609 | * the substitution that must be applied to the transition |
607 | that provided the receiving action | 610 | that provided the receiving action |
608 | - | 611 | + |
609 | >>> m = MultiAction([Action('a', True, [Variable('x'), Value(2)]), | 612 | >>> m = MultiAction([Action('a', True, [Variable('x'), Value(2)]), |
610 | ... Action('a', True, [Value(3), Variable('y')]), | 613 | ... Action('a', True, [Value(3), Variable('y')]), |
611 | ... Action('b', False, [Variable('x'), Variable('y')])]) | 614 | ... Action('b', False, [Variable('x'), Variable('y')])]) |
... | @@ -615,7 +618,7 @@ class MultiAction (object) : | ... | @@ -615,7 +618,7 @@ class MultiAction (object) : |
615 | ... print('%s %s %s %s' % (str(a), str(x), list(sorted(u.items())), list(sorted(v.items())))) | 618 | ... print('%s %s %s %s' % (str(a), str(x), list(sorted(u.items())), list(sorted(v.items())))) |
616 | a!(w,2) [a!(3,y), b?(w,y), c?(a)] [('a', Value(2)), ('x', Variable('w'))] [('a', Value(2)), ('x', Variable('w')), ('y', Variable('a'))] | 619 | a!(w,2) [a!(3,y), b?(w,y), c?(a)] [('a', Value(2)), ('x', Variable('w'))] [('a', Value(2)), ('x', Variable('w')), ('y', Variable('a'))] |
617 | a!(3,a) [a!(x,2), b?(x,a), c?(a)] [('w', Value(3)), ('y', Variable('a'))] [('w', Value(3)), ('y', Variable('a'))] | 620 | a!(3,a) [a!(x,2), b?(x,a), c?(a)] [('w', Value(3)), ('y', Variable('a'))] [('w', Value(3)), ('y', Variable('a'))] |
618 | - | 621 | + |
619 | @param other: the other multiaction to synchronise with | 622 | @param other: the other multiaction to synchronise with |
620 | @type other: `MultiAction` | 623 | @type other: `MultiAction` |
621 | @param name: the name of the action to synchronise on | 624 | @param name: the name of the action to synchronise on | ... | ... |
... | @@ -3,6 +3,8 @@ | ... | @@ -3,6 +3,8 @@ |
3 | Petri nets objects are saved in PNML, other Python objects are saved | 3 | Petri nets objects are saved in PNML, other Python objects are saved |
4 | in a readable format when possible and pickled as a last solution. | 4 | in a readable format when possible and pickled as a last solution. |
5 | This should result in a complete PNML serialization of any object. | 5 | This should result in a complete PNML serialization of any object. |
6 | + | ||
7 | +@todo: revise documentation | ||
6 | """ | 8 | """ |
7 | 9 | ||
8 | import xml.dom.minidom | 10 | import xml.dom.minidom |
... | @@ -160,7 +162,7 @@ class _set (object) : | ... | @@ -160,7 +162,7 @@ class _set (object) : |
160 | 162 | ||
161 | class Tree (object) : | 163 | class Tree (object) : |
162 | """Abstraction of a PNML tree | 164 | """Abstraction of a PNML tree |
163 | - | 165 | + |
164 | >>> Tree('tag', 'data', Tree('child', None), attr='attribute value') | 166 | >>> Tree('tag', 'data', Tree('child', None), attr='attribute value') |
165 | <?xml version="1.0" encoding="utf-8"?> | 167 | <?xml version="1.0" encoding="utf-8"?> |
166 | <pnml> | 168 | <pnml> |
... | @@ -172,7 +174,7 @@ class Tree (object) : | ... | @@ -172,7 +174,7 @@ class Tree (object) : |
172 | """ | 174 | """ |
173 | def __init__ (self, _name, _data, *_children, **_attributes) : | 175 | def __init__ (self, _name, _data, *_children, **_attributes) : |
174 | """Initialize a PNML tree | 176 | """Initialize a PNML tree |
175 | - | 177 | + |
176 | >>> Tree('tag', 'data', | 178 | >>> Tree('tag', 'data', |
177 | ... Tree('first_child', None), | 179 | ... Tree('first_child', None), |
178 | ... Tree('second_child', None), | 180 | ... Tree('second_child', None), |
... | @@ -186,10 +188,10 @@ class Tree (object) : | ... | @@ -186,10 +188,10 @@ class Tree (object) : |
186 | data | 188 | data |
187 | </tag> | 189 | </tag> |
188 | </pnml> | 190 | </pnml> |
189 | - | 191 | + |
190 | Note: parameters names start with a '_' in order to allow for | 192 | Note: parameters names start with a '_' in order to allow for |
191 | using them as attributes. | 193 | using them as attributes. |
192 | - | 194 | + |
193 | @param _name: the name of the tag | 195 | @param _name: the name of the tag |
194 | @type _name: `str` | 196 | @type _name: `str` |
195 | @param _data: the text held by the tag or `None` | 197 | @param _data: the text held by the tag or `None` |
... | @@ -225,7 +227,7 @@ class Tree (object) : | ... | @@ -225,7 +227,7 @@ class Tree (object) : |
225 | return result | 227 | return result |
226 | def to_pnml (self) : | 228 | def to_pnml (self) : |
227 | """Dumps a PNML tree to an XML string | 229 | """Dumps a PNML tree to an XML string |
228 | - | 230 | + |
229 | >>> print(Tree('tag', 'data', Tree('child', None), attr='value').to_pnml()) | 231 | >>> print(Tree('tag', 'data', Tree('child', None), attr='value').to_pnml()) |
230 | <?xml version="1.0" encoding="utf-8"?> | 232 | <?xml version="1.0" encoding="utf-8"?> |
231 | <pnml> | 233 | <pnml> |
... | @@ -234,7 +236,7 @@ class Tree (object) : | ... | @@ -234,7 +236,7 @@ class Tree (object) : |
234 | data | 236 | data |
235 | </tag> | 237 | </tag> |
236 | </pnml> | 238 | </pnml> |
237 | - | 239 | + |
238 | @return: the XML string that represents the PNML tree | 240 | @return: the XML string that represents the PNML tree |
239 | @rtype: `str` | 241 | @rtype: `str` |
240 | """ | 242 | """ |
... | @@ -269,7 +271,7 @@ class Tree (object) : | ... | @@ -269,7 +271,7 @@ class Tree (object) : |
269 | @classmethod | 271 | @classmethod |
270 | def from_dom (cls, node) : | 272 | def from_dom (cls, node) : |
271 | """Load a PNML tree from an XML DOM representation | 273 | """Load a PNML tree from an XML DOM representation |
272 | - | 274 | + |
273 | >>> src = Tree('object', '42', type='int').to_pnml() | 275 | >>> src = Tree('object', '42', type='int').to_pnml() |
274 | >>> dom = xml.dom.minidom.parseString(src) | 276 | >>> dom = xml.dom.minidom.parseString(src) |
275 | >>> Tree.from_dom(dom.documentElement) | 277 | >>> Tree.from_dom(dom.documentElement) |
... | @@ -279,7 +281,7 @@ class Tree (object) : | ... | @@ -279,7 +281,7 @@ class Tree (object) : |
279 | 42 | 281 | 42 |
280 | </object> | 282 | </object> |
281 | </pnml> | 283 | </pnml> |
282 | - | 284 | + |
283 | @param node: the DOM node to load | 285 | @param node: the DOM node to load |
284 | @type node: `xml.dom.minidom.Element` | 286 | @type node: `xml.dom.minidom.Element` |
285 | @return: the loaded PNML tree | 287 | @return: the loaded PNML tree |
... | @@ -299,7 +301,7 @@ class Tree (object) : | ... | @@ -299,7 +301,7 @@ class Tree (object) : |
299 | @classmethod | 301 | @classmethod |
300 | def from_pnml (cls, source, plugins=[]) : | 302 | def from_pnml (cls, source, plugins=[]) : |
301 | """Load a PNML tree from an XML string representation | 303 | """Load a PNML tree from an XML string representation |
302 | - | 304 | + |
303 | >>> src = Tree('object', '42', type='int').to_pnml() | 305 | >>> src = Tree('object', '42', type='int').to_pnml() |
304 | >>> Tree.from_pnml(src) | 306 | >>> Tree.from_pnml(src) |
305 | <?xml version="1.0" encoding="utf-8"?> | 307 | <?xml version="1.0" encoding="utf-8"?> |
... | @@ -308,7 +310,7 @@ class Tree (object) : | ... | @@ -308,7 +310,7 @@ class Tree (object) : |
308 | 42 | 310 | 42 |
309 | </object> | 311 | </object> |
310 | </pnml> | 312 | </pnml> |
311 | - | 313 | + |
312 | @param source: the XML string to load or an opened file that | 314 | @param source: the XML string to load or an opened file that |
313 | contains it | 315 | contains it |
314 | @type source: `str` or `file` | 316 | @type source: `str` or `file` |
... | @@ -360,7 +362,7 @@ class Tree (object) : | ... | @@ -360,7 +362,7 @@ class Tree (object) : |
360 | return result | 362 | return result |
361 | def nodes (self) : | 363 | def nodes (self) : |
362 | """Iterate over all the nodes (top-down) in a tree | 364 | """Iterate over all the nodes (top-down) in a tree |
363 | - | 365 | + |
364 | >>> t = Tree('foo', None, | 366 | >>> t = Tree('foo', None, |
365 | ... Tree('bar', None), | 367 | ... Tree('bar', None), |
366 | ... Tree('egg', None, | 368 | ... Tree('egg', None, |
... | @@ -371,7 +373,7 @@ class Tree (object) : | ... | @@ -371,7 +373,7 @@ class Tree (object) : |
371 | <PNML tree 'bar'> | 373 | <PNML tree 'bar'> |
372 | <PNML tree 'egg'> | 374 | <PNML tree 'egg'> |
373 | <PNML tree 'spam'> | 375 | <PNML tree 'spam'> |
374 | - | 376 | + |
375 | @return: an iterator on all the nodes in the tree, including | 377 | @return: an iterator on all the nodes in the tree, including |
376 | this one | 378 | this one |
377 | @rtype: `generator` | 379 | @rtype: `generator` |
... | @@ -383,7 +385,7 @@ class Tree (object) : | ... | @@ -383,7 +385,7 @@ class Tree (object) : |
383 | def update (self, other) : | 385 | def update (self, other) : |
384 | """Incorporates children, attributes and data from another PNML | 386 | """Incorporates children, attributes and data from another PNML |
385 | tree | 387 | tree |
386 | - | 388 | + |
387 | >>> t = Tree('foo', 'hello', | 389 | >>> t = Tree('foo', 'hello', |
388 | ... Tree('bar', None), | 390 | ... Tree('bar', None), |
389 | ... Tree('egg', None, | 391 | ... Tree('egg', None, |
... | @@ -411,7 +413,7 @@ class Tree (object) : | ... | @@ -411,7 +413,7 @@ class Tree (object) : |
411 | >>> try : t.update(o) | 413 | >>> try : t.update(o) |
412 | ... except SnakesError : print(sys.exc_info()[1]) | 414 | ... except SnakesError : print(sys.exc_info()[1]) |
413 | tag mismatch 'foo', 'oops' | 415 | tag mismatch 'foo', 'oops' |
414 | - | 416 | + |
415 | @param other: the other tree to get data from | 417 | @param other: the other tree to get data from |
416 | @type other: `Tree` | 418 | @type other: `Tree` |
417 | @raise SnakesError: when `other` has not the same tag as | 419 | @raise SnakesError: when `other` has not the same tag as |
... | @@ -424,7 +426,7 @@ class Tree (object) : | ... | @@ -424,7 +426,7 @@ class Tree (object) : |
424 | self.add_data(other.data) | 426 | self.add_data(other.data) |
425 | def add_child (self, child) : | 427 | def add_child (self, child) : |
426 | """Add a child to a PNML tree | 428 | """Add a child to a PNML tree |
427 | - | 429 | + |
428 | >>> t = Tree('foo', None) | 430 | >>> t = Tree('foo', None) |
429 | >>> t.add_child(Tree('bar', None)) | 431 | >>> t.add_child(Tree('bar', None)) |
430 | >>> t | 432 | >>> t |
... | @@ -434,14 +436,14 @@ class Tree (object) : | ... | @@ -434,14 +436,14 @@ class Tree (object) : |
434 | <bar/> | 436 | <bar/> |
435 | </foo> | 437 | </foo> |
436 | </pnml> | 438 | </pnml> |
437 | - | 439 | + |
438 | @param child: the PNML tree to append | 440 | @param child: the PNML tree to append |
439 | @type child: `Tree` | 441 | @type child: `Tree` |
440 | """ | 442 | """ |
441 | self.children.append(child) | 443 | self.children.append(child) |
442 | def add_data (self, data, sep='\n') : | 444 | def add_data (self, data, sep='\n') : |
443 | """Appends data to the current node | 445 | """Appends data to the current node |
444 | - | 446 | + |
445 | >>> t = Tree('foo', None) | 447 | >>> t = Tree('foo', None) |
446 | >>> t.add_data('hello') | 448 | >>> t.add_data('hello') |
447 | >>> t | 449 | >>> t |
... | @@ -469,7 +471,7 @@ class Tree (object) : | ... | @@ -469,7 +471,7 @@ class Tree (object) : |
469 | world! | 471 | world! |
470 | </foo> | 472 | </foo> |
471 | </pnml> | 473 | </pnml> |
472 | - | 474 | + |
473 | @param data: the data to add | 475 | @param data: the data to add |
474 | @type data: `str` | 476 | @type data: `str` |
475 | @param sep: separator to insert between pieces of data | 477 | @param sep: separator to insert between pieces of data |
... | @@ -486,14 +488,14 @@ class Tree (object) : | ... | @@ -486,14 +488,14 @@ class Tree (object) : |
486 | pass | 488 | pass |
487 | def __getitem__ (self, name) : | 489 | def __getitem__ (self, name) : |
488 | """Returns one attribute | 490 | """Returns one attribute |
489 | - | 491 | + |
490 | >>> Tree('foo', None, x='egg', y='spam')['x'] | 492 | >>> Tree('foo', None, x='egg', y='spam')['x'] |
491 | 'egg' | 493 | 'egg' |
492 | >>> Tree('foo', None, x='egg', y='spam')['z'] | 494 | >>> Tree('foo', None, x='egg', y='spam')['z'] |
493 | Traceback (most recent call last): | 495 | Traceback (most recent call last): |
494 | ... | 496 | ... |
495 | KeyError: 'z' | 497 | KeyError: 'z' |
496 | - | 498 | + |
497 | @param name: the name of the attribute | 499 | @param name: the name of the attribute |
498 | @type name: `str` | 500 | @type name: `str` |
499 | @return: the value of the attribute | 501 | @return: the value of the attribute |
... | @@ -503,7 +505,7 @@ class Tree (object) : | ... | @@ -503,7 +505,7 @@ class Tree (object) : |
503 | return self.attributes[name] | 505 | return self.attributes[name] |
504 | def __setitem__ (self, name, value) : | 506 | def __setitem__ (self, name, value) : |
505 | """Sets an attribute | 507 | """Sets an attribute |
506 | - | 508 | + |
507 | >>> t = Tree('foo', None) | 509 | >>> t = Tree('foo', None) |
508 | >>> t['egg'] = 'spam' | 510 | >>> t['egg'] = 'spam' |
509 | >>> t | 511 | >>> t |
... | @@ -511,7 +513,7 @@ class Tree (object) : | ... | @@ -511,7 +513,7 @@ class Tree (object) : |
511 | <pnml> | 513 | <pnml> |
512 | <foo egg="spam"/> | 514 | <foo egg="spam"/> |
513 | </pnml> | 515 | </pnml> |
514 | - | 516 | + |
515 | @param name: the name of the attribute | 517 | @param name: the name of the attribute |
516 | @type name: `str` | 518 | @type name: `str` |
517 | @param value: the value of the attribute | 519 | @param value: the value of the attribute |
... | @@ -520,20 +522,20 @@ class Tree (object) : | ... | @@ -520,20 +522,20 @@ class Tree (object) : |
520 | self.attributes[name] = value | 522 | self.attributes[name] = value |
521 | def __iter__ (self) : | 523 | def __iter__ (self) : |
522 | """Iterate over children nodes | 524 | """Iterate over children nodes |
523 | - | 525 | + |
524 | >>> [str(node) for node in Tree('foo', None, | 526 | >>> [str(node) for node in Tree('foo', None, |
525 | ... Tree('egg', None), | 527 | ... Tree('egg', None), |
526 | ... Tree('spam', None, | 528 | ... Tree('spam', None, |
527 | ... Tree('bar', None)))] | 529 | ... Tree('bar', None)))] |
528 | ["<PNML tree 'egg'>", "<PNML tree 'spam'>"] | 530 | ["<PNML tree 'egg'>", "<PNML tree 'spam'>"] |
529 | - | 531 | + |
530 | @return: an iterator over direct children of the node | 532 | @return: an iterator over direct children of the node |
531 | @rtype: `generator` | 533 | @rtype: `generator` |
532 | """ | 534 | """ |
533 | return iter(self.children) | 535 | return iter(self.children) |
534 | def has_child (self, name) : | 536 | def has_child (self, name) : |
535 | """Test if the tree has the given tag as a direct child | 537 | """Test if the tree has the given tag as a direct child |
536 | - | 538 | + |
537 | >>> t = Tree('foo', None, | 539 | >>> t = Tree('foo', None, |
538 | ... Tree('egg', None), | 540 | ... Tree('egg', None), |
539 | ... Tree('spam', None, | 541 | ... Tree('spam', None, |
... | @@ -544,7 +546,7 @@ class Tree (object) : | ... | @@ -544,7 +546,7 @@ class Tree (object) : |
544 | False | 546 | False |
545 | >>> t.has_child('python') | 547 | >>> t.has_child('python') |
546 | False | 548 | False |
547 | - | 549 | + |
548 | @param name: tag name to search for | 550 | @param name: tag name to search for |
549 | @type name: `str` | 551 | @type name: `str` |
550 | @return: a Boolean value indicating wether such a child was | 552 | @return: a Boolean value indicating wether such a child was |
... | @@ -557,7 +559,7 @@ class Tree (object) : | ... | @@ -557,7 +559,7 @@ class Tree (object) : |
557 | return False | 559 | return False |
558 | def child (self, name=None) : | 560 | def child (self, name=None) : |
559 | """Return the direct child that as the given tag | 561 | """Return the direct child that as the given tag |
560 | - | 562 | + |
561 | >>> t = Tree('foo', None, | 563 | >>> t = Tree('foo', None, |
562 | ... Tree('egg', 'first'), | 564 | ... Tree('egg', 'first'), |
563 | ... Tree('egg', 'second'), | 565 | ... Tree('egg', 'second'), |
... | @@ -582,7 +584,7 @@ class Tree (object) : | ... | @@ -582,7 +584,7 @@ class Tree (object) : |
582 | >>> try : t.child() | 584 | >>> try : t.child() |
583 | ... except SnakesError : print(sys.exc_info()[1]) | 585 | ... except SnakesError : print(sys.exc_info()[1]) |
584 | multiple children | 586 | multiple children |
585 | - | 587 | + |
586 | @param name: name of the tag to search for, if `None`, the | 588 | @param name: name of the tag to search for, if `None`, the |
587 | fisrt child is returned if it is the only child | 589 | fisrt child is returned if it is the only child |
588 | @type name: `str` or `None` | 590 | @type name: `str` or `None` |
... | @@ -606,7 +608,7 @@ class Tree (object) : | ... | @@ -606,7 +608,7 @@ class Tree (object) : |
606 | return result | 608 | return result |
607 | def get_children (self, name=None) : | 609 | def get_children (self, name=None) : |
608 | """Iterates over direct children having the given tag | 610 | """Iterates over direct children having the given tag |
609 | - | 611 | + |
610 | >>> t = Tree('foo', None, | 612 | >>> t = Tree('foo', None, |
611 | ... Tree('egg', 'first'), | 613 | ... Tree('egg', 'first'), |
612 | ... Tree('egg', 'second'), | 614 | ... Tree('egg', 'second'), |
... | @@ -620,7 +622,7 @@ class Tree (object) : | ... | @@ -620,7 +622,7 @@ class Tree (object) : |
620 | [] | 622 | [] |
621 | >>> [str(n) for n in t.get_children('bar')] | 623 | >>> [str(n) for n in t.get_children('bar')] |
622 | [] | 624 | [] |
623 | - | 625 | + |
624 | @param name: tag to search for or `None` | 626 | @param name: tag to search for or `None` |
625 | @type name: `str` or `None` | 627 | @type name: `str` or `None` |
626 | @return: iterator over all the children if `name` is `None`, | 628 | @return: iterator over all the children if `name` is `None`, |
... | @@ -632,20 +634,20 @@ class Tree (object) : | ... | @@ -632,20 +634,20 @@ class Tree (object) : |
632 | yield child | 634 | yield child |
633 | def __str__ (self) : | 635 | def __str__ (self) : |
634 | """Return a simple string representation of the node | 636 | """Return a simple string representation of the node |
635 | - | 637 | + |
636 | >>> str(Tree('foo', None, Tree('child', None))) | 638 | >>> str(Tree('foo', None, Tree('child', None))) |
637 | "<PNML tree 'foo'>" | 639 | "<PNML tree 'foo'>" |
638 | - | 640 | + |
639 | @return: simple string representation of the node | 641 | @return: simple string representation of the node |
640 | @rtype: `str` | 642 | @rtype: `str` |
641 | """ | 643 | """ |
642 | return "<PNML tree %r>" % self.name | 644 | return "<PNML tree %r>" % self.name |
643 | def __repr__ (self) : | 645 | def __repr__ (self) : |
644 | """Return a detailed representation of the node. | 646 | """Return a detailed representation of the node. |
645 | - | 647 | + |
646 | This is actually the XML text that corresponds to the `Tree`, | 648 | This is actually the XML text that corresponds to the `Tree`, |
647 | as returned by `Tree.to_pnml`. | 649 | as returned by `Tree.to_pnml`. |
648 | - | 650 | + |
649 | >>> print(repr(Tree('foo', None, Tree('child', None)))) | 651 | >>> print(repr(Tree('foo', None, Tree('child', None)))) |
650 | <?xml version="1.0" encoding="utf-8"?> | 652 | <?xml version="1.0" encoding="utf-8"?> |
651 | <pnml> | 653 | <pnml> |
... | @@ -653,7 +655,7 @@ class Tree (object) : | ... | @@ -653,7 +655,7 @@ class Tree (object) : |
653 | <child/> | 655 | <child/> |
654 | </foo> | 656 | </foo> |
655 | </pnml> | 657 | </pnml> |
656 | - | 658 | + |
657 | @return: XML string representation of the node | 659 | @return: XML string representation of the node |
658 | @rtype: `str` | 660 | @rtype: `str` |
659 | """ | 661 | """ |
... | @@ -663,10 +665,10 @@ class Tree (object) : | ... | @@ -663,10 +665,10 @@ class Tree (object) : |
663 | @classmethod | 665 | @classmethod |
664 | def from_obj (cls, obj) : | 666 | def from_obj (cls, obj) : |
665 | """Builds a PNML tree from an object. | 667 | """Builds a PNML tree from an object. |
666 | - | 668 | + |
667 | Objects defined in SNAKES usually have a method `__pnmldump__` | 669 | Objects defined in SNAKES usually have a method `__pnmldump__` |
668 | that handles the conversion, for instance: | 670 | that handles the conversion, for instance: |
669 | - | 671 | + |
670 | >>> import snakes.nets | 672 | >>> import snakes.nets |
671 | >>> Tree.from_obj(snakes.nets.Place('p')) | 673 | >>> Tree.from_obj(snakes.nets.Place('p')) |
672 | <?xml version="1.0" encoding="utf-8"?> | 674 | <?xml version="1.0" encoding="utf-8"?> |
... | @@ -678,9 +680,9 @@ class Tree (object) : | ... | @@ -678,9 +680,9 @@ class Tree (object) : |
678 | </initialMarking> | 680 | </initialMarking> |
679 | </place> | 681 | </place> |
680 | </pnml> | 682 | </pnml> |
681 | - | 683 | + |
682 | Most basic Python classes are handled has readable XML: | 684 | Most basic Python classes are handled has readable XML: |
683 | - | 685 | + |
684 | >>> Tree.from_obj(42) | 686 | >>> Tree.from_obj(42) |
685 | <?xml version="1.0" encoding="utf-8"?> | 687 | <?xml version="1.0" encoding="utf-8"?> |
686 | <pnml> | 688 | <pnml> |
... | @@ -703,10 +705,10 @@ class Tree (object) : | ... | @@ -703,10 +705,10 @@ class Tree (object) : |
703 | </object> | 705 | </object> |
704 | </object> | 706 | </object> |
705 | </pnml> | 707 | </pnml> |
706 | - | 708 | + |
707 | Otherwise, the object is serialised using module `pickle`, | 709 | Otherwise, the object is serialised using module `pickle`, |
708 | which allows to embed almost anything into PNML. | 710 | which allows to embed almost anything into PNML. |
709 | - | 711 | + |
710 | >>> import re | 712 | >>> import re |
711 | >>> Tree.from_obj(re.compile('foo|bar')) # serialized data replaced with '...' | 713 | >>> Tree.from_obj(re.compile('foo|bar')) # serialized data replaced with '...' |
712 | <?xml version="1.0" encoding="utf-8"?> | 714 | <?xml version="1.0" encoding="utf-8"?> |
... | @@ -715,7 +717,7 @@ class Tree (object) : | ... | @@ -715,7 +717,7 @@ class Tree (object) : |
715 | ... | 717 | ... |
716 | </object> | 718 | </object> |
717 | </pnml> | 719 | </pnml> |
718 | - | 720 | + |
719 | @param obj: the object to convert to PNML | 721 | @param obj: the object to convert to PNML |
720 | @type obj: `object` | 722 | @type obj: `object` |
721 | @return: the corresponding PNML tree | 723 | @return: the corresponding PNML tree |
... | @@ -854,7 +856,7 @@ class Tree (object) : | ... | @@ -854,7 +856,7 @@ class Tree (object) : |
854 | return pickle.loads(self.data) | 856 | return pickle.loads(self.data) |
855 | def to_obj (self) : | 857 | def to_obj (self) : |
856 | """Build an object from its PNML representation | 858 | """Build an object from its PNML representation |
857 | - | 859 | + |
858 | This is just the reverse as `Tree.from_obj`, objects that have | 860 | This is just the reverse as `Tree.from_obj`, objects that have |
859 | a `__pnmldump__` method should also have a `__pnmlload__` | 861 | a `__pnmldump__` method should also have a `__pnmlload__` |
860 | class method to perform the reverse operation, together with | 862 | class method to perform the reverse operation, together with |
... | @@ -863,10 +865,10 @@ class Tree (object) : | ... | @@ -863,10 +865,10 @@ class Tree (object) : |
863 | that `C.__pnmltag__ == 'foo'` is searched in module | 865 | that `C.__pnmltag__ == 'foo'` is searched in module |
864 | `snakes.nets` and `C.__pnmlload__(tree)` is called to rebuild | 866 | `snakes.nets` and `C.__pnmlload__(tree)` is called to rebuild |
865 | the object. | 867 | the object. |
866 | - | 868 | + |
867 | Standard Python objects and pickled ones are also recognised | 869 | Standard Python objects and pickled ones are also recognised |
868 | and correctly rebuilt. | 870 | and correctly rebuilt. |
869 | - | 871 | + |
870 | >>> import snakes.nets | 872 | >>> import snakes.nets |
871 | >>> Tree.from_obj(snakes.nets.Place('p')).to_obj() | 873 | >>> Tree.from_obj(snakes.nets.Place('p')).to_obj() |
872 | Place('p', MultiSet([]), tAll) | 874 | Place('p', MultiSet([]), tAll) |
... | @@ -877,7 +879,7 @@ class Tree (object) : | ... | @@ -877,7 +879,7 @@ class Tree (object) : |
877 | >>> import re | 879 | >>> import re |
878 | >>> Tree.from_obj(re.compile('foo|bar')).to_obj() | 880 | >>> Tree.from_obj(re.compile('foo|bar')).to_obj() |
879 | <... object at ...> | 881 | <... object at ...> |
880 | - | 882 | + |
881 | @return: the Python object encoded by the PNML tree | 883 | @return: the Python object encoded by the PNML tree |
882 | @rtype: `object` | 884 | @rtype: `object` |
883 | """ | 885 | """ |
... | @@ -910,7 +912,7 @@ class Tree (object) : | ... | @@ -910,7 +912,7 @@ class Tree (object) : |
910 | 912 | ||
911 | def dumps (obj) : | 913 | def dumps (obj) : |
912 | """Dump an object to a PNML string | 914 | """Dump an object to a PNML string |
913 | - | 915 | + |
914 | >>> print(dumps(42)) | 916 | >>> print(dumps(42)) |
915 | <?xml version="1.0" encoding="utf-8"?> | 917 | <?xml version="1.0" encoding="utf-8"?> |
916 | <pnml> | 918 | <pnml> |
... | @@ -918,7 +920,7 @@ def dumps (obj) : | ... | @@ -918,7 +920,7 @@ def dumps (obj) : |
918 | 42 | 920 | 42 |
919 | </object> | 921 | </object> |
920 | </pnml> | 922 | </pnml> |
921 | - | 923 | + |
922 | @param obj: the object to dump | 924 | @param obj: the object to dump |
923 | @type obj: `object` | 925 | @type obj: `object` |
924 | @return: the PNML that represents the object | 926 | @return: the PNML that represents the object |
... | @@ -928,10 +930,10 @@ def dumps (obj) : | ... | @@ -928,10 +930,10 @@ def dumps (obj) : |
928 | 930 | ||
929 | def loads (source, plugins=[]) : | 931 | def loads (source, plugins=[]) : |
930 | """Load an object from a PNML string | 932 | """Load an object from a PNML string |
931 | - | 933 | + |
932 | >>> loads(dumps(42)) | 934 | >>> loads(dumps(42)) |
933 | 42 | 935 | 42 |
934 | - | 936 | + |
935 | @param source: the data to parse | 937 | @param source: the data to parse |
936 | @type source: `str` | 938 | @type source: `str` |
937 | @return: the object represented by the source | 939 | @return: the object represented by the source | ... | ... |
... | @@ -60,6 +60,8 @@ TypeError: ... | ... | @@ -60,6 +60,8 @@ TypeError: ... |
60 | Traceback (most recent call last): | 60 | Traceback (most recent call last): |
61 | ... | 61 | ... |
62 | TypeError: ... | 62 | TypeError: ... |
63 | + | ||
64 | +@todo: revise documentation | ||
63 | """ | 65 | """ |
64 | 66 | ||
65 | import inspect, sys | 67 | import inspect, sys | ... | ... |
1 | +""" | ||
2 | +@todo: revise (actually make) documentation | ||
3 | +""" | ||
4 | + | ||
1 | import sys, os, os.path | 5 | import sys, os, os.path |
2 | -import inspect, fnmatch, collections | 6 | +import inspect, fnmatch, collections, re, shlex |
3 | -import textwrap, doctest, ast | 7 | +import textwrap, doctest |
4 | import snakes | 8 | import snakes |
5 | from snakes.lang import unparse | 9 | from snakes.lang import unparse |
10 | +from snakes.lang.python.parser import parse, ast | ||
11 | + | ||
12 | +try : | ||
13 | + import markdown | ||
14 | +except : | ||
15 | + markdown = None | ||
6 | 16 | ||
7 | ## | 17 | ## |
8 | ## console messages | 18 | ## console messages |
... | @@ -62,6 +72,13 @@ class DocExtract (object) : | ... | @@ -62,6 +72,13 @@ class DocExtract (object) : |
62 | self.out = None | 72 | self.out = None |
63 | self.exclude = exclude | 73 | self.exclude = exclude |
64 | self._last = "\n\n" | 74 | self._last = "\n\n" |
75 | + def md (self, text, inline=True) : | ||
76 | + if markdown is None : | ||
77 | + return text | ||
78 | + elif inline : | ||
79 | + return re.sub("</?p>", "\n", markdown.markdown(text), re.I) | ||
80 | + else : | ||
81 | + return markdown.markdown(text) | ||
65 | def openout (self, path) : | 82 | def openout (self, path) : |
66 | if self.out is not None : | 83 | if self.out is not None : |
67 | self.out.close() | 84 | self.out.close() |
... | @@ -81,6 +98,10 @@ class DocExtract (object) : | ... | @@ -81,6 +98,10 @@ class DocExtract (object) : |
81 | return False | 98 | return False |
82 | outdir = os.path.join(self.outpath, relpath) | 99 | outdir = os.path.join(self.outpath, relpath) |
83 | outpath = os.path.join(outdir, target) | 100 | outpath = os.path.join(outdir, target) |
101 | + if os.path.exists(outpath) : | ||
102 | + if os.stat(path).st_mtime <= os.stat(outpath).st_mtime : | ||
103 | + return False | ||
104 | + self.inpath = path | ||
84 | info("%s -> %r" % (self.module, outpath)) | 105 | info("%s -> %r" % (self.module, outpath)) |
85 | if not os.path.exists(outdir) : | 106 | if not os.path.exists(outdir) : |
86 | os.makedirs(outdir) | 107 | os.makedirs(outdir) |
... | @@ -114,56 +135,89 @@ class DocExtract (object) : | ... | @@ -114,56 +135,89 @@ class DocExtract (object) : |
114 | def process (self) : | 135 | def process (self) : |
115 | for dirpath, dirnames, filenames in os.walk(self.path) : | 136 | for dirpath, dirnames, filenames in os.walk(self.path) : |
116 | for name in sorted(filenames) : | 137 | for name in sorted(filenames) : |
117 | - if not name.endswith(".py") : | 138 | + if not name.endswith(".py") or name.startswith(".") : |
118 | continue | 139 | continue |
119 | path = os.path.join(dirpath, name) | 140 | path = os.path.join(dirpath, name) |
120 | if not self.openout(path) : | 141 | if not self.openout(path) : |
121 | continue | 142 | continue |
122 | - node = ast.parse(open(path).read()) | 143 | + node = parse(open(path).read()) |
123 | if ".plugins." in self.module : | 144 | if ".plugins." in self.module : |
124 | self.visit_plugin(node) | 145 | self.visit_plugin(node) |
125 | else : | 146 | else : |
126 | self.visit_module(node) | 147 | self.visit_module(node) |
127 | def _pass (self, node) : | 148 | def _pass (self, node) : |
128 | pass | 149 | pass |
150 | + def directive (self, node) : | ||
151 | + lines = node.st.text.lexer.lines | ||
152 | + num = node.st.srow - 2 | ||
153 | + while num >= 0 and (not lines[num].strip() | ||
154 | + or lines[num].strip().startswith("@")) : | ||
155 | + num -= 1 | ||
156 | + if num >= 0 and lines[num].strip().startswith("#") : | ||
157 | + dirline = lines[num].lstrip("# \t").rstrip() | ||
158 | + items = shlex.split(dirline) | ||
159 | + if len(items) >= 2 and items[0].lower() == "apidoc" : | ||
160 | + if len(items) == 2 and items[1].lower() in ("skip", "stop") : | ||
161 | + return items[1] | ||
162 | + elif items[1].lower() == "include" : | ||
163 | + path = items[2] | ||
164 | + try : | ||
165 | + args = dict(i.split("=", 1) for i in items[3:]) | ||
166 | + except : | ||
167 | + err("invalid directive %r (line %s)" | ||
168 | + % (dirline, num+1)) | ||
169 | + self.write_include(path, **args) | ||
170 | + else : | ||
171 | + err("unknown directive %r (line %s)" | ||
172 | + % (items[1], num+1)) | ||
173 | + return None | ||
174 | + def children (self, node) : | ||
175 | + for child in ast.iter_child_nodes(node) : | ||
176 | + directive = self.directive(child) | ||
177 | + if directive == "skip" : | ||
178 | + continue | ||
179 | + elif directive == "stop" : | ||
180 | + break | ||
181 | + yield child | ||
129 | def visit (self, node) : | 182 | def visit (self, node) : |
130 | name = getattr(node, "name", "__") | 183 | name = getattr(node, "name", "__") |
131 | if (name.startswith("_") and not (name.startswith("__") | 184 | if (name.startswith("_") and not (name.startswith("__") |
132 | and name.endswith("__"))) : | 185 | and name.endswith("__"))) : |
133 | return | 186 | return |
134 | try : | 187 | try : |
135 | - getattr(self, "visit_" + node.__class__.__name__, self._pass)(node) | 188 | + getattr(self, "visit_" + node.__class__.__name__, |
189 | + self._pass)(node) | ||
136 | except : | 190 | except : |
137 | - src = unparse(node) | 191 | + src = node.st.source() |
138 | if len(src) > 40 : | 192 | if len(src) > 40 : |
139 | src = src[:40] + "..." | 193 | src = src[:40] + "..." |
140 | err("line %s source %r" % (node.lineno, src)) | 194 | err("line %s source %r" % (node.lineno, src)) |
141 | raise | 195 | raise |
142 | def visit_module (self, node) : | 196 | def visit_module (self, node) : |
143 | self.write_module() | 197 | self.write_module() |
144 | - for child in ast.iter_child_nodes(node) : | 198 | + for child in self.children(node) : |
145 | self.visit(child) | 199 | self.visit(child) |
146 | def visit_plugin (self, node) : | 200 | def visit_plugin (self, node) : |
147 | self.write_module() | 201 | self.write_module() |
148 | extend = None | 202 | extend = None |
149 | - for child in ast.iter_child_nodes(node) : | 203 | + for child in self.children(node) : |
150 | if (getattr(child, "name", None) == "extend" | 204 | if (getattr(child, "name", None) == "extend" |
151 | and isinstance(child, ast.FunctionDef)) : | 205 | and isinstance(child, ast.FunctionDef)) : |
152 | extend = child | 206 | extend = child |
153 | else : | 207 | else : |
154 | self.visit(child) | 208 | self.visit(child) |
155 | self.write_plugin() | 209 | self.write_plugin() |
156 | - for child in ast.iter_child_nodes(extend) : | 210 | + for child in self.children(extend) : |
157 | self.visit(child) | 211 | self.visit(child) |
158 | def visit_ClassDef (self, node) : | 212 | def visit_ClassDef (self, node) : |
159 | self.write_class(node) | 213 | self.write_class(node) |
160 | self.classname = node.name | 214 | self.classname = node.name |
161 | - for child in ast.iter_child_nodes(node) : | 215 | + for child in self.children(node) : |
162 | self.visit(child) | 216 | self.visit(child) |
163 | self.classname = None | 217 | self.classname = None |
164 | def visit_FunctionDef (self, node) : | 218 | def visit_FunctionDef (self, node) : |
165 | self.write_function(node) | 219 | self.write_function(node) |
166 | - self.args = [n.id for n in node.args.args] | 220 | + self.args = [n.arg for n in node.args.args] |
167 | if self.args and self.args[0] == "self" : | 221 | if self.args and self.args[0] == "self" : |
168 | del self.args[0] | 222 | del self.args[0] |
169 | if node.args.vararg : | 223 | if node.args.vararg : |
... | @@ -193,26 +247,32 @@ class DocExtract (object) : | ... | @@ -193,26 +247,32 @@ class DocExtract (object) : |
193 | else : | 247 | else : |
194 | self.writeline("### Function `%s` ###" % node.name) | 248 | self.writeline("### Function `%s` ###" % node.name) |
195 | self.newline() | 249 | self.newline() |
196 | - self.writeline(" :::python") | 250 | + self.write_def(node) |
197 | - for line in unparse(node).splitlines() : | ||
198 | - if line.startswith("def") : | ||
199 | - self.writeline(" %s ..." % line) | ||
200 | - break | ||
201 | - else : | ||
202 | - self.writeline(" " + line) | ||
203 | - self.newline | ||
204 | def write_class (self, node) : | 251 | def write_class (self, node) : |
205 | self.newline() | 252 | self.newline() |
206 | self.writeline("### Class `%s` ###" % node.name) | 253 | self.writeline("### Class `%s` ###" % node.name) |
254 | + self.write_def(node) | ||
255 | + def write_def (self, node) : | ||
256 | + indent = node.st.scol | ||
257 | + if node.st[0].symbol == "decorated" : | ||
258 | + srow, scol = node.st[0][0][0][0].srow, node.st[0][0][0][0].scol | ||
259 | + erow, ecol = node.st[0][1][-2].erow, node.st[0][1][-2].ecol | ||
260 | + else : | ||
261 | + srow, scol = node.st[0].srow, node.st[0].scol | ||
262 | + erow, ecol = node.st[0][-2].erow, node.st[0][-2].ecol | ||
263 | + lines = node.st.text.lexer.lines | ||
264 | + if srow == erow : | ||
265 | + source = [lines[srow-1][scol:ecol+1]] | ||
266 | + else : | ||
267 | + source = lines[srow-1:erow] | ||
268 | + source[0] = source[0][scol:] | ||
269 | + source[1:-1] = [s[indent:] for s in source[1:-1]] | ||
270 | + source[-1] = source[-1][indent:ecol+1].rstrip() + " ..." | ||
207 | self.newline() | 271 | self.newline() |
208 | self.writeline(" :::python") | 272 | self.writeline(" :::python") |
209 | - for line in unparse(node).splitlines() : | 273 | + for line in source : |
210 | - if line.startswith("class") : | 274 | + self.writeline(" " + line) |
211 | - self.writeline(" %s ..." % line) | 275 | + self.newline() |
212 | - break | ||
213 | - else : | ||
214 | - self.writeline(" " + line) | ||
215 | - self.newline | ||
216 | parse = doctest.DocTestParser().parse | 276 | parse = doctest.DocTestParser().parse |
217 | def write_doc (self, doc) : | 277 | def write_doc (self, doc) : |
218 | if doc is None : | 278 | if doc is None : |
... | @@ -240,7 +300,9 @@ class DocExtract (object) : | ... | @@ -240,7 +300,9 @@ class DocExtract (object) : |
240 | if not test : | 300 | if not test : |
241 | test = True | 301 | test = True |
242 | self.newline() | 302 | self.newline() |
243 | - self.writeline(" :::python") | 303 | + self.writetext("<!-- this comment avoids a bug in" |
304 | + " Markdown parsing -->") | ||
305 | + self.writeline(" :::pycon") | ||
244 | for i, line in enumerate(doc.source.splitlines()) : | 306 | for i, line in enumerate(doc.source.splitlines()) : |
245 | if i > 0 : | 307 | if i > 0 : |
246 | self.writeline(" ... %s" % line) | 308 | self.writeline(" ... %s" % line) |
... | @@ -281,65 +343,74 @@ class DocExtract (object) : | ... | @@ -281,65 +343,74 @@ class DocExtract (object) : |
281 | if any(k in info for k in ("author", "organization", "copyright", | 343 | if any(k in info for k in ("author", "organization", "copyright", |
282 | "license", "contact")) : | 344 | "license", "contact")) : |
283 | self.newline() | 345 | self.newline() |
284 | - self.writeline('<div class="api-info">') | 346 | + self.writeline('<ul id="api-info">') |
285 | - for tag in ("author", "organization", "copyright", | 347 | + for tag in ("author", "organization", "contact", |
286 | - "license", "contact") : | 348 | + "copyright", "license", ) : |
287 | if tag in info : | 349 | if tag in info : |
288 | - self.writeline('<div class="api-%s">' % tag) | 350 | + self.writeline('<li id="api-%s">' % tag) |
289 | self.writetext('<span class="api-title">%s:</span> %s' | 351 | self.writetext('<span class="api-title">%s:</span> %s' |
290 | - % (tag.capitalize(), info[tag]), | 352 | + % (tag.capitalize(), |
353 | + self.md(info[tag])), | ||
291 | subsequent_indent=" ") | 354 | subsequent_indent=" ") |
292 | - self.writeline('</div>') | 355 | + self.writeline('</li>') |
293 | - self.writeline('</div>') | 356 | + self.writeline('</ul>') |
294 | if any(info[k] for k in | 357 | if any(info[k] for k in |
295 | ("todo", "note", "attention", "bug", "warning")) : | 358 | ("todo", "note", "attention", "bug", "warning")) : |
296 | self.newline() | 359 | self.newline() |
297 | - self.writeline('<div class="api-remarks">') | 360 | + self.writeline('<div id="api-remarks">') |
298 | - self.writeline("##### Remarks #####") | ||
299 | - self.newline() | ||
300 | for tag in ("note", "todo", "attention", "bug", "warning") : | 361 | for tag in ("note", "todo", "attention", "bug", "warning") : |
301 | for text in info[tag] : | 362 | for text in info[tag] : |
302 | self.writeline('<div class="api-%s">' % tag) | 363 | self.writeline('<div class="api-%s">' % tag) |
303 | self.writetext('<span class="api-title">%s:</span> %s' | 364 | self.writetext('<span class="api-title">%s:</span> %s' |
304 | - % (tag.capitalize(), text), | 365 | + % (tag.capitalize(), self.md(text)), |
305 | subsequent_indent=" ") | 366 | subsequent_indent=" ") |
306 | self.writeline('</div>') | 367 | self.writeline('</div>') |
307 | self.writeline('</div>') | 368 | self.writeline('</div>') |
308 | if (any(info[k] for k in ("param", "type", "keyword")) | 369 | if (any(info[k] for k in ("param", "type", "keyword")) |
309 | or any(k in info for k in ("return", "rtype"))) : | 370 | or any(k in info for k in ("return", "rtype"))) : |
310 | self.newline() | 371 | self.newline() |
311 | - self.writeline('<div class="api-call">') | ||
312 | self.writeline("##### Call API #####") | 372 | self.writeline("##### Call API #####") |
313 | self.newline() | 373 | self.newline() |
314 | for arg in self.args : | 374 | for arg in self.args : |
315 | if arg in info["param"] : | 375 | if arg in info["param"] : |
316 | - self.writelist("`%s` (%s): %s" | 376 | + self.writelist("`%s %s`: %s" |
317 | - % (arg, | 377 | + % (info["type"].get(arg, "object").strip("`"), |
318 | - info["type"].get(arg, "`object`"), | 378 | + arg, |
319 | info["param"][arg])) | 379 | info["param"][arg])) |
320 | else : | 380 | else : |
321 | - self.writelist("`%s` (%s)" | 381 | + self.writelist("`%s %s`" |
322 | - % (arg, | 382 | + % (info["type"].get(arg, "object").strip("`"), |
323 | - info["type"].get(arg, "`object`"))) | 383 | + arg)) |
324 | for kw, text in sorted(info["keyword"].items()) : | 384 | for kw, text in sorted(info["keyword"].items()) : |
325 | self.writelist("`%s`: %s" % (kw, text)) | 385 | self.writelist("`%s`: %s" % (kw, text)) |
326 | if any(k in info for k in ("return", "rtype")) : | 386 | if any(k in info for k in ("return", "rtype")) : |
327 | if "return" in info : | 387 | if "return" in info : |
328 | - self.writelist("return %s: %s" | 388 | + self.writelist("`return %s`: %s" |
329 | - % (info.get("rtype", "`object`"), | 389 | + % (info.get("rtype", "object").strip("`"), |
330 | info["return"])) | 390 | info["return"])) |
331 | else : | 391 | else : |
332 | - self.writelist("return %s" | 392 | + self.writelist("`return %s`" |
333 | - % (info.get("rtype", "`object`"))) | 393 | + % (info.get("rtype", "object").strip("`"))) |
334 | - self.writeline('</div>') | ||
335 | if info["raise"] : | 394 | if info["raise"] : |
336 | self.newline() | 395 | self.newline() |
337 | - self.writeline('<div class="api-errors">') | ||
338 | self.writeline("##### Exceptions #####") | 396 | self.writeline("##### Exceptions #####") |
339 | self.newline() | 397 | self.newline() |
340 | for exc, reason in sorted(info["raise"].items()) : | 398 | for exc, reason in sorted(info["raise"].items()) : |
341 | self.writelist("`%s`: %s" % (exc, reason)) | 399 | self.writelist("`%s`: %s" % (exc, reason)) |
342 | - self.writeline('</div>') | 400 | + self.newline() |
401 | + def write_include (self, name, lang="python") : | ||
402 | + if os.path.exists(name) : | ||
403 | + path = name | ||
404 | + else : | ||
405 | + path = os.path.join(os.path.dirname(self.inpath), name) | ||
406 | + if not os.path.exists(path) : | ||
407 | + err("include file %r not found" % name) | ||
408 | + with open(path) as infile : | ||
409 | + self.newline() | ||
410 | + self.writeline(" :::%s" % lang) | ||
411 | + for line in infile : | ||
412 | + self.writeline(" " + line.rstrip()) | ||
413 | + self.newline() | ||
343 | 414 | ||
344 | def main (finder, args) : | 415 | def main (finder, args) : |
345 | try : | 416 | try : | ... | ... |
-
Please register or login to post a comment