-
-
Notifications
You must be signed in to change notification settings - Fork 222
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
Add reset_contextvars and update bind_contextvars #339
Conversation
I’m gonna have to ask you to write some narrative docs for contextvars.rst so I have a clue what this is about. 😅 i have to admit that my understanding of contextvars is rather superficial. |
70fa295
to
4aa209b
Compare
Done in the latest revision. Is it any clearer now? |
src/structlog/contextvars.py
Outdated
@@ -98,16 +98,22 @@ def clear_contextvars() -> None: | |||
k.set(Ellipsis) | |||
|
|||
|
|||
def bind_contextvars(**kw: Any) -> None: | |||
""" | |||
def bind_contextvars(**kw: Any) -> Mapping[str, contextvars.Token]: |
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 think for some reason, Sphinx is getting confused trying to resolve the occurrences of contextvars.Token
in these typehints and docstrings, causing a spurious warning (which is getting turned into a spurious error).
I noticed the old-(pre-Sphinx-1.0)-format intersphinx_mapping
was being used, so I tried updating it to the up-to-date format, but that wasn't enough to appease Sphinx. 🤷
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.
Meant to say, I also tried several other things (e.g. adding from contextvars import Token
and changing the typehint to just Token
, and when that didn't work, tried spelling these references a bunch of other ways), but nothing I tried worked, and I gave up after the better part of an hour. I wonder if it's confusing Sphinx that both structlog
and the standard library have modules named contextvars
?
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.
Unfortunately Sphinx and types is hit and miss. :(
If you can't make it work, add it to
Lines 69 to 81 in b39a720
nitpick_ignore = [ | |
("py:class", "BinaryIO"), | |
("py:class", "ILogObserver"), | |
("py:class", "PlainFileObserver"), | |
("py:class", "TLLogger"), | |
("py:class", "TextIO"), | |
("py:class", "traceback"), | |
("py:class", "structlog._base.BoundLoggerBase"), | |
("py:class", "structlog.dev._Styles"), | |
("py:class", "structlog.types.EventDict"), | |
("py:obj", "sync_bl"), | |
("py:obj", "entries"), | |
] |
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! Done in the latest revision. (After rebasing on top of latest main
, I also had to add an entry for bare "TLLogger"
, to ignore a new warning I was getting that is unrelated to my changes.)
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.
Just a few stylistic changes.
Other than that, it needs a changelog entry. I would suggest some high-level description telling why ppl should be excited?
Maybe something like:
``structlog.contextvars.bind_contextvars()`` now returns a mapping of keys to ``contextvars.Token``\ s that allow to reset values using the new ``structlog.contextvars.reset_contextvars()``.
docs/contextvars.rst
Outdated
If e.g. your request handler calls a helper function that needs to | ||
temporarily override some contextvars before restoring them back to | ||
their original values, you can use the :class:`~contextvars.contextvars.Token`\s | ||
returned by :func:`~structlog.contextvars.bind_contextvars` along with | ||
:func:`~structlog.contextvars.reset_contextvars` to accomplish this | ||
(much like how :meth:`contextvars.ContextVar.reset` works): |
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 e.g. your request handler calls a helper function that needs to | |
temporarily override some contextvars before restoring them back to | |
their original values, you can use the :class:`~contextvars.contextvars.Token`\s | |
returned by :func:`~structlog.contextvars.bind_contextvars` along with | |
:func:`~structlog.contextvars.reset_contextvars` to accomplish this | |
(much like how :meth:`contextvars.ContextVar.reset` works): | |
If e.g. your request handler calls a helper function that needs to temporarily override some contextvars before restoring them back to their original values, you can use the :class:`~contextvars.contextvars.Token`\s returned by :func:`~structlog.contextvars.bind_contextvars` along with :func:`~structlog.contextvars.reset_contextvars` to accomplish this (much like how :meth:`contextvars.ContextVar.reset` works): |
We use semantic newlines.
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.
Done in the latest revision.
(Though, as a fan of semantic line breaks myself, I was surprised to get this suggestion. I think adding additional line breaks at appropriate positions within a single sentence is actually encouraged, not forbidden. See the example at https://sembr.org starting with "We can further clarify the source text by adding a line break after the clause". This makes reading and editing docs (and diffs) easier in editors that are not set to soft-wrap long lines, as well as pagers and other tools.)
@@ -116,7 +122,20 @@ def bind_contextvars(**kw: Any) -> None: | |||
var = contextvars.ContextVar(structlog_k, default=Ellipsis) | |||
_CONTEXT_VARS[structlog_k] = var | |||
|
|||
var.set(v) | |||
rv[k] = var.set(v) | |||
return rv |
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.
return rv | |
return rv |
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.
Done in the latest revision.
tests/test_contextvars.py
Outdated
bind_contextvars(a=1) | ||
assert {"a": 1} == get_contextvars() | ||
await event_loop.create_task(nested_coro()) |
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.
bind_contextvars(a=1) | |
assert {"a": 1} == get_contextvars() | |
await event_loop.create_task(nested_coro()) | |
bind_contextvars(a=1) | |
assert {"a": 1} == get_contextvars() | |
await event_loop.create_task(nested_coro()) |
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.
Done in the latest revision.
tests/test_contextvars.py
Outdated
assert {"a": 2, "b": 3} == get_contextvars() | ||
reset_contextvars(**tokens) | ||
assert {"a": 1} == get_contextvars() |
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.
assert {"a": 2, "b": 3} == get_contextvars() | |
reset_contextvars(**tokens) | |
assert {"a": 1} == get_contextvars() | |
assert {"a": 2, "b": 3} == get_contextvars() | |
reset_contextvars(**tokens) | |
assert {"a": 1} == get_contextvars() |
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.
Done in the latest revision.
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 reviewing, @hynek! I believe I've addressed all your requested changes.
docs/contextvars.rst
Outdated
If e.g. your request handler calls a helper function that needs to | ||
temporarily override some contextvars before restoring them back to | ||
their original values, you can use the :class:`~contextvars.contextvars.Token`\s | ||
returned by :func:`~structlog.contextvars.bind_contextvars` along with | ||
:func:`~structlog.contextvars.reset_contextvars` to accomplish this | ||
(much like how :meth:`contextvars.ContextVar.reset` works): |
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.
Done in the latest revision.
(Though, as a fan of semantic line breaks myself, I was surprised to get this suggestion. I think adding additional line breaks at appropriate positions within a single sentence is actually encouraged, not forbidden. See the example at https://sembr.org starting with "We can further clarify the source text by adding a line break after the clause". This makes reading and editing docs (and diffs) easier in editors that are not set to soft-wrap long lines, as well as pagers and other tools.)
src/structlog/contextvars.py
Outdated
@@ -98,16 +98,22 @@ def clear_contextvars() -> None: | |||
k.set(Ellipsis) | |||
|
|||
|
|||
def bind_contextvars(**kw: Any) -> None: | |||
""" | |||
def bind_contextvars(**kw: Any) -> Mapping[str, contextvars.Token]: |
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! Done in the latest revision. (After rebasing on top of latest main
, I also had to add an entry for bare "TLLogger"
, to ignore a new warning I was getting that is unrelated to my changes.)
@@ -116,7 +122,20 @@ def bind_contextvars(**kw: Any) -> None: | |||
var = contextvars.ContextVar(structlog_k, default=Ellipsis) | |||
_CONTEXT_VARS[structlog_k] = var | |||
|
|||
var.set(v) | |||
rv[k] = var.set(v) | |||
return rv |
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.
Done in the latest revision.
tests/test_contextvars.py
Outdated
bind_contextvars(a=1) | ||
assert {"a": 1} == get_contextvars() | ||
await event_loop.create_task(nested_coro()) |
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.
Done in the latest revision.
tests/test_contextvars.py
Outdated
assert {"a": 2, "b": 3} == get_contextvars() | ||
reset_contextvars(**tokens) | ||
assert {"a": 1} == get_contextvars() |
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.
Done in the latest revision.
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.
mypy is failing:
src/structlog/contextvars.py:101: error: Missing type parameters for generic type "Token"
src/structlog/contextvars.py:130: error: Missing type parameters for generic type "Token"
I suspect (vacationing rn) you have to set it to Token[Any]
?
@hynek should be fixed now! Thanks for catching that, and sorry I missed that when testing locally. (Each time I update this PR, the CI checks don't run until you approve running them, since this is my first structlog PR. If there were some way for you to pre-approve running the checks for future updates of this PR, I would have noticed and fixed that by the time you took your next look. Not sure if that's possible?) Hope you've been having a great vacation! |
Sorry terse because phone:
|
structlog.contextvars.bind_contextvars() now returns a Mapping[str, contextvar.Token] corresponding to the results of setting the requested contextvars. This return value is suitable for use with the newly-added structlog.contextvars.reset_contextvars() function, which resets the requested contextvars to their previous values using the given Tokens.
Not sure what's going on with the required codecov status checks. Please let me know if there's anything else you need me to do about those. Thanks for reviewing! |
Quickly approved before leaving. As long as builders are failing, you can ignore codecov, because of fast-failing alone (you can see that some builders don’t even start). |
🎉 |
Thanks for your perseverance! |
Thanks for merging! And for structlog and your other great work! |
JFTR, I've run into So I've fixed it today: python/cpython#29533 |
Update
structlog.contextvars.bind_contextvars()
to return aMapping[str, contextvar.Token]
corresponding to the resultsof setting the requested contextvars.
This return value is suitable for use with the newly-added
structlog.contextvars.reset_contextvars()
function, which resets the requested contextvars to their previous values using the given Tokens.Pull Request Check List
This is just a friendly reminder about the most common mistakes. Please make sure that you tick all boxes. But please read our contribution guide at least once, it will save you unnecessary review cycles!
If an item doesn't apply to your pull request, check it anyway to make it apparent that there's nothing left to do.
docs/api.rst
by hand.versionadded
,versionchanged
, ordeprecated
directives. Find the appropriate next version in our__init__.py
file..rst
files is written using semantic newlines.If you have any questions to any of the points above, just submit and ask! This checklist is here to help you, not to deter you from contributing!