summaryrefslogtreecommitdiffstats
path: root/contrib/python
diff options
context:
space:
mode:
authorAlexander Smirnov <[email protected]>2025-07-22 16:16:01 +0000
committerAlexander Smirnov <[email protected]>2025-07-22 16:16:01 +0000
commit6bf496db7343a23f405f67a79b4198e06fdd7f42 (patch)
treeebbfbb677ebb39843c45be8a5c37d5f9066fc0ee /contrib/python
parent81c6c7f73ad64139f8cbb947130d639554d3bc79 (diff)
parent3102e1630f400423c5b7b71a1d9254680d6d9731 (diff)
Merge branch 'rightlib' into merge-libs-250722-1614
Diffstat (limited to 'contrib/python')
-rw-r--r--contrib/python/fonttools/.dist-info/METADATA9
-rw-r--r--contrib/python/fonttools/fontTools/__init__.py2
-rw-r--r--contrib/python/fonttools/fontTools/feaLib/ast.py3
-rw-r--r--contrib/python/fonttools/fontTools/feaLib/builder.py5
-rw-r--r--contrib/python/fonttools/fontTools/misc/visitor.py8
-rw-r--r--contrib/python/fonttools/fontTools/otlLib/builder.py30
-rw-r--r--contrib/python/fonttools/fontTools/varLib/instancer/__init__.py58
-rw-r--r--contrib/python/fonttools/ya.make2
-rw-r--r--contrib/python/future/py3/future/backports/email/message.py41
-rw-r--r--contrib/python/future/py3/future/backports/email/mime/audio.py80
-rw-r--r--contrib/python/future/py3/future/backports/email/mime/image.py113
-rw-r--r--contrib/python/future/py3/patches/07-support-python-3.13.patch65
-rw-r--r--contrib/python/future/py3/patches/08-support-python-3.13.patch103
-rw-r--r--contrib/python/future/py3/patches/09-support-python-3.13.patch131
-rw-r--r--contrib/python/moto/py3/moto/s3/responses.py5
-rw-r--r--contrib/python/moto/py3/patches/03-arcadia.patch14
-rw-r--r--contrib/python/scramp/.dist-info/METADATA9
-rw-r--r--contrib/python/scramp/README.md5
-rw-r--r--contrib/python/scramp/scramp/__init__.py2
-rw-r--r--contrib/python/scramp/ya.make2
-rw-r--r--contrib/python/types-protobuf/.dist-info/METADATA6
-rw-r--r--contrib/python/types-protobuf/README.md4
-rw-r--r--contrib/python/types-protobuf/google-stubs/protobuf/internal/containers.pyi8
-rw-r--r--contrib/python/types-protobuf/ya.make2
24 files changed, 609 insertions, 98 deletions
diff --git a/contrib/python/fonttools/.dist-info/METADATA b/contrib/python/fonttools/.dist-info/METADATA
index ddc8be2d7de..164ca311dc3 100644
--- a/contrib/python/fonttools/.dist-info/METADATA
+++ b/contrib/python/fonttools/.dist-info/METADATA
@@ -1,6 +1,6 @@
Metadata-Version: 2.4
Name: fonttools
-Version: 4.58.4
+Version: 4.58.5
Summary: Tools to manipulate font files
Home-page: http://github.com/fonttools/fonttools
Author: Just van Rossum
@@ -388,6 +388,13 @@ Have fun!
Changelog
~~~~~~~~~
+4.58.5 (released 2025-07-03)
+----------------------------
+
+- [feaLib] Don't try to combine ligature & multisub rules (#3874).
+- [feaLib/ast] Use weakref proxies to avoid cycles in visitor (#3873).
+- [varLib.instancer] Fixed instancing CFF2 fonts where VarData contains more than 64k items (#3858).
+
4.58.4 (released 2025-06-13)
----------------------------
diff --git a/contrib/python/fonttools/fontTools/__init__.py b/contrib/python/fonttools/fontTools/__init__.py
index 155d9250220..306cd68a6be 100644
--- a/contrib/python/fonttools/fontTools/__init__.py
+++ b/contrib/python/fonttools/fontTools/__init__.py
@@ -3,6 +3,6 @@ from fontTools.misc.loggingTools import configLogger
log = logging.getLogger(__name__)
-version = __version__ = "4.58.4"
+version = __version__ = "4.58.5"
__all__ = ["version", "log", "configLogger"]
diff --git a/contrib/python/fonttools/fontTools/feaLib/ast.py b/contrib/python/fonttools/fontTools/feaLib/ast.py
index 9663f73b4c8..2624e6b9d6d 100644
--- a/contrib/python/fonttools/fontTools/feaLib/ast.py
+++ b/contrib/python/fonttools/fontTools/feaLib/ast.py
@@ -1,3 +1,4 @@
+import weakref
from fontTools.feaLib.error import FeatureLibError
from fontTools.feaLib.location import FeatureLibLocation
from fontTools.misc.encodingTools import getEncoding
@@ -529,7 +530,7 @@ class MarkClass(object):
def addDefinition(self, definition):
"""Add a :class:`MarkClassDefinition` statement to this mark class."""
assert isinstance(definition, MarkClassDefinition)
- self.definitions.append(definition)
+ self.definitions.append(weakref.proxy(definition))
for glyph in definition.glyphSet():
if glyph in self.glyphs:
otherLoc = self.glyphs[glyph].location
diff --git a/contrib/python/fonttools/fontTools/feaLib/builder.py b/contrib/python/fonttools/fontTools/feaLib/builder.py
index ce9515bd68d..25b319c0b01 100644
--- a/contrib/python/fonttools/fontTools/feaLib/builder.py
+++ b/contrib/python/fonttools/fontTools/feaLib/builder.py
@@ -259,12 +259,13 @@ class Builder(object):
key = (script, lang, feature_name)
self.features_.setdefault(key, []).append(lookup)
- def get_lookup_(self, location, builder_class):
+ def get_lookup_(self, location, builder_class, mapping=None):
if (
self.cur_lookup_
and type(self.cur_lookup_) == builder_class
and self.cur_lookup_.lookupflag == self.lookupflag_
and self.cur_lookup_.markFilterSet == self.lookupflag_markFilterSet_
+ and self.cur_lookup_.can_add_mapping(mapping)
):
return self.cur_lookup_
if self.cur_lookup_name_ and self.cur_lookup_:
@@ -1305,7 +1306,7 @@ class Builder(object):
# GSUB rules
def add_any_subst_(self, location, mapping):
- lookup = self.get_lookup_(location, AnySubstBuilder)
+ lookup = self.get_lookup_(location, AnySubstBuilder, mapping=mapping)
for key, value in mapping.items():
if key in lookup.mapping:
if value == lookup.mapping[key]:
diff --git a/contrib/python/fonttools/fontTools/misc/visitor.py b/contrib/python/fonttools/fontTools/misc/visitor.py
index 6de432ef934..65f305632de 100644
--- a/contrib/python/fonttools/fontTools/misc/visitor.py
+++ b/contrib/python/fonttools/fontTools/misc/visitor.py
@@ -1,11 +1,19 @@
"""Generic visitor pattern implementation for Python objects."""
import enum
+import weakref
class Visitor(object):
defaultStop = False
+ _visitors = {
+ # By default we skip visiting weak references to avoid recursion
+ # issues. Users can override this by registering a visit
+ # function for weakref.ProxyType.
+ weakref.ProxyType: {None: lambda self, obj, *args, **kwargs: False}
+ }
+
@classmethod
def _register(celf, clazzes_attrs):
assert celf != Visitor, "Subclass Visitor instead."
diff --git a/contrib/python/fonttools/fontTools/otlLib/builder.py b/contrib/python/fonttools/fontTools/otlLib/builder.py
index da00e9c5ebd..c4b482f02b4 100644
--- a/contrib/python/fonttools/fontTools/otlLib/builder.py
+++ b/contrib/python/fonttools/fontTools/otlLib/builder.py
@@ -256,6 +256,10 @@ class LookupBuilder(object):
)
)
+ def can_add_mapping(self, _mapping) -> bool:
+ # used by AnySubstBuilder, below
+ return True
+
class AlternateSubstBuilder(LookupBuilder):
"""Builds an Alternate Substitution (GSUB3) lookup.
@@ -1376,6 +1380,32 @@ class AnySubstBuilder(LookupBuilder):
def _add_to_ligature_subst(self, builder, key, value):
builder.ligatures[key] = value[0]
+ def can_add_mapping(self, mapping) -> bool:
+ if mapping is None:
+ return True
+ # single sub rules can be treated as (degenerate) liga-or-multi sub
+ # rules, but multi and liga sub rules themselves have incompatible
+ # representations. It is uncommon that these are in the same set of
+ # rules, but it happens.
+ is_multi = any(len(v) > 1 for v in mapping.values())
+ is_liga = any(len(k) > 1 for k in mapping.keys())
+
+ has_existing_multi = False
+ has_existing_liga = False
+
+ for k, v in self.mapping.items():
+ if k[0] == self.SUBTABLE_BREAK_:
+ continue
+ if len(k) > 1:
+ has_existing_liga = True
+ if len(v) > 1:
+ has_existing_multi = True
+
+ can_reuse = not (has_existing_multi and is_liga) and not (
+ has_existing_liga and is_multi
+ )
+ return can_reuse
+
def promote_lookup_type(self, is_named_lookup):
# https://github.com/fonttools/fonttools/issues/612
# A multiple substitution may have a single destination, in which case
diff --git a/contrib/python/fonttools/fontTools/varLib/instancer/__init__.py b/contrib/python/fonttools/fontTools/varLib/instancer/__init__.py
index a0b832a3c18..76901880553 100644
--- a/contrib/python/fonttools/fontTools/varLib/instancer/__init__.py
+++ b/contrib/python/fonttools/fontTools/varLib/instancer/__init__.py
@@ -723,9 +723,7 @@ def instantiateCFF2(
minor = varDataCursor[major]
varDataCursor[major] += 1
- varIdx = (major << 16) + minor
-
- defaultValue += round(defaultDeltas[varIdx])
+ defaultValue += round(defaultDeltas[major][minor])
newDefaults.append(defaultValue)
varData = varStore.VarData[major]
@@ -781,7 +779,9 @@ def instantiateCFF2(
storeBlendsToVarStore(value + [count])
# Instantiate VarStore
- defaultDeltas = instantiateItemVariationStore(varStore, fvarAxes, axisLimits)
+ defaultDeltas = instantiateItemVariationStore(
+ varStore, fvarAxes, axisLimits, hierarchical=True
+ )
# Read back new charstring blends from the instantiated VarStore
varDataCursor = [0] * len(varStore.VarData)
@@ -839,18 +839,13 @@ def instantiateCFF2(
varData.Item = []
varData.ItemCount = 0
- # Remove vsindex commands that are no longer needed, collect those that are.
- usedVsindex = set()
- for commands in allCommands:
- if any(isinstance(arg, list) for command in commands for arg in command[1]):
- vsindex = 0
- for command in commands:
- if command[0] == "vsindex":
- vsindex = command[1][0]
- continue
- if any(isinstance(arg, list) for arg in command[1]):
- usedVsindex.add(vsindex)
- else:
+ # Collect surviving vsindexes
+ usedVsindex = set(
+ i for i in range(len(varStore.VarData)) if varStore.VarData[i].VarRegionCount
+ )
+ # Remove vsindex commands that are no longer needed
+ for commands, private in zip(allCommands, allCommandPrivates):
+ if not any(isinstance(arg, list) for command in commands for arg in command[1]):
commands[:] = [command for command in commands if command[0] != "vsindex"]
# Remove unused VarData and update vsindex values
@@ -863,10 +858,14 @@ def instantiateCFF2(
for command in commands:
if command[0] == "vsindex":
command[1][0] = vsindexMapping[command[1][0]]
+ for private in privateDicts:
+ if hasattr(private, "vsindex"):
+ private.vsindex = vsindexMapping[private.vsindex]
# Remove initial vsindex commands that are implied
- for commands in allCommands:
- if commands and commands[0] == ("vsindex", [0]):
+ for commands, private in zip(allCommands, allCommandPrivates):
+ vsindex = getattr(private, "vsindex", 0)
+ if commands and commands[0] == ("vsindex", [vsindex]):
commands.pop(0)
# Ship the charstrings!
@@ -1247,7 +1246,9 @@ class _TupleVarStoreAdapter(object):
return itemVarStore
-def instantiateItemVariationStore(itemVarStore, fvarAxes, axisLimits):
+def instantiateItemVariationStore(
+ itemVarStore, fvarAxes, axisLimits, hierarchical=False
+):
"""Compute deltas at partial location, and update varStore in-place.
Remove regions in which all axes were instanced, or fall outside the new axis
@@ -1279,12 +1280,19 @@ def instantiateItemVariationStore(itemVarStore, fvarAxes, axisLimits):
assert itemVarStore.VarDataCount == newItemVarStore.VarDataCount
itemVarStore.VarData = newItemVarStore.VarData
- defaultDeltas = {
- ((major << 16) + minor): delta
- for major, deltas in enumerate(defaultDeltaArray)
- for minor, delta in enumerate(deltas)
- }
- defaultDeltas[itemVarStore.NO_VARIATION_INDEX] = 0
+ if not hierarchical:
+ defaultDeltas = {
+ ((major << 16) + minor): delta
+ for major, deltas in enumerate(defaultDeltaArray)
+ for minor, delta in enumerate(deltas)
+ }
+ defaultDeltas[itemVarStore.NO_VARIATION_INDEX] = 0
+ else:
+ defaultDeltas = {0xFFFF: {0xFFFF: 0}} # NO_VARIATION_INDEX
+ for major, deltas in enumerate(defaultDeltaArray):
+ defaultDeltasForMajor = defaultDeltas.setdefault(major, {})
+ for minor, delta in enumerate(deltas):
+ defaultDeltasForMajor[minor] = delta
return defaultDeltas
diff --git a/contrib/python/fonttools/ya.make b/contrib/python/fonttools/ya.make
index f2a7b5ccf30..e114871a154 100644
--- a/contrib/python/fonttools/ya.make
+++ b/contrib/python/fonttools/ya.make
@@ -2,7 +2,7 @@
PY3_LIBRARY()
-VERSION(4.58.4)
+VERSION(4.58.5)
LICENSE(MIT)
diff --git a/contrib/python/future/py3/future/backports/email/message.py b/contrib/python/future/py3/future/backports/email/message.py
index d8d9615d7d7..8b4a974944b 100644
--- a/contrib/python/future/py3/future/backports/email/message.py
+++ b/contrib/python/future/py3/future/backports/email/message.py
@@ -10,7 +10,6 @@ from future.builtins import list, range, str, zip
__all__ = ['Message']
import re
-import uu
import base64
import binascii
from io import BytesIO, StringIO
@@ -106,6 +105,37 @@ def _unquotevalue(value):
return utils.unquote(value)
+def _decode_uu(encoded):
+ """Decode uuencoded data."""
+ decoded_lines = []
+ encoded_lines_iter = iter(encoded.splitlines())
+ for line in encoded_lines_iter:
+ if line.startswith(b"begin "):
+ mode, _, path = line.removeprefix(b"begin ").partition(b" ")
+ try:
+ int(mode, base=8)
+ except ValueError:
+ continue
+ else:
+ break
+ else:
+ raise ValueError("`begin` line not found")
+ for line in encoded_lines_iter:
+ if not line:
+ raise ValueError("Truncated input")
+ elif line.strip(b' \t\r\n\f') == b'end':
+ break
+ try:
+ decoded_line = binascii.a2b_uu(line)
+ except binascii.Error:
+ # Workaround for broken uuencoders by /Fredrik Lundh
+ nbytes = (((line[0]-32) & 63) * 4 + 5) // 3
+ decoded_line = binascii.a2b_uu(line[:nbytes])
+ decoded_lines.append(decoded_line)
+
+ return b''.join(decoded_lines)
+
+
class Message(object):
"""Basic message object.
@@ -262,13 +292,10 @@ class Message(object):
self.policy.handle_defect(self, defect)
return value
elif cte in ('x-uuencode', 'uuencode', 'uue', 'x-uue'):
- in_file = BytesIO(bpayload)
- out_file = BytesIO()
try:
- uu.decode(in_file, out_file, quiet=True)
- return out_file.getvalue()
- except uu.Error:
- # Some decoding problem
+ return _decode_uu(bpayload)
+ except ValueError:
+ # Some decoding problem.
return bpayload
if isinstance(payload, str):
return bpayload
diff --git a/contrib/python/future/py3/future/backports/email/mime/audio.py b/contrib/python/future/py3/future/backports/email/mime/audio.py
index 4989c114207..0cd703fdc31 100644
--- a/contrib/python/future/py3/future/backports/email/mime/audio.py
+++ b/contrib/python/future/py3/future/backports/email/mime/audio.py
@@ -9,37 +9,11 @@ from __future__ import absolute_import
__all__ = ['MIMEAudio']
-import sndhdr
-
from io import BytesIO
from future.backports.email import encoders
from future.backports.email.mime.nonmultipart import MIMENonMultipart
-_sndhdr_MIMEmap = {'au' : 'basic',
- 'wav' :'x-wav',
- 'aiff':'x-aiff',
- 'aifc':'x-aiff',
- }
-
-# There are others in sndhdr that don't have MIME types. :(
-# Additional ones to be added to sndhdr? midi, mp3, realaudio, wma??
-def _whatsnd(data):
- """Try to identify a sound file type.
-
- sndhdr.what() has a pretty cruddy interface, unfortunately. This is why
- we re-do it here. It would be easier to reverse engineer the Unix 'file'
- command and use the standard 'magic' file, as shipped with a modern Unix.
- """
- hdr = data[:512]
- fakefile = BytesIO(hdr)
- for testfn in sndhdr.tests:
- res = testfn(hdr, fakefile)
- if res is not None:
- return _sndhdr_MIMEmap.get(res[0])
- return None
-
-
class MIMEAudio(MIMENonMultipart):
"""Class for generating audio/* MIME documents."""
@@ -66,9 +40,61 @@ class MIMEAudio(MIMENonMultipart):
header.
"""
if _subtype is None:
- _subtype = _whatsnd(_audiodata)
+ _subtype = _what(_audiodata)
if _subtype is None:
raise TypeError('Could not find audio MIME subtype')
MIMENonMultipart.__init__(self, 'audio', _subtype, **_params)
self.set_payload(_audiodata)
_encoder(self)
+
+
+_rules = []
+
+
+# Originally from the sndhdr module.
+#
+# There are others in sndhdr that don't have MIME types. :(
+# Additional ones to be added to sndhdr? midi, mp3, realaudio, wma??
+def _what(data):
+ # Try to identify a sound file type.
+ #
+ # sndhdr.what() had a pretty cruddy interface, unfortunately. This is why
+ # we re-do it here. It would be easier to reverse engineer the Unix 'file'
+ # command and use the standard 'magic' file, as shipped with a modern Unix.
+ for testfn in _rules:
+ if res := testfn(data):
+ return res
+ else:
+ return None
+
+
+def rule(rulefunc):
+ _rules.append(rulefunc)
+ return rulefunc
+
+
+@rule
+def _aiff(h):
+ if not h.startswith(b'FORM'):
+ return None
+ if h[8:12] in {b'AIFC', b'AIFF'}:
+ return 'x-aiff'
+ else:
+ return None
+
+
+@rule
+def _au(h):
+ if h.startswith(b'.snd'):
+ return 'basic'
+ else:
+ return None
+
+
+@rule
+def _wav(h):
+ # 'RIFF' <len> 'WAVE' 'fmt ' <len>
+ if not h.startswith(b'RIFF') or h[8:12] != b'WAVE' or h[12:16] != b'fmt ':
+ return None
+ else:
+ return "x-wav"
diff --git a/contrib/python/future/py3/future/backports/email/mime/image.py b/contrib/python/future/py3/future/backports/email/mime/image.py
index a03602464aa..b8fa87930f0 100644
--- a/contrib/python/future/py3/future/backports/email/mime/image.py
+++ b/contrib/python/future/py3/future/backports/email/mime/image.py
@@ -9,8 +9,6 @@ from __future__ import absolute_import
__all__ = ['MIMEImage']
-import imghdr
-
from future.backports.email import encoders
from future.backports.email.mime.nonmultipart import MIMENonMultipart
@@ -40,9 +38,118 @@ class MIMEImage(MIMENonMultipart):
header.
"""
if _subtype is None:
- _subtype = imghdr.what(None, _imagedata)
+ _subtype = _what(_imagedata)
if _subtype is None:
raise TypeError('Could not guess image MIME subtype')
MIMENonMultipart.__init__(self, 'image', _subtype, **_params)
self.set_payload(_imagedata)
_encoder(self)
+
+
+_rules = []
+
+
+# Originally from the imghdr module.
+def _what(data):
+ for rule in _rules:
+ if res := rule(data):
+ return res
+ else:
+ return None
+
+
+def rule(rulefunc):
+ _rules.append(rulefunc)
+ return rulefunc
+
+
+@rule
+def _jpeg(h):
+ """JPEG data with JFIF or Exif markers; and raw JPEG"""
+ if h[6:10] in (b'JFIF', b'Exif'):
+ return 'jpeg'
+ elif h[:4] == b'\xff\xd8\xff\xdb':
+ return 'jpeg'
+
+
+@rule
+def _png(h):
+ if h.startswith(b'\211PNG\r\n\032\n'):
+ return 'png'
+
+
+@rule
+def _gif(h):
+ """GIF ('87 and '89 variants)"""
+ if h[:6] in (b'GIF87a', b'GIF89a'):
+ return 'gif'
+
+
+@rule
+def _tiff(h):
+ """TIFF (can be in Motorola or Intel byte order)"""
+ if h[:2] in (b'MM', b'II'):
+ return 'tiff'
+
+
+@rule
+def _rgb(h):
+ """SGI image library"""
+ if h.startswith(b'\001\332'):
+ return 'rgb'
+
+
+@rule
+def _pbm(h):
+ """PBM (portable bitmap)"""
+ if len(h) >= 3 and \
+ h[0] == ord(b'P') and h[1] in b'14' and h[2] in b' \t\n\r':
+ return 'pbm'
+
+
+@rule
+def _pgm(h):
+ """PGM (portable graymap)"""
+ if len(h) >= 3 and \
+ h[0] == ord(b'P') and h[1] in b'25' and h[2] in b' \t\n\r':
+ return 'pgm'
+
+
+@rule
+def _ppm(h):
+ """PPM (portable pixmap)"""
+ if len(h) >= 3 and \
+ h[0] == ord(b'P') and h[1] in b'36' and h[2] in b' \t\n\r':
+ return 'ppm'
+
+
+@rule
+def _rast(h):
+ """Sun raster file"""
+ if h.startswith(b'\x59\xA6\x6A\x95'):
+ return 'rast'
+
+
+@rule
+def _xbm(h):
+ """X bitmap (X10 or X11)"""
+ if h.startswith(b'#define '):
+ return 'xbm'
+
+
+@rule
+def _bmp(h):
+ if h.startswith(b'BM'):
+ return 'bmp'
+
+
+@rule
+def _webp(h):
+ if h.startswith(b'RIFF') and h[8:12] == b'WEBP':
+ return 'webp'
+
+
+@rule
+def _exr(h):
+ if h.startswith(b'\x76\x2f\x31\x01'):
+ return 'exr'
diff --git a/contrib/python/future/py3/patches/07-support-python-3.13.patch b/contrib/python/future/py3/patches/07-support-python-3.13.patch
new file mode 100644
index 00000000000..c0e15bbbc33
--- /dev/null
+++ b/contrib/python/future/py3/patches/07-support-python-3.13.patch
@@ -0,0 +1,65 @@
+--- contrib/python/future/py3/future/backports/email/message.py (index)
++++ contrib/python/future/py3/future/backports/email/message.py (working tree)
+@@ -10,7 +10,6 @@ from future.builtins import list, range, str, zip
+ __all__ = ['Message']
+
+ import re
+-import uu
+ import base64
+ import binascii
+ from io import BytesIO, StringIO
+@@ -106,6 +105,37 @@ def _unquotevalue(value):
+ return utils.unquote(value)
+
+
++def _decode_uu(encoded):
++ """Decode uuencoded data."""
++ decoded_lines = []
++ encoded_lines_iter = iter(encoded.splitlines())
++ for line in encoded_lines_iter:
++ if line.startswith(b"begin "):
++ mode, _, path = line.removeprefix(b"begin ").partition(b" ")
++ try:
++ int(mode, base=8)
++ except ValueError:
++ continue
++ else:
++ break
++ else:
++ raise ValueError("`begin` line not found")
++ for line in encoded_lines_iter:
++ if not line:
++ raise ValueError("Truncated input")
++ elif line.strip(b' \t\r\n\f') == b'end':
++ break
++ try:
++ decoded_line = binascii.a2b_uu(line)
++ except binascii.Error:
++ # Workaround for broken uuencoders by /Fredrik Lundh
++ nbytes = (((line[0]-32) & 63) * 4 + 5) // 3
++ decoded_line = binascii.a2b_uu(line[:nbytes])
++ decoded_lines.append(decoded_line)
++
++ return b''.join(decoded_lines)
++
++
+ class Message(object):
+ """Basic message object.
+
+@@ -262,13 +292,10 @@ class Message(object):
+ self.policy.handle_defect(self, defect)
+ return value
+ elif cte in ('x-uuencode', 'uuencode', 'uue', 'x-uue'):
+- in_file = BytesIO(bpayload)
+- out_file = BytesIO()
+ try:
+- uu.decode(in_file, out_file, quiet=True)
+- return out_file.getvalue()
+- except uu.Error:
+- # Some decoding problem
++ return _decode_uu(bpayload)
++ except ValueError:
++ # Some decoding problem.
+ return bpayload
+ if isinstance(payload, str):
+ return bpayload
diff --git a/contrib/python/future/py3/patches/08-support-python-3.13.patch b/contrib/python/future/py3/patches/08-support-python-3.13.patch
new file mode 100644
index 00000000000..9b726f25e98
--- /dev/null
+++ b/contrib/python/future/py3/patches/08-support-python-3.13.patch
@@ -0,0 +1,103 @@
+--- contrib/python/future/py3/future/backports/email/mime/audio.py (index)
++++ contrib/python/future/py3/future/backports/email/mime/audio.py (working tree)
+@@ -9,37 +9,11 @@ from __future__ import absolute_import
+
+ __all__ = ['MIMEAudio']
+
+-import sndhdr
+-
+ from io import BytesIO
+ from future.backports.email import encoders
+ from future.backports.email.mime.nonmultipart import MIMENonMultipart
+
+
+-_sndhdr_MIMEmap = {'au' : 'basic',
+- 'wav' :'x-wav',
+- 'aiff':'x-aiff',
+- 'aifc':'x-aiff',
+- }
+-
+-# There are others in sndhdr that don't have MIME types. :(
+-# Additional ones to be added to sndhdr? midi, mp3, realaudio, wma??
+-def _whatsnd(data):
+- """Try to identify a sound file type.
+-
+- sndhdr.what() has a pretty cruddy interface, unfortunately. This is why
+- we re-do it here. It would be easier to reverse engineer the Unix 'file'
+- command and use the standard 'magic' file, as shipped with a modern Unix.
+- """
+- hdr = data[:512]
+- fakefile = BytesIO(hdr)
+- for testfn in sndhdr.tests:
+- res = testfn(hdr, fakefile)
+- if res is not None:
+- return _sndhdr_MIMEmap.get(res[0])
+- return None
+-
+-
+ class MIMEAudio(MIMENonMultipart):
+ """Class for generating audio/* MIME documents."""
+
+@@ -66,9 +40,61 @@ class MIMEAudio(MIMENonMultipart):
+ header.
+ """
+ if _subtype is None:
+- _subtype = _whatsnd(_audiodata)
++ _subtype = _what(_audiodata)
+ if _subtype is None:
+ raise TypeError('Could not find audio MIME subtype')
+ MIMENonMultipart.__init__(self, 'audio', _subtype, **_params)
+ self.set_payload(_audiodata)
+ _encoder(self)
++
++
++_rules = []
++
++
++# Originally from the sndhdr module.
++#
++# There are others in sndhdr that don't have MIME types. :(
++# Additional ones to be added to sndhdr? midi, mp3, realaudio, wma??
++def _what(data):
++ # Try to identify a sound file type.
++ #
++ # sndhdr.what() had a pretty cruddy interface, unfortunately. This is why
++ # we re-do it here. It would be easier to reverse engineer the Unix 'file'
++ # command and use the standard 'magic' file, as shipped with a modern Unix.
++ for testfn in _rules:
++ if res := testfn(data):
++ return res
++ else:
++ return None
++
++
++def rule(rulefunc):
++ _rules.append(rulefunc)
++ return rulefunc
++
++
++@rule
++def _aiff(h):
++ if not h.startswith(b'FORM'):
++ return None
++ if h[8:12] in {b'AIFC', b'AIFF'}:
++ return 'x-aiff'
++ else:
++ return None
++
++
++@rule
++def _au(h):
++ if h.startswith(b'.snd'):
++ return 'basic'
++ else:
++ return None
++
++
++@rule
++def _wav(h):
++ # 'RIFF' <len> 'WAVE' 'fmt ' <len>
++ if not h.startswith(b'RIFF') or h[8:12] != b'WAVE' or h[12:16] != b'fmt ':
++ return None
++ else:
++ return "x-wav"
diff --git a/contrib/python/future/py3/patches/09-support-python-3.13.patch b/contrib/python/future/py3/patches/09-support-python-3.13.patch
new file mode 100644
index 00000000000..ebcd7356378
--- /dev/null
+++ b/contrib/python/future/py3/patches/09-support-python-3.13.patch
@@ -0,0 +1,131 @@
+--- contrib/python/future/py3/future/backports/email/mime/image.py (index)
++++ contrib/python/future/py3/future/backports/email/mime/image.py (working tree)
+@@ -9,8 +9,6 @@ from __future__ import absolute_import
+
+ __all__ = ['MIMEImage']
+
+-import imghdr
+-
+ from future.backports.email import encoders
+ from future.backports.email.mime.nonmultipart import MIMENonMultipart
+
+@@ -40,9 +38,118 @@ class MIMEImage(MIMENonMultipart):
+ header.
+ """
+ if _subtype is None:
+- _subtype = imghdr.what(None, _imagedata)
++ _subtype = _what(_imagedata)
+ if _subtype is None:
+ raise TypeError('Could not guess image MIME subtype')
+ MIMENonMultipart.__init__(self, 'image', _subtype, **_params)
+ self.set_payload(_imagedata)
+ _encoder(self)
++
++
++_rules = []
++
++
++# Originally from the imghdr module.
++def _what(data):
++ for rule in _rules:
++ if res := rule(data):
++ return res
++ else:
++ return None
++
++
++def rule(rulefunc):
++ _rules.append(rulefunc)
++ return rulefunc
++
++
++@rule
++def _jpeg(h):
++ """JPEG data with JFIF or Exif markers; and raw JPEG"""
++ if h[6:10] in (b'JFIF', b'Exif'):
++ return 'jpeg'
++ elif h[:4] == b'\xff\xd8\xff\xdb':
++ return 'jpeg'
++
++
++@rule
++def _png(h):
++ if h.startswith(b'\211PNG\r\n\032\n'):
++ return 'png'
++
++
++@rule
++def _gif(h):
++ """GIF ('87 and '89 variants)"""
++ if h[:6] in (b'GIF87a', b'GIF89a'):
++ return 'gif'
++
++
++@rule
++def _tiff(h):
++ """TIFF (can be in Motorola or Intel byte order)"""
++ if h[:2] in (b'MM', b'II'):
++ return 'tiff'
++
++
++@rule
++def _rgb(h):
++ """SGI image library"""
++ if h.startswith(b'\001\332'):
++ return 'rgb'
++
++
++@rule
++def _pbm(h):
++ """PBM (portable bitmap)"""
++ if len(h) >= 3 and \
++ h[0] == ord(b'P') and h[1] in b'14' and h[2] in b' \t\n\r':
++ return 'pbm'
++
++
++@rule
++def _pgm(h):
++ """PGM (portable graymap)"""
++ if len(h) >= 3 and \
++ h[0] == ord(b'P') and h[1] in b'25' and h[2] in b' \t\n\r':
++ return 'pgm'
++
++
++@rule
++def _ppm(h):
++ """PPM (portable pixmap)"""
++ if len(h) >= 3 and \
++ h[0] == ord(b'P') and h[1] in b'36' and h[2] in b' \t\n\r':
++ return 'ppm'
++
++
++@rule
++def _rast(h):
++ """Sun raster file"""
++ if h.startswith(b'\x59\xA6\x6A\x95'):
++ return 'rast'
++
++
++@rule
++def _xbm(h):
++ """X bitmap (X10 or X11)"""
++ if h.startswith(b'#define '):
++ return 'xbm'
++
++
++@rule
++def _bmp(h):
++ if h.startswith(b'BM'):
++ return 'bmp'
++
++
++@rule
++def _webp(h):
++ if h.startswith(b'RIFF') and h[8:12] == b'WEBP':
++ return 'webp'
++
++
++@rule
++def _exr(h):
++ if h.startswith(b'\x76\x2f\x31\x01'):
++ return 'exr'
diff --git a/contrib/python/moto/py3/moto/s3/responses.py b/contrib/python/moto/py3/moto/s3/responses.py
index 8784d98632d..06171e79c75 100644
--- a/contrib/python/moto/py3/moto/s3/responses.py
+++ b/contrib/python/moto/py3/moto/s3/responses.py
@@ -362,10 +362,7 @@ class S3Response(BaseResponse):
#
# Workaround - manually reverse the encoding.
# Keep the + encoded, ensuring that parse_qsl doesn't replace it, and parse_qsl will unquote it afterwards
- #
- # YQ-1825: Replace was commented out as the version of `Werkzeug`
- # that we are using is 2.0.3 (lesser than 2.1.0) and workaround is not needed
- qs = (parsed_url.query or "") #.replace("+", "%2B")
+ qs = (parsed_url.query or "").replace("+", "%2B")
return parse_qs(qs, keep_blank_values=True)
def _bucket_response_head(
diff --git a/contrib/python/moto/py3/patches/03-arcadia.patch b/contrib/python/moto/py3/patches/03-arcadia.patch
deleted file mode 100644
index 4f01e0d0a40..00000000000
--- a/contrib/python/moto/py3/patches/03-arcadia.patch
+++ /dev/null
@@ -1,14 +0,0 @@
---- contrib/python/moto/py3/moto/s3/responses.py (index)
-+++ contrib/python/moto/py3/moto/s3/responses.py (working tree)
-@@ -362,7 +362,10 @@ class S3Response(BaseResponse):
- #
- # Workaround - manually reverse the encoding.
- # Keep the + encoded, ensuring that parse_qsl doesn't replace it, and parse_qsl will unquote it afterwards
-- qs = (parsed_url.query or "").replace("+", "%2B")
-+ #
-+ # YQ-1825: Replace was commented out as the version of `Werkzeug`
-+ # that we are using is 2.0.3 (lesser than 2.1.0) and workaround is not needed
-+ qs = (parsed_url.query or "") #.replace("+", "%2B")
- return parse_qs(qs, keep_blank_values=True)
-
- def _bucket_response_head(
diff --git a/contrib/python/scramp/.dist-info/METADATA b/contrib/python/scramp/.dist-info/METADATA
index 0058fe6943a..e3fded9df5b 100644
--- a/contrib/python/scramp/.dist-info/METADATA
+++ b/contrib/python/scramp/.dist-info/METADATA
@@ -1,6 +1,6 @@
-Metadata-Version: 2.3
+Metadata-Version: 2.4
Name: scramp
-Version: 1.4.5
+Version: 1.4.6
Summary: An implementation of the SCRAM protocol.
Project-URL: Homepage, https://github.com/tlocke/scramp
Author: The Contributors
@@ -409,6 +409,11 @@ Run `tox` to make sure all tests pass, then update the release notes, then do:
## Release Notes
+### Version 1.4.6, 2025-07-05
+
+- Drop support for Python 3.8, and add support for 3.13
+
+
### Version 1.4.5, 2024-04-13
- Drop support for Python 3.7, which means we're not dependent on `importlib-metadata` anymore.
diff --git a/contrib/python/scramp/README.md b/contrib/python/scramp/README.md
index 43641445be5..71793c1b378 100644
--- a/contrib/python/scramp/README.md
+++ b/contrib/python/scramp/README.md
@@ -383,6 +383,11 @@ Run `tox` to make sure all tests pass, then update the release notes, then do:
## Release Notes
+### Version 1.4.6, 2025-07-05
+
+- Drop support for Python 3.8, and add support for 3.13
+
+
### Version 1.4.5, 2024-04-13
- Drop support for Python 3.7, which means we're not dependent on `importlib-metadata` anymore.
diff --git a/contrib/python/scramp/scramp/__init__.py b/contrib/python/scramp/scramp/__init__.py
index 8bfbcd20725..4d7a7083e5e 100644
--- a/contrib/python/scramp/scramp/__init__.py
+++ b/contrib/python/scramp/scramp/__init__.py
@@ -7,6 +7,6 @@ from scramp.core import (
make_channel_binding,
)
-__all__ = [ScramClient, ScramMechanism, ScramException, make_channel_binding]
+__all__ = ["ScramClient", "ScramException", "ScramMechanism", "make_channel_binding"]
__version__ = version("scramp")
diff --git a/contrib/python/scramp/ya.make b/contrib/python/scramp/ya.make
index 787e9aa7e5c..99e03e01548 100644
--- a/contrib/python/scramp/ya.make
+++ b/contrib/python/scramp/ya.make
@@ -2,7 +2,7 @@
PY3_LIBRARY()
-VERSION(1.4.5)
+VERSION(1.4.6)
LICENSE(MIT-0)
diff --git a/contrib/python/types-protobuf/.dist-info/METADATA b/contrib/python/types-protobuf/.dist-info/METADATA
index 0bf803fbc14..eed8dfd2af2 100644
--- a/contrib/python/types-protobuf/.dist-info/METADATA
+++ b/contrib/python/types-protobuf/.dist-info/METADATA
@@ -1,6 +1,6 @@
Metadata-Version: 2.4
Name: types-protobuf
-Version: 6.30.2.20250516
+Version: 6.30.2.20250703
Summary: Typing stubs for protobuf
License-Expression: Apache-2.0
Project-URL: Homepage, https://github.com/python/typeshed
@@ -42,8 +42,8 @@ for more details. The source for this package can be found in the
directory.
This package was tested with
-mypy 1.15.0,
+mypy 1.16.1,
pyright 1.1.400,
and pytype 2024.10.11.
It was generated from typeshed commit
-[`126768408a69b7a3a09b7d3992970b289f92937e`](https://github.com/python/typeshed/commit/126768408a69b7a3a09b7d3992970b289f92937e).
+[`dbd3ad356ef3bceae506fb71a29a48b6192213ba`](https://github.com/python/typeshed/commit/dbd3ad356ef3bceae506fb71a29a48b6192213ba).
diff --git a/contrib/python/types-protobuf/README.md b/contrib/python/types-protobuf/README.md
index 5b485981e77..4734a9b1ff7 100644
--- a/contrib/python/types-protobuf/README.md
+++ b/contrib/python/types-protobuf/README.md
@@ -25,8 +25,8 @@ for more details. The source for this package can be found in the
directory.
This package was tested with
-mypy 1.15.0,
+mypy 1.16.1,
pyright 1.1.400,
and pytype 2024.10.11.
It was generated from typeshed commit
-[`126768408a69b7a3a09b7d3992970b289f92937e`](https://github.com/python/typeshed/commit/126768408a69b7a3a09b7d3992970b289f92937e). \ No newline at end of file
+[`dbd3ad356ef3bceae506fb71a29a48b6192213ba`](https://github.com/python/typeshed/commit/dbd3ad356ef3bceae506fb71a29a48b6192213ba). \ No newline at end of file
diff --git a/contrib/python/types-protobuf/google-stubs/protobuf/internal/containers.pyi b/contrib/python/types-protobuf/google-stubs/protobuf/internal/containers.pyi
index 75261371607..1431c3b1379 100644
--- a/contrib/python/types-protobuf/google-stubs/protobuf/internal/containers.pyi
+++ b/contrib/python/types-protobuf/google-stubs/protobuf/internal/containers.pyi
@@ -72,7 +72,9 @@ class ScalarMap(MutableMapping[_K, _ScalarV]):
@overload
def get(self, key: _K, default: None = None) -> _ScalarV | None: ...
@overload
- def get(self, key: _K, default: _ScalarV | _T) -> _ScalarV | _T: ...
+ def get(self, key: _K, default: _ScalarV) -> _ScalarV: ...
+ @overload
+ def get(self, key: _K, default: _T) -> _ScalarV | _T: ...
def setdefault(self, key: _K, value: _ScalarV | None = None) -> _ScalarV: ...
def MergeFrom(self, other: Self): ...
def InvalidateIterators(self) -> None: ...
@@ -95,7 +97,9 @@ class MessageMap(MutableMapping[_K, _MessageV]):
@overload
def get(self, key: _K, default: None = None) -> _MessageV | None: ...
@overload
- def get(self, key: _K, default: _MessageV | _T) -> _MessageV | _T: ...
+ def get(self, key: _K, default: _MessageV) -> _MessageV: ...
+ @overload
+ def get(self, key: _K, default: _T) -> _MessageV | _T: ...
def get_or_create(self, key: _K) -> _MessageV: ...
def setdefault(self, key: _K, value: _MessageV | None = None) -> _MessageV: ...
def MergeFrom(self, other: Self): ...
diff --git a/contrib/python/types-protobuf/ya.make b/contrib/python/types-protobuf/ya.make
index 33f3f6ac13c..c70d8edee22 100644
--- a/contrib/python/types-protobuf/ya.make
+++ b/contrib/python/types-protobuf/ya.make
@@ -2,7 +2,7 @@
PY3_LIBRARY()
-VERSION(6.30.2.20250516)
+VERSION(6.30.2.20250703)
LICENSE(Apache-2.0)