Skip to content
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

importlib.machinery.ExtensionFileLoader cannot load several modules from the same shared object #60625

Closed
eudoxos mannequin opened this issue Nov 6, 2012 · 25 comments
Closed
Assignees
Labels
extension-modules C modules in the Modules dir type-bug An unexpected behavior, bug, or error

Comments

@eudoxos
Copy link
Mannequin

eudoxos mannequin commented Nov 6, 2012

BPO 16421
Nosy @brettcannon, @amauryfa, @ncoghlan, @pitrou, @vstinner, @bitdancer, @asvetlov, @ericsnowcurrently
Files
  • many-modules-in-one-so_1.diff
  • many-modules-in-one-so_2.diff: Patch version 2, with tests
  • many-modules-in-one-so_3.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 = 'https://github.com/asvetlov'
    closed_at = <Date 2012-12-15.16:28:40.662>
    created_at = <Date 2012-11-06.14:42:53.120>
    labels = ['extension-modules', 'type-bug']
    title = 'importlib.machinery.ExtensionFileLoader cannot load several modules from the same shared object'
    updated_at = <Date 2012-12-15.16:28:40.660>
    user = 'https://bugs.python.org/eudoxos'

    bugs.python.org fields:

    activity = <Date 2012-12-15.16:28:40.660>
    actor = 'asvetlov'
    assignee = 'asvetlov'
    closed = True
    closed_date = <Date 2012-12-15.16:28:40.662>
    closer = 'asvetlov'
    components = ['Extension Modules']
    creation = <Date 2012-11-06.14:42:53.120>
    creator = 'eudoxos'
    dependencies = []
    files = ['27909', '27911', '27918']
    hgrepos = []
    issue_num = 16421
    keywords = ['patch']
    message_count = 25.0
    messages = ['174967', '174970', '174971', '174972', '174975', '174976', '174977', '174981', '174988', '174992', '175004', '175059', '175087', '175090', '175103', '175124', '176654', '176662', '177461', '177462', '177466', '177535', '177536', '177537', '177538']
    nosy_count = 12.0
    nosy_names = ['brett.cannon', 'amaury.forgeotdarc', 'ncoghlan', 'pitrou', 'vstinner', 'Arfrever', 'r.david.murray', 'asvetlov', 'docs@python', 'python-dev', 'eric.snow', 'eudoxos']
    pr_nums = []
    priority = 'normal'
    resolution = 'fixed'
    stage = 'resolved'
    status = 'closed'
    superseder = None
    type = 'behavior'
    url = 'https://bugs.python.org/issue16421'
    versions = ['Python 3.4']

    @eudoxos
    Copy link
    Mannequin Author

    eudoxos mannequin commented Nov 6, 2012

    This issue was split off bpo-16194 (I am not copying the whole discussion here). It was suggested a new issue is opened for Python3, where a proper fix can be done.

    Python internally caches dynamically loaded modules, but the cache is based on the filename only. If one file contains several modules, only the first of them is imported and initialized properly. This interface was previously exposed via imp.load_dynamic, the same codepath is used by importlib.machinery.ExtensionFileLoader now.

    A solution is to cache by the (filename, modulename) tuple, which avoids any ambiguity.

    I am attaching a simple patch for that, agains current hg tip (80272:ec00f8570c55), and tested with the scripot attached to bpo-16194.

    I have not modified the test suite, I am not sure whether testing compiled modules is actually supported (did not see any compiled files in there), I will be glad for help.

    @eudoxos eudoxos mannequin added extension-modules C modules in the Modules dir type-bug An unexpected behavior, bug, or error labels Nov 6, 2012
    @asvetlov
    Copy link
    Contributor

    asvetlov commented Nov 6, 2012

    Storing several modules in single so/pyd file is crazy idea from my perspective.

    The test is definitely required.

    BTW, Why version is set to 3.5?
    Should component be set to "Interpreter code"?

    @amauryfa
    Copy link
    Member

    amauryfa commented Nov 6, 2012

    It's not that crazy, if you consider that all builtin modules are stored in python33.dll.

    @eudoxos
    Copy link
    Mannequin Author

    eudoxos mannequin commented Nov 6, 2012

    Storing several modules in one .so file offloads some issues which have to be dealt with manually (like one module needing symbols from other module, or even cross-dependencies) to the linker. In any case, unless forbidden and signalled, it should be supported.

    I set version to 3.4 and component to "Interpreter core", as you suggested, it is probably more appropriate.

    How do I write test which requires a custom module to be compiled?

    @eudoxos eudoxos mannequin added interpreter-core (Objects, Python, Grammar, and Parser dirs) and removed extension-modules C modules in the Modules dir labels Nov 6, 2012
    @asvetlov
    Copy link
    Contributor

    asvetlov commented Nov 6, 2012

    Amaury, I'm ok with pushing several modules into python33.dll or embedding it directly into executable.
    For standard so/dll files you have to use different file names for modules to make regular import statement work. It can be done via symlink/hardlink, but looks a bit hairy.

    Václav, python already have _testbuffer and _testcapi modules used for testing only. I think you can add yet another one.

    @bitdancer
    Copy link
    Member

    There is an example in the test suite somewhere. Probably in the distutils tests. Search for xxmodule...but you'll need to create your own source. I'd see if you can write it out from the test rather than checking in another data file, but a data file is an option if needed.

    @bitdancer bitdancer added extension-modules C modules in the Modules dir type-feature A feature request or enhancement and removed interpreter-core (Objects, Python, Grammar, and Parser dirs) type-bug An unexpected behavior, bug, or error labels Nov 6, 2012
    @eudoxos
    Copy link
    Mannequin Author

    eudoxos mannequin commented Nov 6, 2012

    @andrew: I was using symlinks to achieve this, until I found recently that some exotic systems (read: windows) have still troubles there, like not letting non-admins create symlinks.

    @eudoxos eudoxos mannequin added type-bug An unexpected behavior, bug, or error and removed type-feature A feature request or enhancement labels Nov 6, 2012
    @bitdancer
    Copy link
    Member

    Sorry, didn't mean to change the component back.

    @bitdancer bitdancer added interpreter-core (Objects, Python, Grammar, and Parser dirs) type-feature A feature request or enhancement and removed extension-modules C modules in the Modules dir type-bug An unexpected behavior, bug, or error labels Nov 6, 2012
    @eudoxos
    Copy link
    Mannequin Author

    eudoxos mannequin commented Nov 6, 2012

    I added the test, with a module Modules/_testimportmultiple.c.

    The test uses the (undocumented) imp module, but all othet tests in Lib/test/test_imp.py do the same, so I assume it is OK?

    @brettcannon
    Copy link
    Member

    It's fine to cheat in tests, although test_imp predates importlib which is why it uses an undocumented API.

    @asvetlov
    Copy link
    Contributor

    asvetlov commented Nov 6, 2012

    Reviewed and commented the last patch.

    @eudoxos
    Copy link
    Mannequin Author

    eudoxos mannequin commented Nov 7, 2012

    Attaching patch based on Andrew's review, agains latest hg (80291:859ef54bdce).

    For the MSVC files, I copied what was there for _testcapimodule in PC/VS9.0 and PCbuild, and created two new UUIDs: one for _testimportmultiple itself (36D0C52C-DF4E-45D0-8BC7-E294C3ABC781; used in .sln, .vcproj and .vcxproj files), and one for _testimportmultiple.vcxproj.filters (1ec38ad9-1abf-4b80-8628-ac43ccba324b; used only once).

    Please check that I did that correctly. (I am wondering how can one maintain such a build system.)

    I also added myself to Misc/ACKS (and sent contributor agreement by mail), added the entry to Misc/NEWS.

    @eudoxos eudoxos mannequin added extension-modules C modules in the Modules dir type-bug An unexpected behavior, bug, or error and removed interpreter-core (Objects, Python, Grammar, and Parser dirs) type-feature A feature request or enhancement labels Nov 7, 2012
    @asvetlov
    Copy link
    Contributor

    asvetlov commented Nov 7, 2012

    Looks better, will check on Windows a bit later.

    BTW, ACKS and NEWS are usually edited by committer, but leave that as is for now.

    @eudoxos
    Copy link
    Mannequin Author

    eudoxos mannequin commented Nov 7, 2012

    Good, will let editors do that next time.

    I was following http://docs.python.org/devguide/patch.html#preparation which says "Sixth, if you are not already in the Misc/ACKS file then add your name."

    For NEWS, I was reading http://docs.python.org/devguide/committing.html#news-entries, but it is true it talks about commits, not about patches.

    @ncoghlan
    Copy link
    Contributor

    ncoghlan commented Nov 7, 2012

    Yeah, ACKS is fine (we just don't mind doing it if the submitter leaves it out). Updating NEWS is less useful because it almost inevitably causes a conflict when the patch is applied. (We occasionally mutter about adopting a less conflict-prone approach to handling NEWS entries, but nobody has ever found it annoying enough to design a solution and officially propose switching to it)

    @asvetlov
    Copy link
    Contributor

    asvetlov commented Nov 7, 2012

    Václav, your patch passed on Windows.
    Will commit it after double check.
    Thanks.

    @asvetlov asvetlov self-assigned this Nov 7, 2012
    @ncoghlan
    Copy link
    Contributor

    One nice feature of this is the potential to simplify single-file distribution - pack your application into a zip file, and only need to extract a single shared library for *all* your extension modules, which could be handled via a utility function called in __main__.py rather than needing to be built into the interpreter.

    @brettcannon
    Copy link
    Member

    Are you still planning on committing this, Andrew?

    @python-dev
    Copy link
    Mannequin

    python-dev mannequin commented Dec 14, 2012

    New changeset 6eefe4d537b3 by Andrew Svetlov in branch 'default':
    Issue bpo-16421: allow to load multiple modules from the same shared object.
    http://hg.python.org/cpython/rev/6eefe4d537b3

    @asvetlov
    Copy link
    Contributor

    Committed. Sorry for delay.
    Thanks, Vaclav!

    @vstinner
    Copy link
    Member

    Some tests are failing since the changeset 6eefe4d537b3.

    Example:
    http://buildbot.python.org/all/builders/x86%20RHEL%206%203.x/builds/1431/steps/test/logs/stdio

    Please check buildbots.

    [176/371] test_pkgutil
    test_getdata_filesys (test.test_pkgutil.PkgutilTests) ... ok
    test_getdata_zipfile (test.test_pkgutil.PkgutilTests) ... ok
    test_unreadable_dir_on_syspath (test.test_pkgutil.PkgutilTests) ... ok
    test_alreadyloaded (test.test_pkgutil.PkgutilPEP302Tests) ... ERROR
    test_getdata_pep302 (test.test_pkgutil.PkgutilPEP302Tests) ... ERROR
    test_mixed_namespace (test.test_pkgutil.ExtendPathTests) ... ERROR
    test_simple (test.test_pkgutil.ExtendPathTests) ... ERROR
    test_nested (test.test_pkgutil.NestedNamespacePackageTest) ... ok
    test_get_importer_avoids_emulation (test.test_pkgutil.ImportlibMigrationTests) ... ok
    test_get_loader_avoids_emulation (test.test_pkgutil.ImportlibMigrationTests) ... ok
    test_importer_deprecated (test.test_pkgutil.ImportlibMigrationTests) ... ok
    test_iter_importers_avoids_emulation (test.test_pkgutil.ImportlibMigrationTests) ... ok
    test_loader_deprecated (test.test_pkgutil.ImportlibMigrationTests) ... ok

    ======================================================================
    ERROR: test_alreadyloaded (test.test_pkgutil.PkgutilPEP302Tests)
    ----------------------------------------------------------------------

    Traceback (most recent call last):
      File "/home/buildbot/buildarea/3.x.coghlan-redhat/build/Lib/test/test_pkgutil.py", line 139, in test_alreadyloaded
        self.assertEqual(foo.loads, 1)
    AttributeError: 'module' object has no attribute 'loads'

    ======================================================================
    ERROR: test_getdata_pep302 (test.test_pkgutil.PkgutilPEP302Tests)
    ----------------------------------------------------------------------

    Traceback (most recent call last):
      File "/home/buildbot/buildarea/3.x.coghlan-redhat/build/Lib/pkgutil.py", line 502, in find_loader
        return importlib.find_loader(fullname, path)
      File "/home/buildbot/buildarea/3.x.coghlan-redhat/build/Lib/importlib/__init__.py", line 64, in find_loader
        loader = sys.modules[name].__loader__
    AttributeError: 'module' object has no attribute '__loader__'
    
    The above exception was the direct cause of the following exception:
    
    Traceback (most recent call last):
      File "/home/buildbot/buildarea/3.x.coghlan-redhat/build/Lib/test/test_pkgutil.py", line 131, in test_getdata_pep302
        self.assertEqual(pkgutil.get_data('foo', 'dummy'), "Hello, world!")
      File "/home/buildbot/buildarea/3.x.coghlan-redhat/build/Lib/pkgutil.py", line 625, in get_data
        loader = get_loader(package)
      File "/home/buildbot/buildarea/3.x.coghlan-redhat/build/Lib/pkgutil.py", line 480, in get_loader
        return find_loader(fullname)
      File "/home/buildbot/buildarea/3.x.coghlan-redhat/build/Lib/pkgutil.py", line 508, in find_loader
        raise ImportError(msg.format(fullname, type(ex), ex)) from ex
    ImportError: Error while finding loader for 'foo' (<class 'AttributeError'>: 'module' object has no attribute '__loader__')

    ======================================================================
    ERROR: test_mixed_namespace (test.test_pkgutil.ExtendPathTests)
    ----------------------------------------------------------------------

    Traceback (most recent call last):
      File "<frozen importlib._bootstrap>", line 1523, in _find_and_load_unlocked
    AttributeError: 'module' object has no attribute '__path__'
    
    During handling of the above exception, another exception occurred:
    
    Traceback (most recent call last):
      File "/home/buildbot/buildarea/3.x.coghlan-redhat/build/Lib/test/test_pkgutil.py", line 198, in test_mixed_namespace
        import foo.bar
    ImportError: No module named 'foo.bar'; foo is not a package

    ======================================================================
    ERROR: test_simple (test.test_pkgutil.ExtendPathTests)
    ----------------------------------------------------------------------

    Traceback (most recent call last):
      File "<frozen importlib._bootstrap>", line 1523, in _find_and_load_unlocked
    AttributeError: 'module' object has no attribute '__path__'
    
    During handling of the above exception, another exception occurred:
    
    Traceback (most recent call last):
      File "/home/buildbot/buildarea/3.x.coghlan-redhat/build/Lib/test/test_pkgutil.py", line 170, in test_simple
        import foo.bar
    ImportError: No module named 'foo.bar'; foo is not a package

    Ran 13 tests in 0.027s

    @vstinner vstinner reopened this Dec 14, 2012
    @pitrou
    Copy link
    Member

    pitrou commented Dec 15, 2012

    Indeed it looks like this commit may be the culprit for numerous buildbot failures.

    @pitrou
    Copy link
    Member

    pitrou commented Dec 15, 2012

    Naming the test modules "foo" and "bar" was perhaps not the best idea.

    @python-dev
    Copy link
    Mannequin

    python-dev mannequin commented Dec 15, 2012

    New changeset 2e492a9a1845 by Andrew Svetlov in branch 'default':
    Rename test module names for bpo-16421 to don't clash with other tests.
    http://hg.python.org/cpython/rev/2e492a9a1845

    @asvetlov
    Copy link
    Contributor

    Fixed.
    Antoine, you are right: foo and bar was bad names.

    @ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Labels
    extension-modules C modules in the Modules dir type-bug An unexpected behavior, bug, or error
    Projects
    None yet
    Development

    No branches or pull requests

    7 participants