Skip to content

logging.Formatter attributes fixed #721

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

Merged
merged 1 commit into from
Nov 30, 2016
Merged

logging.Formatter attributes fixed #721

merged 1 commit into from
Nov 30, 2016

Conversation

ambv
Copy link
Contributor

@ambv ambv commented Nov 29, 2016

Fixes #720.

Related changes: used a NamedTuple for time.struct_time on Python 3, used
sys.version selectors for proper typing of #716, added missing *Style classes
to logging on Python 3.

@ambv
Copy link
Contributor Author

ambv commented Nov 29, 2016

(the NamedTuple was already used on Python 2)

from types import SimpleNamespace

TimeTuple = Tuple[int, int, int, int, int, int, int, int, int]
if sys.version_info >= (3, 3):
TimeTuple = Union[
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this will work right. I tried this simple example:

T = Union[Tuple[int, int], Tuple[int, int, str]]
def f() -> T: pass
a = f()
reveal_type(a[0])
reveal_type(a[2])

and mypy revealed that both a[0] and a[2] have type Any. Without the union it understands that they are int and str, respectively.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see what you're saying. Two thoughts.

  1. This looks like a possible future improvement to Mypy? I don't see the current behavior specified in PEP 484.
  2. The main point of the TimeTuple type is checking arguments to functions (no such name in the actual time module). In this context, it works exactly as expected. See example below.
import time
print(time.struct_time((1,2)))

At runtime this fails with:

Traceback (most recent call last):
  File "/tmp/qwe.py", line 10, in <module>
    print(time.struct_time((1,2)))
TypeError: time.struct_time() takes an at least 9-sequence (2-sequence given)

With my change to time.pyi, Mypy correctly fails as well:

/tmp/qwe.py:10: error: Argument 1 to "struct_time" has incompatible type "Tuple[int, int]"; expected "Union[Tuple[int, int, int, int, int, int, int, int, int], Tuple[int, int, int, int, int, int, int, int, int, str], Tuple[int, int, int, int, int, int, int, int, int, str, int]]"

So, I'd file an issue against the current behavior of Mypy and accept the current union, esp. that time.pyi has no API that returns TimeTuples, it's just a function argument. It also works for type mismatches for tuple fields:

/tmp/qwe.py:2: error: Argument 1 to "struct_time" has incompatible type "Tuple[str, str, str, str, str, str, str, str, str]"; expected "Union[Tuple[int, int, int, int, int, int, int, int, int], Tuple[int, int, int, int, int, int, int, int, int, str], Tuple[int, int, int, int, int, int, int, int, int, str, int]]"

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, filed python/mypy#2509. PEP 484 in general is way under-specified.

I'm still hesitant to accept this, although a bit less so given that there are no APIs returning TimeTuple. (However, there's another definition of TimeTuple in datetime, and that is returned by some methods. However, those stubs should be changed to return struct_time.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regardless of the current implementation state of the type checker, what do you consider a valid type definition for TimeTuple? The old one was overly restrictive.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In what sense is it overly restrictive? All functions that take a TimeTuple also take a struct_time; IMO you should always use the latter when specifying the extra values. The struct_time, when unpacked, always returns exactly 9 values (even if it stores extra values).

The docs are pretty vague; the best I can find is here: https://docs.python.org/3/library/time.html?highlight=mktime#time.mktime -- this still says 9-tuple. Also note the definition of https://docs.python.org/3/library/time.html?highlight=mktime#time.struct_time which says that tm_gmtoff and tm_zone are only available on platforms where the C library supports these.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh my, you are absolutely correct. time.mktime and time.strftime only accept 9-tuples or struct_times! Sorry for the back and forth, restored TimeTuple as a 9-tuple.

@ambv
Copy link
Contributor Author

ambv commented Nov 29, 2016

(restored TimeTuple to a 9-tuple)

Copy link
Member

@gvanrossum gvanrossum left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, another union-related qualm... Then I'll stop!

@@ -79,6 +80,7 @@ class Logger:
def exception(self,
msg: Text, *args: Any, exc_info: _ExcInfoType = ...,
extra: Dict[str, Any] = ..., **kwargs: Any) -> None: ...
def isEnabledFor(self, lvl: int) -> Union[int, bool]: ...
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it even worth keeping the union here? Unions are a pain to use.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right, the only "int" ever returned is 0 which for all intents and purposes is equivalent to False unless somebody does "is False" checks. Will simplify further.

Fixes #720.

Related changes: used a NamedTuple for time.struct_time on Python 3, used
sys.version selectors for proper typing of #716, added missing *Style classes
to logging on Python 3.
@ambv
Copy link
Contributor Author

ambv commented Nov 30, 2016

Fixed.

@gvanrossum gvanrossum merged commit 85807ed into master Nov 30, 2016
@gvanrossum
Copy link
Member

Thanks! (Next time when responding to a code review can you not squash/amend local commits? We squash on merge.)

@gvanrossum gvanrossum deleted the logging_fixes branch November 30, 2016 17:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants