Skip to content

inspect.signature does not work for datetime classes #88784

Closed

Description

@mauvilsa
mannequin
BPO 44618
Nosy @gvanrossum, @hongweipeng, @mauvilsa
PRs
  • bpo-40897:Give priority to using the current class constructor in inspect.signature #27177
  • Note: 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:

    assignee = None
    closed_at = None
    created_at = <Date 2021-07-13.07:41:18.210>
    labels = ['type-bug', '3.8', '3.9', '3.10', '3.7', 'library']
    title = 'inspect.signature does not work for datetime classes'
    updated_at = <Date 2021-07-17.09:51:41.720>
    user = 'https://github.com/mauvilsa'

    bugs.python.org fields:

    activity = <Date 2021-07-17.09:51:41.720>
    actor = 'mauvilsa'
    assignee = 'none'
    closed = False
    closed_date = None
    closer = None
    components = ['Library (Lib)']
    creation = <Date 2021-07-13.07:41:18.210>
    creator = 'mauvilsa'
    dependencies = []
    files = []
    hgrepos = []
    issue_num = 44618
    keywords = ['patch']
    message_count = 6.0
    messages = ['397387', '397481', '397484', '397488', '397713', '397715']
    nosy_count = 3.0
    nosy_names = ['gvanrossum', 'hongweipeng', 'mauvilsa']
    pr_nums = ['27177']
    priority = 'normal'
    resolution = None
    stage = 'patch review'
    status = 'open'
    superseder = None
    type = 'behavior'
    url = 'https://bugs.python.org/issue44618'
    versions = ['Python 3.6', 'Python 3.7', 'Python 3.8', 'Python 3.9', 'Python 3.10']

    Activity

    1. mauvilsa commented on Jul 13, 2021

      mauvilsamannequin
      MannequinAuthor

      Classes in the datetime module are implemented using __new__ with some named parameters. I want to be able to inspect their signature to know which are the names of the parameters it accepts like it works for most classes. However, this does not work for classes in the datetime module. I already mentioned this in https://bugs.python.org/issue40897 but now I am thinking this should be a separate issue so I am creating this one.

      An example is the class timedelta. It has as parameters days, seconds, microseconds, milliseconds, minutes, hours and weeks. If I run the following script trying different python versions

      for py in 36 37 38 39; do
        source py${py}/bin/activate
        echo "=== $(python3 --version) ==="
        python3 -c "
      from datetime import timedelta
      import inspect
      print(inspect.signature(timedelta.__new__))
      print(inspect.signature(timedelta.__init__))
      inspect.signature(timedelta)
      "
        deactivate
      done

      What I get is

      === Python 3.6.9 ===
      (*args, **kwargs)
      (self, /, *args, **kwargs)
      Traceback (most recent call last):
      ...
      ValueError: no signature found for builtin type <class 'datetime.timedelta'>
      === Python 3.7.11 ===
      (*args, **kwargs)
      (self, /, *args, **kwargs)
      Traceback (most recent call last):
      ...
      ValueError: no signature found for builtin type <class 'datetime.timedelta'>
      === Python 3.8.11 ===
      (*args, **kwargs)
      (self, /, *args, **kwargs)
      Traceback (most recent call last):
      ...
      ValueError: no signature found for builtin type <class 'datetime.timedelta'>
      === Python 3.9.6 ===
      (*args, **kwargs)
      (self, /, *args, **kwargs)
      Traceback (most recent call last):
      ...
      ValueError: no signature found for builtin type <class 'datetime.timedelta'>
      
    2. added
      stdlibStandard Library Python modules in the Lib/ directory
      type-bugAn unexpected behavior, bug, or error
      on Jul 13, 2021
    3. gvanrossum commented on Jul 14, 2021

      @gvanrossum
      Member

      Doesn’t it do that with any built in function? Try Len or open, for example. I think that’s a feature, at least not a bug specific to date time.

    4. mauvilsa commented on Jul 14, 2021

      mauvilsamannequin
      MannequinAuthor

      Doesn’t it do that with any built in function?

      Sorry. I did not include what is the behavior for other classes. An example could be calendar.Calendar. In this case the signature gives:

      >>> from calendar import Calendar
      >>> import inspect
      >>> print(inspect.signature(Calendar.__init__))
      (self, firstweekday=0)
      >>> print(inspect.signature(Calendar))
      (firstweekday=0)

      Note that the signature gives firstweekday which is the only init parameter. Calendar is not implemented with __new__ so getting the signature would be for object, that does not include named parameters.

      It also works fine when you implement a class with __new__. For example:

      >>> class MyClass:
          def __new__(cls, paramA, paramB=1):
              obj = object.__new__(cls)
              obj.paramA = paramA
              obj.paramB = paramB
              return obj
      >>> print(inspect.signature(MyClass.__new__))
      (cls, paramA, paramB=1)
      >>> print(inspect.signature(MyClass))
      (paramA, paramB=1)

      I do think it is a bug specific to the datetime classes.

    5. gvanrossum commented on Jul 14, 2021

      @gvanrossum
      Member

      You're right, it seems specific to built-in *classes* like those in datetime. We get the same with inspect.signature(int), since int is also a built-in class.

      I don't know who maintains inspect, but it's not me. :-(

    6. mauvilsa commented on Jul 17, 2021

      mauvilsamannequin
      MannequinAuthor

      Also happens in python 3.10.

      === Python 3.10.0b4 ===

      (*args, **kwargs)
      (self, /, *args, **kwargs)
      Traceback (most recent call last):
      ...
      ValueError: no signature found for builtin type <class 'datetime.timedelta'>
    7. 6 remaining items

    8. added
      3.11only security fixes
      3.12only security fixes
      and removed on May 13, 2023
    9. StanFromIreland commented on Mar 12, 2025

      @StanFromIreland
      Member

      Since this is a problem with how the C extension is configured, maybe we could make some workaround where it calls the python implementation signature? Or encode it by hand?

      >>> from _pydatetime import timedelta
      ... import inspect
      ... print(inspect.signature(timedelta.__new__))
      ... print(inspect.signature(timedelta.__init__))
      ... inspect.signature(timedelta)
      ... 
      (cls, days=0, seconds=0, microseconds=0, milliseconds=0, minutes=0, hours=0, weeks=0)
      (self, /, *args, **kwargs)
      <Signature (days=0, seconds=0, microseconds=0, milliseconds=0, minutes=0, hours=0, weeks=0)>
      
      
    10. removed
      3.11only security fixes
      3.12only security fixes
      on Mar 12, 2025
    11. serhiy-storchaka commented on Aug 9, 2025

      @serhiy-storchaka
      Member

      #136573 fixes this issue, most cases. The only cases without signature/with unsupported signature are:

      • The tzinfo constructor. This is an abstract class, you should not create instances of it. There is a difference between Python and C implementations. Python implementation does not accept any argument, C implementation accepts any arguments.
      • The timezone constructor. Python implementation takes optional name argument with default value None. In C implementation, passing None and not passing anything give different results, so None cannot be used as the default value. help() shows it as timezone(offset, name=<unrepresentable>).
      • All replace() methods. They are the same as __replace__() methods, so we can give them the same signature, __replace__(self, /, **changes), but it does not show which keywords are accepted. So, help() shows the datetime.replace() signature as replace(self, /, year=unchanged, month=unchanged, day=unchanged, unchanged, minute=unchanged, second=unchanged, microsecond=unchanged, tzinfo=unchanged, *, fold=unchanged), which is not supported in inspect.signature().

      To support this cases, we need a general solution in inspect.signature() (which would fix many other cases) and somehow resolve the differences between Python and C implementations. These are different issues.

    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

    Metadata

    Metadata

    Labels

    stdlibStandard Library Python modules in the Lib/ directorytype-bugAn unexpected behavior, bug, or error

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions