Skip to content

"TypeError: Item in ``from list'' not a string" message #65919

Description

@davidszotten
BPO 21720
Nosy @brettcannon, @rhettinger, @ncoghlan, @taleinat, @ezio-melotti, @ericsnowcurrently, @berkerpeksag, @serhiy-storchaka, @davidszotten, @timgraham
PRs
  • bpo-21720: Improve exception message of __import__() #4113
  • bpo-21720: Restore the Python 2.7 logic in handling a fromlist. #4118
  • [3.6] bpo-21720: Restore the Python 2.7 logic in handling a fromlist. (GH-4118) #4128
  • Files
  • fromlist.patch
  • fromlist2.patch
  • issue21720.diff
  • issue21720_python3.diff
  • 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 = <Date 2017-10-26.09:03:53.524>
    created_at = <Date 2014-06-11.13:28:45.104>
    labels = ['interpreter-core', 'type-feature', '3.7']
    title = '"TypeError: Item in ``from list\'\' not a string" message'
    updated_at = <Date 2017-10-26.09:03:53.523>
    user = 'https://github.com/davidszotten'

    bugs.python.org fields:

    activity = <Date 2017-10-26.09:03:53.523>
    actor = 'serhiy.storchaka'
    assignee = 'none'
    closed = True
    closed_date = <Date 2017-10-26.09:03:53.524>
    closer = 'serhiy.storchaka'
    components = ['Interpreter Core']
    creation = <Date 2014-06-11.13:28:45.104>
    creator = 'davidszotten@gmail.com'
    dependencies = []
    files = ['36500', '36501', '45006', '45063']
    hgrepos = []
    issue_num = 21720
    keywords = ['patch']
    message_count = 42.0
    messages = ['220267', '221027', '226038', '226039', '226040', '226046', '226047', '226055', '232703', '278252', '278255', '278270', '278330', '278506', '278513', '278515', '278522', '278523', '278527', '278530', '278539', '278783', '278785', '278786', '278794', '304792', '304868', '304954', '304960', '304961', '304967', '304969', '304971', '304984', '304986', '305005', '305006', '305019', '305031', '305032', '305033', '305039']
    nosy_count = 13.0
    nosy_names = ['brett.cannon', 'rhettinger', 'ncoghlan', 'taleinat', 'ezio.melotti', 'bignose', 'python-dev', 'eric.snow', 'berker.peksag', 'serhiy.storchaka', 'Julian.Gindi', 'davidszotten@gmail.com', 'Tim.Graham']
    pr_nums = ['4113', '4118', '4128']
    priority = 'normal'
    resolution = 'fixed'
    stage = 'resolved'
    status = 'closed'
    superseder = None
    type = 'enhancement'
    url = 'https://bugs.python.org/issue21720'
    versions = ['Python 2.7', 'Python 3.6', 'Python 3.7']

    Activity

    1. davidszotten commented on Jun 11, 2014

      davidszottenmannequin
      MannequinAuthor
      >>> __import__('fabric.', fromlist=[u'api'])
      Traceback (most recent call last):
        File "<stdin>", line 1, in <module>
      

      accidentally ended up with something like this via some module that was using unicode_literals. stumped me for a second until i realised that my variable was a string, but not str. would be nice with a custom error message if this is a unicode string, explicitly mentioning that these must not be unicode or similar

    2. ezio-melotti commented on Jun 19, 2014

      @ezio-melotti
      Member

      Do you want to propose a patch?
      I think the standard message in these cases is along the lines of "TypeError: fromlist argument X must be str, not unicode"

    3. JulianGindi commented on Aug 28, 2014

      JulianGindimannequin
      Mannequin

      I'm trying to replicate this issue. I do not get an error when I run

      >>>  __import__('datetime', fromlist=[u'datetime'])
      

      any more information you could provide to help move this issue forward?

    4. davidszotten commented on Aug 28, 2014

      davidszottenmannequin
      MannequinAuthor

      after some trial and error it only appears to break for 3rd party packages (all 20 or so i happened to have installed), whereas everything i tried importing from the standard library worked fine

      >>> __import__('requests.', fromlist=[u'get'])
      Traceback (most recent call last):
        File "<stdin>", line 1, in <module>
      TypeError: Item in ``from list'' not a string
      
      >>> __import__('os.', fromlist=[u'path'])
      <module 'os' from '<snip (virtualenv)>/lib/python2.7/os.pyc'>
      
    5. JulianGindi commented on Aug 28, 2014

      JulianGindimannequin
      Mannequin

      Interesting...I'll try to dig in and see what's going on.

    6. davidszotten commented on Aug 28, 2014

      davidszottenmannequin
      MannequinAuthor

      first ever patch to python, so advice on the patch would be appreciated

      found an example in the stdlib that triggers bug (used in test):

      __import__('encodings', fromlist=[u'aliases'])

    7. berkerpeksag commented on Aug 29, 2014

      @berkerpeksag
      Member

      Thanks for the patch, David!

      + def test_fromlist_error_messages(self):
      + # Test for issue bpo-21720: fromlist unicode error messages
      + try:
      + __import__('encodings', fromlist=[u'aliases'])
      + except TypeError as exc:
      + self.assertIn("must be str, not unicode", str(exc))

      You could use assertRaises here:

          with self.assertRaises(TypeError) as cm:
              # ...
      
          self.assertIn('foo', str(cm.exception))
      •    if (PyUnicode_Check(item)) {
        
      •        PyErr_SetString(PyExc_TypeError,
        
      •                        "Item in ``from list'' must be str, not unicode");
        
      •        Py_DECREF(item);
        
      •        return 0;
        
      •    }
        

      I think it would be better to improve the error message in Python/import.c:

      http://hg.python.org/cpython/file/2.7/Python/import.c#l2571
      

      So you can safely remove this check.

    8. davidszotten commented on Aug 29, 2014

      davidszottenmannequin
      MannequinAuthor

      not sure i follow. we need a different message if e.g. an integer is passed in

      updated the patch to only run the unicode check for non-strings

      or do you have a suggestion for an error message that works nicely in both cases?

    9. bignose commented on Dec 16, 2014

      bignosemannequin
      Mannequin

      Is there room for a better resolution: fix the API so that Unicode objects are accepted in the ‘fromlist’ items?

    10. timgraham commented on Oct 7, 2016

      timgrahammannequin
      Mannequin

      As far as I can tell, this isn't an issue on Python 3. Can this be closed since Python 2 is only receiving bug fixes now?

    11. berkerpeksag commented on Oct 7, 2016

      @berkerpeksag
      Member

      I think we can classify this one as a usability bug and improve the exception message.

    12. 24 remaining items

    13. serhiy-storchaka commented on Oct 25, 2017

      @serhiy-storchaka
      Member
      >>> __import__('encodings', fromlist=iter(('aliases', b'foobar')))
      <module 'encodings' from '/home/serhiy/py/cpython/Lib/encodings/__init__.py'>
    14. berkerpeksag commented on Oct 25, 2017

      @berkerpeksag
      Member

      I don't think the index in error message is needed.

      I'm fine with either format. It's ultimately up to Nick. Should I switch back to the 2.7 version?

      Import is successful because the iterator was exhausted by "'*' in fromlist".

      This shouldn't be a problem in the latest version of PR 4113. While I don't think anyone would pass fromlist=iter(('aliases', b'foobar')) in real life, I can add it to the test. Let me know what do you think.

    15. ncoghlan commented on Oct 25, 2017

      @ncoghlan
      Contributor

      I'm fine with the approach in the latest version of the PR - it does make "from x import y" slightly slower due to the extra error checking, but folks should be avoiding doing that in performance critical loops or functions anyway.

      It would be nice if we could avoid that overhead for the import statement case, but we can't readily tell the difference between "__import__ called via syntax" and "__import__ called directly", and I don't think this is going to be performance critical enough to be worth introducing that complexity.

      The question of how best to handle passing a consumable iterator as the from list would be a separate question, if we decided to do anything about it at all (the current implementation implicitly assumes the input is reiterable, but passing a non-container seems like a harder mistake to make than accidentally passing bytes instead of a string).

    16. serhiy-storchaka commented on Oct 25, 2017

      @serhiy-storchaka
      Member

      The from import already is much slower than simple import:

      $ ./python -m timeit 'from encodings import aliases'
      500000 loops, best of 5: 475 nsec per loop
      $ ./python -m timeit 'import encodings.aliases as aliases'
      1000000 loops, best of 5: 289 nsec per loop

      The latter executes only C code if the module already is imported, but the former executes Python code. It may be worth to add the C acceleration for this case too.

      PR 4113 makes it yet slower:

      $ ./python -m timeit 'from encodings import aliases'
      500000 loops, best of 5: 793 nsec per loop

    17. serhiy-storchaka commented on Oct 25, 2017

      @serhiy-storchaka
      Member

      There are other differences between Python 2.7 and Python 3. PR 4118 restores the Python 2.7 logic. It adds type checking, but its overhead is smaller.

      $ ./python -m timeit 'from encodings import aliases'
      500000 loops, best of 5: 542 nsec per loop

      Actually in some cases (with '*') the new code is even slightly faster.

      I don't know whether these differences were intentional, but all tests are passed.

      The type of items in __all__ also is checked.

    18. taleinat commented on Oct 25, 2017

      @taleinat
      Contributor

      I can't say I agree that the performance here is practically insignificant. This will affect the startup time of Python process, and adding even 10% to that in some cases is significant.

      In some of the larger codebases I've worked on, even simple scripts would import large portions of the system, and there would be thousands of such imports done in the process. There are "basic" utilities in the stdlib which are imported very often in different modules, so the performance of the import statement is not necessarily insignificant compared to that of actually loading the modules.

      That being said I'm all for getting this in and implementing an optimization of the slower path in time for 3.7.

    19. brettcannon commented on Oct 25, 2017

      @brettcannon
      Member

      As Nick said, if the overhead of an import statement is that critical, then you should NOT use the from ... import ... form at all and just stick with import ... and if necessary, bind local names to objects off of the final module or a local name for the overall module.

    20. taleinat commented on Oct 25, 2017

      @taleinat
      Contributor

      I understand that there is a workaround. I'm just thinking about the many existing large codebases where re-writing thousands of imports because of this is unlikely to be done, yet having somewhat longer process launch times would be surprising and unwanted.

      Anyways I do think it's a very small price to pay for better error messages, and there's a good chance nobody will actually feel the difference, so let's definitely move forward with this.

    21. ncoghlan commented on Oct 26, 2017

      @ncoghlan
      Contributor

      Serhiy's PR avoids the cryptic BytesWarning on Py3 while minimising the overhead of the new typecheck, so I've closed Berker's PR in favour of that one (which now has approved reviews from both Brett and I, so Serhiy will merge it when he's ready to do so).

      Thanks for both patches!

    22. serhiy-storchaka commented on Oct 26, 2017

      @serhiy-storchaka
      Member

      New changeset 41c5694 by Serhiy Storchaka in branch 'master':
      bpo-21720: Restore the Python 2.7 logic in handling a fromlist. (bpo-4118)
      41c5694

    23. serhiy-storchaka commented on Oct 26, 2017

      @serhiy-storchaka
      Member

      Is it worth to backport PR 4118 to 3.6?

    24. ncoghlan commented on Oct 26, 2017

      @ncoghlan
      Contributor

      Given that the automated cherry-pick failed, I'd consider a 3.6 backport nice to have, but definitely not essential.

      My rationale for that is that "from __future__ import unicode_literals" makes it fairly easy to stumble over the 2.7 variant of this error message, but we're not aware of a similarly implicit way of encountering the 3.x variant.

    25. serhiy-storchaka commented on Oct 26, 2017

      @serhiy-storchaka
      Member

      New changeset 2b5cbbb by Serhiy Storchaka in branch '3.6':
      [3.6] bpo-21720: Restore the Python 2.7 logic in handling a fromlist. (GH-4118) (bpo-4128)
      2b5cbbb

    26. transferred this issue fromon Apr 10, 2022
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

    Metadata

    Metadata

    Assignees

    No one assigned

      Labels

      3.7 (EOL)end of lifeinterpreter-core(Objects, Python, Grammar, and Parser dirs)type-featureA feature request or enhancement

      Projects

      No projects

        Milestone

        No milestone

        Relationships

        None yet

        Development

        No branches or pull requests

        Issue actions