Skip to content

Commit fa4561b

Browse files
Handle kwargs+multimethods in a backward compatibile way (#923)
* CQ-specific multimethod * Use cqmultimethod in cq.Shape * Imports cleanup * cqmultimethod test * doc/primer: added multimethod section Co-authored-by: Marcus Boyd <[email protected]>
1 parent 6c8502f commit fa4561b

File tree

5 files changed

+54
-6
lines changed

5 files changed

+54
-6
lines changed

cadquery/cq.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,18 +45,15 @@
4545
Face,
4646
Solid,
4747
Compound,
48-
sortWiresByBuildOrder,
4948
wiresToFaces,
5049
)
5150

5251
from .occ_impl.exporters.svg import getSVG, exportSVG
5352

54-
from .utils import deprecate_kwarg, deprecate
53+
from .utils import deprecate
5554

5655
from .selectors import (
5756
Selector,
58-
PerpendicularDirSelector,
59-
NearestToPointSelector,
6057
StringSyntaxSelector,
6158
)
6259

cadquery/occ_impl/shapes.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,13 @@
1717

1818
from io import BytesIO
1919

20-
from multimethod import multimethod
21-
2220
from vtkmodules.vtkCommonDataModel import vtkPolyData
2321
from vtkmodules.vtkFiltersCore import vtkTriangleFilter, vtkPolyDataNormals
2422

2523
from .geom import Vector, BoundBox, Plane, Location, Matrix
2624

25+
from ..utils import cqmultimethod as multimethod
26+
2727
import OCP.TopAbs as ta # Tolopolgy type enum
2828
import OCP.GeomAbs as ga # Geometry type enum
2929

cadquery/utils.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
from inspect import signature
33
from warnings import warn
44

5+
from multimethod import multimethod, DispatchError
6+
57

68
class deprecate_kwarg:
79
def __init__(self, name, new_value):
@@ -36,3 +38,12 @@ def wrapped(*args, **kwargs):
3638
return f(*args, **kwargs)
3739

3840
return wrapped
41+
42+
43+
class cqmultimethod(multimethod):
44+
def __call__(self, *args, **kwargs):
45+
46+
try:
47+
return super().__call__(*args, **kwargs)
48+
except DispatchError:
49+
return next(iter(self.values()))(*args, **kwargs)

doc/primer.rst

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,19 @@ If you want to cast an OCCT object into a Direct API one you can just pass it as
352352
.. note::
353353
You can cast into the direct API the types found `here <https://dev.opencascade.org/doc/refman/html/class_topo_d_s___shape.html>`_
354354

355+
Multimethods
356+
------------
357+
358+
CadQuery uses `Multimethod <https://coady.github.io/multimethod/>`_ to allow a call to a method to
359+
be dispatched depending on the types of the arguments. An example is :meth:`~cadquery.Sketch.arc`,
360+
where ``a_sketch.arc((1, 2), (2, 3))`` would be dispatched to one method but ``a_sketch.arc((1, 2),
361+
(2, 3), (3, 4))`` would be dispatched to a different method. For multimethods to work, you should
362+
not use keyword arguments to specify positional parameters. For example, you **should not** write
363+
``a_sketch.arc(p1=(1, 2), p2=(2, 3), p3=(3, 4))``, instead you should use the previous example.
364+
Note CadQuery makes an attempt to fall back on the first registered multimethod in the event of a
365+
dispatch error, but it is still best practise to not use keyword arguments to specify positional
366+
arguments in CadQuery.
367+
355368
An Introspective Example
356369
------------------------
357370

tests/test_utils.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
from cadquery.utils import cqmultimethod as multimethod
2+
3+
from pytest import raises
4+
5+
6+
def test_multimethod():
7+
class A:
8+
@multimethod
9+
def f(self, a: int, c: str = "s"):
10+
return 1
11+
12+
@f.register
13+
def f(self, a: int, b: int, c: str = "b"):
14+
return 2
15+
16+
assert A().f(0, "s") == 1
17+
assert A().f(0, c="s") == 1
18+
assert A().f(0) == 1
19+
20+
assert A().f(0, 1, c="s") == 2
21+
assert A().f(0, 1, "s") == 2
22+
assert A().f(0, 1) == 2
23+
24+
assert A().f(a=0, c="s") == 1
25+
26+
with raises(TypeError):
27+
A().f(a=0, b=1, c="s")

0 commit comments

Comments
 (0)