diff --git a/src/pretix/base/plugins.py b/src/pretix/base/plugins.py index 41eed1b24c..79e6d23a9d 100644 --- a/src/pretix/base/plugins.py +++ b/src/pretix/base/plugins.py @@ -24,9 +24,11 @@ import sys from enum import Enum from typing import List +import importlib_metadata as metadata from django.apps import AppConfig, apps from django.conf import settings from django.core.exceptions import ImproperlyConfigured +from packaging.requirements import Requirement class PluginType(Enum): @@ -81,12 +83,11 @@ class PluginConfig(AppConfig, metaclass=PluginConfigMeta): raise ImproperlyConfigured("A pretix plugin config should have a PretixPluginMeta inner class.") if hasattr(self.PretixPluginMeta, 'compatibility') and not os.environ.get("PRETIX_IGNORE_CONFLICTS") == "True": - import pkg_resources - try: - pkg_resources.require(self.PretixPluginMeta.compatibility) - except pkg_resources.VersionConflict as e: + req = Requirement(self.PretixPluginMeta.compatibility) + requirement_version = metadata.version(req.name) + if not req.specifier.contains(requirement_version, prereleases=True): print("Incompatible plugins found!") print("Plugin {} requires you to have {}, but you installed {}.".format( - self.name, e.req, e.dist + self.name, req, requirement_version )) sys.exit(1) diff --git a/src/pretix/control/views/global_settings.py b/src/pretix/control/views/global_settings.py index c893234eb3..2db9ff60d6 100644 --- a/src/pretix/control/views/global_settings.py +++ b/src/pretix/control/views/global_settings.py @@ -31,8 +31,7 @@ # Unless required by applicable law or agreed to in writing, software distributed under the Apache License 2.0 is # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations under the License. - -import pkg_resources +import importlib_metadata as metadata from django.contrib import messages from django.http import JsonResponse from django.shortcuts import get_object_or_404, redirect, reverse @@ -132,14 +131,14 @@ class LicenseCheckView(StaffMemberRequiredMixin, FormView): if not d: d['source_notice'] = 'pretix (AGPLv3 with additional terms): https://github.com/pretix/pretix' seen = set() - for entry_point in pkg_resources.iter_entry_points(group='pretix.plugin', name=None): - if entry_point.dist.key not in seen: + for entry_point in metadata.entry_points(group='pretix.plugin'): + if entry_point.dist.name not in seen: try: - license, url = self._get_license_for_pkg(entry_point.dist.key) + license, url = self._get_license_for_pkg(entry_point.dist.name) except FileNotFoundError: license, url = '?', '?' - d['source_notice'] += f'\n{entry_point.dist.key} ({license}): {url}' - seen.add(entry_point.dist.key) + d['source_notice'] += f'\n{entry_point.dist.name} ({license}): {url}' + seen.add(entry_point.dist.name) return d @@ -168,17 +167,15 @@ class LicenseCheckView(StaffMemberRequiredMixin, FormView): def _get_license_for_pkg(self, pkg): license, url = None, None try: - pkg = pkg_resources.get_distribution(pkg) + pkg = metadata.distribution(pkg) except: return None, None try: - for line in pkg.get_metadata_lines(pkg.PKG_INFO): - if ': ' in line: - (k, v) = line.split(': ', 1) - if k == "License": - license = v - if k == "Home-page": - url = v + for k, v in pkg.metadata.items(): + if k == "License": + license = v + if k == "Home-page": + url = v except FileNotFoundError: license = '?' url = '?' @@ -232,14 +229,14 @@ class LicenseCheckView(StaffMemberRequiredMixin, FormView): 'restrictions). Make sure to keep it up to date!') )) - for entry_point in pkg_resources.iter_entry_points(group='pretix.plugin', name=None): - license, url = self._get_license_for_pkg(entry_point.dist.key) + for entry_point in metadata.entry_points(group='pretix.plugin'): + license, url = self._get_license_for_pkg(entry_point.dist.name) if not license or not any(l in license for l in ('Apache', 'MIT', 'BSD', 'pretix Enterprise', 'GPL')): res.append(( 'muted', 'warning', _('We found the plugin "{plugin}" with license "{license}" which this tool does not know about and ' - 'therefore cannot give any recommendations.').format(plugin=entry_point.dist.key, license=license) + 'therefore cannot give any recommendations.').format(plugin=entry_point.dist.name, license=license) )) continue @@ -247,21 +244,21 @@ class LicenseCheckView(StaffMemberRequiredMixin, FormView): res.append(( 'danger', 'exclamation-circle', _('You selected that you have no active pretix Enterprise licenses, but we found the following ' - 'Enterprise plugin: {plugin}').format(plugin=entry_point.dist.key) + 'Enterprise plugin: {plugin}').format(plugin=entry_point.dist.name) )) if not input.get('plugins_copyleft') and any(l in license for l in ('GPL',)): res.append(( 'danger', 'exclamation-circle', _('You selected that you have no copyleft-licensed plugins installed, but we found the ' - 'plugin "{plugin}" with license "{license}".').format(plugin=entry_point.dist.key, license=license) + 'plugin "{plugin}" with license "{license}".').format(plugin=entry_point.dist.name, license=license) )) if not input.get('plugins_free') and any(l in license for l in ('Apache', 'MIT', 'BSD')): res.append(( 'danger', 'exclamation-circle', _('You selected that you have no free plugins installed, but we found the ' - 'plugin "{plugin}" with license "{license}".').format(plugin=entry_point.dist.key, license=license) + 'plugin "{plugin}" with license "{license}".').format(plugin=entry_point.dist.name, license=license) )) return res diff --git a/src/pretix/settings.py b/src/pretix/settings.py index 6b76ec5878..bd907e697c 100644 --- a/src/pretix/settings.py +++ b/src/pretix/settings.py @@ -41,9 +41,9 @@ from urllib.parse import urlparse from json import loads import django.conf.locale +import importlib_metadata as metadata from django.utils.crypto import get_random_string from kombu import Queue -from pkg_resources import iter_entry_points from pycountry import currencies from . import __version__ @@ -401,11 +401,11 @@ except ImportError: pass PLUGINS = [] -for entry_point in iter_entry_points(group='pretix.plugin', name=None): - if entry_point.module_name in PRETIX_PLUGINS_EXCLUDE: +for entry_point in metadata.entry_points(group='pretix.plugin'): + if entry_point.module in PRETIX_PLUGINS_EXCLUDE: continue - PLUGINS.append(entry_point.module_name) - INSTALLED_APPS.append(entry_point.module_name) + PLUGINS.append(entry_point.module) + INSTALLED_APPS.append(entry_point.module) HIJACK_PERMISSION_CHECK = "hijack.permissions.superusers_and_staff" HIJACK_INSERT_BEFORE = None diff --git a/src/setup.py b/src/setup.py index abcaf2934f..a1c4c214ae 100644 --- a/src/setup.py +++ b/src/setup.py @@ -192,6 +192,7 @@ setup( 'dnspython==2.2.*', 'drf_ujson2==1.7.*', 'geoip2==4.*', + 'importlib-metadata==6.4.*', # Polyfill, we can probably drop this once we require Python 3.10+ 'isoweek', 'jsonschema', 'kombu==5.2.*',