-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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
Use fire without editing code directly #29
Comments
Cool idea. Let's think through some of the behavior specifics.
|
Great point on executing ifmain by accident. This set me on to a neat idea - what if you could just pass in any fully qualified python module/function/class? I snagged the AppEngine mapreduce's
branch here with initial doodle - https://github.com/jtratner/python-fire/tree/run-on-any-fully-qualified-name If we could get it to work so that I'll think about your other questions and get back to you later (have to get a deliverable together). |
|
That's nice 👍 . I think we'd want to support 'fire filepath.py' as well, as in your original idea.
Interesting. So, this would behave as if 'fire.Fire()' were appended to the module you're running Haven't tried this fully yet, but I think something like this could work:
|
Here's a working first pass for supporting file paths:
We'll want to replace 'command' with 'argv'. |
The issue of Just to clarify what I mean about namespaces:
Under the hood would be essentially the same as what you have, but using import_module instead.
Which would then cause all of the module's locals (or maybe So then you could end up with something like:
|
Could be a good way to simplify loading, but I'm not really sure what you'd gain there / what it would mean. (would that mean you run the module's main function?) Ideally I'd like fire to always import modules and classes with namespaces intact.
That would simplify the user experience a little - easy to understand "fire options come before specifying what to operate on".
Good question - seems like it should be able to work the same way. It would be cool to be able to "teach" fire how to handle nested completion, e.g. I say:
and the completion script somehow dumps completions for methods1 2 and 3 ;) |
Agreed. Exactly how I'd expect it to work. (and we could either automagically determine what user meant on CLI or have different flags depending on what you are referencing) |
How do you feel about this as precedence for loading modules vs. loading classes / methods vs. loading files (
|
Yes, would love to get to that point. I put a draft of the tab completion doc at #32. Need to think more about the precedence idea. On the one hand, it's nice if a tool like this 'just works'. On the other hand, it's good to conform to standards set by tools like |
Fire shares similarities with hug: Embrace the APIs of the future, which also generates RESTful web interfaces. Hug supports both a Exploring how it works with some existing python modules is probably a good idea. E.g. I was delighted to to see @dbieber's quick implementation work like this:
But trying to use it for b85encode ran into the question of how to create a "bytes" input parameter
|
OK, I figured out that the join operation in @dbieber's version is what was breaking the use of arguments of type The attached python script (with a So now this works:
|
Glad you found the For sharing code like fire.txt, consider using a gist or pastebin in the future instead of attaching a text file. Python question: is there a way to do the equivalent of "from X import *" inside a Python function? I know the naive approach gives a syntax error, since "import *" is only allowed at the module scope. Design thought: I think we'll want a sensible default so that people don't have to specify -m or -f. I'm inclined to take the precedence approach (first check if it's a file path that exists. if not, check if it describes a Python object using the for_name approach that jtratner described.) Will have to think more carefully about ways in which this might violate the user's expectations though. On the subject of Hug, one of my low-priority plans for Fire is to experiment with adding a |
You can just push into locals(). Eg
```
for k, v in vars(module):
if k.startswith('_'):
continue
else:
locals()[k] = v
```
…On Sun, Mar 26, 2017 at 6:08 PM David Bieber ***@***.***> wrote:
Glad you found the bytes workaround 👍 .
For sharing code like fire.txt, consider using a gist
<https://gist.github.com/> or pastebin <http://pastebin.com/> in the
future instead of attaching a text file.
Python question: is there a way to do the equivalent of "from X import *"
inside a Python function? I know the naive approach gives a syntax error,
since "import *" is only allowed at the module scope.
Design thought: I think we'll want a sensible default so that people don't
have to specify -m or -f. I'm inclined to take the precedence approach
(first check if it's a file path that exists. if not, check if it describes
a Python object using the for_name approach that jtratner described.) Will
have to think more carefully about ways in which this might violate the
user's expectations though.
On the subject of Hug, one of my low-priority plans for Fire is to
experiment with adding a --serve flag to Fire CLIs. Much like how Fire
CLIs expose an object or a whole program as a CLI, a Fire Server would
expose an object or a whole program over HTTP. I can open a separate issue
if you want to discuss this further or are interested in exploring the idea
/ contributing.
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
<#29 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ABhjqy5CCBOPYz4P8ZyYKBdc4UHB1jqCks5rpwwLgaJpZM4Mlta4>
.
|
My general sense is that the PEP 20 advice Explicit is better than implicit applies here, and would lead to the explicit specification of whether the user wants a module or a file (e.g. via -f / -m), and not magically inferring that from an argument. That would make it harder to break a command by just running it in a different directory, for example. And I'm wondering if the |
It seems very rare for a module or file to overlap (i.e., very uncommon to have modules whose name ends with |
@jtratner I think I'm warming to the idea of having a little magic here, since a reasonable goal for fire is probably minimizing the need for keystrokes. Hug does it the way I used (-m and -f), but I agree that the typical presence of a And thanks for pointing out the autoreload aspects of the implementation. I'll have to look at that some more. I also wonder if having a Lots of tricky bits here. A good set of test cases will be critical, so please keep them coming. The more concrete the examples, the better. |
I wonder why hug uses both -m and -f, rather than -m for module and no flag for file (which is how python/ipython/pyspark do it). I'm not really familiar with hug, so I don't know if there's a compelling reason or if it was just an arbitrary choice (presumably motivated by explicit>implicit). |
* fire.py: Use fire on arbitrary file or module. Based on the discussion at [Use fire without editing code directly · Issue #29 · google/python-fire](#29) Of course, still needs better error handling, documentation, installation support, etc. * rename fire.py to fire_script.py in repo Should fix the build problem for python 2. Later, get it installed as "fire" via setup.py * rename fire_script.py __main__.py Following advice from Python Apps the Right Way: entry points and scripts | Chris Warrick https://chriswarrick.com/blog/2014/09/15/python-apps-the-right-way-entry_points-and-scripts/
I think using fire with modules will be the most common usage, so I would lean toward @jtratner's notion that not requiring a
I've left out trying to interpret the first argument as a class or method, since it seems more complex to specify syntax for those names than to use the existing fire approach to accessing those. But I'm open to examples that motivate adding that. I've made a first shot at implementing the above in https://github.com/nealmcb/python-fire/tree/issue29-fire-without-edits I'm happy to either add functionality as we go along via pull requests to the google branch, or playing for a while in my own repo. |
Thanks, @jack17529, for offering to help with testing, at pull #35 (comment). I'm not sure, but I guess its better to continue the discussion here than in that old pull request. There are a few aspects of testing the CLI. First is how to implement the tests. We want it to fit in with and leverage the existing fire unittest approach, but also need to test the invocation of the command itself, probably including the script which setup.py will build. Input on exactly how to do that is most welcome. Then of course we want some specific test cases to exercise the functionality, and cover some of the tricky aspects of this, like the |
API
I actually suspect (just a guess of course!) that using it with files will be the most common usage. One reason for this is that everyone's default tab-completion completes files but not modules. Another reason is that I don't know of any command line tools that accept module specifications w/o a flag (e.g. python -m, ipython -m, hug -m). Specifying modules at the command line just isn't a common practice (yet :P). This is why I think we should flip your 1 and 2 (check if it's a file path that exists before checking if it's a valid module specification). To clarify my hunch some more: I think people will use this with things they work on themselves more than with builtins. Testing Related to testing: internally at Google we have additional tests that do test Fire CLIs by running them as separate processes the way you'd normally run a CLI (that is, the tests use |
@dbieber - I'm personally most interested in using this to work dynamically with libraries I've pip installed. Currently we do what fire does via some decorators with types similar to how click works, but I'd love to make building a CLI for a library to be equivalent to exposing the method at the top-level of the library API. E.g.:
Or
Plus I could imagine some interesting use cases with pandas or with django hooking together an existing models file:
|
Good to know. Maybe I'm wrong about how people will use this.
I agree that all three of those commands should work exactly like that. The place where my proposal differs is that I think if there's a file in your current directory literally called 'sequencer', 'sequencer.cli', or 'myproject.models' then that file should get used instead of the module of the same name. Aside: will that last example really work w/ django? That's really cool 👍. |
Oh totally true - agreed :) |
When I quickly went thru system modules, I found fewer compelling use cases there than I had hoped. Using fire for testing should be popular, and |
[Elaborating on how we could use Fire to write this.] Ideally we could do something like this:
This lets us avoid having to deal with sys.argv at all. However there might be some issues w/ this approach:
|
We're introducing the simplest possible version of this in Fire 0.3.0. This uses @jtratner's code from #110. Starting in 0.3.0, you'll be able to run This includes builtin modules like calendar, installed modules (like fire itself!), and modules referenced relative to your current working directory. So if you're in a directory with |
Currently you have to add something like this to the end of your file just to mess around with fire:
and then run with
But it'd be neat if instead you could just do
and that does equivalent of
exec
appending the ifmain statement to the end.Not sure how to do it - I know kernprof does some magic to inject into builtins before exec'ing code. (or maybe you get a code object back from exit) - but this would make fire even better as a debugging tool as well.
The text was updated successfully, but these errors were encountered: