diff --git a/newsfragments/4262.feature.rst b/newsfragments/4262.feature.rst new file mode 100644 index 0000000000..7bbdba87d2 --- /dev/null +++ b/newsfragments/4262.feature.rst @@ -0,0 +1,3 @@ +Improved `AttributeError` error message if ``pkg_resources.EntryPoint.require`` is called without extras or distribution +Gracefully "do nothing" when trying to activate a ``pkg_resources.Distribution`` with a `None` location, rather than raising a `TypeError` +-- by :user:`Avasam` diff --git a/pkg_resources/__init__.py b/pkg_resources/__init__.py index 675b728f9d..d32b095a88 100644 --- a/pkg_resources/__init__.py +++ b/pkg_resources/__init__.py @@ -920,10 +920,10 @@ def find_plugins(self, plugin_env, full_env=None, installer=None, fallback=True) # success, no need to try any more versions of this project break - distributions = list(distributions) - distributions.sort() + sorted_distributions = list(distributions) + sorted_distributions.sort() - return distributions, error_info + return sorted_distributions, error_info def require(self, *requirements): """Ensure that distributions matching `requirements` are activated @@ -1635,7 +1635,7 @@ def _validate_resource_path(path): ) def _get(self, path) -> bytes: - if hasattr(self.loader, 'get_data'): + if hasattr(self.loader, 'get_data') and self.loader: return self.loader.get_data(path) raise NotImplementedError( "Can't perform this operation for loaders without 'get_data()'" @@ -2490,8 +2490,9 @@ def resolve(self): raise ImportError(str(exc)) from exc def require(self, env=None, installer=None): - if self.extras and not self.dist: - raise UnknownExtra("Can't require() without a distribution", self) + if not self.dist: + error_cls = UnknownExtra if self.extras else AttributeError + raise error_cls("Can't require() without a distribution", self) # Get the requirements for this entry point with all its extras and # then resolve them. We have to pass `extras` along when resolving so @@ -2557,11 +2558,11 @@ def parse_group(cls, group, lines, dist=None): def parse_map(cls, data, dist=None): """Parse a map of entry point groups""" if isinstance(data, dict): - data = data.items() + _data = data.items() else: - data = split_sections(data) + _data = split_sections(data) maps = {} - for group, lines in data: + for group, lines in _data: if group is None: if not lines: continue @@ -2823,7 +2824,7 @@ def activate(self, path=None, replace=False): if path is None: path = sys.path self.insert_on(path, replace=replace) - if path is sys.path: + if path is sys.path and self.location is not None: fixup_namespace_packages(self.location) for pkg in self._get_metadata('namespace_packages.txt'): if pkg in sys.modules: @@ -2891,15 +2892,13 @@ def load_entry_point(self, group, name): def get_entry_map(self, group=None): """Return the entry point map for `group`, or the full entry map""" - try: - ep_map = self._ep_map - except AttributeError: - ep_map = self._ep_map = EntryPoint.parse_map( + if not hasattr(self, "_ep_map"): + self._ep_map = EntryPoint.parse_map( self._get_metadata('entry_points.txt'), self ) if group is not None: - return ep_map.get(group, {}) - return ep_map + return self._ep_map.get(group, {}) + return self._ep_map def get_entry_info(self, group, name): """Return the EntryPoint object for `group`+`name`, or ``None``"""