Call a function at invocation
There are many ways to invoke a function from the commandline. You can use setuptools' console_scripts entrypoint. You can use a decorator from click. And of course you can always do the classic if __name__ == "__main__": main() to call whatever main() is. But there are inconveniences with these approaches. For setuptools, you have to actually run setup, somehow. For click, you have to install click. And for __name__, you are either locked into a single function name, or you have to write some arg parsing to determine what name to use. I propose it would be nice to be able to call a function from python, using syntax like python -m module:thunk The simplest proposal, I think, is if the function must accept no arguments -- or at least no required ones. This could be as straightforward as just being shorthand for python -c 'import module; module.thunk()' and remove a small amount of code that is repeated very frequently. I picked the colon syntax because that is what several other tools that enable calling functions from the commandline seem to do, but if your only objection is the specific syntax I picked, please propose a different one. What do you think?
I think it would be a tad more convincing if there was a way to pass arguments too (even if just a list of strings). At the very least extra arguments should end up in sys.argv[1:]. Then again, presumably the function must be specially crafted for this usage. Why can't you just specially craft a module's main()? On Tue, Oct 20, 2020 at 7:10 PM Michael Smith <michael@smith-li.com> wrote:
There are many ways to invoke a function from the commandline. You can use setuptools' console_scripts entrypoint. You can use a decorator from click. And of course you can always do the classic
if __name__ == "__main__": main()
to call whatever main() is. But there are inconveniences with these approaches. For setuptools, you have to actually run setup, somehow. For click, you have to install click. And for __name__, you are either locked into a single function name, or you have to write some arg parsing to determine what name to use.
I propose it would be nice to be able to call a function from python, using syntax like
python -m module:thunk
The simplest proposal, I think, is if the function must accept no arguments -- or at least no required ones. This could be as straightforward as just being shorthand for
python -c 'import module; module.thunk()'
and remove a small amount of code that is repeated very frequently.
I picked the colon syntax because that is what several other tools that enable calling functions from the commandline seem to do, but if your only objection is the specific syntax I picked, please propose a different one.
What do you think? _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/JWLFOE... Code of Conduct: http://python.org/psf/codeofconduct/
-- --Guido van Rossum (python.org/~guido) *Pronouns: he/him **(why is my pronoun here?)* <http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-change-the-world/>
On Tue, Oct 20, 2020 at 10:19 PM Guido van Rossum <guido@python.org> wrote:
I think it would be a tad more convincing if there was a way to pass arguments too (even if just a list of strings). At the very least extra arguments should end up in sys.argv[1:].
Could python -m 'module:thunk' have exactly the same behavior with respect to arguments as `python3.8 -m module` does today? ``` $ cat bar.py import pprint, sys def thunk(): pprint.pprint(sys.argv) if __name__ == "__main__": thunk() $ python3.8 -m bar -- -1 --two --three=3 ['/Users/michael/bar.py', '--', '-1', '--two', '--three=3'] ``` So then with the same bar.py, `python -m bar:thunk -- -2 --three --four=4` would print `['/Users/michael/bar.py', '--', '-1', '--two', '--three=3']`. I like this better than my previous suggestion to shorthand python -c.
Then again, presumably the function must be specially crafted for this usage. Why can't you just specially craft a module's main()?
I'm not sure I know what you mean by "specially crafted", other than the function only needs not require any formal parameters. It doesn't need to be special-er than that. It can handle args via sys.argv, as you suggested. Most of the `main` functions I write today are just like that.
On Tue, Oct 20, 2020 at 7:10 PM Michael Smith <michael@smith-li.com> wrote:
There are many ways to invoke a function from the commandline. You can use setuptools' console_scripts entrypoint. You can use a decorator from click. And of course you can always do the classic
if __name__ == "__main__": main()
to call whatever main() is. But there are inconveniences with these approaches. For setuptools, you have to actually run setup, somehow. For click, you have to install click. And for __name__, you are either locked into a single function name, or you have to write some arg parsing to determine what name to use.
I propose it would be nice to be able to call a function from python, using syntax like
python -m module:thunk
The simplest proposal, I think, is if the function must accept no arguments -- or at least no required ones. This could be as straightforward as just being shorthand for
python -c 'import module; module.thunk()'
and remove a small amount of code that is repeated very frequently.
I picked the colon syntax because that is what several other tools that enable calling functions from the commandline seem to do, but if your only objection is the specific syntax I picked, please propose a different one.
What do you think? _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/JWLFOE... Code of Conduct: http://python.org/psf/codeofconduct/
-- --Guido van Rossum (python.org/~guido) Pronouns: he/him (why is my pronoun here?)
On Tue, Oct 20, 2020 at 8:06 PM Michael Smith <michael@smith-li.com> wrote:
On Tue, Oct 20, 2020 at 10:19 PM Guido van Rossum <guido@python.org> wrote:
I think it would be a tad more convincing if there was a way to pass
arguments too (even if just a list of strings). At the very least extra arguments should end up in sys.argv[1:].
Could python -m 'module:thunk' have exactly the same behavior with respect to arguments as `python3.8 -m module` does today?
``` $ cat bar.py import pprint, sys
def thunk(): pprint.pprint(sys.argv)
if __name__ == "__main__": thunk()
$ python3.8 -m bar -- -1 --two --three=3 ['/Users/michael/bar.py', '--', '-1', '--two', '--three=3'] ```
So then with the same bar.py, `python -m bar:thunk -- -2 --three --four=4` would print `['/Users/michael/bar.py', '--', '-1', '--two', '--three=3']`. I like this better than my previous suggestion to shorthand python -c.
Actually it should print the same except for sys.argv[0]. (We could argue about what sys.argv[0] should be.)
Then again, presumably the function must be specially crafted for this usage. Why can't you just specially craft a module's main()?
I'm not sure I know what you mean by "specially crafted", other than the function only needs not require any formal parameters. It doesn't need to be special-er than that. It can handle args via sys.argv, as you suggested. Most of the `main` functions I write today are just like that.
Okay, so this is just a way to choose an alternative main() function. I'm kind of meh at this point, I'll leave it to the usual crowd. :-) -- --Guido van Rossum (python.org/~guido) *Pronouns: he/him **(why is my pronoun here?)* <http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-change-the-world/>
On Tue, Oct 20, 2020 at 23:12 Guido van Rossum <guido@python.org> wrote:
On Tue, Oct 20, 2020 at 8:06 PM Michael Smith <michael@smith-li.com> wrote:
On Tue, Oct 20, 2020 at 10:19 PM Guido van Rossum <guido@python.org> wrote:
I think it would be a tad more convincing if there was a way to pass
arguments too (even if just a list of strings). At the very least extra arguments should end up in sys.argv[1:].
Could python -m 'module:thunk' have exactly the same behavior with respect to arguments as `python3.8 -m module` does today?
``` $ cat bar.py import pprint, sys
def thunk(): pprint.pprint(sys.argv)
if __name__ == "__main__": thunk()
$ python3.8 -m bar -- -1 --two --three=3 ['/Users/michael/bar.py', '--', '-1', '--two', '--three=3'] ```
So then with the same bar.py, `python -m bar:thunk -- -2 --three --four=4` would print `['/Users/michael/bar.py', '--', '-1', '--two', '--three=3']`. I like this better than my previous suggestion to shorthand python -c.
Actually it should print the same except for sys.argv[0]. (We could argue about what sys.argv[0] should be.)
Then again, presumably the function must be specially crafted for this usage. Why can't you just specially craft a module's main()?
I'm not sure I know what you mean by "specially crafted", other than the function only needs not require any formal parameters. It doesn't need to be special-er than that. It can handle args via sys.argv, as you suggested. Most of the `main` functions I write today are just like that.
Okay, so this is just a way to choose an alternative main() function.
Am I missing something important here? What's special about naming a function "main"? Don't you still have to do something else to invoke it from the cli, such as calling it expressly in the module or pointing console entry points to it? ``` $ echo 'def main(): print("hi")' > xyz.py $ python -m xyz <no output> $ ``` I'm kind of meh at this point, I'll leave it to the usual crowd. :-)
I appreciate the engagement you've given this already. :) --
--Guido van Rossum (python.org/~guido) *Pronouns: he/him **(why is my pronoun here?)* <http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-change-the-world/>
The ‘if __name__…’ idiom makes one function special. Hm... So if the module has that, will that main() still be called with your proposal? I.e., is __name__ still ‘__main__’? On Tue, Oct 20, 2020 at 20:32 Michael Smith <michael@smith-li.com> wrote:
On Tue, Oct 20, 2020 at 23:12 Guido van Rossum <guido@python.org> wrote:
On Tue, Oct 20, 2020 at 8:06 PM Michael Smith <michael@smith-li.com> wrote:
On Tue, Oct 20, 2020 at 10:19 PM Guido van Rossum <guido@python.org> wrote:
I think it would be a tad more convincing if there was a way to pass
arguments too (even if just a list of strings). At the very least extra arguments should end up in sys.argv[1:].
Could python -m 'module:thunk' have exactly the same behavior with respect to arguments as `python3.8 -m module` does today?
``` $ cat bar.py import pprint, sys
def thunk(): pprint.pprint(sys.argv)
if __name__ == "__main__": thunk()
$ python3.8 -m bar -- -1 --two --three=3 ['/Users/michael/bar.py', '--', '-1', '--two', '--three=3'] ```
So then with the same bar.py, `python -m bar:thunk -- -2 --three --four=4` would print `['/Users/michael/bar.py', '--', '-1', '--two', '--three=3']`. I like this better than my previous suggestion to shorthand python -c.
Actually it should print the same except for sys.argv[0]. (We could argue about what sys.argv[0] should be.)
Then again, presumably the function must be specially crafted for this usage. Why can't you just specially craft a module's main()?
I'm not sure I know what you mean by "specially crafted", other than the function only needs not require any formal parameters. It doesn't need to be special-er than that. It can handle args via sys.argv, as you suggested. Most of the `main` functions I write today are just like that.
Okay, so this is just a way to choose an alternative main() function.
Am I missing something important here? What's special about naming a function "main"? Don't you still have to do something else to invoke it from the cli, such as calling it expressly in the module or pointing console entry points to it?
``` $ echo 'def main(): print("hi")' > xyz.py $ python -m xyz <no output> $ ```
I'm kind of meh at this point, I'll leave it to the usual crowd. :-)
I appreciate the engagement you've given this already. :)
--
--Guido van Rossum (python.org/~guido) *Pronouns: he/him **(why is my pronoun here?)* <http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-change-the-world/>
--
--Guido (mobile)
On Tue, Oct 20, 2020 at 23:43 Guido van Rossum <guido@python.org> wrote:
The ‘if __name__…’ idiom makes one function special. Hm... So if the module has that, will that main() still be called with your proposal? I.e., is __name__ still ‘__main__’?
Perhaps not. If __name__ were still '__main__' and calling the function implied importing the module, then anything in `if __name__ == '__main__'` would still get run. I think that would be inconvenient for folks. I think __name__ should be the module name in the context of the module, and the function name in the context of the function, in this case. On Tue, Oct 20, 2020 at 20:32 Michael Smith <michael@smith-li.com> wrote:
On Tue, Oct 20, 2020 at 23:12 Guido van Rossum <guido@python.org> wrote:
On Tue, Oct 20, 2020 at 8:06 PM Michael Smith <michael@smith-li.com> wrote:
On Tue, Oct 20, 2020 at 10:19 PM Guido van Rossum <guido@python.org> wrote:
I think it would be a tad more convincing if there was a way to pass
arguments too (even if just a list of strings). At the very least extra arguments should end up in sys.argv[1:].
Could python -m 'module:thunk' have exactly the same behavior with respect to arguments as `python3.8 -m module` does today?
``` $ cat bar.py import pprint, sys
def thunk(): pprint.pprint(sys.argv)
if __name__ == "__main__": thunk()
$ python3.8 -m bar -- -1 --two --three=3 ['/Users/michael/bar.py', '--', '-1', '--two', '--three=3'] ```
So then with the same bar.py, `python -m bar:thunk -- -2 --three --four=4` would print `['/Users/michael/bar.py', '--', '-1', '--two', '--three=3']`. I like this better than my previous suggestion to shorthand python -c.
Actually it should print the same except for sys.argv[0]. (We could argue about what sys.argv[0] should be.)
Then again, presumably the function must be specially crafted for this usage. Why can't you just specially craft a module's main()?
I'm not sure I know what you mean by "specially crafted", other than the function only needs not require any formal parameters. It doesn't need to be special-er than that. It can handle args via sys.argv, as you suggested. Most of the `main` functions I write today are just like that.
Okay, so this is just a way to choose an alternative main() function.
Am I missing something important here? What's special about naming a function "main"? Don't you still have to do something else to invoke it from the cli, such as calling it expressly in the module or pointing console entry points to it?
``` $ echo 'def main(): print("hi")' > xyz.py $ python -m xyz <no output> $ ```
I'm kind of meh at this point, I'll leave it to the usual crowd. :-)
I appreciate the engagement you've given this already. :)
--
--Guido van Rossum (python.org/~guido) *Pronouns: he/him **(why is my pronoun here?)* <http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-change-the-world/>
--
--Guido (mobile)
Hello, On Wed, 21 Oct 2020 00:24:47 -0400 Michael Smith <michael@smith-li.com> wrote:
On Tue, Oct 20, 2020 at 23:43 Guido van Rossum <guido@python.org> wrote:
The ‘if __name__…’ idiom makes one function special. Hm... So if the module has that, will that main() still be called with your proposal? I.e., is __name__ still ‘__main__’?
Perhaps not. If __name__ were still '__main__' and calling the function implied importing the module, then anything in `if __name__ == '__main__'` would still get run. I think that would be inconvenient for folks.
Alternative valuation is that your proposal is inconvenient to folks, as it leaves too many gaps. Which, as it seems, you're eager to bravely patch, but that does/will lead to only more confusion.
I think __name__ should be the module name in the context of the module, and the function name in the context of the function, in this case.
__name__ is the name of the module. Or, as a special exception, it's "__main__" for a module directly invoked as a script or via "-m" switch. There's no need to complicate it any further (it's already complicated enough; my bet that half of Python users won't be able to formulate it like above by heart). Back to the original proposal, there's no general need to invoke an arbitrary function in an arbitrary module. That just makes no sense, as most functions depend on context. If *you* need that, then, besides other options you mentioned in your original mail, it's trivial to write a module which will do it for you, like: python -m my_super_invocator module:thunk Actually, if you look on PyPI, I bet you'll find a few like that.
On Tue, Oct 20, 2020 at 20:32 Michael Smith <michael@smith-li.com> wrote:
On Tue, Oct 20, 2020 at 23:12 Guido van Rossum <guido@python.org> wrote:
On Tue, Oct 20, 2020 at 8:06 PM Michael Smith <michael@smith-li.com> wrote:
On Tue, Oct 20, 2020 at 10:19 PM Guido van Rossum <guido@python.org> wrote:
I think it would be a tad more convincing if there was a way to pass
arguments too (even if just a list of strings). At the very least extra arguments should end up in sys.argv[1:].
Could python -m 'module:thunk' have exactly the same behavior with respect to arguments as `python3.8 -m module` does today?
``` $ cat bar.py import pprint, sys
def thunk(): pprint.pprint(sys.argv)
if __name__ == "__main__": thunk()
$ python3.8 -m bar -- -1 --two --three=3 ['/Users/michael/bar.py', '--', '-1', '--two', '--three=3'] ```
So then with the same bar.py, `python -m bar:thunk -- -2 --three --four=4` would print `['/Users/michael/bar.py', '--', '-1', '--two', '--three=3']`. I like this better than my previous suggestion to shorthand python -c.
Actually it should print the same except for sys.argv[0]. (We could argue about what sys.argv[0] should be.)
Then again, presumably the function must be specially crafted for this usage. Why can't you just specially craft a module's main()?
I'm not sure I know what you mean by "specially crafted", other than the function only needs not require any formal parameters. It doesn't need to be special-er than that. It can handle args via sys.argv, as you suggested. Most of the `main` functions I write today are just like that.
Okay, so this is just a way to choose an alternative main() function.
Am I missing something important here? What's special about naming a function "main"? Don't you still have to do something else to invoke it from the cli, such as calling it expressly in the module or pointing console entry points to it?
``` $ echo 'def main(): print("hi")' > xyz.py $ python -m xyz <no output> $ ```
I'm kind of meh at this point, I'll leave it to the usual crowd. :-)
I appreciate the engagement you've given this already. :)
--
--Guido van Rossum (python.org/~guido) *Pronouns: he/him **(why is my pronoun here?)* <http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-change-the-world/>
--
--Guido (mobile)
-- Best regards, Paul mailto:pmiscml@gmail.com
FWIW, one of my intro students just yesterday asked about this: Is there a way to call a function in a python file directly from the command line? I have no idea what their programming background is, or why they expected that to be possible, but there you go -- at least one newbie expected it to be possible :-) However: This was literally class number one -- I had not yet showed them the "if __name__ == '__main__':" idiom yet. Also, I'm pretty sure this student's expectation was that there would not have to be anything special about the function (except maybe taking only string arguments?) -- so it's probably not a good idea to try to solve that use case anyway. But that was the first time I was ever asked that question -- and here it is on python-ideas -- quite a coincidence! -CHB On Tue, Oct 20, 2020 at 11:16 PM Paul Sokolovsky <pmiscml@gmail.com> wrote:
Hello,
On Wed, 21 Oct 2020 00:24:47 -0400 Michael Smith <michael@smith-li.com> wrote:
On Tue, Oct 20, 2020 at 23:43 Guido van Rossum <guido@python.org> wrote:
The ‘if __name__…’ idiom makes one function special. Hm... So if the module has that, will that main() still be called with your proposal? I.e., is __name__ still ‘__main__’?
Perhaps not. If __name__ were still '__main__' and calling the function implied importing the module, then anything in `if __name__ == '__main__'` would still get run. I think that would be inconvenient for folks.
Alternative valuation is that your proposal is inconvenient to folks, as it leaves too many gaps. Which, as it seems, you're eager to bravely patch, but that does/will lead to only more confusion.
I think __name__ should be the module name in the context of the module, and the function name in the context of the function, in this case.
__name__ is the name of the module. Or, as a special exception, it's "__main__" for a module directly invoked as a script or via "-m" switch.
There's no need to complicate it any further (it's already complicated enough; my bet that half of Python users won't be able to formulate it like above by heart).
Back to the original proposal, there's no general need to invoke an arbitrary function in an arbitrary module. That just makes no sense, as most functions depend on context.
If *you* need that, then, besides other options you mentioned in your original mail, it's trivial to write a module which will do it for you, like:
python -m my_super_invocator module:thunk
Actually, if you look on PyPI, I bet you'll find a few like that.
On Tue, Oct 20, 2020 at 20:32 Michael Smith <michael@smith-li.com> wrote:
On Tue, Oct 20, 2020 at 23:12 Guido van Rossum <guido@python.org> wrote:
On Tue, Oct 20, 2020 at 8:06 PM Michael Smith <michael@smith-li.com> wrote:
On Tue, Oct 20, 2020 at 10:19 PM Guido van Rossum <guido@python.org> wrote: > > I think it would be a tad more convincing if there was a way > to pass arguments too (even if just a list of strings). At the very least extra arguments should end up in sys.argv[1:].
Could python -m 'module:thunk' have exactly the same behavior with respect to arguments as `python3.8 -m module` does today?
``` $ cat bar.py import pprint, sys
def thunk(): pprint.pprint(sys.argv)
if __name__ == "__main__": thunk()
$ python3.8 -m bar -- -1 --two --three=3 ['/Users/michael/bar.py', '--', '-1', '--two', '--three=3'] ```
So then with the same bar.py, `python -m bar:thunk -- -2 --three --four=4` would print `['/Users/michael/bar.py', '--', '-1', '--two', '--three=3']`. I like this better than my previous suggestion to shorthand python -c.
Actually it should print the same except for sys.argv[0]. (We could argue about what sys.argv[0] should be.)
> Then again, presumably the function must be specially crafted > for this usage. Why can't you just specially craft a module's main()?
I'm not sure I know what you mean by "specially crafted", other than the function only needs not require any formal parameters. It doesn't need to be special-er than that. It can handle args via sys.argv, as you suggested. Most of the `main` functions I write today are just like that.
Okay, so this is just a way to choose an alternative main() function.
Am I missing something important here? What's special about naming a function "main"? Don't you still have to do something else to invoke it from the cli, such as calling it expressly in the module or pointing console entry points to it?
``` $ echo 'def main(): print("hi")' > xyz.py $ python -m xyz <no output> $ ```
I'm kind of meh at this point, I'll leave it to the usual crowd. :-)
I appreciate the engagement you've given this already. :)
--
--Guido van Rossum (python.org/~guido) *Pronouns: he/him **(why is my pronoun here?)* <
http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-c...
-- --Guido (mobile)
-- Best regards, Paul mailto:pmiscml@gmail.com _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/7RFFX3... Code of Conduct: http://python.org/psf/codeofconduct/
-- Christopher Barker, PhD Python Language Consulting - Teaching - Scientific Software Development - Desktop GUI and Web Development - wxPython, numpy, scipy, Cython
What a few responders have said is along the lines that my proposal 1. Can already be done. 2. Has gaps/is too simple. I will try to address those points here, but before I start, I'm getting the impression I don't have a great grasp of the communication style of this list. I assumed that a simple proposal with _some value_ would meet less resistance than a complex one with more value, so I left out features (like handling arguments). I will try to avoid MVP-ing my proposals in the future, as I think that led to a more "meh" initial response than my idea deserves. --------- Can calling a function from the command line already be done? Yes, I led with that. But my idea would lead to the following improvements: 1. Being able to call two different functions from the same module. (AND) 2. Being able to call some functions that exist today without modification or rearrangement. (AND) 3. Being able to invoke these things from python without installing a module from pip. There are solutions that do some of these, but nothing that does them all. I think it's surprising that the python makers have found worthwhile three different solutions for invoking modules, but this list so far has seen little value in invoking a function. ----- Is my proposal oversimplified? Maybe? I actually think it's pretty nice just to be able to call a couple of arbitrary functions by name that know how to access args via argparse or whatever. It would definitely be more empowering to be able to describe the command line args to such an invocation using the args to the function. But, I guess the real weakness of my proposal was that it required anything special about the function at all. It'd be easy to handle some functions with arguments, certainly if they're all strings. Other primitive scalar types may be doable if we map type hints to constructors. But I can't think of a reasonable way to handle a function that expects a complex object for an argument. So, how about if the proposal expands to include functions with any arity of string-only arguments? I think that makes it possible to use a wide variety of functions without any special work. We could also say that positional arguments are treated positionally, and kwargs need to be expressed on the command line as --kwarg=value What else is missing? On Wed, Oct 21, 2020 at 13:15 Christopher Barker <pythonchb@gmail.com> wrote:
FWIW, one of my intro students just yesterday asked about this:
Is there a way to call a function in a python file directly from the command line?
I have no idea what their programming background is, or why they expected that to be possible, but there you go -- at least one newbie expected it to be possible :-)
However: This was literally class number one -- I had not yet showed them the "if __name__ == '__main__':" idiom yet.
Also, I'm pretty sure this student's expectation was that there would not have to be anything special about the function (except maybe taking only string arguments?) -- so it's probably not a good idea to try to solve that use case anyway.
But that was the first time I was ever asked that question -- and here it is on python-ideas -- quite a coincidence!
-CHB
On Tue, Oct 20, 2020 at 11:16 PM Paul Sokolovsky <pmiscml@gmail.com> wrote:
Hello,
On Wed, 21 Oct 2020 00:24:47 -0400 Michael Smith <michael@smith-li.com> wrote:
On Tue, Oct 20, 2020 at 23:43 Guido van Rossum <guido@python.org> wrote:
The ‘if __name__…’ idiom makes one function special. Hm... So if the module has that, will that main() still be called with your proposal? I.e., is __name__ still ‘__main__’?
Perhaps not. If __name__ were still '__main__' and calling the function implied importing the module, then anything in `if __name__ == '__main__'` would still get run. I think that would be inconvenient for folks.
Alternative valuation is that your proposal is inconvenient to folks, as it leaves too many gaps. Which, as it seems, you're eager to bravely patch, but that does/will lead to only more confusion.
I think __name__ should be the module name in the context of the module, and the function name in the context of the function, in this case.
__name__ is the name of the module. Or, as a special exception, it's "__main__" for a module directly invoked as a script or via "-m" switch.
There's no need to complicate it any further (it's already complicated enough; my bet that half of Python users won't be able to formulate it like above by heart).
Back to the original proposal, there's no general need to invoke an arbitrary function in an arbitrary module. That just makes no sense, as most functions depend on context.
If *you* need that, then, besides other options you mentioned in your original mail, it's trivial to write a module which will do it for you, like:
python -m my_super_invocator module:thunk
Actually, if you look on PyPI, I bet you'll find a few like that.
On Tue, Oct 20, 2020 at 20:32 Michael Smith <michael@smith-li.com> wrote:
On Tue, Oct 20, 2020 at 23:12 Guido van Rossum <guido@python.org> wrote:
On Tue, Oct 20, 2020 at 8:06 PM Michael Smith <michael@smith-li.com> wrote:
> On Tue, Oct 20, 2020 at 10:19 PM Guido van Rossum > <guido@python.org> wrote: > > > > I think it would be a tad more convincing if there was a way > > to pass > arguments too (even if just a list of strings). At the very > least extra arguments should end up in sys.argv[1:]. > > Could python -m 'module:thunk' have exactly the same behavior > with respect to arguments as `python3.8 -m module` does today? > > ``` > $ cat bar.py > import pprint, sys > > def thunk(): > pprint.pprint(sys.argv) > > if __name__ == "__main__": > thunk() > > $ python3.8 -m bar -- -1 --two --three=3 > ['/Users/michael/bar.py', '--', '-1', '--two', '--three=3'] > ``` > > So then with the same bar.py, `python -m bar:thunk -- -2 --three > --four=4` would print `['/Users/michael/bar.py', '--', '-1', > '--two', '--three=3']`. I like this better than my previous > suggestion to shorthand python -c. >
Actually it should print the same except for sys.argv[0]. (We could argue about what sys.argv[0] should be.)
> > Then again, presumably the function must be specially crafted > > for > this usage. Why can't you just specially craft a module's main()? > > I'm not sure I know what you mean by "specially crafted", other > than the function only needs not require any formal parameters. > It doesn't need to be special-er than that. It can handle args > via sys.argv, as you suggested. Most of the `main` functions I > write today are just like that. >
Okay, so this is just a way to choose an alternative main() function.
Am I missing something important here? What's special about naming a function "main"? Don't you still have to do something else to invoke it from the cli, such as calling it expressly in the module or pointing console entry points to it?
``` $ echo 'def main(): print("hi")' > xyz.py $ python -m xyz <no output> $ ```
I'm kind of meh at this point, I'll leave it to the usual crowd. :-)
I appreciate the engagement you've given this already. :)
--
--Guido van Rossum (python.org/~guido) *Pronouns: he/him **(why is my pronoun here?)* <
http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-c...
-- --Guido (mobile)
-- Best regards, Paul mailto:pmiscml@gmail.com
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/7RFFX3...
Code of Conduct: http://python.org/psf/codeofconduct/
-- Christopher Barker, PhD
Python Language Consulting - Teaching - Scientific Software Development - Desktop GUI and Web Development - wxPython, numpy, scipy, Cython
I really don't see this goal as general purpose enough to merit Python syntax or standard library inclusion. Needing a PyPI package to do something slightly uncommon really doesn't feel like a bad obstacle. Click is perfectly great. It's a nice package for creating a certain kind of command line interface, especially handy with subcommands. Argparse also supports subcommands. But the cases where there is a single mapping from every function in a module to an available command line argument/subcommand, always using the same name, feel limited to me. If that is what you want, that's fine, it's not hard to do. It can be as simple as an `eval()` in the __main__ block. That particular use pattern feels niche to me. Figuring out arguments to pass into functions, along with their types, is certainly something that a command-line language COULD handle. But it doesn't seem like something that every command-line program should want to handle in the same way. On Fri, Oct 23, 2020 at 2:07 AM Michael Smith <michael@smith-li.com> wrote:
What a few responders have said is along the lines that my proposal
1. Can already be done. 2. Has gaps/is too simple.
I will try to address those points here, but before I start, I'm getting the impression I don't have a great grasp of the communication style of this list. I assumed that a simple proposal with _some value_ would meet less resistance than a complex one with more value, so I left out features (like handling arguments). I will try to avoid MVP-ing my proposals in the future, as I think that led to a more "meh" initial response than my idea deserves.
---------
Can calling a function from the command line already be done? Yes, I led with that. But my idea would lead to the following improvements:
1. Being able to call two different functions from the same module. (AND) 2. Being able to call some functions that exist today without modification or rearrangement. (AND) 3. Being able to invoke these things from python without installing a module from pip.
There are solutions that do some of these, but nothing that does them all. I think it's surprising that the python makers have found worthwhile three different solutions for invoking modules, but this list so far has seen little value in invoking a function.
-----
Is my proposal oversimplified? Maybe? I actually think it's pretty nice just to be able to call a couple of arbitrary functions by name that know how to access args via argparse or whatever.
It would definitely be more empowering to be able to describe the command line args to such an invocation using the args to the function.
But, I guess the real weakness of my proposal was that it required anything special about the function at all. It'd be easy to handle some functions with arguments, certainly if they're all strings. Other primitive scalar types may be doable if we map type hints to constructors. But I can't think of a reasonable way to handle a function that expects a complex object for an argument.
So, how about if the proposal expands to include functions with any arity of string-only arguments? I think that makes it possible to use a wide variety of functions without any special work.
We could also say that positional arguments are treated positionally, and kwargs need to be expressed on the command line as --kwarg=value
What else is missing?
On Wed, Oct 21, 2020 at 13:15 Christopher Barker <pythonchb@gmail.com> wrote:
FWIW, one of my intro students just yesterday asked about this:
Is there a way to call a function in a python file directly from the command line?
I have no idea what their programming background is, or why they expected that to be possible, but there you go -- at least one newbie expected it to be possible :-)
However: This was literally class number one -- I had not yet showed them the "if __name__ == '__main__':" idiom yet.
Also, I'm pretty sure this student's expectation was that there would not have to be anything special about the function (except maybe taking only string arguments?) -- so it's probably not a good idea to try to solve that use case anyway.
But that was the first time I was ever asked that question -- and here it is on python-ideas -- quite a coincidence!
-CHB
On Tue, Oct 20, 2020 at 11:16 PM Paul Sokolovsky <pmiscml@gmail.com> wrote:
Hello,
On Wed, 21 Oct 2020 00:24:47 -0400 Michael Smith <michael@smith-li.com> wrote:
On Tue, Oct 20, 2020 at 23:43 Guido van Rossum <guido@python.org> wrote:
The ‘if __name__…’ idiom makes one function special. Hm... So if the module has that, will that main() still be called with your proposal? I.e., is __name__ still ‘__main__’?
Perhaps not. If __name__ were still '__main__' and calling the function implied importing the module, then anything in `if __name__ == '__main__'` would still get run. I think that would be inconvenient for folks.
Alternative valuation is that your proposal is inconvenient to folks, as it leaves too many gaps. Which, as it seems, you're eager to bravely patch, but that does/will lead to only more confusion.
I think __name__ should be the module name in the context of the module, and the function name in the context of the function, in this case.
__name__ is the name of the module. Or, as a special exception, it's "__main__" for a module directly invoked as a script or via "-m" switch.
There's no need to complicate it any further (it's already complicated enough; my bet that half of Python users won't be able to formulate it like above by heart).
Back to the original proposal, there's no general need to invoke an arbitrary function in an arbitrary module. That just makes no sense, as most functions depend on context.
If *you* need that, then, besides other options you mentioned in your original mail, it's trivial to write a module which will do it for you, like:
python -m my_super_invocator module:thunk
Actually, if you look on PyPI, I bet you'll find a few like that.
On Tue, Oct 20, 2020 at 20:32 Michael Smith <michael@smith-li.com> wrote:
On Tue, Oct 20, 2020 at 23:12 Guido van Rossum <guido@python.org> wrote: > On Tue, Oct 20, 2020 at 8:06 PM Michael Smith > <michael@smith-li.com> wrote: > >> On Tue, Oct 20, 2020 at 10:19 PM Guido van Rossum >> <guido@python.org> wrote: >> > >> > I think it would be a tad more convincing if there was a way >> > to pass >> arguments too (even if just a list of strings). At the very >> least extra arguments should end up in sys.argv[1:]. >> >> Could python -m 'module:thunk' have exactly the same behavior >> with respect to arguments as `python3.8 -m module` does today? >> >> ``` >> $ cat bar.py >> import pprint, sys >> >> def thunk(): >> pprint.pprint(sys.argv) >> >> if __name__ == "__main__": >> thunk() >> >> $ python3.8 -m bar -- -1 --two --three=3 >> ['/Users/michael/bar.py', '--', '-1', '--two', '--three=3'] >> ``` >> >> So then with the same bar.py, `python -m bar:thunk -- -2 --three >> --four=4` would print `['/Users/michael/bar.py', '--', '-1', >> '--two', '--three=3']`. I like this better than my previous >> suggestion to shorthand python -c. >> > > Actually it should print the same except for sys.argv[0]. (We > could argue about what sys.argv[0] should be.) > > >> > Then again, presumably the function must be specially crafted >> > for >> this usage. Why can't you just specially craft a module's main()? >> >> I'm not sure I know what you mean by "specially crafted", other >> than the function only needs not require any formal parameters. >> It doesn't need to be special-er than that. It can handle args >> via sys.argv, as you suggested. Most of the `main` functions I >> write today are just like that. >> > > Okay, so this is just a way to choose an alternative main() > function.
Am I missing something important here? What's special about naming a function "main"? Don't you still have to do something else to invoke it from the cli, such as calling it expressly in the module or pointing console entry points to it?
``` $ echo 'def main(): print("hi")' > xyz.py $ python -m xyz <no output> $ ```
I'm kind of meh at this point, I'll leave it to the usual crowd. :-) >
I appreciate the engagement you've given this already. :)
-- > --Guido van Rossum (python.org/~guido) > *Pronouns: he/him **(why is my pronoun here?)* > <
http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-c...
> -- --Guido (mobile)
-- Best regards, Paul mailto:pmiscml@gmail.com
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/7RFFX3...
Code of Conduct: http://python.org/psf/codeofconduct/
-- Christopher Barker, PhD
Python Language Consulting - Teaching - Scientific Software Development - Desktop GUI and Web Development - wxPython, numpy, scipy, Cython
_______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/DFG3KW... Code of Conduct: http://python.org/psf/codeofconduct/
-- The dead increasingly dominate and strangle both the living and the not-yet born. Vampiric capital and undead corporate persons abuse the lives and control the thoughts of homo faber. Ideas, once born, become abortifacients against new conceptions.
On 2020-10-22 at 20:04:14 -0400, Michael Smith <michael@smith-li.com> wrote:
1. Being able to call two different functions from the same module. (AND) 2. Being able to call some functions that exist today without modification or rearrangement. (AND) 3. Being able to invoke these things from python without installing a module from pip.
There are solutions that do some of these, but nothing that does them all. I think it's surprising that the python makers have found worthwhile three different solutions for invoking modules, but this list so far has seen little value in invoking a function.
The following module meets your three criteria: %% begin Python code def f(): print("This is f.") def g(): print("This is g.") h = 'hello' i = lambda x: print(f"Hello, {x}.") if __name__ == '__main__': import sys try: function_name, *arguments = sys.argv[1:] except (IndexError, ValueError): print('missing function name') sys.exit(1) function = sys.modules[__name__].__dict__.get(function_name) if not function or not callable(function): print('cannot find or cannot call', function_name) sys.exit(1) function(*arguments) %% end Python code It's not polished, and it only handles positional string parameters, but it should be fairly self-explanatory. The __name__ == '__main__' idiom allows the module to be imported by other modules without incident. IMO, at best, it might be the beginning of a recipe somewhere rather than being included in the standard library. I agree with David Mertz that as soon as it gets more complex, every application is going to want something a little different.
It would definitely be more empowering to be able to describe the command line args to such an invocation using the args to the function.
Such enhancements are left as an exercise to the interested reader. HTH, Dan
21.10.20 05:05, Michael Smith пише:
There are many ways to invoke a function from the commandline. You can use setuptools' console_scripts entrypoint. You can use a decorator from click. And of course you can always do the classic
if __name__ == "__main__": main()
to call whatever main() is. But there are inconveniences with these approaches. For setuptools, you have to actually run setup, somehow. For click, you have to install click. And for __name__, you are either locked into a single function name, or you have to write some arg parsing to determine what name to use.
I propose it would be nice to be able to call a function from python, using syntax like
python -m module:thunk
Currently you can do this using packages. Convert module into package, make the thunk subdirectory, and write you code into module/thunk/__main__.py. Invoking "python -m module.thunk" will execute that code. Invoking "python -m module" will execute the code in module/__main__.py.
participants (7)
-
2QdxY4RzWzUUiLuE@potatochowder.com
-
Christopher Barker
-
David Mertz
-
Guido van Rossum
-
Michael Smith
-
Paul Sokolovsky
-
Serhiy Storchaka