Skip to content
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

Add an --expression flag to specify what cq-cli should render #26

Merged
merged 7 commits into from
Nov 26, 2023

Conversation

justbuchanan
Copy link
Member

This is an attempt to implement the feature in #18.

Usage: cq-cli --infile model.py --outfile out.step --entrypoint="show_object(mypart())"

As-is, this requires show_object to be part of the entrypoint, which doesn't seem great, but I don't think it's too unexpected for users since the code in --infile previously would require at least one call to show_object anyways. Making --entrypoint not require the show_object call may be quite a pain, as you outlined in #18 (comment)

Other potential names for the flag: --expr/--expression, --snippet?

@jmwright
Copy link
Member

Thanks @justbuchanan

I can only get it to work if I am calling show_object as well. Is this expected behavior? How do you envision this working?

cq-cli --entrypoint make_box --infile /home/jwright/Downloads/temp/entrypoint_test.py --codec stl
import cadquery as cq

def make_box():
    box = cq.Workplane().box(10, 10, 10)

    return box

show_object(make_box())

Without the show_object call, I get the following error.

Conversion codec error: Traceback (most recent call last):
  File "/home/jwright/repos/cq-cli/src/cq_cli/main.py", line 453, in main
    converted = codec_module.convert(build_result, outfile, errfile, output_opts)
  File "/home/jwright/repos/cq-cli/src/cq_cli/cqcodecs/cq_codec_stl.py", line 24, in convert
    build_result.results[0].shape.val().exportStl(
IndexError: list index out of range

@justbuchanan
Copy link
Member Author

justbuchanan commented Nov 21, 2023

I can only get it to work if I am calling show_object as well. Is this expected behavior?

As currently-implemented, yes this is expected. I can see an argument for wanting it to work the other way though where you supply the name of a function and cq-cli calls the function and renders the return value. Implementing the feature that way has two main challenges that I see:

  • I looked through cqgi.py and I think it will take a large amount of reworking things to support this.
    • caveat: if we require the entrypoint to be a function, we could do something simple like: script_str += "show_object(" + args.entrypoint + "())" instead of what this PR currently does: script_str += args.entrypoint
  • if the script already contains a show_object() call, do we want the final result to contain both the script's show_object() and the entrypoint? Or do we want to ignore the script's rendering and only render the thing specified in the entrypoint?

I envision it working like this:

# model.py

import cadquery as cq

def make_box():
    box = cq.Workplane().box(10, 10, 10)
    return box

def make_cylinder():
    cyl = cq.Workplane().circle(3).extrude(10)
    return cyl

# this code does not run under cq-cli, but does when viewing the model with cq-editor
if __name__ == '__cq_main__':
    asm = cq.Assembly()
    asm.add(make_box(), ...)
    asm.add(make_cylinder(), ...)
    show_object(asm)
# export individual parts
cq-cli --entrypoint "show_object(make_box())" --infile model.py --outfile box.stl
cq-cli --entrypoint "show_object(make_cylinder())" --infile model.py --outfile cylinder.stl

--entrypoint is now just the name of a python function to call and
show
@justbuchanan
Copy link
Member Author

I reworked this a little so that entrypoint no longer requires show_object(). See 8af4998

@justbuchanan
Copy link
Member Author

Thinking about this a bit more, I actually like the initial approach better where we just append entrypoint to the input source. Doing it that way allows the user to also to pass parameters to the function (i.e. make_box(h=10)). If we still want to avoid making the entrypoint require show_object, we could require that entrypoint be a python expression that is evaluated. Then cq-cli would essentially do: script_src += "show_object({expr})".format(expr=args.entrypoint) where entrypoint would be something like make_box() or make_box(h=10).

@jmwright
Copy link
Member

Switching back to the way you initially had it, you could inject all sorts of code.

cq-cli --infile model.py --outfile out.step --entrypoint="cq.exporters.export(mypart(), 'mypart.gltf')"

or

cq-cli --infile model.py --outfile out.step --entrypoint="show_object(mypart());show_object(myotherpart())"

That second one will probably have weird consequences when using CQGI though.

So maybe your suggestion of using --expression for the flag would be better. I think I got stuck on the name entrypoint as meaning something different than what this PR seems to be doing.

@justbuchanan
Copy link
Member Author

Sounds good, I changed this to accept a python expression and renamed the flag.

I think I got stuck on the name entrypoint as meaning something different than what this PR seems to be doing.

What did you have in mind for --entrypoint? Does this PR cover the same / similar functionality or were you thinking of doing something different?

@justbuchanan justbuchanan changed the title quick attempt at adding --entrypoint flag Add an --expression flag to specify what cq-cli should render Nov 22, 2023
@jmwright
Copy link
Member

What did you have in mind for --entrypoint?

The original though was sparked by my idea of FreeCAD support where you might have multiple parts inside a file. I think the same thing applies with CadQuery files where you have multiple part methods and maybe an assembly. I have scripts where I have separate methods for a regular assembly and an exploded assembly, and it would be nice to be able to tell cq-cli to use one over the other so that I don't have to hard code the calls into the code, add command line switches, and/or add conditionals.

Maybe I'm approaching this from the wrong angle though. Thoughts?

@justbuchanan
Copy link
Member Author

It sounds like our use cases are roughly the same here - I also typically have a python function for each part and for each assembly. For 3d printing, I want to export each part defined in the model as an individual stl. I think the --expression flag as implemented will make it easy to export individual parts/assemblies:

cq-cli --infile model.py --expression "part1()" --outfile part1.stl
cq-cli --infile model.py --expression "part2()" --outfile part2.stl
cq-cli --infile model.py --expression "my_assembly()" --outfile asm.gltf

@jmwright
Copy link
Member

@justbuchanan Are you ok with --expression? If so, could you add a test for this feature?

@justbuchanan
Copy link
Member Author

I think this is good as-is if you're ok with it. Just added a test.

Copy link
Member

@jmwright jmwright left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for adding this @justbuchanan !

@jmwright jmwright merged commit 583da30 into CadQuery:main Nov 26, 2023
3 checks passed
@justbuchanan justbuchanan deleted the entrypoint branch November 27, 2023 02:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants