-
-
Notifications
You must be signed in to change notification settings - Fork 30.1k
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
Improve the __main__ module documentation #83633
Comments
This PR will apply the following changes on the
|
There are some serious problems with the PR. You state that these two phrases are from the runpy documentation:
but neither of those phrases appear in the runpy documentation here: https://docs.python.org/3/library/runpy.html You also say:
but this is incorrect, and I think based on a misunderstanding of PEP-338. The title of PEP-338, "Executing modules as scripts", is not exclusive: the PEP is about the -m mechanism for locating the module in order to run it as a script. It doesn't imply that In common parlance, "run as a script" certainly does include the case where you specify the module by filename
are correctly described as "running spam.py as a script" (and other variations). They differ in how the script is specified, but both mechanisms treat the spam.py file as a script and run it. See for example https://duckduckgo.com/?q=how+to+run+a+python+script for examples of common usage. Consequently, it is simply wrong to say that the intended usage of "run a script" is the -m mechanism. The PR changes the term "scope" to "environment", but I think that is wrong. An environment is potentially greater than a scope. The PR introduces the phrase "when the module is run from the file system" to mean the case where a script is run using (It is conceivable that -m could locate and run a built-in module, but I don't know any cases where that actually works. Even if it does, we surely don't need to complicate the docs for this corner case. It's enough to know that -m will locate the module and run it.) The PR describes three cases: running from the file system, running from stdin, and running "from the module namespace" but that last one is a clumsy phrase which, it seems to me, is not correct. How do you run a module from its own namespace? Modules *are* a namespace, and we say code runs *in* a namespace, not "from" it. In any case, it doesn't matter whether the script is specified on the command line as a file name, or as a module name with -m, or double-clicked in a GUI, in all three cases the module's code is executed in the module's namespace. So it is wrong to distinguish "from the file system" and "from (in) the module namespace" as two distinct cases. They are the same case. The PR replaces the comment inside the
with a comment above the `if` statement:
but the new comment is factually incorrect on two counts. Firstly, it is not correct that the if print("Hello, this always runs!") or __name__ == '__main__':
# execute only if run as a script
print('running as a script')
else:
# execute only if *not* run as a script
print('not run as a script') Placing the comment above the The second problem is that when running a module with -m it *is* imported. PEP-338 is clear about this: "if -m is used to execute a module the PEP-302 import mechanisms are used to locate the module and retrieve its compiled code, before executing the module" (in other words: import the module). We can test this, for example, if you create a package:
and then run There may be other issues with the PR. |
Thanks for your extended review Steven.
I agree. Actually the first paragraph of the page uses the phrases:
so instead of saying:
I simplified to:
But since the terminology is misleading I have used these phrases instead:
What the documentation tries to explain is that in all of these cases except the last one, code is executed in the __main__ module. I have updated the PR. ----
I disagree. According to Wikipedia (https://en.wikipedia.org/wiki/Scope_(computer_science)), the term "scope" is the part of a program where a name binding is valid, while the term "environment" (synonym of "context") is the set of name bindings that are valid within a part of a program. Therefore "scope" is a property of a name binding (a name binding has a scope), and "environment" is a property of a part of a program (a part of a program has an environment). And the term "environment" is actually already used in the original title and synopsis of the document (and it is correct):
So my change to the body fixes the inconsistent and incorrect usage of "scope":
----
I agree. Sometimes you see comments before if statements but they usually don't start with "execute". I have updated the PR. ----
I agree. I should have said "when the module is not initialized from an import statement". But note that even before my change the original document already used the phrase "not imported":
+ # Execute only if the module is not imported. I have updated the PR. |
The main issue I have with the existing doc is its use of 'top-level' to mean the main, initial, startup module that first executes the user code for a python 'program'. We routinely use 'top-level' instead for the global scope of a module. Example: https://docs.python.org/3/glossary.html, 'qualified name' entry, line 2: "For top-level functions and classes, ..." Within '__main__', some code is top-level, but class and function bodies are not. But this does not have to be part of this PR. |
I agree with you Terry. Another thing that bothers me: in the current document, the __main__ module is reduced to its environment (aka context or dictionary), whereas a module object has other important attributes such as its code. So how about adding the following changes?
|
Hi All, As I wrote on the PR::
Feel free to leave any feedback for me on the GitHub PR, I'm looking forward to continuing to develop this work based on community feedback. |
Hi All, I'm pinging everyone here on the bpo because my GitHub PR has been through a lot of revision and review. Maybe it's close to being ready to merge (I hope)! Feel free to take a look if you are interested: #26883 |
Thanks a lot, Géry and Jack! ✨ 🍰 ✨ |
Thanks, the rewrite is great! I have one nit: did you consider which of these two idioms is better? if __name__ == "__main__":
main() vs. if __name__ == "__main__":
sys.exit(main()) Your docs seem to promote the second, whereas I've usually preferred the former. Was this a considered choice on your part? |
@jack__d Thanks for the rewrite! This is a great expansion. Unfortunately I didn’t have the time to review it before the merge. If I find something to be improved I will let you know.
Are you sure? Yet in your 2003 blog post Python main() functions you promoted the opposite idiom
I am interested in the rationale if you changed your mind. |
You're right, I'm being inconsistent. :-( I withdraw my objection. There are cases where sys.exit() is easier than returning an exit code, e.g. when the error is discovered deep inside some other code. But it's probably better to raise a dedicated exception in that case and catch it in main(), rather than just calling sys.exit() deep inside the other code. It's probably too fine a point for a tutorial. Sorry! |
First and foremost, stupid GitHub is not letting the permalink load for some As far as my perspective, I also never personally use the sys.exit idiom I was, however, surprised to learn how pip treats console script entry points I do think we can tweak the document slightly to make it less prescriptive, I attached a diff that steers in that direction. What do you all think? It is |
No worries, it was almost twenty years ago.
Yes I agree, and I think you explained very clearly why it is better in the blog post:
So I think you made two independent points:
|
These changes are excellent - thanks for the patch! Something even the updated version doesn't cover yet is directory and zipfile execution, so I filed bpo-45149 as a follow up ticket for that (the info does exist elsewhere in the documentation, so it's mostly just a matter of adding it to the newly expanded page, and deciding what new cross-references, if any, would be appropriate) |
__main__
(GH-29379) #29449Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: