Franck Pommereau

merged

......@@ -8,3 +8,4 @@ dput.sh
.gone
,*
*.class
*.bak
......
"""SNAKES is the Net Algebra Kit for Editors and Simulators
@author: Franck Pommereau
@organization: University of Paris 12
@copyright: (C) 2005 Franck Pommereau
@license: GNU Lesser General Public Licence (aka. GNU LGPL),
see the file C{doc/COPYING} in the distribution or visit U{the GNU
web site<http://www.gnu.org/licenses/licenses.html#LGPL>}
@contact: pommereau@univ-paris12.fr
SNAKES is a Python library allowing to model all sorts of Petri nets
and to execute them. It is very general as most Petri nets annotations
can be arbitrary Python expressions while most values can be arbitrary
......@@ -16,6 +8,14 @@ Python objects.
SNAKES can be further extended with plugins, several ones being
already provided, in particular two plugins implement the Petri nets
compositions defined for the Petri Box Calculus and its successors.
@author: Franck Pommereau
@organization: University of Evry/Paris-Saclay
@copyright: (C) 2005-2013 Franck Pommereau
@license: GNU Lesser General Public Licence (aka. GNU LGPL), see the
file `doc/COPYING` in the distribution or visit [the GNU web
site](http://www.gnu.org/licenses/licenses.html#LGPL)
@contact: franck.pommereau@ibisc.univ-evry.fr
"""
version = "0.9.16"
......
This diff is collapsed. Click to expand it.
"""Hashable mutable objets.
This module proposes hashable version of the mutable containers
C{list}, C{dict} and C{set}, called respectively C{hlist}, C{hdict}
and C{hset}. After one object has been hashed, it becomes not mutable
and raises a ValueError if a method which changes the object (let call
a I{mutation} such a method) is invoqued. The object can be then
un-hashed by calling C{unhash} on it so that it becomes mutable again.
`list`, `dict` and `set`, called respectively `hlist`, `hdict` and
`hset`. After one object has been hashed, it becomes not mutable and
raises a ValueError if a method which changes the object (let call a
_mutation_ such a method) is invoqued. The object can be then un-
hashed by calling `unhash` on it so that it becomes mutable again.
Notice that this may cause troubles if the object is stored in a set
or dict which uses its hashcode to locate it. Notice also that
hashable containers cannot be hashed if they contain non hashable
......@@ -24,9 +24,9 @@ ValueError: hashed 'hlist' object is not mutable
>>> l
hlist([0, 1, 2, 3, 4, 5])
Testing if a C{hlist} is in a C{set}, C{dict}, C{hset} or C{hdict}
causes its hashing. If this is not desirable, you should either
compensate with a call to C{unhash}, or test if a copy is in the set:
Testing if a `hlist` is in a `set`, `dict`, `hset` or `hdict` causes
its hashing. If this is not desirable, you should either compensate
with a call to `unhash`, or test if a copy is in the set:
>>> s = set()
>>> s.add(list(range(4)))
......@@ -54,7 +54,7 @@ from snakes.compat import *
def unhash (obj) :
"""Make the object hashable again.
>>> l = hlist(range(3))
>>> _ = hash(l)
>>> l.append(3)
......@@ -63,9 +63,9 @@ def unhash (obj) :
ValueError: hashed 'hlist' object is not mutable
>>> unhash(l)
>>> l.append(3)
@param obj: any object
@type obj: C{object}
@type obj: `object`
"""
try :
del obj._hash
......@@ -95,7 +95,7 @@ def hashable (cls) :
__hash__.__doc__ = classdict["__hash__"].__doc__
cls.__hash__ = __hash__
def __mutable__ (self) :
"Raise C{ValueError} if the %s has been hashed."
"Raise `ValueError` if the %s has been hashed."
if self.hashed() :
raise ValueError("hashed '%s' object is not mutable" % classname)
try :
......@@ -123,7 +123,7 @@ def hashable (cls) :
class hlist (list) :
"""Hashable lists.
>>> l = hlist(range(5))
>>> l
hlist([0, 1, 2, 3, 4])
......@@ -201,7 +201,7 @@ hlist = hashable(hlist)
class hdict (dict) :
"""Hashable dictionnaries.
>>> l = hlist(range(5))
>>> d = hdict([(l, 0)])
>>> d
......@@ -272,7 +272,7 @@ hdict = hashable(hdict)
class hset (set) :
"""Hashable sets.
>>> s = hset()
>>> l = hlist(range(5))
>>> s.add(l)
......
......@@ -17,7 +17,8 @@ class memoize(object):
return call
def __get__(self, obj, objtype):
"""Support instance methods."""
"""Support instance methods.
"""
return partial(self.__call__, obj)
def component_has_cycle(node, graph, proceeding, visited):
......@@ -237,7 +238,8 @@ class CodeGen (asdl.VisitorBase) :
return "\n".join(python(code, 0))
def compile_asdl(infilename, outfilename):
""" Helper function to compile asdl files. """
"""Helper function to compile asdl files.
"""
infile = open(infilename, 'r')
outfile = open(outfilename, 'w')
......
This diff is collapsed. Click to expand it.
......@@ -41,7 +41,7 @@ class Token (str) :
non-mutable object and this __init__ could not assign a str
content. For more information see:
http://docs.python.org/reference/datamodel.html#object.__new__
http://docs.python.org/reference/datamodel.html#object.__new__
"""
kind = token[0]
text = token[1]
......@@ -196,10 +196,8 @@ class Tokenizer (object) :
- skip: a collection of tokens that the tokenizer will
automatically skip (default to [COMMENT, NL])
- additional keywords arguments allow to define new tokens,
for instance, providing
DOLLAR='$'
defines a new token called 'DOLLAR' (its kind will be
automatically computed)
for instance, providing DOLLAR='$' defines a new token
called 'DOLLAR' (its kind will be automatically computed)
An instance of Tokenizer has the following attributes:
- self.opmap: a dict mapping operators token literals to the
......
......@@ -111,7 +111,7 @@ class ASDLParser(spark.GenericParser, object):
raise ASDLSyntaxError(tok.lineno, tok)
def p_module_0(self, arg):
" module ::= Id Id version { } "
"module ::= Id Id version { }"
(module, name, version, _0, _1) = arg
if module.value != "module":
raise ASDLSyntaxError(module.lineno,
......@@ -119,7 +119,7 @@ class ASDLParser(spark.GenericParser, object):
return Module(name, None, version)
def p_module(self, arg):
" module ::= Id Id version { definitions } "
"module ::= Id Id version { definitions }"
(module, name, version, _0, definitions, _1) = arg
if module.value != "module":
raise ASDLSyntaxError(module.lineno,
......@@ -135,32 +135,32 @@ class ASDLParser(spark.GenericParser, object):
return V
def p_definition_0(self, arg):
" definitions ::= definition "
"definitions ::= definition"
(definition,) = arg
return definition
def p_definition_1(self, arg):
" definitions ::= definition definitions "
"definitions ::= definition definitions"
(definitions, definition) = arg
return definitions + definition
def p_definition(self, arg):
" definition ::= Id = type "
"definition ::= Id = type"
(id, _, type) = arg
return [Type(id, type)]
def p_type_0(self, arg):
" type ::= product "
"type ::= product"
(product,) = arg
return product
def p_type_1(self, arg):
" type ::= sum "
"type ::= sum"
(sum,) = arg
return Sum(sum)
def p_type_2(self, arg):
" type ::= sum Id ( fields ) "
"type ::= sum Id ( fields )"
(sum, id, _0, attributes, _1) = arg
if id.value != "attributes":
raise ASDLSyntaxError(id.lineno,
......@@ -170,74 +170,74 @@ class ASDLParser(spark.GenericParser, object):
return Sum(sum, attributes)
def p_product(self, arg):
" product ::= ( fields ) "
"product ::= ( fields )"
(_0, fields, _1) = arg
fields.reverse()
return Product(fields)
def p_sum_0(self, arg):
" sum ::= constructor """
"sum ::= constructor"""
(constructor,) = arg
return [constructor]
def p_sum_1(self, arg):
" sum ::= constructor | sum "
"sum ::= constructor | sum"
(constructor, _, sum) = arg
return [constructor] + sum
def p_sum_2(self, arg):
" sum ::= constructor | sum "
"sum ::= constructor | sum"
(constructor, _, sum) = arg
return [constructor] + sum
def p_constructor_0(self, arg):
" constructor ::= Id "
"constructor ::= Id"
(id,) = arg
return Constructor(id)
def p_constructor_1(self, arg):
" constructor ::= Id ( fields ) "
"constructor ::= Id ( fields )"
(id, _0, fields, _1) = arg
fields.reverse()
return Constructor(id, fields)
def p_fields_0(self, arg):
" fields ::= field "
"fields ::= field"
(field,) = arg
return [field]
def p_fields_1(self, arg):
" fields ::= field , fields "
"fields ::= field , fields"
(field, _, fields) = arg
return fields + [field]
def p_field_0(self, arg):
" field ::= Id "
"field ::= Id"
(type,) = arg
return Field(type)
def p_field_1(self, arg):
" field ::= Id Id "
"field ::= Id Id"
(type, name) = arg
return Field(type, name)
def p_field_2(self, arg):
" field ::= Id * Id "
"field ::= Id * Id"
(type, _, name) = arg
return Field(type, name, seq=1)
def p_field_3(self, arg):
" field ::= Id ? Id "
"field ::= Id ? Id"
(type, _, name) = arg
return Field(type, name, opt=1)
def p_field_4(self, arg):
" field ::= Id * "
"field ::= Id *"
(type, _) = arg
return Field(type, seq=1)
def p_field_5(self, arg):
" field ::= Id ? "
"field ::= Id ?"
(type, _) = arg
return Field(type, opt=1)
......
......@@ -1623,7 +1623,7 @@ class Translator (object) :
return self.ST.Set(lineno=st.srow, col_offset=st.scol,
elts=[self.do(st[0], ctx)])
elif st[1].text == ":" :
if st[3].text == "," :
if len(st) < 4 or st[3].text == "," :
return self.ST.Dict(lineno=st.srow, col_offset=st.scol,
keys=[self.do(child, ctx)
for child in st[::4]],
......
......@@ -17,13 +17,16 @@ def interleave(inter, f, seq):
f(x)
class Unparser:
"""Methods in this class recursively traverse an AST and
output source code for the abstract syntax; original formatting
is disregarged. """
"""Methods in this class recursively traverse an AST and output
source code for the abstract syntax; original formatting is
disregarged.
"""
def __init__(self, tree, file = sys.stdout):
"""Unparser(tree, file=sys.stdout) -> None.
Print the source for tree to file."""
Print the source for tree to file.
"""
self.f = file
self._indent = 0
self.dispatch(tree)
......@@ -31,7 +34,9 @@ class Unparser:
self.f.flush()
def fill(self, text = ""):
"Indent a piece of text, according to the current indentation level"
"""Indent a piece of text, according to the current indentation
level
"""
self.f.write("\n" + " "*self._indent + text)
def write(self, text):
......
This diff could not be displayed because it is too large.
"""A plugins system.
The first example shows how to load a plugin: we load
C{snakes.plugins.hello} and plug it into C{snakes.nets}, which results
in a new module that actually C{snakes.nets} extended by
C{snakes.plugins.hello}.
`snakes.plugins.hello` and plug it into `snakes.nets`, which results
in a new module that actually `snakes.nets` extended by
`snakes.plugins.hello`.
>>> import snakes.plugins as plugins
>>> hello_nets = plugins.load('hello', 'snakes.nets')
......@@ -14,14 +14,14 @@ Hello from N
>>> n.hello()
Hi, this is N!
The next example shows how to simulate the effect of C{import module}:
we give to C{load} a thrid argument that is the name of the created
module, from which it becomes possible to import names or C{*}.
The next example shows how to simulate the effect of `import module`:
we give to `load` a thrid argument that is the name of the created
module, from which it becomes possible to import names or `*`.
B{Warning:} this feature will not work C{load} is not called from the
module where we then do the C{from ... import ...}. This is exactly
the same when, from a module C{foo} that you load a module C{bar}: if
C{bar} loads other modules they will not be imported in C{foo}.
**Warning:** this feature will not work `load` is not called from the
module where we then do the `from ... import ...`. This is exactly the
same when, from a module `foo` that you load a module `bar`: if `bar`
loads other modules they will not be imported in `foo`.
>>> plugins.load('hello', 'snakes.nets', 'another_version')
<module ...>
......@@ -33,7 +33,7 @@ Hello from another net
>>> n.hello()
Hi, this is yet another net!
How to define a plugin is explained in the example C{hello}.
How to define a plugin is explained in the example `hello`.
"""
import imp, sys, inspect
......@@ -56,21 +56,20 @@ def update (module, objects) :
def build (name, module, *objects) :
"""Builds an extended module.
The parameter C{module} is exactly that taken by the function
C{extend} of a plugin. This list argument C{objects} holds all the
objects, constructed in C{extend}, that are extensions of objects
from C{module}. The resulting value should be returned by
C{extend}.
The parameter `module` is exactly that taken by the function
`extend` of a plugin. This list argument `objects` holds all the
objects, constructed in `extend`, that are extensions of objects
from `module`. The resulting value should be returned by `extend`.
@param name: the name of the constructed module
@type name: C{str}
@type name: `str`
@param module: the extended module
@type module: C{module}
@type module: `module`
@param objects: the sub-objects
@type objects: each is a class object
@return: the new module
@rtype: C{module}
@rtype: `module`
"""
result = imp.new_module(name)
result.__dict__.update(module.__dict__)
......@@ -85,22 +84,22 @@ def build (name, module, *objects) :
def load (plugins, base, name=None) :
"""Load plugins.
C{plugins} can be a single plugin name or module or a list of such
values. If C{name} is not C{None}, the extended module is loaded
ad C{name} in C{sys.modules} as well as in the global environment
from which C{load} was called.
@param plugins: the module that implements the plugin, or its name,
or a collection of such values
@type plugins: C{str} or C{module}, or a C{list}/C{tuple}/... of
such values
`plugins` can be a single plugin name or module or a list of such
values. If `name` is not `None`, the extended module is loaded ad
`name` in `sys.modules` as well as in the global environment from
which `load` was called.
@param plugins: the module that implements the plugin, or its
name, or a collection of such values
@type plugins: `str` or `module`, or a `list`/`tuple`/... of such
values
@param base: the module being extended or its name
@type base: C{str} or C{module}
@type base: `str` or `module`
@param name: the name of the created module
@type name: C{str}
@type name: `str`
@return: the extended module
@rtype: C{module}
@rtype: `module`
"""
if type(base) is str :
result = __import__(base, fromlist=["__name__"])
......@@ -128,7 +127,7 @@ def load (plugins, base, name=None) :
def plugin (base, depends=[], conflicts=[]) :
"""Decorator for extension functions
@param base: name of base module (usually 'snakes.nets')
@type base: str
@param depends: list of plugins on which this one depends
......@@ -166,7 +165,7 @@ def plugin (base, depends=[], conflicts=[]) :
return wrapper
def new_instance (cls, obj) :
"""Create a copy of C{obj} which is an instance of C{cls}
"""Create a copy of `obj` which is an instance of `cls`
"""
result = object.__new__(cls)
result.__dict__.update(obj.__dict__)
......
......@@ -12,7 +12,6 @@ class Cluster (object) :
... Cluster(['3', '4', '5'],
... [Cluster(['C', 'D'])])])
Cluster(...)
"""
self._nodes = set(nodes)
self._children = []
......@@ -160,7 +159,6 @@ class Cluster (object) :
[Cluster(['A'], [])]),
Cluster(['...', '...'],
[Cluster(['...', '...'], [])])])
"""
if name in self._cluster :
self._cluster[name].remove_node(name)
......
"""Draw Petri nets using PyGraphViz
- adds a method C{draw} to C{PetriNet} and C{StateGraph} that creates
a drawing of the object in a file.
* adds a method `draw` to `PetriNet` and `StateGraph` that creates
a drawing of the object in a file.
>>> import snakes.plugins
>>> snakes.plugins.load('gv', 'snakes.nets', 'nets')
......@@ -16,14 +16,11 @@
>>> n.add_output('p11', 't10', Expression('x+1'))
>>> n.add_input('p11', 't01', Variable('y'))
>>> n.add_output('p00', 't01', Expression('y-1'))
>>> for engine in ('neato', 'dot', 'circo', 'twopi', 'fdp') :
... n.draw(',test-gv-%s.png' % engine, engine=engine)
>>> s = StateGraph(n)
>>> s.build()
>>> s.draw(',test-gv-graph.png')
>>> for node in sorted(n.node(), key=str) :
... node.pos.moveto(-100, -100)
>>> n.layout()
......@@ -151,36 +148,37 @@ class Graph (Cluster) :
"snakes.plugins.pos"])
def extend (module) :
class PetriNet (module.PetriNet) :
"An extension with a method C{draw}"
"An extension with a method `draw`"
def draw (self, filename=None, engine="dot", debug=False,
graph_attr=None, cluster_attr=None,
place_attr=None, trans_attr=None, arc_attr=None) :
"""
@param filename: the name of the image file to create or
C{None} if only the computed graph is needed
@type filename: C{None} or C{str}
`None` if only the computed graph is needed
@type filename: `None` or `str`
@param engine: the layout engine to use: 'dot' (default),
'neato', 'circo', 'twopi' or 'fdp'
@type engine: C{str}
'neato', 'circo', 'twopi' or 'fdp'
@type engine: `str`
@param place_attr: a function to format places, it will be
called with the place and its attributes dict as
parameters
@type place_attr: C{function(Place,dict)->None}
called with the place and its attributes dict as
parameters
@type place_attr: `function(Place,dict)->None`
@param trans_attr: a function to format transitions, it
will be called with the transition and its attributes dict
as parameters
@type trans_attr: C{function(Transition,dict)->None}
@param arc_attr: a function to format arcs, it will be
called with the label and its attributes dict as
parameters
@type arc_attr: C{function(ArcAnnotation,dict)->None}
will be called with the transition and its attributes
dict as parameters
@type trans_attr: `function(Transition,dict)->None`
@param arc_attr: a function to format arcs, it will be
called with the label and its attributes dict as
parameters
@type arc_attr: `function(ArcAnnotation,dict)->None`
@param cluster_attr: a function to format clusters of
nodes, it will be called with the cluster and its
attributes dict as parameters
@type cluster_attr: C{function(snakes.plugins.clusters.Cluster,dict)->None}
@return: C{None} if C{filename} is not C{None}, the
computed graph otherwise
@rtype: C{None} or C{pygraphviz.AGraph}
nodes, it will be called with the cluster and its
attributes dict as parameters
@type cluster_attr:
`function(snakes.plugins.clusters.Cluster,dict)->None`
@return: `None` if `filename` is not `None`, the computed
graph otherwise
@rtype: `None` or `pygraphviz.AGraph`
"""
nodemap = dict((node.name, "node_%s" % num)
for num, node in enumerate(self.node()))
......@@ -243,31 +241,31 @@ def extend (module) :
self.node(node[n]).pos.moveto(x*xscale, y*yscale)
class StateGraph (module.StateGraph) :
"An extension with a method C{draw}"
"An extension with a method `draw`"
def draw (self, filename=None, engine="dot", debug=False,
node_attr=None, edge_attr=None, graph_attr=None) :
"""
@param filename: the name of the image file to create or
C{None} if only the computed graph is needed
@type filename: C{None} or C{str}
"""@param filename: the name of the image file to create or
`None` if only the computed graph is needed
@type filename: `None` or `str`
@param engine: the layout engine to use: 'dot' (default),
'neato', 'circo', 'twopi' or 'fdp'
@type engine: C{str}
'neato', 'circo', 'twopi' or 'fdp'
@type engine: `str`
@param node_attr: a function to format nodes, it will be
called with the state number, the C{StateGraph} object
and attributes dict as parameters
@type node_attr: C{function(int,StateGraph,dict)->None}
@param edge_attr: a function to format edges, it
will be called with the transition, its mode and
attributes dict as parameters
@type trans_attr: C{function(Transition,Substitution,dict)->None}
@param graph_attr: a function to format grapg, it
will be called with the state graphe and attributes dict
as parameters
@type graph_attr: C{function(StateGraph,dict)->None}
@return: C{None} if C{filename} is not C{None}, the
computed graph otherwise
@rtype: C{None} or C{pygraphviz.AGraph}
called with the state number, the `StateGraph` object
and attributes dict as parameters
@type node_attr: `function(int,StateGraph,dict)->None`
@param edge_attr: a function to format edges, it will be
called with the transition, its mode and attributes
dict as parameters
@type trans_attr:
`function(Transition,Substitution,dict)->None`
@param graph_attr: a function to format grapg, it will be
called with the state graphe and attributes dict as
parameters
@type graph_attr: `function(StateGraph,dict)->None`
@return: `None` if `filename` is not `None`, the computed
graph otherwise
@rtype: `None` or `pygraphviz.AGraph`
"""
attr = dict(style="invis",
splines="true")
......
"""An example plugin that allows instances class C{PetriNet} to say hello.
"""An example plugin that allows instances class `PetriNet` to say hello.
A new method C{hello} is added. The constructor is added a keyword
argument C{hello} that must be the C{str} to print when calling
C{hello}, with one C{%s} that will be replaced by the name of the net
when C{hello} is called.
A new method `hello` is added. The constructor is added a keyword
argument `hello` that must be the `str` to print when calling `hello`,
with one `%s` that will be replaced by the name of the net when
`hello` is called.
Defining a plugins need writing a module with a single function called
C{extend} that takes a single argument that is the module to be
`extend` that takes a single argument that is the module to be
extended.
Inside the function, extensions of the classes in the module are
defined as normal sub-classes.
The function C{extend} should return the extended module created by
C{snakes.plugins.build} that takes as arguments: the name of the
The function `extend` should return the extended module created by
`snakes.plugins.build` that takes as arguments: the name of the
extended module, the module taken as argument and the sub-classes
defined (expected as a list argument C{*args} in no special order).
defined (expected as a list argument `*args` in no special order).
If the plugin depends on other plugins, for instance C{foo} and
C{bar}, the function C{extend} should be decorated by
C{@depends('foo', 'bar')}.
If the plugin depends on other plugins, for instance `foo` and `bar`,
the function `extend` should be decorated by `@depends('foo', 'bar')`.
Read the source code of this module to have an example
"""
......@@ -28,34 +27,34 @@ import snakes.plugins
@snakes.plugins.plugin("snakes.nets")
def extend (module) :
"""Extends C{module}
"""Extends `module`
"""
class PetriNet (module.PetriNet) :
"""Extension of the class C{PetriNet} in C{module}
"""Extension of the class `PetriNet` in `module`
"""
def __init__ (self, name, **args) :
"""When extending an existing method, take care that you
may be working on an already extended class, so you so not
"""When extending an existing method, take care that you may
be working on an already extended class, so you so not
know how its arguments have been changed. So, always use
those from the unextended class plus C{**args}, remove
from it what your plugin needs and pass it to the method
of the extended class if you need to call it.
those from the unextended class plus `**args`, remove from
it what your plugin needs and pass it to the method of the
extended class if you need to call it.
>>> PetriNet('N').hello()
Hello from N
>>> PetriNet('N', hello='Hi! This is %s...').hello()
Hi! This is N...
@param args: plugin options
@keyword hello: the message to print, with C{%s} where the
net name should appear.
@type hello: C{str}
@keyword hello: the message to print, with `%s` where the
net name should appear.
@type hello: `str`
"""
self._hello = args.pop("hello", "Hello from %s")
module.PetriNet.__init__(self, name, **args)
def hello (self) :
"""A new method C{hello}
"""A new method `hello`
>>> n = PetriNet('N')
>>> n.hello()
Hello from N
......
"""A plugin to add labels to nodes and nets.
"""
from snakes.plugins import plugin, new_instance
......
"""A plugin to add positions to the nodes.
- C{Place} and C{Transition} constructors are added an optional
argument C{pos=(x,y)} to set their position
- C{Place} and C{Transition} are added an attribute C{pos} that is
pair of numbers with attributes C{x} and C{y} and methods
C{shift(dx, dy)} and C{moveto(x, y)}
- Petri nets are added methods C{bbox()} that returns a pair of
extrema C{((xmin, ymin), (xmax, ymax))}, a method C{shift(dx, dy)}
that shift all the nodes, and a method C{transpose()} that rotates
* `Place` and `Transition` constructors are added an optional argument
`pos=(x,y)` to set their position
* `Place` and `Transition` are added an attribute `pos` that is pair
of numbers with attributes `x` and `y` and methods `shift(dx, dy)`
and `moveto(x, y)`
* Petri nets are added methods `bbox()` that returns a pair of
extrema `((xmin, ymin), (xmax, ymax))`, a method `shift(dx, dy)`
that shift all the nodes, and a method `transpose()` that rotates
the net in such a way that the top-down direction becomes
left-right
......
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
......@@ -40,7 +40,8 @@ class Decl (object) :
setattr(self, key, val)
class GetInstanceArgs (object) :
"""Bind arguments for a net instance"""
"""Bind arguments for a net instance
"""
def __init__ (self, node) :
self.argspec = []
self.arg = {}
......