-
-
Notifications
You must be signed in to change notification settings - Fork 30.8k
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
gh-71587: Establish global state in _datetime
#110475
gh-71587: Establish global state in _datetime
#110475
Conversation
erlend-aasland
commented
Oct 6, 2023
•
edited
Loading
edited
- Establish global state
- Put singletons in global state
- Issue: Datetime NoneType after calling Py_Finalize and Py_Initialize #71587
_datetime
_datetime
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 with shorter names, you can just write get_datetime_state()->utc
directly (for example).
PTAL, @vstinner |
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 PyInit__datetime() fails, I suppose that the next call may override global state without clearing the previous strong refererence: reference leak. I don't think that we should bother since this state is going to become more dynamic and set differently, no?
Well, it is easy to already now add the machinery needed to clear the state (future Note that parts of the state actually is cleared if the module exec function fails. |
Perhaps we should start with a PR that cleans up |
if (x == NULL) { | ||
return -1; | ||
if (st->utc == NULL) { | ||
goto error; |
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.
Apparently, now exec function has two different parts:
- First part uses return -1
- Second part initializes the static state and uses goto to make sure that the state always stays in a consistent state: either fully initialized, or cleared
I suggest to split the function in two parts (create a subfunction). I don't think that a second PR is needed.
Maybe just add a second _datetime_init_state() function?
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.
Sure, we can bake it into this PR. I'll get to it later tonight.
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.
I added some helpers in a9e8d1a (init_state
and create_timezone_from_delta
). Initialisation should now be slightly more robust than before, unless I missed something :)
st->seconds_per_day = PyLong_FromLong(24 * 3600); | ||
if (st->seconds_per_day == NULL) { | ||
return -1; | ||
} |
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 we want to initialise the state members in the order they are declared, we'll have to move this. However, the following comment will then need to be tweaked. I'm not sure it is worth it.
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, thanks.
Thanks for the review, Victor! |
There are lots of paths we can take for the follow-up PRs. Alt 1, continue adding to static state:
Alt 2, try to save the encapsulated C API by moving static state to the interpreter
What do you think, Victor? |
Sounds like a good step.
I would prefer to consider that after converting types to heap types. IMO the C API like PyDateTime_Check() will prevent to make this state per module. Instead, you can consider splitting this state in two states:
You simply cannot have more than one instance of the same type beause of PyDateTime_Check(). PyDateTime_Check() will be per-interpreter. I had the exact same problem with PyAST_Check(): int PyAST_Check(PyObject* obj)
{
struct ast_state *state = get_ast_state();
if (state == NULL) {
return -1;
}
return PyObject_IsInstance(obj, state->AST_type);
} |
if (state == NULL) {
return -1;
} By the way, the error case could be avoided by running the initialization at Python startup. |
Hi Erlend, would it be possible for you to support this for Python 3.12? |
No; that would be a breaking change. |
* Use explicit initialiser for m_base * Add module state stub; establish global state on stack * Put conversion factors in state struct * Move PyDateTime_TimeZone_UTC to state * Move PyDateTime_Epoch to state struct * Fix ref leaks in and clean up initialisation