-
Notifications
You must be signed in to change notification settings - Fork 299
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
filter/map/apply/sort/[]/invoke #1514
Conversation
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## master #1514 +/- ##
==========================================
+ Coverage 94.86% 94.91% +0.05%
==========================================
Files 28 28
Lines 6228 6259 +31
Branches 1262 1271 +9
==========================================
+ Hits 5908 5941 +33
+ Misses 193 192 -1
+ Partials 127 126 -1 ☔ View full report in Codecov by Sentry. |
Thanks, it too me a while to get to this. I'll do some rework. I'd like to descope group for now, feels like too big of a change. |
I like the intent behind With |
|
@jmwright @lorenzncode @voneiden what do you think about it? I'd say this would be it (minus docs and groupby). I'm still wondering if we should allow to map via |
Looks pretty neat and clean to me, I like it. Trivial: do you mind if I tidy up the commits a bit? I'd like to amend my original commit message at least since it's very ambiguous. |
I'm going to squash anyhows, so why not. Additional idea: allow callbacks with 0 arity or no rv for debugging (if multimethod allows to dispatch on that). Use case would be quick debugging. w.apply(breakpoint).apply(show) |
Alright, if gets squashed then I suppose it's fine as is with the surrounding context. The idea you presented seems like it could be useful, but IMO the current interface is very clean and easy to understand. I'd slightly lean towards having a separate method for this use case but no strong feelings. Multimethod could fine too, if the docstring explains the secondary behaviour in layman terms. |
Looks good with minimal testing so far! I'll play with it more.
Does this mean something like the following works without an explicit call to import cadquery as cq
from cadquery.occ_impl.shapes import *
def mycallback(obj):
if obj.Center().x > 0:
# return compound([obj.moved((0, -2, 0)), obj.moved((0, 2, 0))])
return [obj.moved((0, -2, 0)), obj.moved((0, 2, 0))]
else:
return obj
r = cq.Workplane().rarray(20, 20, 2, 2).box(1, 1, 1, combine=False).map(mycallback) |
This would actually imply |
If the more generic form can work it might be useful. It looks like there is a workaround for this case if not. |
In the meantime I added |
I added some docs and I think this is ready to be merged. Any thoughts @lorenzncode @voneiden @jmwright ? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
invoke
is another very useful addition! I like the new option for extending CQ. The docs are clear.
Regarding invoke
with builtin and arity 0 - my understanding is breakpoint
is the primary intended use case (perhaps other special cases).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for the slow review, I'm in 🌴 mode. 😃
cadquery/cq.py
Outdated
if isbuiltin(f): | ||
arity = 0 # assume 0 arity for builtins; they cannot be introspected | ||
else: | ||
arity = f.__code__.co_argcount # NB: this is not understood by mypy | ||
|
||
rv = self | ||
|
||
if arity == 0: | ||
f() # type: ignore | ||
elif arity == 1: | ||
res = f(self) # type: ignore | ||
if res is not None: | ||
rv = res | ||
else: | ||
raise ValueError("Provided function {f} accepts too many arguemnts") | ||
|
||
return rv |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not requesting this to be changed, but I think something like this would be a bit more mundane...?
if isbuiltin(f): | |
arity = 0 # assume 0 arity for builtins; they cannot be introspected | |
else: | |
arity = f.__code__.co_argcount # NB: this is not understood by mypy | |
rv = self | |
if arity == 0: | |
f() # type: ignore | |
elif arity == 1: | |
res = f(self) # type: ignore | |
if res is not None: | |
rv = res | |
else: | |
raise ValueError("Provided function {f} accepts too many arguemnts") | |
return rv | |
rv = self | |
try: | |
res = f(self) # type: ignore | |
except TypeError: | |
res = f() # type: ignore | |
if res is not None: | |
rv = res | |
return rv |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, but I find mine more clear. Also it has slightly different semantics, f could throw for other reason than wrong number of parameters.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me. Thanks @voneiden !
Co-authored-by: Matti Eiden <[email protected]>
Co-authored-by: Matti Eiden <[email protected]>
Merging, thanks @voneiden ! |
Some time back I made cq-filter to allow easier manipulation of workplane objects without breaking out of the fluent API. @adam-urbanczyk requested in voneiden/cq-filter#1 to merge some features from cq-filter into cadquery, namely:
and optionally
First off, I've decided to rename
filter
tofilter_objects
andsort
tosort_objects
. I think the verbosity is warranted asWorkplane
is a fairly complex object.The cq-filter implementation of
group
created an intermediary workplane with extra fields to support slicing groups. I never particularly liked doing it this way, so I spent some time thinking how this could be done without the intermediary workplane. One option, used in this PR, is to create a separate Group object that supports slicing. This does require however the ability for theGroup
to iterate through candidate objects independently, so it can not be used withfilter_objects
as it allows the supplied filter function to operate only one oneCQObject
at a time.Therefore I needed to introduce another method, currently named as
map_objects
which hands over the workplane objects to the map function and expects a new list of objects to be returned.Group supports fixed window groups (xn - x0 <= tol) and moving window groups (xn - xn-1 <= tol)
Currently the PR is missing documentation and tests, but I'm opening this to allow discussion of implementation details. I'm flexible regarding the scope of this PR, if it feels like
Group
doesn't belong here then we'll drop it.I'm a bit low on free dev time for the time being so this might progress at a snails pace but we'll get there.