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

DM-25627 make qgraph and run subcommands for pipetask #347

Merged
merged 16 commits into from Aug 18, 2020
Merged

Conversation

n8pease
Copy link
Contributor

@n8pease n8pease commented Aug 11, 2020

No description provided.

cls=OptionSection)(f)


class MWPath(click.Path):
Copy link
Member

Choose a reason for hiding this comment

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

When specifying a butler configuration file you can't use anything that assumes that it can open a local file. From the ctrl_mpexec PR I see that this is used for butler configs. Butler configs can be URIs that may or may not include the "butler.yaml" at the end (they can be s3:// etc). You could use ButlerURI.exists() to see if it exists but better to pass the string to Butler() directly without trying to check it.

Copy link
Contributor

@andy-slac andy-slac left a comment

Choose a reason for hiding this comment

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

Looks OK in general, bunch of minor comments. My concern after reading through all new additions is that it looks like you have to fight click to force it to do what we want. To my taste it's too much code that we did not have to write.

python/lsst/daf/butler/cli/butler.py Outdated Show resolved Hide resolved
@@ -22,11 +22,11 @@

import click

from lsst.daf.butler.cli.utils import MWOption
from lsst.daf.butler.cli.utils import MWOption, MWOptionDecorator
Copy link
Contributor

Choose a reason for hiding this comment

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

Could use relative import for this?

@classmethod
def _update(cls):
"""Use the click.Option to generate the kwarg name and the list of
flags
Copy link
Contributor

Choose a reason for hiding this comment

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

Here and few other places - need period at the end of sentences.

defaultHelp : `str`
The default help text.
"""
pass
Copy link
Contributor

Choose a reason for hiding this comment

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

This should probably be raise NotImplementedError() just in case someone calls this method, same for optionFlags.

separator : str, optional
The character that separates key-value pairs. May not be a comma or an
empty space (for space separators use Click's default implementation
for tuples; `type=(str, str)`). By default "=".
unseparated_okay : `bool`, optional
If True, allow values that do not have a separator. They will be
returned in the values dict as a tuple of values in the key '', that
is: `values[''] = (unseparated_values, )`.
is: `values[''] = (unseparated_values, )`. By default False.
return_type : `str`, one of "dict" or "tuple"
Copy link
Contributor

Choose a reason for hiding this comment

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

Instead of string you can accept type itself (dict or tuple), would at least reduce chance of typo (and need to check for that).


Parameters
----------
optionDecorators : `list` or `tuple` [`MWOptionDecorator`]
Copy link
Contributor

Choose a reason for hiding this comment

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

Should it be mwOptions instead of optionDecorators?

"""

def __init__(self, mwOptions=None):
self.functionKwargs = {}
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm confused, mwOptions is not used at all?


Parameters
----------
mwOptions : `list` or `tuple` [`MWOption`]
Copy link
Contributor

Choose a reason for hiding this comment

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

Can be iterable instead of list or tuple?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

well I guess it could be a dict but it really oughtn't be.

self.run_test(helper.cli,
self.makeInputs(self.optionFlag, val),
self.verifyError,
"") # the error strings are too varied, don't test.f
Copy link
Contributor

Choose a reason for hiding this comment

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

"test.f"? You did not finish sentence 😸

Comment on lines 433 to 436
if False:
ForwardObjectsTest.cli()
else:
unittest.main()
Copy link
Contributor

Choose a reason for hiding this comment

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

Why if False?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

was temp. will remove.

@n8pease
Copy link
Contributor Author

n8pease commented Aug 13, 2020

@andy-slac

Looks OK in general, bunch of minor comments. My concern after reading through all new additions is that it looks like you have to fight click to force it to do what we want. To my taste it's too much code that we did not have to write.

Why does it feel that way to you? I didn't feel like I was fighting or forcing click, rather extending it, where I wanted to slightly change behavior or get a bit of information.

I think I could remove a lot of the code that "extends" Click by getting rid of chained commands and command forwarding and going back to your definitions of build, qgraph, and run. Maybe that's a better way to go?

@andy-slac
Copy link
Contributor

My impression that click is not cooperating is mostly from looking at utils.py and what you had to do for pipeline actions in ctrl_mpexec. option_section looks more like a hack in click than an extension. All extra classes that you added to support chaining/forwarding also tells me that click idea of how things should work is different from what we need.

And I'm not a fan of chaining, so if you say you want to drop it with all extra classes I won't object 🙂

Another idea that occurred to me - the list of options is big and probably growing, if we want to simplify reuse it may be worth to "package" related options into one decorator, i.e. instead of:

@output_option()
@output_run_option()
@extend_run_option()
@replace_run_option()
@prune_replaced_option()
def something()

do

@all_output_options()
def something()

(that example is for ctrl_mpexec options but we may have something similar in other places).

@n8pease
Copy link
Contributor Author

n8pease commented Aug 14, 2020

That all makes sense. I had coded up a batch decorator for the butler config options, but had hoped chaining would prevent the need to use it. Of course it turns out that qgraph and run still accept the butler options anyway. Given that , and that the chaining implementation requires more hacking on Click than you'd like, and that the number of lines of code in this review is more than people would like, it's sounding to me like the way to go is to take out chaining and making the commands behave the same as with the existing ctrl_mpexec command line parser.

@timj
Copy link
Member

timj commented Aug 14, 2020

I'm not completely averse to chaining, but it's impossible to work out what chaining really means from this pull request. I thought we had agreed to a community post to discuss things.

@n8pease
Copy link
Contributor Author

n8pease commented Aug 15, 2020

A community post after getting code checked in, which assumed I could get it past review 🙃

@timj
Copy link
Member

timj commented Aug 17, 2020

Ok. Firstly, please fix the tests so that the PR can build.

Secondly, we have a chicken and egg problem. It's really hard to review the pipetask code without the context of understanding subcommands. It's a very large pull request to understand without that context. Since pipetask2 is not something that people are using it seems like we can only break this impasse by merging the ctrl_mpexec PR, writing the community post, letting people experiment, and then being prepared to rip the code out again.

@n8pease n8pease force-pushed the tickets/DM-25627 branch 2 times, most recently from 864854d to 14296fe Compare August 18, 2020 03:57
@n8pease
Copy link
Contributor Author

n8pease commented Aug 18, 2020

Ok, sounds fine. I just started a Jenkins build, once that's complete I'll check it in. I will start working on the community post tomorrow morning.

Allows section headings to be injected between options when the
Click command help is printed.
click.Path can verify a file (or dir) does exist, but does not
have support for not-exists. MWPath subclasses Path and provides
that feature.
Called MWOptionDecorator. This facilitates unit testing by
declaring abstract methods and helper methods that allow the unit
tests to determine things about the option, like what the
parameter declarations (option flags, command function keyword
argument name) will be.

This change also changes all abstract class properties in shared
options to abstract static methods.
Even though arguments don't use a common abstract base class
(yet...) they need to follow the change made to shared options,
to use a static method for 'defualtHelp' instead of a class
property, because the api needs to match.

There's probably room for an MWArgumentDecorator class here that
would be very similar to MWOptionDecorator. They could even have
a common MWParameterDecorator base. TBD when it's just insanity.
For now it seems Good Enough to have the option decorator, and
just make this change; arguments are infrequent enough.
It was making a directory with the temporary file name. This fix
splits the tempfile name and calls makedirs when needed, and then
creates the file in that location.
In some cases now, the command test calls multiple subcommands in
a single execution (e.g. "pipetask2 qgraph <args> run <args" calls
the "qgraph" and "run" subcommands). This change allows the test
code to assert both mocked commands were called with the expected
arguments.
Now if there is a blank line between paragraphs in a triple-quoted
string, unwrap will preserve that blank line.
split_kv used to put all values into a dict. Some pipetask options
want the value to be a tuple of two-item tuples. Some pipetasks
reverse the key and value so that --opt k=v becomes dict(v=k) or
((v, k),). This adds those options to the split_kv callback, they
can be set when passing the callback by using functools.partial.
Option forwarding allows CLI option values passed to one subcommand
to be "forwarded" to the next subcommans without the user having
to re-enter the same options for the next subcommands.

For example, "pieptask qgraph <butler options> run" allows butler
options passed to the qgraph subcommand to be used by the run
subcommand.
Instead of print_exc. This eliminates the need for a temporary
string object.
MWOptionDecorator used to be a subclass for shared option
decorator types. This changes it to be a factory that
generates a callable type that returns a click.option
with the shared parameters prepopulated (using
functools.partial). It also implements a few helper
functions for e.g. getting the name of the argument
with which the option will call the command function.
@n8pease n8pease merged commit a2728ea into master Aug 18, 2020
@timj timj deleted the tickets/DM-25627 branch February 16, 2024 17:18
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.

None yet

3 participants