mirror of https://github.com/KLayout/klayout.git
Synchronizing Python PCellDeclarationHelper between the two implementations (for standalone module + build-in for app)
This commit is contained in:
parent
7d0964655d
commit
3e8f03ef5f
|
|
@ -459,7 +459,7 @@ class _PCellDeclarationHelper(pya.PCellDeclaration):
|
||||||
|
|
||||||
def produce(self, layout, layers, parameters, cell):
|
def produce(self, layout, layers, parameters, cell):
|
||||||
"""
|
"""
|
||||||
coerce parameters (make consistent)
|
produces the layout
|
||||||
"""
|
"""
|
||||||
self.init_values(parameters, layers)
|
self.init_values(parameters, layers)
|
||||||
self.cell = cell
|
self.cell = cell
|
||||||
|
|
|
||||||
|
|
@ -2,298 +2,309 @@ from klayout.db import Trans, PCellDeclaration, PCellParameterDeclaration
|
||||||
|
|
||||||
|
|
||||||
class _PCellDeclarationHelperLayerDescriptor(object):
|
class _PCellDeclarationHelperLayerDescriptor(object):
|
||||||
"""
|
"""
|
||||||
A descriptor object which translates the PCell parameters into class attributes
|
A descriptor object which translates the PCell parameters into class attributes
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, param_index):
|
def __init__(self, param_index):
|
||||||
self.param_index = param_index
|
self.param_index = param_index
|
||||||
|
|
||||||
def __get__(self, obj, type=None):
|
def __get__(self, obj, type = None):
|
||||||
return obj._layers[self.param_index]
|
return obj._layers[self.param_index]
|
||||||
|
|
||||||
def __set__(self, obj, value):
|
def __set__(self, obj, value):
|
||||||
raise AttributeError("can't change layer attribute")
|
raise AttributeError("can't change layer attribute")
|
||||||
|
|
||||||
|
|
||||||
class _PCellDeclarationHelperParameterDescriptor(object):
|
class _PCellDeclarationHelperParameterDescriptor(object):
|
||||||
"""
|
"""
|
||||||
A descriptor object which translates the PCell parameters into class attributes
|
A descriptor object which translates the PCell parameters into class attributes
|
||||||
|
|
||||||
In some cases (i.e. can_convert_from_shape), these placeholders are not
|
|
||||||
connected to real parameters (obj._param_values is None). In this case,
|
|
||||||
the descriptor acts as a value holder (self.value)
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, param_index):
|
|
||||||
self.param_index = param_index
|
|
||||||
self.value = None
|
|
||||||
|
|
||||||
def __get__(self, obj, type=None):
|
|
||||||
if obj._param_values:
|
|
||||||
return obj._param_values[self.param_index]
|
|
||||||
else:
|
|
||||||
return self.value
|
|
||||||
|
|
||||||
def __set__(self, obj, value):
|
|
||||||
if obj._param_values:
|
|
||||||
obj._param_values[self.param_index] = value
|
|
||||||
else:
|
|
||||||
self.value = value
|
|
||||||
|
|
||||||
|
In some cases (i.e. can_convert_from_shape), these placeholders are not
|
||||||
|
connected to real parameters (obj._param_values is None). In this case,
|
||||||
|
the descriptor acts as a value holder (self.value)
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, param_index, param_name):
|
||||||
|
self.param_index = param_index
|
||||||
|
self.param_name = param_name
|
||||||
|
self.value = None
|
||||||
|
|
||||||
|
def __get__(self, obj, type = None):
|
||||||
|
if obj._param_values:
|
||||||
|
return obj._param_values[self.param_index]
|
||||||
|
elif obj._param_states:
|
||||||
|
return obj._param_states.parameter(self.param_name)
|
||||||
|
else:
|
||||||
|
return self.value
|
||||||
|
|
||||||
|
def __set__(self, obj, value):
|
||||||
|
if obj._param_values:
|
||||||
|
obj._param_values[self.param_index] = value
|
||||||
|
else:
|
||||||
|
self.value = value
|
||||||
|
|
||||||
class _PCellDeclarationHelper(PCellDeclaration):
|
class _PCellDeclarationHelper(PCellDeclaration):
|
||||||
|
"""
|
||||||
|
A helper class that somewhat simplifies the implementation
|
||||||
|
of a PCell
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
"""
|
"""
|
||||||
A helper class that somewhat simplifies the implementation
|
initialize this instance
|
||||||
of a PCell
|
|
||||||
"""
|
"""
|
||||||
|
# "private" attributes
|
||||||
|
self._param_decls = []
|
||||||
|
self._param_values = None
|
||||||
|
self._param_states = None
|
||||||
|
self._layer_param_index = []
|
||||||
|
self._layers = []
|
||||||
|
# public attributes
|
||||||
|
self.layout = None
|
||||||
|
self.shape = None
|
||||||
|
self.layer = None
|
||||||
|
self.cell = None
|
||||||
|
|
||||||
def __init__(self):
|
def param(self, name, value_type, description, hidden = False, readonly = False, unit = None, default = None, choices = None):
|
||||||
"""
|
"""
|
||||||
initialize this instance
|
Defines a parameter
|
||||||
"""
|
name -> the short name of the parameter
|
||||||
# "private" attributes
|
type -> the type of the parameter
|
||||||
self._param_decls = []
|
description -> the description text
|
||||||
self._param_values = None
|
named parameters
|
||||||
self._layer_param_index = []
|
hidden -> (boolean) true, if the parameter is not shown in the dialog
|
||||||
self._layers = []
|
readonly -> (boolean) true, if the parameter cannot be edited
|
||||||
# public attributes
|
unit -> the unit string
|
||||||
self.layout = None
|
default -> the default value
|
||||||
self.shape = None
|
choices -> ([ [ d, v ], ...) choice descriptions/value for choice type
|
||||||
self.layer = None
|
this method defines accessor methods for the parameters
|
||||||
self.cell = None
|
{name} -> read accessor
|
||||||
|
set_{name} -> write accessor ({name}= does not work because the
|
||||||
|
Ruby confuses that method with variables)
|
||||||
|
{name}_layer -> read accessor for the layer index for TypeLayer parameters
|
||||||
|
"""
|
||||||
|
|
||||||
|
# create accessor methods for the parameters
|
||||||
|
param_index = len(self._param_decls)
|
||||||
|
setattr(type(self), name, _PCellDeclarationHelperParameterDescriptor(param_index, name))
|
||||||
|
|
||||||
def param(
|
if value_type == type(self).TypeLayer:
|
||||||
self,
|
setattr(type(self), name + "_layer", _PCellDeclarationHelperLayerDescriptor(len(self._layer_param_index)))
|
||||||
name,
|
self._layer_param_index.append(param_index)
|
||||||
value_type,
|
|
||||||
description,
|
# store the parameter declarations
|
||||||
hidden=False,
|
pdecl = PCellParameterDeclaration(name, value_type, description)
|
||||||
readonly=False,
|
self._param_decls.append(pdecl)
|
||||||
unit=None,
|
|
||||||
default=None,
|
# set additional attributes of the parameters
|
||||||
choices=None,
|
pdecl.hidden = hidden
|
||||||
):
|
pdecl.readonly = readonly
|
||||||
"""
|
if not (default is None):
|
||||||
Defines a parameter
|
pdecl.default = default
|
||||||
name -> the short name of the parameter
|
if not (unit is None):
|
||||||
type -> the type of the parameter
|
pdecl.unit = unit
|
||||||
description -> the description text
|
if not (choices is None):
|
||||||
named parameters
|
if not isinstance(choices, list) and not isinstance(choices, tuple):
|
||||||
hidden -> (boolean) true, if the parameter is not shown in the dialog
|
raise "choices value must be an list/tuple of two-element arrays (description, value)"
|
||||||
readonly -> (boolean) true, if the parameter cannot be edited
|
for c in choices:
|
||||||
unit -> the unit string
|
if (not isinstance(choices, list) and not isinstance(choices, tuple)) or len(c) != 2:
|
||||||
default -> the default value
|
raise "choices value must be an list/tuple of two-element arrays (description, value)"
|
||||||
choices -> ([ [ d, v ], ...) choice descriptions/value for choice type
|
pdecl.add_choice(c[0],c[1])
|
||||||
this method defines accessor methods for the parameters
|
|
||||||
{name} -> read accessor
|
# return the declaration object for further operations
|
||||||
set_{name} -> write accessor ({name}= does not work because the
|
return pdecl
|
||||||
Ruby confuses that method with variables)
|
|
||||||
{name}_layer -> read accessor for the layer index for TypeLayer parameters
|
def display_text(self, parameters):
|
||||||
"""
|
"""
|
||||||
|
implementation of display_text
|
||||||
|
"""
|
||||||
|
self._param_values = parameters
|
||||||
|
try:
|
||||||
|
text = self.display_text_impl()
|
||||||
|
finally:
|
||||||
|
self._param_values = None
|
||||||
|
return text
|
||||||
|
|
||||||
|
def get_parameters(self):
|
||||||
|
"""
|
||||||
|
gets the parameters
|
||||||
|
"""
|
||||||
|
return self._param_decls
|
||||||
|
|
||||||
# create accessor methods for the parameters
|
def get_values(self):
|
||||||
param_index = len(self._param_decls)
|
"""
|
||||||
setattr(
|
gets the temporary parameter values
|
||||||
type(self), name, _PCellDeclarationHelperParameterDescriptor(param_index)
|
"""
|
||||||
)
|
v = self._param_values
|
||||||
|
self._param_values = None
|
||||||
|
return v
|
||||||
|
|
||||||
|
def init_values(self, values = None, layers = None, states = None):
|
||||||
|
"""
|
||||||
|
initializes the temporary parameter values
|
||||||
|
"values" are the original values. If "None" is given, the
|
||||||
|
default values will be used.
|
||||||
|
"layers" are the layer indexes corresponding to the layer
|
||||||
|
parameters.
|
||||||
|
"""
|
||||||
|
self._param_values = None
|
||||||
|
self._param_states = None
|
||||||
|
if states:
|
||||||
|
self._param_states = states
|
||||||
|
elif not values:
|
||||||
|
self._param_values = []
|
||||||
|
for pd in self._param_decls:
|
||||||
|
self._param_values.append(pd.default)
|
||||||
|
else:
|
||||||
|
self._param_values = values
|
||||||
|
self._layers = layers
|
||||||
|
|
||||||
if value_type == type(self).TypeLayer:
|
def finish(self):
|
||||||
setattr(
|
"""
|
||||||
type(self),
|
Needs to be called at the end of an implementation
|
||||||
name + "_layer",
|
"""
|
||||||
_PCellDeclarationHelperLayerDescriptor(len(self._layer_param_index)),
|
self._param_values = None
|
||||||
)
|
self._param_states = None
|
||||||
self._layer_param_index.append(param_index)
|
self._layers = None
|
||||||
|
self._cell = None
|
||||||
|
self._layout = None
|
||||||
|
self._layer = None
|
||||||
|
self._shape = None
|
||||||
|
|
||||||
|
def get_layers(self, parameters):
|
||||||
|
"""
|
||||||
|
gets the layer definitions
|
||||||
|
"""
|
||||||
|
layers = []
|
||||||
|
for i in self._layer_param_index:
|
||||||
|
layers.append(parameters[i])
|
||||||
|
return layers
|
||||||
|
|
||||||
|
def callback(self, layout, name, states):
|
||||||
|
"""
|
||||||
|
callback (change state on parameter change)
|
||||||
|
"""
|
||||||
|
self.init_values(states = states)
|
||||||
|
self.layout = layout
|
||||||
|
try:
|
||||||
|
self.callback_impl(name)
|
||||||
|
finally:
|
||||||
|
self.finish()
|
||||||
|
|
||||||
# store the parameter declarations
|
def coerce_parameters(self, layout, parameters):
|
||||||
pdecl = PCellParameterDeclaration(name, value_type, description)
|
"""
|
||||||
self._param_decls.append(pdecl)
|
coerce parameters (make consistent)
|
||||||
|
"""
|
||||||
|
self.init_values(parameters)
|
||||||
|
self.layout = layout
|
||||||
|
try:
|
||||||
|
self.coerce_parameters_impl()
|
||||||
|
parameters = self.get_values()
|
||||||
|
finally:
|
||||||
|
self.finish()
|
||||||
|
return parameters
|
||||||
|
|
||||||
# set additional attributes of the parameters
|
def produce(self, layout, layers, parameters, cell):
|
||||||
pdecl.hidden = hidden
|
"""
|
||||||
pdecl.readonly = readonly
|
produces the layout
|
||||||
if not (default is None):
|
"""
|
||||||
pdecl.default = default
|
self.init_values(parameters, layers)
|
||||||
if not (unit is None):
|
self.cell = cell
|
||||||
pdecl.unit = unit
|
self.layout = layout
|
||||||
if not (choices is None):
|
try:
|
||||||
if not isinstance(choices, list) and not isinstance(choices, tuple):
|
self.produce_impl()
|
||||||
raise Exception(
|
finally:
|
||||||
"choices value must be an list/tuple of two-element arrays (description, value)"
|
self.finish()
|
||||||
)
|
|
||||||
for c in choices:
|
|
||||||
if (
|
|
||||||
not isinstance(choices, list) and not isinstance(choices, tuple)
|
|
||||||
) or len(c) != 2:
|
|
||||||
raise Exception(
|
|
||||||
"choices value must be an list/tuple of two-element arrays (description, value)"
|
|
||||||
)
|
|
||||||
pdecl.add_choice(c[0], c[1])
|
|
||||||
|
|
||||||
# return the declaration object for further operations
|
|
||||||
return pdecl
|
|
||||||
|
|
||||||
def display_text(self, parameters):
|
|
||||||
"""
|
|
||||||
implementation of display_text
|
|
||||||
"""
|
|
||||||
self._param_values = parameters
|
|
||||||
text = self.display_text_impl()
|
|
||||||
self._param_values = None
|
|
||||||
return text
|
|
||||||
|
|
||||||
def get_parameters(self):
|
|
||||||
"""
|
|
||||||
gets the parameters
|
|
||||||
"""
|
|
||||||
return self._param_decls
|
|
||||||
|
|
||||||
def get_values(self):
|
|
||||||
"""
|
|
||||||
gets the temporary parameter values
|
|
||||||
"""
|
|
||||||
v = self._param_values
|
|
||||||
self._param_values = None
|
|
||||||
return v
|
|
||||||
|
|
||||||
def init_values(self, values=None, layers=None):
|
|
||||||
"""
|
|
||||||
initializes the temporary parameter values
|
|
||||||
"values" are the original values. If "None" is given, the
|
|
||||||
default values will be used.
|
|
||||||
"layers" are the layer indexes corresponding to the layer
|
|
||||||
parameters.
|
|
||||||
"""
|
|
||||||
if not values:
|
|
||||||
self._param_values = []
|
|
||||||
for pd in self._param_decls:
|
|
||||||
self._param_values.append(pd.default)
|
|
||||||
else:
|
|
||||||
self._param_values = values
|
|
||||||
self._layers = layers
|
|
||||||
|
|
||||||
def finish(self):
|
|
||||||
"""
|
|
||||||
Needs to be called at the end of produce() after init_values was used
|
|
||||||
"""
|
|
||||||
self._param_values = None
|
|
||||||
self._layers = None
|
|
||||||
|
|
||||||
def get_layers(self, parameters):
|
|
||||||
"""
|
|
||||||
get the layer definitions
|
|
||||||
"""
|
|
||||||
layers = []
|
|
||||||
for i in self._layer_param_index:
|
|
||||||
layers.append(parameters[i])
|
|
||||||
return layers
|
|
||||||
|
|
||||||
def coerce_parameters(self, layout, parameters):
|
|
||||||
"""
|
|
||||||
coerce parameters (make consistent)
|
|
||||||
"""
|
|
||||||
self.init_values(parameters)
|
|
||||||
self.layout = layout
|
|
||||||
self.coerce_parameters_impl()
|
|
||||||
self.layout = None
|
|
||||||
return self.get_values()
|
|
||||||
|
|
||||||
def produce(self, layout, layers, parameters, cell):
|
|
||||||
"""
|
|
||||||
coerce parameters (make consistent)
|
|
||||||
"""
|
|
||||||
self.init_values(parameters, layers)
|
|
||||||
self.cell = cell
|
|
||||||
self.layout = layout
|
|
||||||
self.produce_impl()
|
|
||||||
self.cell = None
|
|
||||||
self.layout = None
|
|
||||||
self.finish()
|
|
||||||
|
|
||||||
def can_create_from_shape(self, layout, shape, layer):
|
|
||||||
"""
|
|
||||||
produce a helper for can_create_from_shape
|
|
||||||
"""
|
|
||||||
self.layout = layout
|
|
||||||
self.shape = shape
|
|
||||||
self.layer = layer
|
|
||||||
ret = self.can_create_from_shape_impl()
|
|
||||||
self.layout = None
|
|
||||||
self.shape = None
|
|
||||||
self.layer = None
|
|
||||||
return ret
|
|
||||||
|
|
||||||
def transformation_from_shape(self, layout, shape, layer):
|
|
||||||
"""
|
|
||||||
produce a helper for parameters_from_shape
|
|
||||||
"""
|
|
||||||
self.layout = layout
|
|
||||||
self.shape = shape
|
|
||||||
self.layer = layer
|
|
||||||
t = self.transformation_from_shape_impl()
|
|
||||||
self.layout = None
|
|
||||||
self.shape = None
|
|
||||||
self.layer = None
|
|
||||||
return t
|
|
||||||
|
|
||||||
def parameters_from_shape(self, layout, shape, layer):
|
|
||||||
"""
|
|
||||||
produce a helper for parameters_from_shape
|
|
||||||
with this helper, the implementation can use the parameter setters
|
|
||||||
"""
|
|
||||||
self.init_values()
|
|
||||||
self.layout = layout
|
|
||||||
self.shape = shape
|
|
||||||
self.layer = layer
|
|
||||||
self.parameters_from_shape_impl()
|
|
||||||
param = self.get_values()
|
|
||||||
self.layout = None
|
|
||||||
self.shape = None
|
|
||||||
self.layer = None
|
|
||||||
return param
|
|
||||||
|
|
||||||
def display_text_impl(self):
|
|
||||||
"""
|
|
||||||
default implementation
|
|
||||||
"""
|
|
||||||
return ""
|
|
||||||
|
|
||||||
def coerce_parameters_impl(self):
|
|
||||||
"""
|
|
||||||
default implementation
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
def produce_impl(self):
|
|
||||||
"""
|
|
||||||
default implementation
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
def can_create_from_shape_impl(self):
|
|
||||||
"""
|
|
||||||
default implementation
|
|
||||||
"""
|
|
||||||
return False
|
|
||||||
|
|
||||||
def parameters_from_shape_impl(self):
|
|
||||||
"""
|
|
||||||
default implementation
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
def transformation_from_shape_impl(self):
|
|
||||||
"""
|
|
||||||
default implementation
|
|
||||||
"""
|
|
||||||
return Trans()
|
|
||||||
|
|
||||||
|
def can_create_from_shape(self, layout, shape, layer):
|
||||||
|
"""
|
||||||
|
produce a helper for can_create_from_shape
|
||||||
|
"""
|
||||||
|
self.layout = layout
|
||||||
|
self.shape = shape
|
||||||
|
self.layer = layer
|
||||||
|
try:
|
||||||
|
ret = self.can_create_from_shape_impl()
|
||||||
|
finally:
|
||||||
|
self.finish()
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def transformation_from_shape(self, layout, shape, layer):
|
||||||
|
"""
|
||||||
|
produce a helper for parameters_from_shape
|
||||||
|
"""
|
||||||
|
self.layout = layout
|
||||||
|
self.shape = shape
|
||||||
|
self.layer = layer
|
||||||
|
try:
|
||||||
|
t = self.transformation_from_shape_impl()
|
||||||
|
finally:
|
||||||
|
self.finish()
|
||||||
|
return t
|
||||||
|
|
||||||
|
def parameters_from_shape(self, layout, shape, layer):
|
||||||
|
"""
|
||||||
|
produce a helper for parameters_from_shape
|
||||||
|
with this helper, the implementation can use the parameter setters
|
||||||
|
"""
|
||||||
|
self.init_values()
|
||||||
|
self.layout = layout
|
||||||
|
self.shape = shape
|
||||||
|
self.layer = layer
|
||||||
|
try:
|
||||||
|
self.parameters_from_shape_impl()
|
||||||
|
param = self.get_values()
|
||||||
|
finally:
|
||||||
|
self.finish()
|
||||||
|
return param
|
||||||
|
|
||||||
|
def display_text_impl(self):
|
||||||
|
"""
|
||||||
|
default implementation
|
||||||
|
"""
|
||||||
|
return ""
|
||||||
|
|
||||||
|
def coerce_parameters_impl(self):
|
||||||
|
"""
|
||||||
|
default implementation
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def callback_impl(self, name):
|
||||||
|
"""
|
||||||
|
default implementation
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def produce_impl(self):
|
||||||
|
"""
|
||||||
|
default implementation
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def can_create_from_shape_impl(self):
|
||||||
|
"""
|
||||||
|
default implementation
|
||||||
|
"""
|
||||||
|
return False
|
||||||
|
|
||||||
|
def parameters_from_shape_impl(self):
|
||||||
|
"""
|
||||||
|
default implementation
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def transformation_from_shape_impl(self):
|
||||||
|
"""
|
||||||
|
default implementation
|
||||||
|
"""
|
||||||
|
return Trans()
|
||||||
|
|
||||||
# import the Type... constants from PCellParameterDeclaration
|
# import the Type... constants from PCellParameterDeclaration
|
||||||
for k in dir(PCellParameterDeclaration):
|
for k in dir(PCellParameterDeclaration):
|
||||||
if k.startswith("Type"):
|
if k.startswith("Type"):
|
||||||
setattr(_PCellDeclarationHelper, k, getattr(PCellParameterDeclaration, k))
|
setattr(_PCellDeclarationHelper, k, getattr(PCellParameterDeclaration, k))
|
||||||
|
|
||||||
# Inject the PCellDeclarationHelper into pya module for consistency:
|
# Inject the PCellDeclarationHelper into module for consistency:
|
||||||
PCellDeclarationHelper = _PCellDeclarationHelper
|
PCellDeclarationHelper = _PCellDeclarationHelper
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue