-
-
Notifications
You must be signed in to change notification settings - Fork 32k
bpo-45445: Fail if an invalid X-option is provided in the command line #28823
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
Conversation
Hey @vstinner, would you be ok merging some refined version of this draft? We found that using |
@@ -2121,6 +2121,19 @@ _PyConfig_InitImportConfig(PyConfig *config) | |||
return config_init_import(config, 1); | |||
} | |||
|
|||
const wchar_t* known_xoptions[] = { | |||
L"faulthandler", | |||
L"showrefcount", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should Python ignore silently this option if Python is not build with Py_REF_DEBUG? Or should we add #ifdef Py_REF_DEBUG
? Using PYTHONDUMPREFS=1 env var doesn't fail with an error even if Python is not build with Py_TRACE_REFS.
IMO the least surprising behavior is to ignore silently the option. So leave the code as it is.
@@ -2136,6 +2149,11 @@ config_read(PyConfig *config, int compute_path_config) | |||
} | |||
|
|||
/* -X options */ | |||
const wchar_t* option = _Py_check_xoptions(&config->xoptions, known_xoptions); | |||
if (option != NULL) { | |||
return PyStatus_Error("Unknown value for option -X"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe document in Doc/using/cmdline.rst that Python now fails if it gets an unknown -X option to help detecting typos.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you know if there is any way using the PyStatus_Error
to provide a custom string? I would like to include the failed option but seems that nothing cleans the string provided here so I am not sure if is possible to customize the erro with the actual option :(
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you know if there is any way using the PyStatus_Error to provide a custom string?
Currently, it's not possible. You should extend the API for that. You should add a static buffer just for that somewhere, or allocate a string, and decide when and how it's released. For PEP 587, I decided to keep it simple (KISS) and only use constant string.
@vstinner Done! I have addressed your feedback and I have updated some tests that were failing. |
@@ -18,7 +18,7 @@ | |||
class AuditTest(unittest.TestCase): | |||
def do_test(self, *args): | |||
with subprocess.Popen( | |||
[sys.executable, "-X utf8", AUDIT_TESTS_PY, *args], | |||
[sys.executable, "-Xutf8", AUDIT_TESTS_PY, *args], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, or you can write "-X", "utf8". I suppose that both work.
@@ -18,7 +18,7 @@ | |||
class AuditTest(unittest.TestCase): | |||
def do_test(self, *args): | |||
with subprocess.Popen( | |||
[sys.executable, "-X utf8", AUDIT_TESTS_PY, *args], | |||
[sys.executable, "-Xutf8", AUDIT_TESTS_PY, *args], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, or you can write "-X", "utf8". I suppose that both work.
Lib/unittest/test/test_runner.py
Outdated
pass | ||
|
||
with self.assertRaises(TypeError): | ||
foo(w=40000,z=50000,o=60000) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Secrets 👀
@@ -2121,6 +2121,45 @@ _PyConfig_InitImportConfig(PyConfig *config) | |||
return config_init_import(config, 1); | |||
} | |||
|
|||
const wchar_t* known_xoptions[] = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would you mind to add a comment saying that all options are listed, even if they are only available if a specific macro is set, like -X showrefcount which requires a debug build (Py_REF_DEBUG). Say that unknown options are silently ignored in this case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
@@ -2136,6 +2149,11 @@ config_read(PyConfig *config, int compute_path_config) | |||
} | |||
|
|||
/* -X options */ | |||
const wchar_t* option = _Py_check_xoptions(&config->xoptions, known_xoptions); | |||
if (option != NULL) { | |||
return PyStatus_Error("Unknown value for option -X"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you know if there is any way using the PyStatus_Error to provide a custom string?
Currently, it's not possible. You should extend the API for that. You should add a static buffer just for that somewhere, or allocate a string, and decide when and how it's released. For PEP 587, I decided to keep it simple (KISS) and only use constant string.
@@ -0,0 +1,2 @@ | |||
Python now fails to initialize if an invalid :option:`-X` option in the | |||
command line. Patch by Pablo Galindo. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if... what? :-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, thanks for the fix :-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. There is just a typo in the NEWS entry.
Misc/NEWS.d/next/Core and Builtins/2021-10-12-14-41-39.bpo-45445._F5cMf.rst
Outdated
Show resolved
Hide resolved
@vstinner I have added a small static buffer for now in b6fe156 to allow customizing the message. I will prepare a better generic API in a different PR in the future. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pablogsal Thanks 👍 Looks great ⭐
Should we update an example in sys._xoptions docs? It crashes with this patch. We could use e.g. -Xutf8 -Xpycache_prefix=pycachepath
.
@@ -83,8 +83,17 @@ def get_xoptions(*args): | |||
opts = get_xoptions() | |||
self.assertEqual(opts, {}) | |||
|
|||
opts = get_xoptions('-Xa', '-Xb=c,d=e') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we have tests do X-options with values? Maybe we can use pycache_prefix
to keep this covered.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
test_embed
has a bunch, but I can add one here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Corrected in the last commit! Thanks for the suggestion @felixxm
…bpo-45445._F5cMf.rst
…-41-39.bpo-45445._F5cMf.rst
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for updates 👍
@pablogsal The PR has added test_foo.py in the repo's toplevel directory. Is it used somewhere in the tests where it's specifically needs to be in toplevel directory rather than under tests folders? |
🤦♂️No, that was a mistake that slip us. I will clean it up. Apologies |
Fixed in #28972 |
No worries, thanks @pablogsal :) |
Cross posting: Quoting your own documentation: There is client software out there relying on this. kovidgoyal/kitty#5223 Please do not randomnly break backwards compatibility, without even a deprecation period, because something "annoys" you. |
Apparently in Python-land its acceptable behavior to break backward compatibility with documented interfaces on a whim. Bloody joke. python/cpyt F42D hon#28823 Fixes #5223
The documentation still says that arbitrary values may be passed: https://docs.python.org/3.11/using/cmdline.html#cmdoption-X The
|
I've never had a use for I feel the python command line is not a public API in the same way that we talk about APIs for Python code. And doubly so for the Before we roll this back I would like to understand what problem Kitty is solving by passing its own |
I would say that CLI is an API for shell scripts. As a result, we need to account that eventhough scripts that pass nonexistent |
If a script was passing an incorrect |
Let's redirect the discussion to the issue (#89608) so we can discuss in a single place |
On Thu, Jun 23, 2022 at 02:04:45PM -0700, Guido van Rossum wrote:
I've never had a use for `sys._xoptions`, but I've mistyped (or mis-guessed) `-X` flag names many times, so at least a warning about a misspelling would be appreciated.
Yes, start with a warning, then after a couple of releases make it a
fatal error. Starting with a fatal error is not the way.
I feel the python command line is not a public API in the same way that we talk about APIs for Python code. And doubly so for the `-X` flag which is (usually) used to control interpreter internals.
Before we roll this back I would like to understand what problem Kitty is solving by passing its own `-X` flags (the Kitty issue doesn't say, it was just immediately closed as "bug in CPython"). Maybe we can help the Kitty devs find a better solution for their problem?
The problem was passing some data from the C runtime environment into
the python interpreter. Before Python 3.8, there was no good way to run
code between initialising the python interpreter and running it, without
keeping track of a bunch of interpreter internals, that tended to change
with versions. Since the introduction of PyConfig that is no longer the
case. I now just initialise the interpreter and then set a dict on sys
analogous to sys._xoptions myself using PySys_SetObject(). As I said,
this issue does not affect me (or kitty) anymore. I reported it here
because it seems very wrong to me to change documented API in the most
hostile fashion possible (an interpreter fatal exit) without some kind
of deprecation period or any consideration to backwards compat at all.
And while here I will note that even now if someone sets up some scripts
that run python as
python -X foo
and in the future foo is removed, it will again be a interpreter
shutdown.
|
…mand line (pythonGH-28823)" This reverts commit db2b6a2.
… in the command line (pythonGH-28823)" (pythonGH-94745) (cherry picked from commit aa37ffd) Co-authored-by: Pablo Galindo Salgado <Pablogsal@gmail.com>
|
https://bugs.python.org/issue45445