mirror of
https://git.yoctoproject.org/poky
synced 2026-02-05 16:28:43 +01:00
Changelog: https://docs.python.org/3/whatsnew/changelog.html#python-3-13-6-final Handles CVE-2025-8194 and 4 other vulnerabilities without CVE numbers. Refresh patches via devtool. (From OE-Core rev: 55b31ad3cf221dc07ef0ef1bc50c02f7c2e628ef) Signed-off-by: Peter Marko <peter.marko@siemens.com> Signed-off-by: Mathieu Dubois-Briand <mathieu.dubois-briand@bootlin.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
165 lines
5.9 KiB
Diff
165 lines
5.9 KiB
Diff
From a65c29adc027b3615154cab73aaedd58a6aa23da Mon Sep 17 00:00:00 2001
|
|
From: "Jason R. Coombs" <jaraco@jaraco.com>
|
|
Date: Tue, 23 Jul 2024 08:36:16 -0400
|
|
Subject: [PATCH] Prioritize valid dists to invalid dists when retrieving by
|
|
name.
|
|
|
|
Closes python/importlib_metadata#489
|
|
|
|
Upstream-Status: Backport [https://github.com/python/importlib_metadata/commit/a65c29adc027b3615154cab73aaedd58a6aa23da]
|
|
Signed-off-by: Ross Burton <ross.burton@arm.com>
|
|
---
|
|
Lib/importlib/metadata/__init__.py | 14 +++-
|
|
Lib/importlib/metadata/_itertools.py | 98 ++++++++++++++++++++++++++++
|
|
2 files changed, 110 insertions(+), 2 deletions(-)
|
|
|
|
diff --git a/Lib/importlib/metadata/__init__.py b/Lib/importlib/metadata/__init__.py
|
|
index 8ce62dd..085378c 100644
|
|
--- a/Lib/importlib/metadata/__init__.py
|
|
+++ b/Lib/importlib/metadata/__init__.py
|
|
@@ -21,7 +21,7 @@ import collections
|
|
from . import _meta
|
|
from ._collections import FreezableDefaultDict, Pair
|
|
from ._functools import method_cache, pass_none
|
|
-from ._itertools import always_iterable, unique_everseen
|
|
+from ._itertools import always_iterable, bucket, unique_everseen
|
|
from ._meta import PackageMetadata, SimplePath
|
|
|
|
from contextlib import suppress
|
|
@@ -404,7 +404,7 @@ class Distribution(DeprecatedNonAbstract):
|
|
if not name:
|
|
raise ValueError("A distribution name is required.")
|
|
try:
|
|
- return next(iter(cls.discover(name=name)))
|
|
+ return next(iter(cls._prefer_valid(cls.discover(name=name))))
|
|
except StopIteration:
|
|
raise PackageNotFoundError(name)
|
|
|
|
@@ -428,6 +428,16 @@ class Distribution(DeprecatedNonAbstract):
|
|
resolver(context) for resolver in cls._discover_resolvers()
|
|
)
|
|
|
|
+ @staticmethod
|
|
+ def _prefer_valid(dists: Iterable[Distribution]) -> Iterable[Distribution]:
|
|
+ """
|
|
+ Prefer (move to the front) distributions that have metadata.
|
|
+
|
|
+ Ref python/importlib_resources#489.
|
|
+ """
|
|
+ buckets = bucket(dists, lambda dist: bool(dist.metadata))
|
|
+ return itertools.chain(buckets[True], buckets[False])
|
|
+
|
|
@staticmethod
|
|
def at(path: str | os.PathLike[str]) -> Distribution:
|
|
"""Return a Distribution for the indicated metadata path.
|
|
diff --git a/Lib/importlib/metadata/_itertools.py b/Lib/importlib/metadata/_itertools.py
|
|
index d4ca9b9..79d3719 100644
|
|
--- a/Lib/importlib/metadata/_itertools.py
|
|
+++ b/Lib/importlib/metadata/_itertools.py
|
|
@@ -1,3 +1,4 @@
|
|
+from collections import defaultdict, deque
|
|
from itertools import filterfalse
|
|
|
|
|
|
@@ -71,3 +72,100 @@ def always_iterable(obj, base_type=(str, bytes)):
|
|
return iter(obj)
|
|
except TypeError:
|
|
return iter((obj,))
|
|
+
|
|
+
|
|
+# Copied from more_itertools 10.3
|
|
+class bucket:
|
|
+ """Wrap *iterable* and return an object that buckets the iterable into
|
|
+ child iterables based on a *key* function.
|
|
+
|
|
+ >>> iterable = ['a1', 'b1', 'c1', 'a2', 'b2', 'c2', 'b3']
|
|
+ >>> s = bucket(iterable, key=lambda x: x[0]) # Bucket by 1st character
|
|
+ >>> sorted(list(s)) # Get the keys
|
|
+ ['a', 'b', 'c']
|
|
+ >>> a_iterable = s['a']
|
|
+ >>> next(a_iterable)
|
|
+ 'a1'
|
|
+ >>> next(a_iterable)
|
|
+ 'a2'
|
|
+ >>> list(s['b'])
|
|
+ ['b1', 'b2', 'b3']
|
|
+
|
|
+ The original iterable will be advanced and its items will be cached until
|
|
+ they are used by the child iterables. This may require significant storage.
|
|
+
|
|
+ By default, attempting to select a bucket to which no items belong will
|
|
+ exhaust the iterable and cache all values.
|
|
+ If you specify a *validator* function, selected buckets will instead be
|
|
+ checked against it.
|
|
+
|
|
+ >>> from itertools import count
|
|
+ >>> it = count(1, 2) # Infinite sequence of odd numbers
|
|
+ >>> key = lambda x: x % 10 # Bucket by last digit
|
|
+ >>> validator = lambda x: x in {1, 3, 5, 7, 9} # Odd digits only
|
|
+ >>> s = bucket(it, key=key, validator=validator)
|
|
+ >>> 2 in s
|
|
+ False
|
|
+ >>> list(s[2])
|
|
+ []
|
|
+
|
|
+ """
|
|
+
|
|
+ def __init__(self, iterable, key, validator=None):
|
|
+ self._it = iter(iterable)
|
|
+ self._key = key
|
|
+ self._cache = defaultdict(deque)
|
|
+ self._validator = validator or (lambda x: True)
|
|
+
|
|
+ def __contains__(self, value):
|
|
+ if not self._validator(value):
|
|
+ return False
|
|
+
|
|
+ try:
|
|
+ item = next(self[value])
|
|
+ except StopIteration:
|
|
+ return False
|
|
+ else:
|
|
+ self._cache[value].appendleft(item)
|
|
+
|
|
+ return True
|
|
+
|
|
+ def _get_values(self, value):
|
|
+ """
|
|
+ Helper to yield items from the parent iterator that match *value*.
|
|
+ Items that don't match are stored in the local cache as they
|
|
+ are encountered.
|
|
+ """
|
|
+ while True:
|
|
+ # If we've cached some items that match the target value, emit
|
|
+ # the first one and evict it from the cache.
|
|
+ if self._cache[value]:
|
|
+ yield self._cache[value].popleft()
|
|
+ # Otherwise we need to advance the parent iterator to search for
|
|
+ # a matching item, caching the rest.
|
|
+ else:
|
|
+ while True:
|
|
+ try:
|
|
+ item = next(self._it)
|
|
+ except StopIteration:
|
|
+ return
|
|
+ item_value = self._key(item)
|
|
+ if item_value == value:
|
|
+ yield item
|
|
+ break
|
|
+ elif self._validator(item_value):
|
|
+ self._cache[item_value].append(item)
|
|
+
|
|
+ def __iter__(self):
|
|
+ for item in self._it:
|
|
+ item_value = self._key(item)
|
|
+ if self._validator(item_value):
|
|
+ self._cache[item_value].append(item)
|
|
+
|
|
+ yield from self._cache.keys()
|
|
+
|
|
+ def __getitem__(self, value):
|
|
+ if not self._validator(value):
|
|
+ return iter(())
|
|
+
|
|
+ return self._get_values(value)
|