cqparts.params package

Submodules

cqparts.params.parameter module

class cqparts.params.parameter.Parameter(default=None, doc=None)

Bases: object

Used to set parameters of a ParametricObject.

All instances of this class defined in a class’ __dict__ will be valid input to the object’s constructor.

Creating your own Parameter

To create your own parameter type, inherit from this class and override the type() method.

To demonstrate, let’s create a parameter that takes an integer, and multiplies it by 10.

>>> from cqparts.params import Parameter
>>> class Tens(Parameter):
...     _doc_type = ":class:`int`"
...     def type(self, value):
...         return int(value) * 10

Now to use it in a ParametricObject

>>> from cqparts.params import ParametricObject
>>> class Foo(ParametricObject):
...     a = Tens(5, doc="a in groups of ten")
...     def bar(self):
...         print("a = %i" % self.a)

>>> f = Foo(a=8)
>>> f.bar()
a = 80
__init__(default=None, doc=None)
Parameters:default – default value, will cast before storing
cast(value)

First layer of type casting, used for high-level verification.

If value is None, type() is not called to cast the value further.

Parameters:value – the value given to the ParametricObject’s constructor
Returns:value or None
Raises:ParameterError – if type is invalid
classmethod deserialize(value)

Converts json deserialized value to its python equivalent.

Parameters:valuejson deserialized value
Returns:python equivalent of value

Important

value must be deserialized to be a valid input to cast()

More information on this in serialize()

classmethod new(default=None)

Create new instance of the parameter with a new default doc

Parameters:default – new parameter instance default value
classmethod serialize(value)

Converts value to something serializable by json.

Parameters:value – value to convert
Returns:json serializable equivalent

By default, returns value, to pass straight to json

Warning

serialize() and deserialize() are not symmetrical.

Example of serializing then deserializing a custom object

Let’s create our own Color class we’d like to represent as a parameter.

>>> class Color(object):
...     def __init__(self, r, g, b):
...         self.r = r
...         self.g = g
...         self.b = b
...
...     def __eq__(self, other):
...         return (
...             type(self) == type(other) and \
...             self.r == other.r and \
...             self.g == other.g and \
...             self.b == other.b
...         )
...
...     def __repr__(self):
...         return "<Color: %i, %i, %i>" % (self.r, self.g, self.b)

>>> from cqparts.params import Parameter
>>> class ColorParam(Parameter):
...     _doc_type = ":class:`list`"  # for sphinx documentation
...     def type(self, value):
...         (r, g, b) = value
...         return Color(r, g, b)
...
...     @classmethod
...     def serialize(cls, value):
...         # the default serialize will fail, we know this
...         # because json.dumps(Color(0,0,0)) raises an exception
...         if value is None:  # parameter is nullable
...             return None
...         return [value.r, value.g, value.b]
...
...     @classmethod
...     def deserialize(cls, value):
...         # the de-serialized rgb list is good to pass to type
...         return value

Note that json_deserialize does not return a Color instance. Instead, it returns a list to be used as an input to cast() (which is ultimately passed to type())

This is because when the values are deserialized, they’re used as the default values for a newly created ParametricObject class.

So now when we use them in a ParametricObject:

>>> from cqparts.params import ParametricObject, Float
>>> class MyObject(ParametricObject):
...     color = ColorParam(default=[127, 127, 127])  # default 50% grey
...     height = Float(10)

>>> my_object = MyObject(color=[100, 200, 255])
>>> my_object.color  # is a Color instance (not a list)
<Color: 100, 200, 255>

Now to demonstrate how a parameter goes in and out of being serialized, we’ll create a test method that, doesn’t do anything, except that it should not throw any exceptions from its assertions, or the call to json.dumps()

>>> import json

>>> def test(value, obj_class=Color, param_class=ColorParam):
...     orig_obj = param_class().cast(value)
...
...     # serialize
...     if value is None:
...         assert orig_obj == None
...     else:
...         assert isinstance(orig_obj, obj_class)
...     serialized = json.dumps(param_class.serialize(orig_obj))
...
...     # show serialized value
...     print(serialized)  # as a json string
...
...     # deserialize
...     ds_value = param_class.deserialize(json.loads(serialized))
...     new_obj = param_class().cast(ds_value)
...
...     # now orig_obj and new_obj should be identical
...     assert orig_obj == new_obj
...     print("all good")

>>> test([1, 2, 3])
[1, 2, 3]
all good
>>> test(None)
null
all good

These are used to serialize and deserialize ParametricObject instances, so they may be added to a catalogue, then re-created.

To learn more, go to ParametricObject.serialize()

type(value)

Second layer of type casting, usually overridden to change the given value into the parameter’s type.

Casts given value to the type dictated by this parameter type.

Raise a ParameterError on errors.

Parameters:value – the value given to the ParametricObject’s constructor
Returns:value cast to parameter’s type
Raises:ParameterError – if type is invalid

cqparts.params.parametric_object module

class cqparts.params.parametric_object.ParametricObject(**kwargs)

Bases: object

Parametric objects may be defined like so:

>>> from cqparts.params import (
...     ParametricObject,
...     PositiveFloat, IntRange,
... )

>>> class Foo(ParametricObject):
...     x = PositiveFloat(5)
...     i = IntRange(1, 10, 3)  # between 1 and 10, defaults to 3
...     blah = 100

>>> a = Foo(i=8)
>>> (a.x, a.i)
(5.0, 8)

>>> a = Foo(i=11) # raises exception 
ParameterError: value of 11 outside the range {1, 10}

>>> a = Foo(z=1)  # raises exception 
ParameterError: <class 'Foo'> does not accept parameter(s): z

>>> a = Foo(x='123', i='2')
>>> (a.x, a.i)
(123.0, 2)

>>> a = Foo(blah=200)  # raises exception, parameters must be Parameter types 
ParameterError: <class 'Foo'> does not accept any of the parameters: blah

>>> a = Foo(x=None)  # a.x is None, a.i=3
>>> (a.x, a.i)
(None, 3)

Internally to the object, parameters may be accessed simply with self.x, self.i These will always return the type defined

classmethod class_param_names(hidden=True)

Return the names of all class parameters.

Parameters:hidden (bool) – if False, excludes parameters with a _ prefix.
Returns:set of parameter names
Return type:set
classmethod class_params(hidden=True)

Gets all class parameters, and their Parameter instances.

Returns:dict of the form: {<name>: <Parameter instance>, ... }
Return type:dict

Note

The Parameter instances returned do not have a value, only a default value.

To get a list of an instance’s parameters and values, use params() instead.

static deserialize(data)

Create instance from serial data

initialize_parameters()

A place to set default parameters more intelligently than just a simple default value (does nothing by default)

Returns:None

Executed just prior to exiting the __init__() function.

When overriding, strongly consider calling super().

params(hidden=True)

Gets all instance parameters, and their cast values.

Returns:dict of the form: {<name>: <value>, ... }
Return type:dict
serialize()

Encode a ParametricObject instance to an object that can be encoded by the json module.

Returns:a dict of the format:
Return type:dict
{
    'lib': {  # library information
        'name': 'cqparts',
        'version': '0.1.0',
    },
    'class': {  # importable class
        'module': 'yourpartslib.submodule',  # module containing class
        'name': 'AwesomeThing',  # class being serialized
    },
    'params': {  # serialized parameters of AwesomeThing
        'x': 10,
        'y': 20,
    }
}

value of params key comes from serialize_parameters()

Important

Serialize pulls the class name from the classes __name__ parameter.

This must be the same name of the object holding the class data, or the instance cannot be re-instantiated by deserialize().

Examples (good / bad)

>>> from cqparts.params import ParametricObject, Int

>>> # GOOD Example
>>> class A(ParametricObject):
...     x = Int(10)
>>> A().serialize()['class']['name']
'A'

>>> # BAD Example
>>> B = type('Foo', (ParametricObject,), {'x': Int(10)})
>>> B().serialize()['class']['name']  
'Foo'

In the second example, the classes import name is expected to be B. But instead, the name Foo is recorded. This mismatch will be irreconcilable when attempting to deserialize().

serialize_parameters()

Get the parameter data in its serialized form.

Data is serialized by each parameter’s Parameter.serialize() implementation.

Returns:serialized parameter data in the form: {<name>: <serial data>, ...}
Return type:dict

cqparts.params.types module

class cqparts.params.types.Boolean(default=None, doc=None)

Bases: cqparts.params.parameter.Parameter

Boolean value

type(value)
class cqparts.params.types.ComponentRef(default=None, doc=None)

Bases: cqparts.params.parameter.Parameter

Reference to a Component

Initially introduced as a means to reference a sub-component’s parent

import cadquery
from cqparts import Part, Component
from cqparts.params import *

class Eighth(Part):
    parent = ComponentRef(doc="part's parent")

    def make(self):
        size = self.parent.size / 2.
        return cadquery.Workplane('XY').box(size, size, size)

class Cube(Assembly):
    size = PositiveFloat(10, doc="cube size")

    def make_components(self):
        # create a single cube 1/8 the volume of the whole cube
        return {
            'a': Eighth(parent=self),
        }

    def make_constraints(self):
        return [
            Fixed(self.components['a'].mate_origin),
        ]
type(value)
class cqparts.params.types.Float(default=None, doc=None)

Bases: cqparts.params.parameter.Parameter

Floating point

type(value)
class cqparts.params.types.FloatRange(min, max, default, doc='[no description]')

Bases: cqparts.params.types.Float

Floating point in the given range (inclusive)

__init__(min, max, default, doc='[no description]')

{min <= value <= max}

Parameters:
  • min (float) – minimum value
  • max (float) – maximum value
type(value)
class cqparts.params.types.Int(default=None, doc=None)

Bases: cqparts.params.parameter.Parameter

Integer value

type(value)
class cqparts.params.types.IntRange(min, max, default, doc='[no description]')

Bases: cqparts.params.types.Int

Integer in the given range (inclusive)

__init__(min, max, default, doc='[no description]')

{min <= value <= max}

Parameters:
  • min (int) – minimum value
  • max (int) – maximum value
type(value)
class cqparts.params.types.LowerCaseString(default=None, doc=None)

Bases: cqparts.params.types.String

Lower case string

type(value)
class cqparts.params.types.NonNullParameter(default=None, doc=None)

Bases: cqparts.params.parameter.Parameter

Non-nullable parameter

cast(value)
class cqparts.params.types.PartsList(default=None, doc=None)

Bases: cqparts.params.parameter.Parameter

type(value)
class cqparts.params.types.PositiveFloat(default=None, doc=None)

Bases: cqparts.params.types.Float

Floating point >= 0

type(value)
class cqparts.params.types.PositiveInt(default=None, doc=None)

Bases: cqparts.params.types.Int

Integer >= 0

type(value)
class cqparts.params.types.String(default=None, doc=None)

Bases: cqparts.params.parameter.Parameter

String value

type(value)
class cqparts.params.types.UpperCaseString(default=None, doc=None)

Bases: cqparts.params.types.String

Upper case string

type(value)

cqparts.params.utils module

cqparts.params.utils.as_parameter(nullable=True, strict=True)

Decorate a container class as a functional Parameter class for a ParametricObject.

Parameters:nullable (bool) – if set, parameter’s value may be Null
>>> from cqparts.params import as_parameter, ParametricObject

>>> @as_parameter(nullable=True)
... class Stuff(object):
...     def __init__(self, a=1, b=2, c=3):
...         self.a = a
...         self.b = b
...         self.c = c
...     @property
...     def abc(self):
...         return (self.a, self.b, self.c)

>>> class Thing(ParametricObject):
...     foo = Stuff({'a': 10, 'b': 100}, doc="controls stuff")

>>> thing = Thing(foo={'a': 20})
>>> thing.foo.a
20
>>> thing.foo.abc
(20, 2, 3)

Module contents

class cqparts.params.Parameter(default=None, doc=None)

Bases: object

Used to set parameters of a ParametricObject.

All instances of this class defined in a class’ __dict__ will be valid input to the object’s constructor.

Creating your own Parameter

To create your own parameter type, inherit from this class and override the type() method.

To demonstrate, let’s create a parameter that takes an integer, and multiplies it by 10.

>>> from cqparts.params import Parameter
>>> class Tens(Parameter):
...     _doc_type = ":class:`int`"
...     def type(self, value):
...         return int(value) * 10

Now to use it in a ParametricObject

>>> from cqparts.params import ParametricObject
>>> class Foo(ParametricObject):
...     a = Tens(5, doc="a in groups of ten")
...     def bar(self):
...         print("a = %i" % self.a)

>>> f = Foo(a=8)
>>> f.bar()
a = 80
__init__(default=None, doc=None)
Parameters:default – default value, will cast before storing
cast(value)

First layer of type casting, used for high-level verification.

If value is None, type() is not called to cast the value further.

Parameters:value – the value given to the ParametricObject’s constructor
Returns:value or None
Raises:ParameterError – if type is invalid
classmethod deserialize(value)

Converts json deserialized value to its python equivalent.

Parameters:valuejson deserialized value
Returns:python equivalent of value

Important

value must be deserialized to be a valid input to cast()

More information on this in serialize()

classmethod new(default=None)

Create new instance of the parameter with a new default doc

Parameters:default – new parameter instance default value
classmethod serialize(value)

Converts value to something serializable by json.

Parameters:value – value to convert
Returns:json serializable equivalent

By default, returns value, to pass straight to json

Warning

serialize() and deserialize() are not symmetrical.

Example of serializing then deserializing a custom object

Let’s create our own Color class we’d like to represent as a parameter.

>>> class Color(object):
...     def __init__(self, r, g, b):
...         self.r = r
...         self.g = g
...         self.b = b
...
...     def __eq__(self, other):
...         return (
...             type(self) == type(other) and \
...             self.r == other.r and \
...             self.g == other.g and \
...             self.b == other.b
...         )
...
...     def __repr__(self):
...         return "<Color: %i, %i, %i>" % (self.r, self.g, self.b)

>>> from cqparts.params import Parameter
>>> class ColorParam(Parameter):
...     _doc_type = ":class:`list`"  # for sphinx documentation
...     def type(self, value):
...         (r, g, b) = value
...         return Color(r, g, b)
...
...     @classmethod
...     def serialize(cls, value):
...         # the default serialize will fail, we know this
...         # because json.dumps(Color(0,0,0)) raises an exception
...         if value is None:  # parameter is nullable
...             return None
...         return [value.r, value.g, value.b]
...
...     @classmethod
...     def deserialize(cls, value):
...         # the de-serialized rgb list is good to pass to type
...         return value

Note that json_deserialize does not return a Color instance. Instead, it returns a list to be used as an input to cast() (which is ultimately passed to type())

This is because when the values are deserialized, they’re used as the default values for a newly created ParametricObject class.

So now when we use them in a ParametricObject:

>>> from cqparts.params import ParametricObject, Float
>>> class MyObject(ParametricObject):
...     color = ColorParam(default=[127, 127, 127])  # default 50% grey
...     height = Float(10)

>>> my_object = MyObject(color=[100, 200, 255])
>>> my_object.color  # is a Color instance (not a list)
<Color: 100, 200, 255>

Now to demonstrate how a parameter goes in and out of being serialized, we’ll create a test method that, doesn’t do anything, except that it should not throw any exceptions from its assertions, or the call to json.dumps()

>>> import json

>>> def test(value, obj_class=Color, param_class=ColorParam):
...     orig_obj = param_class().cast(value)
...
...     # serialize
...     if value is None:
...         assert orig_obj == None
...     else:
...         assert isinstance(orig_obj, obj_class)
...     serialized = json.dumps(param_class.serialize(orig_obj))
...
...     # show serialized value
...     print(serialized)  # as a json string
...
...     # deserialize
...     ds_value = param_class.deserialize(json.loads(serialized))
...     new_obj = param_class().cast(ds_value)
...
...     # now orig_obj and new_obj should be identical
...     assert orig_obj == new_obj
...     print("all good")

>>> test([1, 2, 3])
[1, 2, 3]
all good
>>> test(None)
null
all good

These are used to serialize and deserialize ParametricObject instances, so they may be added to a catalogue, then re-created.

To learn more, go to ParametricObject.serialize()

type(value)

Second layer of type casting, usually overridden to change the given value into the parameter’s type.

Casts given value to the type dictated by this parameter type.

Raise a ParameterError on errors.

Parameters:value – the value given to the ParametricObject’s constructor
Returns:value cast to parameter’s type
Raises:ParameterError – if type is invalid
class cqparts.params.ParametricObject(**kwargs)

Bases: object

Parametric objects may be defined like so:

>>> from cqparts.params import (
...     ParametricObject,
...     PositiveFloat, IntRange,
... )

>>> class Foo(ParametricObject):
...     x = PositiveFloat(5)
...     i = IntRange(1, 10, 3)  # between 1 and 10, defaults to 3
...     blah = 100

>>> a = Foo(i=8)
>>> (a.x, a.i)
(5.0, 8)

>>> a = Foo(i=11) # raises exception 
ParameterError: value of 11 outside the range {1, 10}

>>> a = Foo(z=1)  # raises exception 
ParameterError: <class 'Foo'> does not accept parameter(s): z

>>> a = Foo(x='123', i='2')
>>> (a.x, a.i)
(123.0, 2)

>>> a = Foo(blah=200)  # raises exception, parameters must be Parameter types 
ParameterError: <class 'Foo'> does not accept any of the parameters: blah

>>> a = Foo(x=None)  # a.x is None, a.i=3
>>> (a.x, a.i)
(None, 3)

Internally to the object, parameters may be accessed simply with self.x, self.i These will always return the type defined

classmethod class_param_names(hidden=True)

Return the names of all class parameters.

Parameters:hidden (bool) – if False, excludes parameters with a _ prefix.
Returns:set of parameter names
Return type:set
classmethod class_params(hidden=True)

Gets all class parameters, and their Parameter instances.

Returns:dict of the form: {<name>: <Parameter instance>, ... }
Return type:dict

Note

The Parameter instances returned do not have a value, only a default value.

To get a list of an instance’s parameters and values, use params() instead.

static deserialize(data)

Create instance from serial data

initialize_parameters()

A place to set default parameters more intelligently than just a simple default value (does nothing by default)

Returns:None

Executed just prior to exiting the __init__() function.

When overriding, strongly consider calling super().

params(hidden=True)

Gets all instance parameters, and their cast values.

Returns:dict of the form: {<name>: <value>, ... }
Return type:dict
serialize()

Encode a ParametricObject instance to an object that can be encoded by the json module.

Returns:a dict of the format:
Return type:dict
{
    'lib': {  # library information
        'name': 'cqparts',
        'version': '0.1.0',
    },
    'class': {  # importable class
        'module': 'yourpartslib.submodule',  # module containing class
        'name': 'AwesomeThing',  # class being serialized
    },
    'params': {  # serialized parameters of AwesomeThing
        'x': 10,
        'y': 20,
    }
}

value of params key comes from serialize_parameters()

Important

Serialize pulls the class name from the classes __name__ parameter.

This must be the same name of the object holding the class data, or the instance cannot be re-instantiated by deserialize().

Examples (good / bad)

>>> from cqparts.params import ParametricObject, Int

>>> # GOOD Example
>>> class A(ParametricObject):
...     x = Int(10)
>>> A().serialize()['class']['name']
'A'

>>> # BAD Example
>>> B = type('Foo', (ParametricObject,), {'x': Int(10)})
>>> B().serialize()['class']['name']  
'Foo'

In the second example, the classes import name is expected to be B. But instead, the name Foo is recorded. This mismatch will be irreconcilable when attempting to deserialize().

serialize_parameters()

Get the parameter data in its serialized form.

Data is serialized by each parameter’s Parameter.serialize() implementation.

Returns:serialized parameter data in the form: {<name>: <serial data>, ...}
Return type:dict
class cqparts.params.Boolean(default=None, doc=None)

Bases: cqparts.params.parameter.Parameter

Boolean value

type(value)
class cqparts.params.ComponentRef(default=None, doc=None)

Bases: cqparts.params.parameter.Parameter

Reference to a Component

Initially introduced as a means to reference a sub-component’s parent

import cadquery
from cqparts import Part, Component
from cqparts.params import *

class Eighth(Part):
    parent = ComponentRef(doc="part's parent")

    def make(self):
        size = self.parent.size / 2.
        return cadquery.Workplane('XY').box(size, size, size)

class Cube(Assembly):
    size = PositiveFloat(10, doc="cube size")

    def make_components(self):
        # create a single cube 1/8 the volume of the whole cube
        return {
            'a': Eighth(parent=self),
        }

    def make_constraints(self):
        return [
            Fixed(self.components['a'].mate_origin),
        ]
type(value)
class cqparts.params.Float(default=None, doc=None)

Bases: cqparts.params.parameter.Parameter

Floating point

type(value)
class cqparts.params.FloatRange(min, max, default, doc='[no description]')

Bases: cqparts.params.types.Float

Floating point in the given range (inclusive)

__init__(min, max, default, doc='[no description]')

{min <= value <= max}

Parameters:
  • min (float) – minimum value
  • max (float) – maximum value
type(value)
class cqparts.params.Int(default=None, doc=None)

Bases: cqparts.params.parameter.Parameter

Integer value

type(value)
class cqparts.params.IntRange(min, max, default, doc='[no description]')

Bases: cqparts.params.types.Int

Integer in the given range (inclusive)

__init__(min, max, default, doc='[no description]')

{min <= value <= max}

Parameters:
  • min (int) – minimum value
  • max (int) – maximum value
type(value)
class cqparts.params.LowerCaseString(default=None, doc=None)

Bases: cqparts.params.types.String

Lower case string

type(value)
class cqparts.params.NonNullParameter(default=None, doc=None)

Bases: cqparts.params.parameter.Parameter

Non-nullable parameter

cast(value)
class cqparts.params.PartsList(default=None, doc=None)

Bases: cqparts.params.parameter.Parameter

type(value)
class cqparts.params.PositiveFloat(default=None, doc=None)

Bases: cqparts.params.types.Float

Floating point >= 0

type(value)
class cqparts.params.PositiveInt(default=None, doc=None)

Bases: cqparts.params.types.Int

Integer >= 0

type(value)
class cqparts.params.String(default=None, doc=None)

Bases: cqparts.params.parameter.Parameter

String value

type(value)
class cqparts.params.UpperCaseString(default=None, doc=None)

Bases: cqparts.params.types.String

Upper case string

type(value)
cqparts.params.as_parameter(nullable=True, strict=True)

Decorate a container class as a functional Parameter class for a ParametricObject.

Parameters:nullable (bool) – if set, parameter’s value may be Null
>>> from cqparts.params import as_parameter, ParametricObject

>>> @as_parameter(nullable=True)
... class Stuff(object):
...     def __init__(self, a=1, b=2, c=3):
...         self.a = a
...         self.b = b
...         self.c = c
...     @property
...     def abc(self):
...         return (self.a, self.b, self.c)

>>> class Thing(ParametricObject):
...     foo = Stuff({'a': 10, 'b': 100}, doc="controls stuff")

>>> thing = Thing(foo={'a': 20})
>>> thing.foo.a
20
>>> thing.foo.abc
(20, 2, 3)