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

Use modern Python import features for product enumeration #1240

Merged
merged 3 commits into from
Nov 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ https://github.com/zopefoundation/Zope/blob/4.x/CHANGES.rst
in ``constraints.txt``.
(`#1234 <https://github.com/zopefoundation/Zope/pull/1234>`_)

- Use modern Python import features for product enumeration
(`#1239 <https://github.com/zopefoundation/Zope/issues/1239>`_).


5.11.1 (2024-11-03)
-------------------
Expand Down
54 changes: 15 additions & 39 deletions src/OFS/Application.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"""Application support
"""

import os
import pkgutil
import sys
from logging import getLogger
from urllib.parse import urlparse
Expand Down Expand Up @@ -378,15 +378,15 @@ def install_products(app=None):
folder_permissions = get_folder_permissions()
meta_types = []
done = {}
for priority, product_name, index, product_dir in get_products():
for priority, product_name, index, finder in get_products():
# For each product, we will import it and try to call the
# intialize() method in the product __init__ module. If
# the method doesnt exist, we put the old-style information
# together and do a default initialization.
if product_name in done:
continue
done[product_name] = 1
install_product(app, product_dir, product_name, meta_types,
install_product(app, finder, product_name, meta_types,
folder_permissions)

# Delayed install of packages-as-products
Expand All @@ -397,55 +397,34 @@ def install_products(app=None):
InitializeClass(Folder.Folder)


def _is_package(product_dir, product_name):
package_dir = os.path.join(product_dir, product_name)
if not os.path.isdir(package_dir):
return False

init_py = os.path.join(package_dir, '__init__.py')
if not os.path.exists(init_py) and \
not os.path.exists(init_py + 'c') and \
not os.path.exists(init_py + 'o'):
return False
return True


def get_products():
""" Return a list of tuples in the form:
[(priority, dir_name, index, base_dir), ...] for each Product directory
[(priority, product_name, index, finder), ...] for each Product directory
found, sort before returning """
products = []
for index, product_dir in enumerate(Products.__path__):
product_names = os.listdir(product_dir)
for product_name in product_names:
if _is_package(product_dir, product_name):
# i is used as sort ordering in case a conflict exists
# between Product names. Products will be found as
# per the ordering of Products.__path__
products.append((0, product_name, index, product_dir))
for index, modinfo in enumerate(pkgutil.iter_modules(Products.__path__)):
if modinfo.ispkg:
products.append((0, modinfo.name, index, modinfo.module_finder))
products.sort()
return products


def import_products():
done = {}
for priority, product_name, index, product_dir in get_products():
for priority, product_name, index, finder in get_products():
if product_name in done:
LOG.warning(
'Duplicate Product name: '
'After loading Product %r from %r, '
'I skipped the one in %r.' % (
product_name, done[product_name], product_dir))
'After loading Product %s from %s, '
'I skipped the one in %s.' % (
product_name, done[product_name], finder))
continue
done[product_name] = product_dir
import_product(product_dir, product_name)
done[product_name] = finder
import_product(finder, product_name)
return list(done.keys())


def import_product(product_dir, product_name, raise_exc=None):
if not _is_package(product_dir, product_name):
return

def import_product(finder, product_name, raise_exc=None):
global_dict = globals()
product = __import__("Products.%s" % product_name,
global_dict, global_dict, ('__doc__', ))
Expand All @@ -465,11 +444,8 @@ def get_folder_permissions():
return folder_permissions


def install_product(app, product_dir, product_name, meta_types,
def install_product(app, finder, product_name, meta_types,
folder_permissions, raise_exc=None):
if not _is_package(product_dir, product_name):
return

__traceback_info__ = product_name
global_dict = globals()
product = __import__("Products.%s" % product_name,
Expand Down
Loading