aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/python
diff options
context:
space:
mode:
authorInnokentii Mokin <innokentii@ydb.tech>2024-01-27 10:01:54 +0000
committerInnokentii Mokin <innokentii@ydb.tech>2024-01-27 10:01:54 +0000
commit621e3d86c4e02bf3c88bb68e5aba5856fbf0185d (patch)
tree2d517d0985015d27ce6862003509de502be44ccc /contrib/python
parenta7dad28338e49d920879eb2b3e728ee6dd166b6e (diff)
parent00b9982cd019afca788639aa8279f2dc1f342383 (diff)
downloadydb-621e3d86c4e02bf3c88bb68e5aba5856fbf0185d.tar.gz
Merge branch 'mergelibs11' into main
Diffstat (limited to 'contrib/python')
-rw-r--r--contrib/python/Jinja2/py3/.dist-info/METADATA14
-rw-r--r--contrib/python/Jinja2/py3/README.rst2
-rw-r--r--contrib/python/Jinja2/py3/jinja2/__init__.py2
-rw-r--r--contrib/python/Jinja2/py3/jinja2/async_utils.py2
-rw-r--r--contrib/python/Jinja2/py3/jinja2/compiler.py5
-rw-r--r--contrib/python/Jinja2/py3/jinja2/environment.py12
-rw-r--r--contrib/python/Jinja2/py3/jinja2/ext.py20
-rw-r--r--contrib/python/Jinja2/py3/jinja2/filters.py28
-rw-r--r--contrib/python/Jinja2/py3/jinja2/loaders.py36
-rw-r--r--contrib/python/Jinja2/py3/jinja2/nativetypes.py2
-rw-r--r--contrib/python/Jinja2/py3/jinja2/parser.py16
-rw-r--r--contrib/python/Jinja2/py3/jinja2/runtime.py8
-rw-r--r--contrib/python/Jinja2/py3/jinja2/utils.py4
-rw-r--r--contrib/python/Jinja2/py3/tests/test_ext.py13
-rw-r--r--contrib/python/Jinja2/py3/tests/test_filters.py8
-rw-r--r--contrib/python/Jinja2/py3/tests/test_inheritance.py39
-rw-r--r--contrib/python/Jinja2/py3/tests/test_loader.py6
-rw-r--r--contrib/python/Jinja2/py3/ya.make2
-rw-r--r--contrib/python/fonttools/.dist-info/METADATA14
-rw-r--r--contrib/python/fonttools/fontTools/__init__.py2
-rw-r--r--contrib/python/fonttools/fontTools/merge/__init__.py54
-rw-r--r--contrib/python/fonttools/fontTools/merge/options.py3
-rw-r--r--contrib/python/fonttools/fontTools/otlLib/builder.py26
-rw-r--r--contrib/python/fonttools/fontTools/varLib/featureVars.py35
-rw-r--r--contrib/python/fonttools/fontTools/varLib/interpolatable.py14
-rw-r--r--contrib/python/fonttools/ya.make2
-rw-r--r--contrib/python/google-auth/py3/.dist-info/METADATA2
-rw-r--r--contrib/python/google-auth/py3/google/auth/external_account_authorized_user.py1
-rw-r--r--contrib/python/google-auth/py3/google/auth/version.py2
-rw-r--r--contrib/python/google-auth/py3/tests/data/external_account_authorized_user_non_gdu.json10
-rw-r--r--contrib/python/google-auth/py3/tests/test__default.py13
-rw-r--r--contrib/python/google-auth/py3/ya.make2
-rw-r--r--contrib/python/hypothesis/py3/.dist-info/METADATA2
-rw-r--r--contrib/python/hypothesis/py3/hypothesis/control.py11
-rw-r--r--contrib/python/hypothesis/py3/hypothesis/core.py4
-rw-r--r--contrib/python/hypothesis/py3/hypothesis/errors.py3
-rw-r--r--contrib/python/hypothesis/py3/hypothesis/internal/filtering.py51
-rw-r--r--contrib/python/hypothesis/py3/hypothesis/internal/reflection.py4
-rw-r--r--contrib/python/hypothesis/py3/hypothesis/strategies/_internal/collections.py18
-rw-r--r--contrib/python/hypothesis/py3/hypothesis/version.py2
-rw-r--r--contrib/python/hypothesis/py3/ya.make2
-rw-r--r--contrib/python/ydb/py3/.dist-info/METADATA2
-rw-r--r--contrib/python/ydb/py3/ya.make4
-rw-r--r--contrib/python/ydb/py3/ydb/__init__.py1
-rw-r--r--contrib/python/ydb/py3/ydb/_apis.py26
-rw-r--r--contrib/python/ydb/py3/ydb/draft/__init__.py1
-rw-r--r--contrib/python/ydb/py3/ydb/draft/dynamic_config.py173
-rw-r--r--contrib/python/ydb/py3/ydb/ydb_version.py2
48 files changed, 552 insertions, 153 deletions
diff --git a/contrib/python/Jinja2/py3/.dist-info/METADATA b/contrib/python/Jinja2/py3/.dist-info/METADATA
index f54bb5ca1a..56e942902a 100644
--- a/contrib/python/Jinja2/py3/.dist-info/METADATA
+++ b/contrib/python/Jinja2/py3/.dist-info/METADATA
@@ -1,10 +1,8 @@
Metadata-Version: 2.1
Name: Jinja2
-Version: 3.1.2
+Version: 3.1.3
Summary: A very fast and expressive template engine.
Home-page: https://palletsprojects.com/p/jinja/
-Author: Armin Ronacher
-Author-email: armin.ronacher@active-4.com
Maintainer: Pallets
Maintainer-email: contact@palletsprojects.com
License: BSD-3-Clause
@@ -13,9 +11,7 @@ Project-URL: Documentation, https://jinja.palletsprojects.com/
Project-URL: Changes, https://jinja.palletsprojects.com/changes/
Project-URL: Source Code, https://github.com/pallets/jinja/
Project-URL: Issue Tracker, https://github.com/pallets/jinja/issues/
-Project-URL: Twitter, https://twitter.com/PalletsTeam
Project-URL: Chat, https://discord.gg/pallets
-Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Web Environment
Classifier: Intended Audience :: Developers
@@ -27,9 +23,9 @@ Classifier: Topic :: Text Processing :: Markup :: HTML
Requires-Python: >=3.7
Description-Content-Type: text/x-rst
License-File: LICENSE.rst
-Requires-Dist: MarkupSafe (>=2.0)
+Requires-Dist: MarkupSafe >=2.0
Provides-Extra: i18n
-Requires-Dist: Babel (>=2.7) ; extra == 'i18n'
+Requires-Dist: Babel >=2.7 ; extra == 'i18n'
Jinja
=====
@@ -106,8 +102,4 @@ Links
- PyPI Releases: https://pypi.org/project/Jinja2/
- Source Code: https://github.com/pallets/jinja/
- Issue Tracker: https://github.com/pallets/jinja/issues/
-- Website: https://palletsprojects.com/p/jinja/
-- Twitter: https://twitter.com/PalletsTeam
- Chat: https://discord.gg/pallets
-
-
diff --git a/contrib/python/Jinja2/py3/README.rst b/contrib/python/Jinja2/py3/README.rst
index a197aea647..94b22ecabe 100644
--- a/contrib/python/Jinja2/py3/README.rst
+++ b/contrib/python/Jinja2/py3/README.rst
@@ -73,6 +73,4 @@ Links
- PyPI Releases: https://pypi.org/project/Jinja2/
- Source Code: https://github.com/pallets/jinja/
- Issue Tracker: https://github.com/pallets/jinja/issues/
-- Website: https://palletsprojects.com/p/jinja/
-- Twitter: https://twitter.com/PalletsTeam
- Chat: https://discord.gg/pallets
diff --git a/contrib/python/Jinja2/py3/jinja2/__init__.py b/contrib/python/Jinja2/py3/jinja2/__init__.py
index a684093795..8076e72cd1 100644
--- a/contrib/python/Jinja2/py3/jinja2/__init__.py
+++ b/contrib/python/Jinja2/py3/jinja2/__init__.py
@@ -35,4 +35,4 @@ from .utils import pass_environment as pass_environment
from .utils import pass_eval_context as pass_eval_context
from .utils import select_autoescape as select_autoescape
-__version__ = "3.1.2"
+__version__ = "3.1.3"
diff --git a/contrib/python/Jinja2/py3/jinja2/async_utils.py b/contrib/python/Jinja2/py3/jinja2/async_utils.py
index 1a4f3892ce..715d70119b 100644
--- a/contrib/python/Jinja2/py3/jinja2/async_utils.py
+++ b/contrib/python/Jinja2/py3/jinja2/async_utils.py
@@ -74,7 +74,7 @@ async def auto_aiter(
async for item in t.cast("t.AsyncIterable[V]", iterable):
yield item
else:
- for item in t.cast("t.Iterable[V]", iterable):
+ for item in iterable:
yield item
diff --git a/contrib/python/Jinja2/py3/jinja2/compiler.py b/contrib/python/Jinja2/py3/jinja2/compiler.py
index 3458095f54..ff95c807b0 100644
--- a/contrib/python/Jinja2/py3/jinja2/compiler.py
+++ b/contrib/python/Jinja2/py3/jinja2/compiler.py
@@ -993,7 +993,6 @@ class CodeGenerator(NodeVisitor):
# far, we don't have to add a check if something extended
# the template before this one.
if self.extends_so_far > 0:
-
# if we have a known extends we just add a template runtime
# error into the generated code. We could catch that at compile
# time too, but i welcome it not to confuse users by throwing the
@@ -1407,7 +1406,7 @@ class CodeGenerator(NodeVisitor):
if pass_arg is None:
- def finalize(value: t.Any) -> t.Any:
+ def finalize(value: t.Any) -> t.Any: # noqa: F811
return default(env_finalize(value))
else:
@@ -1415,7 +1414,7 @@ class CodeGenerator(NodeVisitor):
if pass_arg == "environment":
- def finalize(value: t.Any) -> t.Any:
+ def finalize(value: t.Any) -> t.Any: # noqa: F811
return default(env_finalize(self.environment, value))
self._finalize = self._FinalizeInfo(finalize, src)
diff --git a/contrib/python/Jinja2/py3/jinja2/environment.py b/contrib/python/Jinja2/py3/jinja2/environment.py
index ea04e8b443..185d33246e 100644
--- a/contrib/python/Jinja2/py3/jinja2/environment.py
+++ b/contrib/python/Jinja2/py3/jinja2/environment.py
@@ -701,7 +701,7 @@ class Environment:
.. versionadded:: 2.5
"""
- return compile(source, filename, "exec") # type: ignore
+ return compile(source, filename, "exec")
@typing.overload
def compile( # type: ignore
@@ -920,7 +920,7 @@ class Environment:
)
def filter_func(x: str) -> bool:
- return "." in x and x.rsplit(".", 1)[1] in extensions # type: ignore
+ return "." in x and x.rsplit(".", 1)[1] in extensions
if filter_func is not None:
names = [name for name in names if filter_func(name)]
@@ -1253,7 +1253,7 @@ class Template:
t.blocks = namespace["blocks"]
# render function and module
- t.root_render_func = namespace["root"] # type: ignore
+ t.root_render_func = namespace["root"]
t._module = None
# debug and loader helpers
@@ -1349,7 +1349,7 @@ class Template:
ctx = self.new_context(dict(*args, **kwargs))
try:
- yield from self.root_render_func(ctx) # type: ignore
+ yield from self.root_render_func(ctx)
except Exception:
yield self.environment.handle_exception()
@@ -1532,7 +1532,7 @@ class TemplateModule:
" API you are using."
)
- body_stream = list(template.root_render_func(context)) # type: ignore
+ body_stream = list(template.root_render_func(context))
self._body_stream = body_stream
self.__dict__.update(context.get_exported())
@@ -1564,7 +1564,7 @@ class TemplateExpression:
def __call__(self, *args: t.Any, **kwargs: t.Any) -> t.Optional[t.Any]:
context = self._template.new_context(dict(*args, **kwargs))
- consume(self._template.root_render_func(context)) # type: ignore
+ consume(self._template.root_render_func(context))
rv = context.vars["result"]
if self._undefined_to_none and isinstance(rv, Undefined):
rv = None
diff --git a/contrib/python/Jinja2/py3/jinja2/ext.py b/contrib/python/Jinja2/py3/jinja2/ext.py
index d5550540cd..fade1fa3bc 100644
--- a/contrib/python/Jinja2/py3/jinja2/ext.py
+++ b/contrib/python/Jinja2/py3/jinja2/ext.py
@@ -291,14 +291,14 @@ class InternationalizationExtension(Extension):
if hasattr(translations, "pgettext"):
# Python < 3.8
- pgettext = translations.pgettext # type: ignore
+ pgettext = translations.pgettext
else:
def pgettext(c: str, s: str) -> str:
return s
if hasattr(translations, "npgettext"):
- npgettext = translations.npgettext # type: ignore
+ npgettext = translations.npgettext
else:
def npgettext(c: str, s: str, p: str, n: int) -> str:
@@ -495,16 +495,26 @@ class InternationalizationExtension(Extension):
parser.stream.expect("variable_end")
elif parser.stream.current.type == "block_begin":
next(parser.stream)
- if parser.stream.current.test("name:endtrans"):
+ block_name = (
+ parser.stream.current.value
+ if parser.stream.current.type == "name"
+ else None
+ )
+ if block_name == "endtrans":
break
- elif parser.stream.current.test("name:pluralize"):
+ elif block_name == "pluralize":
if allow_pluralize:
break
parser.fail(
"a translatable section can have only one pluralize section"
)
+ elif block_name == "trans":
+ parser.fail(
+ "trans blocks can't be nested; did you mean `endtrans`?"
+ )
parser.fail(
- "control structures in translatable sections are not allowed"
+ f"control structures in translatable sections are not allowed; "
+ f"saw `{block_name}`"
)
elif parser.stream.eos:
parser.fail("unclosed translation block")
diff --git a/contrib/python/Jinja2/py3/jinja2/filters.py b/contrib/python/Jinja2/py3/jinja2/filters.py
index ed07c4c0e2..c7ecc9bb68 100644
--- a/contrib/python/Jinja2/py3/jinja2/filters.py
+++ b/contrib/python/Jinja2/py3/jinja2/filters.py
@@ -248,13 +248,17 @@ def do_items(value: t.Union[t.Mapping[K, V], Undefined]) -> t.Iterator[t.Tuple[K
yield from value.items()
+_space_re = re.compile(r"\s", flags=re.ASCII)
+
+
@pass_eval_context
def do_xmlattr(
eval_ctx: "EvalContext", d: t.Mapping[str, t.Any], autospace: bool = True
) -> str:
"""Create an SGML/XML attribute string based on the items in a dict.
- All values that are neither `none` nor `undefined` are automatically
- escaped:
+
+ If any key contains a space, this fails with a ``ValueError``. Values that
+ are neither ``none`` nor ``undefined`` are automatically escaped.
.. sourcecode:: html+jinja
@@ -273,12 +277,22 @@ def do_xmlattr(
As you can see it automatically prepends a space in front of the item
if the filter returned something unless the second parameter is false.
+
+ .. versionchanged:: 3.1.3
+ Keys with spaces are not allowed.
"""
- rv = " ".join(
- f'{escape(key)}="{escape(value)}"'
- for key, value in d.items()
- if value is not None and not isinstance(value, Undefined)
- )
+ items = []
+
+ for key, value in d.items():
+ if value is None or isinstance(value, Undefined):
+ continue
+
+ if _space_re.search(key) is not None:
+ raise ValueError(f"Spaces are not allowed in attributes: '{key}'")
+
+ items.append(f'{escape(key)}="{escape(value)}"')
+
+ rv = " ".join(items)
if autospace and rv:
rv = " " + rv
diff --git a/contrib/python/Jinja2/py3/jinja2/loaders.py b/contrib/python/Jinja2/py3/jinja2/loaders.py
index 261802176a..dfa2ad7ec5 100644
--- a/contrib/python/Jinja2/py3/jinja2/loaders.py
+++ b/contrib/python/Jinja2/py3/jinja2/loaders.py
@@ -16,7 +16,6 @@ from types import ModuleType
from .exceptions import TemplateNotFound
from .utils import internalcode
-from .utils import open_if_exists
if t.TYPE_CHECKING:
from .environment import Environment
@@ -196,29 +195,30 @@ class FileSystemLoader(BaseLoader):
self, environment: "Environment", template: str
) -> t.Tuple[str, str, t.Callable[[], bool]]:
pieces = split_template_path(template)
+
for searchpath in self.searchpath:
# Use posixpath even on Windows to avoid "drive:" or UNC
# segments breaking out of the search directory.
filename = posixpath.join(searchpath, *pieces)
- f = open_if_exists(filename)
- if f is None:
- continue
- try:
- contents = f.read().decode(self.encoding)
- finally:
- f.close()
- mtime = os.path.getmtime(filename)
+ if os.path.isfile(filename):
+ break
+ else:
+ raise TemplateNotFound(template)
- def uptodate() -> bool:
- try:
- return os.path.getmtime(filename) == mtime
- except OSError:
- return False
+ with open(filename, encoding=self.encoding) as f:
+ contents = f.read()
- # Use normpath to convert Windows altsep to sep.
- return contents, os.path.normpath(filename), uptodate
- raise TemplateNotFound(template)
+ mtime = os.path.getmtime(filename)
+
+ def uptodate() -> bool:
+ try:
+ return os.path.getmtime(filename) == mtime
+ except OSError:
+ return False
+
+ # Use normpath to convert Windows altsep to sep.
+ return contents, os.path.normpath(filename), uptodate
def list_templates(self) -> t.List[str]:
found = set()
@@ -412,7 +412,7 @@ class PackageLoader(BaseLoader):
)
offset = len(prefix)
- for name in self._loader._files.keys(): # type: ignore
+ for name in self._loader._files.keys():
# Find names under the templates directory that aren't directories.
if name.startswith(prefix) and name[-1] != os.path.sep:
results.append(name[offset:].replace(os.path.sep, "/"))
diff --git a/contrib/python/Jinja2/py3/jinja2/nativetypes.py b/contrib/python/Jinja2/py3/jinja2/nativetypes.py
index ac08610348..71db8cc31f 100644
--- a/contrib/python/Jinja2/py3/jinja2/nativetypes.py
+++ b/contrib/python/Jinja2/py3/jinja2/nativetypes.py
@@ -106,7 +106,7 @@ class NativeTemplate(Template):
try:
return self.environment_class.concat( # type: ignore
- self.root_render_func(ctx) # type: ignore
+ self.root_render_func(ctx)
)
except Exception:
return self.environment.handle_exception()
diff --git a/contrib/python/Jinja2/py3/jinja2/parser.py b/contrib/python/Jinja2/py3/jinja2/parser.py
index cefce2dfa1..3354bc9339 100644
--- a/contrib/python/Jinja2/py3/jinja2/parser.py
+++ b/contrib/python/Jinja2/py3/jinja2/parser.py
@@ -311,12 +311,14 @@ class Parser:
# enforce that required blocks only contain whitespace or comments
# by asserting that the body, if not empty, is just TemplateData nodes
# with whitespace data
- if node.required and not all(
- isinstance(child, nodes.TemplateData) and child.data.isspace()
- for body in node.body
- for child in body.nodes # type: ignore
- ):
- self.fail("Required blocks can only contain comments or whitespace")
+ if node.required:
+ for body_node in node.body:
+ if not isinstance(body_node, nodes.Output) or any(
+ not isinstance(output_node, nodes.TemplateData)
+ or not output_node.data.isspace()
+ for output_node in body_node.nodes
+ ):
+ self.fail("Required blocks can only contain comments or whitespace")
self.stream.skip_if("name:" + node.name)
return node
@@ -857,7 +859,7 @@ class Parser:
else:
args.append(None)
- return nodes.Slice(lineno=lineno, *args)
+ return nodes.Slice(lineno=lineno, *args) # noqa: B026
def parse_call_args(self) -> t.Tuple:
token = self.stream.expect("lparen")
diff --git a/contrib/python/Jinja2/py3/jinja2/runtime.py b/contrib/python/Jinja2/py3/jinja2/runtime.py
index 985842b284..58a540ba3f 100644
--- a/contrib/python/Jinja2/py3/jinja2/runtime.py
+++ b/contrib/python/Jinja2/py3/jinja2/runtime.py
@@ -272,9 +272,9 @@ class Context:
# Allow callable classes to take a context
if (
hasattr(__obj, "__call__") # noqa: B004
- and _PassArg.from_obj(__obj.__call__) is not None # type: ignore
+ and _PassArg.from_obj(__obj.__call__) is not None
):
- __obj = __obj.__call__ # type: ignore
+ __obj = __obj.__call__
pass_arg = _PassArg.from_obj(__obj)
@@ -927,9 +927,7 @@ def make_logging_undefined(
logger.addHandler(logging.StreamHandler(sys.stderr))
def _log_message(undef: Undefined) -> None:
- logger.warning( # type: ignore
- "Template variable warning: %s", undef._undefined_message
- )
+ logger.warning("Template variable warning: %s", undef._undefined_message)
class LoggingUndefined(base): # type: ignore
__slots__ = ()
diff --git a/contrib/python/Jinja2/py3/jinja2/utils.py b/contrib/python/Jinja2/py3/jinja2/utils.py
index 9b5f5a50eb..18914a58fd 100644
--- a/contrib/python/Jinja2/py3/jinja2/utils.py
+++ b/contrib/python/Jinja2/py3/jinja2/utils.py
@@ -182,7 +182,7 @@ def object_type_repr(obj: t.Any) -> str:
def pformat(obj: t.Any) -> str:
"""Format an object using :func:`pprint.pformat`."""
- from pprint import pformat # type: ignore
+ from pprint import pformat
return pformat(obj)
@@ -259,7 +259,7 @@ def urlize(
if trim_url_limit is not None:
def trim_url(x: str) -> str:
- if len(x) > trim_url_limit: # type: ignore
+ if len(x) > trim_url_limit:
return f"{x[:trim_url_limit]}..."
return x
diff --git a/contrib/python/Jinja2/py3/tests/test_ext.py b/contrib/python/Jinja2/py3/tests/test_ext.py
index 2e842e0ab5..0b48ca2586 100644
--- a/contrib/python/Jinja2/py3/tests/test_ext.py
+++ b/contrib/python/Jinja2/py3/tests/test_ext.py
@@ -7,6 +7,7 @@ from jinja2 import DictLoader
from jinja2 import Environment
from jinja2 import nodes
from jinja2 import pass_context
+from jinja2 import TemplateSyntaxError
from jinja2.exceptions import TemplateAssertionError
from jinja2.ext import Extension
from jinja2.lexer import count_newlines
@@ -468,6 +469,18 @@ class TestInternationalization:
(3, "npgettext", ("babel", "%(users)s user", "%(users)s users", None), []),
]
+ def test_nested_trans_error(self):
+ s = "{% trans %}foo{% trans %}{% endtrans %}"
+ with pytest.raises(TemplateSyntaxError) as excinfo:
+ i18n_env.from_string(s)
+ assert "trans blocks can't be nested" in str(excinfo.value)
+
+ def test_trans_block_error(self):
+ s = "{% trans %}foo{% wibble bar %}{% endwibble %}{% endtrans %}"
+ with pytest.raises(TemplateSyntaxError) as excinfo:
+ i18n_env.from_string(s)
+ assert "saw `wibble`" in str(excinfo.value)
+
class TestScope:
def test_basic_scope_behavior(self):
diff --git a/contrib/python/Jinja2/py3/tests/test_filters.py b/contrib/python/Jinja2/py3/tests/test_filters.py
index 73f0f0be3c..f50ed13ab5 100644
--- a/contrib/python/Jinja2/py3/tests/test_filters.py
+++ b/contrib/python/Jinja2/py3/tests/test_filters.py
@@ -474,6 +474,12 @@ class TestFilter:
assert 'bar="23"' in out
assert 'blub:blub="&lt;?&gt;"' in out
+ def test_xmlattr_key_with_spaces(self, env):
+ with pytest.raises(ValueError, match="Spaces are not allowed"):
+ env.from_string(
+ "{{ {'src=1 onerror=alert(1)': 'my_class'}|xmlattr }}"
+ ).render()
+
def test_sort1(self, env):
tmpl = env.from_string("{{ [2, 3, 1]|sort }}|{{ [2, 3, 1]|sort(true) }}")
assert tmpl.render() == "[1, 2, 3]|[3, 2, 1]"
@@ -870,4 +876,6 @@ class TestFilter:
with pytest.raises(TemplateRuntimeError, match="No filter named 'f'"):
t1.render(x=42)
+
+ with pytest.raises(TemplateRuntimeError, match="No filter named 'f'"):
t2.render(x=42)
diff --git a/contrib/python/Jinja2/py3/tests/test_inheritance.py b/contrib/python/Jinja2/py3/tests/test_inheritance.py
index 0c20d4da7d..0a525e7ac9 100644
--- a/contrib/python/Jinja2/py3/tests/test_inheritance.py
+++ b/contrib/python/Jinja2/py3/tests/test_inheritance.py
@@ -287,26 +287,34 @@ class TestInheritance:
env = Environment(
loader=DictLoader(
{
- "default": "{% block x required %}data {# #}{% endblock %}",
- "default1": "{% block x required %}{% block y %}"
- "{% endblock %} {% endblock %}",
- "default2": "{% block x required %}{% if true %}"
- "{% endif %} {% endblock %}",
- "level1": "{% if default %}{% extends default %}"
- "{% else %}{% extends 'default' %}{% endif %}"
- "{%- block x %}CHILD{% endblock %}",
+ "empty": "{% block x required %}{% endblock %}",
+ "blank": "{% block x required %} {# c #}{% endblock %}",
+ "text": "{% block x required %}data {# c #}{% endblock %}",
+ "block": "{% block x required %}{% block y %}"
+ "{% endblock %}{% endblock %}",
+ "if": "{% block x required %}{% if true %}"
+ "{% endif %}{% endblock %}",
+ "top": "{% extends t %}{% block x %}CHILD{% endblock %}",
}
)
)
- t = env.get_template("level1")
+ t = env.get_template("top")
+ assert t.render(t="empty") == "CHILD"
+ assert t.render(t="blank") == "CHILD"
- with pytest.raises(
+ required_block_check = pytest.raises(
TemplateSyntaxError,
match="Required blocks can only contain comments or whitespace",
- ):
- assert t.render(default="default")
- assert t.render(default="default2")
- assert t.render(default="default3")
+ )
+
+ with required_block_check:
+ t.render(t="text")
+
+ with required_block_check:
+ t.render(t="block")
+
+ with required_block_check:
+ t.render(t="if")
def test_required_with_scope(self, env):
env = Environment(
@@ -347,8 +355,11 @@ class TestInheritance:
)
)
tmpl = env.get_template("child")
+
with pytest.raises(TemplateSyntaxError):
tmpl.render(default="default1", seq=list(range(3)))
+
+ with pytest.raises(TemplateSyntaxError):
tmpl.render(default="default2", seq=list(range(3)))
diff --git a/contrib/python/Jinja2/py3/tests/test_loader.py b/contrib/python/Jinja2/py3/tests/test_loader.py
index a396e18fec..d3b4ddf1ba 100644
--- a/contrib/python/Jinja2/py3/tests/test_loader.py
+++ b/contrib/python/Jinja2/py3/tests/test_loader.py
@@ -186,6 +186,7 @@ class TestFileSystemLoader:
class TestModuleLoader:
archive = None
+ mod_env = None
def compile_down(self, prefix_loader, zip="deflated"):
log = []
@@ -199,13 +200,14 @@ class TestModuleLoader:
self.mod_env = Environment(loader=loaders.ModuleLoader(self.archive))
return "".join(log)
- def teardown(self):
- if hasattr(self, "mod_env"):
+ def teardown_method(self):
+ if self.archive is not None:
if os.path.isfile(self.archive):
os.remove(self.archive)
else:
shutil.rmtree(self.archive)
self.archive = None
+ self.mod_env = None
def test_log(self, prefix_loader):
log = self.compile_down(prefix_loader)
diff --git a/contrib/python/Jinja2/py3/ya.make b/contrib/python/Jinja2/py3/ya.make
index 67ba20df0c..2c15cb57d4 100644
--- a/contrib/python/Jinja2/py3/ya.make
+++ b/contrib/python/Jinja2/py3/ya.make
@@ -2,7 +2,7 @@
PY3_LIBRARY()
-VERSION(3.1.2)
+VERSION(3.1.3)
LICENSE(BSD-3-Clause)
diff --git a/contrib/python/fonttools/.dist-info/METADATA b/contrib/python/fonttools/.dist-info/METADATA
index f156c42697..f9e01c388f 100644
--- a/contrib/python/fonttools/.dist-info/METADATA
+++ b/contrib/python/fonttools/.dist-info/METADATA
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: fonttools
-Version: 4.47.0
+Version: 4.47.2
Summary: Tools to manipulate font files
Home-page: http://github.com/fonttools/fonttools
Author: Just van Rossum
@@ -375,6 +375,18 @@ Have fun!
Changelog
~~~~~~~~~
+4.47.2 (released 2024-01-11)
+----------------------------
+
+Minor release to fix uploading wheels to PyPI.
+
+4.47.1 (released 2024-01-11)
+----------------------------
+
+- [merge] Improve help message and add standard command line options (#3408)
+- [otlLib] Pass ``ttFont`` to ``name.addName`` in ``buildStatTable`` (#3406)
+- [featureVars] Re-use ``FeatureVariationRecord``'s when possible (#3413)
+
4.47.0 (released 2023-12-18)
----------------------------
diff --git a/contrib/python/fonttools/fontTools/__init__.py b/contrib/python/fonttools/fontTools/__init__.py
index 6c00e567a4..7410d3c7fe 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.47.0"
+version = __version__ = "4.47.2"
__all__ = ["version", "log", "configLogger"]
diff --git a/contrib/python/fonttools/fontTools/merge/__init__.py b/contrib/python/fonttools/fontTools/merge/__init__.py
index 8d8a5213e8..7653e4a079 100644
--- a/contrib/python/fonttools/fontTools/merge/__init__.py
+++ b/contrib/python/fonttools/fontTools/merge/__init__.py
@@ -139,6 +139,7 @@ class Merger(object):
*(vars(table).keys() for table in tables if table is not NotImplemented),
)
for key in allKeys:
+ log.info(" %s", key)
try:
mergeLogic = logic[key]
except KeyError:
@@ -181,17 +182,50 @@ def main(args=None):
args = sys.argv[1:]
options = Options()
- args = options.parse_opts(args, ignore_unknown=["output-file"])
- outfile = "merged.ttf"
+ args = options.parse_opts(args)
fontfiles = []
+ if options.input_file:
+ with open(options.input_file) as inputfile:
+ fontfiles = [
+ line.strip()
+ for line in inputfile.readlines()
+ if not line.lstrip().startswith("#")
+ ]
for g in args:
- if g.startswith("--output-file="):
- outfile = g[14:]
- continue
fontfiles.append(g)
- if len(args) < 1:
- print("usage: pyftmerge font...", file=sys.stderr)
+ if len(fontfiles) < 1:
+ print(
+ "usage: pyftmerge [font1 ... fontN] [--input-file=filelist.txt] [--output-file=merged.ttf] [--import-file=tables.ttx]",
+ file=sys.stderr,
+ )
+ print(
+ " [--drop-tables=tags] [--verbose] [--timing]",
+ file=sys.stderr,
+ )
+ print("", file=sys.stderr)
+ print(" font1 ... fontN Files to merge.", file=sys.stderr)
+ print(
+ " --input-file=<filename> Read files to merge from a text file, each path new line. # Comment lines allowed.",
+ file=sys.stderr,
+ )
+ print(
+ " --output-file=<filename> Specify output file name (default: merged.ttf).",
+ file=sys.stderr,
+ )
+ print(
+ " --import-file=<filename> TTX file to import after merging. This can be used to set metadata.",
+ file=sys.stderr,
+ )
+ print(
+ " --drop-tables=<table tags> Comma separated list of table tags to skip, case sensitive.",
+ file=sys.stderr,
+ )
+ print(
+ " --verbose Output progress information.",
+ file=sys.stderr,
+ )
+ print(" --timing Output progress timing.", file=sys.stderr)
return 1
configLogger(level=logging.INFO if options.verbose else logging.WARNING)
@@ -202,8 +236,12 @@ def main(args=None):
merger = Merger(options=options)
font = merger.merge(fontfiles)
+
+ if options.import_file:
+ font.importXML(options.import_file)
+
with timer("compile and save font"):
- font.save(outfile)
+ font.save(options.output_file)
if __name__ == "__main__":
diff --git a/contrib/python/fonttools/fontTools/merge/options.py b/contrib/python/fonttools/fontTools/merge/options.py
index f134009368..8bc8947138 100644
--- a/contrib/python/fonttools/fontTools/merge/options.py
+++ b/contrib/python/fonttools/fontTools/merge/options.py
@@ -11,6 +11,9 @@ class Options(object):
self.verbose = False
self.timing = False
self.drop_tables = []
+ self.input_file = None
+ self.output_file = "merged.ttf"
+ self.import_file = None
self.set(**kwargs)
diff --git a/contrib/python/fonttools/fontTools/otlLib/builder.py b/contrib/python/fonttools/fontTools/otlLib/builder.py
index 3508a7e28d..4b457f4d9f 100644
--- a/contrib/python/fonttools/fontTools/otlLib/builder.py
+++ b/contrib/python/fonttools/fontTools/otlLib/builder.py
@@ -2781,14 +2781,13 @@ def buildStatTable(
"""
ttFont["STAT"] = ttLib.newTable("STAT")
statTable = ttFont["STAT"].table = ot.STAT()
- nameTable = ttFont["name"]
statTable.ElidedFallbackNameID = _addName(
- nameTable, elidedFallbackName, windows=windowsNames, mac=macNames
+ ttFont, elidedFallbackName, windows=windowsNames, mac=macNames
)
# 'locations' contains data for AxisValue Format 4
axisRecords, axisValues = _buildAxisRecords(
- axes, nameTable, windowsNames=windowsNames, macNames=macNames
+ axes, ttFont, windowsNames=windowsNames, macNames=macNames
)
if not locations:
statTable.Version = 0x00010001
@@ -2797,10 +2796,10 @@ def buildStatTable(
# requires a higher table version
statTable.Version = 0x00010002
multiAxisValues = _buildAxisValuesFormat4(
- locations, axes, nameTable, windowsNames=windowsNames, macNames=macNames
+ locations, axes, ttFont, windowsNames=windowsNames, macNames=macNames
)
axisValues = multiAxisValues + axisValues
- nameTable.names.sort()
+ ttFont["name"].names.sort()
# Store AxisRecords
axisRecordArray = ot.AxisRecordArray()
@@ -2820,14 +2819,14 @@ def buildStatTable(
statTable.AxisValueCount = len(axisValues)
-def _buildAxisRecords(axes, nameTable, windowsNames=True, macNames=True):
+def _buildAxisRecords(axes, ttFont, windowsNames=True, macNames=True):
axisRecords = []
axisValues = []
for axisRecordIndex, axisDict in enumerate(axes):
axis = ot.AxisRecord()
axis.AxisTag = axisDict["tag"]
axis.AxisNameID = _addName(
- nameTable, axisDict["name"], 256, windows=windowsNames, mac=macNames
+ ttFont, axisDict["name"], 256, windows=windowsNames, mac=macNames
)
axis.AxisOrdering = axisDict.get("ordering", axisRecordIndex)
axisRecords.append(axis)
@@ -2837,7 +2836,7 @@ def _buildAxisRecords(axes, nameTable, windowsNames=True, macNames=True):
axisValRec.AxisIndex = axisRecordIndex
axisValRec.Flags = axisVal.get("flags", 0)
axisValRec.ValueNameID = _addName(
- nameTable, axisVal["name"], windows=windowsNames, mac=macNames
+ ttFont, axisVal["name"], windows=windowsNames, mac=macNames
)
if "value" in axisVal:
@@ -2863,9 +2862,7 @@ def _buildAxisRecords(axes, nameTable, windowsNames=True, macNames=True):
return axisRecords, axisValues
-def _buildAxisValuesFormat4(
- locations, axes, nameTable, windowsNames=True, macNames=True
-):
+def _buildAxisValuesFormat4(locations, axes, ttFont, windowsNames=True, macNames=True):
axisTagToIndex = {}
for axisRecordIndex, axisDict in enumerate(axes):
axisTagToIndex[axisDict["tag"]] = axisRecordIndex
@@ -2875,7 +2872,7 @@ def _buildAxisValuesFormat4(
axisValRec = ot.AxisValue()
axisValRec.Format = 4
axisValRec.ValueNameID = _addName(
- nameTable, axisLocationDict["name"], windows=windowsNames, mac=macNames
+ ttFont, axisLocationDict["name"], windows=windowsNames, mac=macNames
)
axisValRec.Flags = axisLocationDict.get("flags", 0)
axisValueRecords = []
@@ -2891,7 +2888,8 @@ def _buildAxisValuesFormat4(
return axisValues
-def _addName(nameTable, value, minNameID=0, windows=True, mac=True):
+def _addName(ttFont, value, minNameID=0, windows=True, mac=True):
+ nameTable = ttFont["name"]
if isinstance(value, int):
# Already a nameID
return value
@@ -2916,5 +2914,5 @@ def _addName(nameTable, value, minNameID=0, windows=True, mac=True):
else:
raise TypeError("value must be int, str, dict or list")
return nameTable.addMultilingualName(
- names, windows=windows, mac=mac, minNameID=minNameID
+ names, ttFont=ttFont, windows=windows, mac=mac, minNameID=minNameID
)
diff --git a/contrib/python/fonttools/fontTools/varLib/featureVars.py b/contrib/python/fonttools/fontTools/varLib/featureVars.py
index a6beb5c7d2..828b843594 100644
--- a/contrib/python/fonttools/fontTools/varLib/featureVars.py
+++ b/contrib/python/fonttools/fontTools/varLib/featureVars.py
@@ -414,6 +414,10 @@ def addFeatureVariationsRaw(font, table, conditionalSubstitutions, featureTag="r
axis.axisTag: axisIndex for axisIndex, axis in enumerate(font["fvar"].axes)
}
+ hasFeatureVariations = (
+ hasattr(table, "FeatureVariations") and table.FeatureVariations is not None
+ )
+
featureVariationRecords = []
for conditionSet, lookupIndices in conditionalSubstitutions:
conditionTable = []
@@ -440,11 +444,19 @@ def addFeatureVariationsRaw(font, table, conditionalSubstitutions, featureTag="r
varFeatureIndex, combinedLookupIndices
)
)
- featureVariationRecords.append(
- buildFeatureVariationRecord(conditionTable, records)
- )
+ if hasFeatureVariations and (
+ fvr := findFeatureVariationRecord(table.FeatureVariations, conditionTable)
+ ):
+ fvr.FeatureTableSubstitution.SubstitutionRecord.extend(records)
+ fvr.FeatureTableSubstitution.SubstitutionCount = len(
+ fvr.FeatureTableSubstitution.SubstitutionRecord
+ )
+ else:
+ featureVariationRecords.append(
+ buildFeatureVariationRecord(conditionTable, records)
+ )
- if hasattr(table, "FeatureVariations") and table.FeatureVariations is not None:
+ if hasFeatureVariations:
if table.FeatureVariations.Version != 0x00010000:
raise VarLibError(
"Unsupported FeatureVariations table version: "
@@ -614,6 +626,21 @@ def buildConditionTable(axisIndex, filterRangeMinValue, filterRangeMaxValue):
return ct
+def findFeatureVariationRecord(featureVariations, conditionTable):
+ """Find a FeatureVariationRecord that has the same conditionTable."""
+ if featureVariations.Version != 0x00010000:
+ raise VarLibError(
+ "Unsupported FeatureVariations table version: "
+ f"0x{featureVariations.Version:08x} (expected 0x00010000)."
+ )
+
+ for fvr in featureVariations.FeatureVariationRecord:
+ if conditionTable == fvr.ConditionSet.ConditionTable:
+ return fvr
+
+ return None
+
+
def sortFeatureList(table):
"""Sort the feature list by feature tag, and remap the feature indices
elsewhere. This is needed after the feature list has been modified.
diff --git a/contrib/python/fonttools/fontTools/varLib/interpolatable.py b/contrib/python/fonttools/fontTools/varLib/interpolatable.py
index 0a9bbebc41..5fc12e04c9 100644
--- a/contrib/python/fonttools/fontTools/varLib/interpolatable.py
+++ b/contrib/python/fonttools/fontTools/varLib/interpolatable.py
@@ -376,9 +376,6 @@ def test_gen(
size1 = m1Vec[0] * m1Vec[0]
midSize = midVector[0] * midVector[0]
- power = 1
- t = tolerance**power
-
for overweight, problem_type in enumerate(
(
InterpolatableProblem.UNDERWEIGHT,
@@ -386,8 +383,7 @@ def test_gen(
)
):
if overweight:
- expectedSize = sqrt(size0 * size1)
- expectedSize = (size0 + size1) - expectedSize
+ expectedSize = max(size0, size1)
continue
else:
expectedSize = sqrt(size0 * size1)
@@ -406,13 +402,9 @@ def test_gen(
) or (overweight and 1e-5 + expectedSize / tolerance < midSize):
try:
if overweight:
- this_tolerance = (expectedSize / midSize) ** (
- 1 / power
- )
+ this_tolerance = expectedSize / midSize
else:
- this_tolerance = (midSize / expectedSize) ** (
- 1 / power
- )
+ this_tolerance = midSize / expectedSize
except ZeroDivisionError:
this_tolerance = 0
log.debug("tolerance %g", this_tolerance)
diff --git a/contrib/python/fonttools/ya.make b/contrib/python/fonttools/ya.make
index 6e76c94da1..4d380b556c 100644
--- a/contrib/python/fonttools/ya.make
+++ b/contrib/python/fonttools/ya.make
@@ -2,7 +2,7 @@
PY3_LIBRARY()
-VERSION(4.47.0)
+VERSION(4.47.2)
LICENSE(MIT)
diff --git a/contrib/python/google-auth/py3/.dist-info/METADATA b/contrib/python/google-auth/py3/.dist-info/METADATA
index 21345a0555..2820e8856d 100644
--- a/contrib/python/google-auth/py3/.dist-info/METADATA
+++ b/contrib/python/google-auth/py3/.dist-info/METADATA
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: google-auth
-Version: 2.26.1
+Version: 2.26.2
Summary: Google Authentication Library
Home-page: https://github.com/googleapis/google-auth-library-python
Author: Google Cloud Platform
diff --git a/contrib/python/google-auth/py3/google/auth/external_account_authorized_user.py b/contrib/python/google-auth/py3/google/auth/external_account_authorized_user.py
index 55230103f4..526588f7e8 100644
--- a/contrib/python/google-auth/py3/google/auth/external_account_authorized_user.py
+++ b/contrib/python/google-auth/py3/google/auth/external_account_authorized_user.py
@@ -342,6 +342,7 @@ class Credentials(
revoke_url=info.get("revoke_url"),
quota_project_id=info.get("quota_project_id"),
scopes=info.get("scopes"),
+ universe_domain=info.get("universe_domain", _DEFAULT_UNIVERSE_DOMAIN),
**kwargs
)
diff --git a/contrib/python/google-auth/py3/google/auth/version.py b/contrib/python/google-auth/py3/google/auth/version.py
index 1c94c2f5f6..6d53c4c411 100644
--- a/contrib/python/google-auth/py3/google/auth/version.py
+++ b/contrib/python/google-auth/py3/google/auth/version.py
@@ -12,4 +12,4 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-__version__ = "2.26.1"
+__version__ = "2.26.2"
diff --git a/contrib/python/google-auth/py3/tests/data/external_account_authorized_user_non_gdu.json b/contrib/python/google-auth/py3/tests/data/external_account_authorized_user_non_gdu.json
new file mode 100644
index 0000000000..b82854c743
--- /dev/null
+++ b/contrib/python/google-auth/py3/tests/data/external_account_authorized_user_non_gdu.json
@@ -0,0 +1,10 @@
+{
+ "type": "external_account_authorized_user",
+ "audience": "//iam.fake_universe_domain/locations/global/workforcePools/$WORKFORCE_POOL_ID/providers/$PROVIDER_ID",
+ "refresh_token": "refreshToken",
+ "token_url": "https://sts.fake_universe_domain/v1/oauth/token",
+ "token_info_url": "https://sts.fake_universe_domain/v1/instrospect",
+ "client_id": "clientId",
+ "client_secret": "clientSecret",
+ "universe_domain": "fake_universe_domain"
+}
diff --git a/contrib/python/google-auth/py3/tests/test__default.py b/contrib/python/google-auth/py3/tests/test__default.py
index d619614790..aaf892f6d0 100644
--- a/contrib/python/google-auth/py3/tests/test__default.py
+++ b/contrib/python/google-auth/py3/tests/test__default.py
@@ -158,6 +158,10 @@ EXTERNAL_ACCOUNT_AUTHORIZED_USER_FILE = os.path.join(
DATA_DIR, "external_account_authorized_user.json"
)
+EXTERNAL_ACCOUNT_AUTHORIZED_USER_NON_GDU_FILE = os.path.join(
+ DATA_DIR, "external_account_authorized_user_non_gdu.json"
+)
+
MOCK_CREDENTIALS = mock.Mock(spec=credentials.CredentialsWithQuotaProject)
MOCK_CREDENTIALS.with_quota_project.return_value = MOCK_CREDENTIALS
@@ -577,6 +581,15 @@ def test_load_credentials_from_file_external_account_authorized_user():
assert project_id is None
+def test_load_credentials_from_file_external_account_authorized_user_non_gdu():
+ credentials, _ = _default.load_credentials_from_file(
+ EXTERNAL_ACCOUNT_AUTHORIZED_USER_NON_GDU_FILE, request=mock.sentinel.request
+ )
+
+ assert isinstance(credentials, external_account_authorized_user.Credentials)
+ assert credentials.universe_domain == "fake_universe_domain"
+
+
def test_load_credentials_from_file_external_account_authorized_user_bad_format(tmpdir):
filename = tmpdir.join("external_account_authorized_user_bad.json")
filename.write(json.dumps({"type": "external_account_authorized_user"}))
diff --git a/contrib/python/google-auth/py3/ya.make b/contrib/python/google-auth/py3/ya.make
index 75848da971..976b926bff 100644
--- a/contrib/python/google-auth/py3/ya.make
+++ b/contrib/python/google-auth/py3/ya.make
@@ -2,7 +2,7 @@
PY3_LIBRARY()
-VERSION(2.26.1)
+VERSION(2.26.2)
LICENSE(Apache-2.0)
diff --git a/contrib/python/hypothesis/py3/.dist-info/METADATA b/contrib/python/hypothesis/py3/.dist-info/METADATA
index 15385afbc9..b4f00cf430 100644
--- a/contrib/python/hypothesis/py3/.dist-info/METADATA
+++ b/contrib/python/hypothesis/py3/.dist-info/METADATA
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: hypothesis
-Version: 6.92.6
+Version: 6.92.8
Summary: A library for property-based testing
Home-page: https://hypothesis.works
Author: David R. MacIver and Zac Hatfield-Dodds
diff --git a/contrib/python/hypothesis/py3/hypothesis/control.py b/contrib/python/hypothesis/py3/hypothesis/control.py
index c49dba2954..3a973f666f 100644
--- a/contrib/python/hypothesis/py3/hypothesis/control.py
+++ b/contrib/python/hypothesis/py3/hypothesis/control.py
@@ -8,6 +8,7 @@
# v. 2.0. If a copy of the MPL was not distributed with this file, You can
# obtain one at https://mozilla.org/MPL/2.0/.
+import inspect
import math
from collections import defaultdict
from typing import NoReturn, Union
@@ -25,6 +26,10 @@ from hypothesis.utils.dynamicvariables import DynamicVariable
from hypothesis.vendor.pretty import IDKey
+def _calling_function_name(frame):
+ return frame.f_back.f_code.co_name
+
+
def reject() -> NoReturn:
if _current_build_context.value is None:
note_deprecation(
@@ -32,7 +37,8 @@ def reject() -> NoReturn:
since="2023-09-25",
has_codemod=False,
)
- raise UnsatisfiedAssumption
+ f = _calling_function_name(inspect.currentframe())
+ raise UnsatisfiedAssumption(f"reject() in {f}")
def assume(condition: object) -> bool:
@@ -49,7 +55,8 @@ def assume(condition: object) -> bool:
has_codemod=False,
)
if not condition:
- raise UnsatisfiedAssumption
+ f = _calling_function_name(inspect.currentframe())
+ raise UnsatisfiedAssumption(f"failed to satisfy assume() in {f}")
return True
diff --git a/contrib/python/hypothesis/py3/hypothesis/core.py b/contrib/python/hypothesis/py3/hypothesis/core.py
index 7c149d1222..86b20ea6f9 100644
--- a/contrib/python/hypothesis/py3/hypothesis/core.py
+++ b/contrib/python/hypothesis/py3/hypothesis/core.py
@@ -1005,10 +1005,10 @@ class StateForActualGivenExecution:
f"{self.test.__name__} returned {result!r} instead.",
HealthCheck.return_value,
)
- except UnsatisfiedAssumption:
+ except UnsatisfiedAssumption as e:
# An "assume" check failed, so instead we inform the engine that
# this test run was invalid.
- data.mark_invalid()
+ data.mark_invalid(e.reason)
except StopTest:
# The engine knows how to handle this control exception, so it's
# OK to re-raise it.
diff --git a/contrib/python/hypothesis/py3/hypothesis/errors.py b/contrib/python/hypothesis/py3/hypothesis/errors.py
index 9ee81cfc36..8387a87586 100644
--- a/contrib/python/hypothesis/py3/hypothesis/errors.py
+++ b/contrib/python/hypothesis/py3/hypothesis/errors.py
@@ -23,6 +23,9 @@ class UnsatisfiedAssumption(HypothesisException):
If you're seeing this error something has gone wrong.
"""
+ def __init__(self, reason=None):
+ self.reason = reason
+
class NoSuchExample(HypothesisException):
"""The condition we have been asked to satisfy appears to be always false.
diff --git a/contrib/python/hypothesis/py3/hypothesis/internal/filtering.py b/contrib/python/hypothesis/py3/hypothesis/internal/filtering.py
index 8af37e453b..4ba92b1da8 100644
--- a/contrib/python/hypothesis/py3/hypothesis/internal/filtering.py
+++ b/contrib/python/hypothesis/py3/hypothesis/internal/filtering.py
@@ -73,6 +73,14 @@ def convert(node: ast.AST, argname: str) -> object:
if node.id != argname:
raise ValueError("Non-local variable")
return ARG
+ if isinstance(node, ast.Call):
+ if (
+ isinstance(node.func, ast.Name)
+ and node.func.id == "len"
+ and len(node.args) == 1
+ ):
+ # error unless comparison is to the len *of the lambda arg*
+ return convert(node.args[0], argname)
return ast.literal_eval(node)
@@ -86,26 +94,28 @@ def comp_to_kwargs(x: ast.AST, op: ast.AST, y: ast.AST, *, argname: str) -> dict
# (and we can't even do `arg == arg`, because what if it's NaN?)
raise ValueError("Can't analyse this comparison")
+ of_len = {"len": True} if isinstance(x, ast.Call) or isinstance(y, ast.Call) else {}
+
if isinstance(op, ast.Lt):
if a is ARG:
- return {"max_value": b, "exclude_max": True}
- return {"min_value": a, "exclude_min": True}
+ return {"max_value": b, "exclude_max": True, **of_len}
+ return {"min_value": a, "exclude_min": True, **of_len}
elif isinstance(op, ast.LtE):
if a is ARG:
- return {"max_value": b}
- return {"min_value": a}
+ return {"max_value": b, **of_len}
+ return {"min_value": a, **of_len}
elif isinstance(op, ast.Eq):
if a is ARG:
- return {"min_value": b, "max_value": b}
- return {"min_value": a, "max_value": a}
+ return {"min_value": b, "max_value": b, **of_len}
+ return {"min_value": a, "max_value": a, **of_len}
elif isinstance(op, ast.GtE):
if a is ARG:
- return {"min_value": b}
- return {"max_value": a}
+ return {"min_value": b, **of_len}
+ return {"max_value": a, **of_len}
elif isinstance(op, ast.Gt):
if a is ARG:
- return {"min_value": b, "exclude_min": True}
- return {"max_value": a, "exclude_max": True}
+ return {"min_value": b, "exclude_min": True, **of_len}
+ return {"max_value": a, "exclude_max": True, **of_len}
raise ValueError("Unhandled comparison operator") # e.g. ast.Ne
@@ -120,6 +130,9 @@ def merge_preds(*con_predicates: ConstructivePredicate) -> ConstructivePredicate
}
predicate = None
for kw, p in con_predicates:
+ assert (
+ not p or not predicate or p is predicate
+ ), "Can't merge two partially-constructive preds"
predicate = p or predicate
if "min_value" in kw:
if kw["min_value"] > base["min_value"]:
@@ -134,6 +147,11 @@ def merge_preds(*con_predicates: ConstructivePredicate) -> ConstructivePredicate
elif kw["max_value"] == base["max_value"]:
base["exclude_max"] |= kw.get("exclude_max", False)
+ has_len = {"len" in kw for kw, _ in con_predicates}
+ assert len(has_len) == 1, "can't mix numeric with length constraints"
+ if has_len == {True}:
+ base["len"] = True
+
if not base["exclude_min"]:
del base["exclude_min"]
if base["min_value"] == -math.inf:
@@ -154,6 +172,8 @@ def numeric_bounds_from_ast(
{"min_value": 0}, None
>>> lambda x: x < 10
{"max_value": 10, "exclude_max": True}, None
+ >>> lambda x: len(x) >= 5
+ {"min_value": 5, "len": True}, None
>>> lambda x: x >= y
{}, lambda x: x >= y
@@ -169,7 +189,10 @@ def numeric_bounds_from_ast(
for comp in comparisons:
try:
kwargs = comp_to_kwargs(*comp, argname=argname)
- bounds.append(ConstructivePredicate(kwargs, None))
+ # Because `len` could be redefined in the enclosing scope, we *always*
+ # have to apply the condition as a filter, in addition to rewriting.
+ pred = fallback.predicate if "len" in kwargs else None
+ bounds.append(ConstructivePredicate(kwargs, pred))
except ValueError:
bounds.append(fallback)
return merge_preds(*bounds)
@@ -209,6 +232,9 @@ def get_numeric_predicate_bounds(predicate: Predicate) -> ConstructivePredicate:
operator.eq: {"min_value": arg, "max_value": arg}, # lambda x: arg == x
operator.ge: {"max_value": arg}, # lambda x: arg >= x
operator.gt: {"max_value": arg, "exclude_max": True}, # lambda x: arg > x
+ # Special-case our default predicates for length bounds
+ min_len: {"min_value": arg, "len": True},
+ max_len: {"max_value": arg, "len": True},
}
if predicate.func in options:
return ConstructivePredicate(options[predicate.func], None)
@@ -270,7 +296,8 @@ def get_integer_predicate_bounds(predicate: Predicate) -> ConstructivePredicate:
elif kwargs.get("exclude_max", False):
kwargs["max_value"] = int(kwargs["max_value"]) - 1
- kwargs = {k: v for k, v in kwargs.items() if k in {"min_value", "max_value"}}
+ kw_categories = {"min_value", "max_value", "len"}
+ kwargs = {k: v for k, v in kwargs.items() if k in kw_categories}
return ConstructivePredicate(kwargs, predicate)
diff --git a/contrib/python/hypothesis/py3/hypothesis/internal/reflection.py b/contrib/python/hypothesis/py3/hypothesis/internal/reflection.py
index 2f0480c987..d5ea7161f3 100644
--- a/contrib/python/hypothesis/py3/hypothesis/internal/reflection.py
+++ b/contrib/python/hypothesis/py3/hypothesis/internal/reflection.py
@@ -19,7 +19,7 @@ import re
import sys
import textwrap
import types
-from functools import wraps
+from functools import partial, wraps
from io import StringIO
from keyword import iskeyword
from tokenize import COMMENT, detect_encoding, generate_tokens, untokenize
@@ -432,6 +432,8 @@ def extract_lambda_source(f):
def get_pretty_function_description(f):
+ if isinstance(f, partial):
+ return pretty(f)
if not hasattr(f, "__name__"):
return repr(f)
name = f.__name__
diff --git a/contrib/python/hypothesis/py3/hypothesis/strategies/_internal/collections.py b/contrib/python/hypothesis/py3/hypothesis/strategies/_internal/collections.py
index 2bee499ac2..1f86f37a42 100644
--- a/contrib/python/hypothesis/py3/hypothesis/strategies/_internal/collections.py
+++ b/contrib/python/hypothesis/py3/hypothesis/strategies/_internal/collections.py
@@ -15,6 +15,7 @@ from hypothesis.errors import InvalidArgument
from hypothesis.internal.conjecture import utils as cu
from hypothesis.internal.conjecture.junkdrawer import LazySequenceCopy
from hypothesis.internal.conjecture.utils import combine_labels
+from hypothesis.internal.filtering import get_integer_predicate_bounds
from hypothesis.internal.reflection import is_identity_function
from hypothesis.strategies._internal.strategies import (
T3,
@@ -199,7 +200,22 @@ class ListStrategy(SearchStrategy):
new = copy.copy(self)
new.min_size = 1
return new
- return super().filter(condition)
+
+ kwargs, pred = get_integer_predicate_bounds(condition)
+ if kwargs.get("len") and ("min_value" in kwargs or "max_value" in kwargs):
+ new = copy.copy(self)
+ new.min_size = max(self.min_size, kwargs.get("min_value", self.min_size))
+ new.max_size = min(self.max_size, kwargs.get("max_value", self.max_size))
+ # Recompute average size; this is cheaper than making it into a property.
+ new.average_size = min(
+ max(new.min_size * 2, new.min_size + 5),
+ 0.5 * (new.min_size + new.max_size),
+ )
+ if pred is None:
+ return new
+ return SearchStrategy.filter(new, condition)
+
+ return SearchStrategy.filter(self, condition)
class UniqueListStrategy(ListStrategy):
diff --git a/contrib/python/hypothesis/py3/hypothesis/version.py b/contrib/python/hypothesis/py3/hypothesis/version.py
index 382bffeb8b..ef8fe6a63a 100644
--- a/contrib/python/hypothesis/py3/hypothesis/version.py
+++ b/contrib/python/hypothesis/py3/hypothesis/version.py
@@ -8,5 +8,5 @@
# v. 2.0. If a copy of the MPL was not distributed with this file, You can
# obtain one at https://mozilla.org/MPL/2.0/.
-__version_info__ = (6, 92, 6)
+__version_info__ = (6, 92, 8)
__version__ = ".".join(map(str, __version_info__))
diff --git a/contrib/python/hypothesis/py3/ya.make b/contrib/python/hypothesis/py3/ya.make
index 2a6ae3478d..92b1d0c734 100644
--- a/contrib/python/hypothesis/py3/ya.make
+++ b/contrib/python/hypothesis/py3/ya.make
@@ -2,7 +2,7 @@
PY3_LIBRARY()
-VERSION(6.92.6)
+VERSION(6.92.8)
LICENSE(MPL-2.0)
diff --git a/contrib/python/ydb/py3/.dist-info/METADATA b/contrib/python/ydb/py3/.dist-info/METADATA
index 058eb80b41..675a1d8825 100644
--- a/contrib/python/ydb/py3/.dist-info/METADATA
+++ b/contrib/python/ydb/py3/.dist-info/METADATA
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: ydb
-Version: 3.7.0
+Version: 3.8.0
Summary: YDB Python SDK
Home-page: http://github.com/ydb-platform/ydb-python-sdk
Author: Yandex LLC
diff --git a/contrib/python/ydb/py3/ya.make b/contrib/python/ydb/py3/ya.make
index f92572fa82..484d68aafd 100644
--- a/contrib/python/ydb/py3/ya.make
+++ b/contrib/python/ydb/py3/ya.make
@@ -2,7 +2,7 @@
PY3_LIBRARY()
-VERSION(3.7.0)
+VERSION(3.8.0)
LICENSE(Apache-2.0)
@@ -66,6 +66,8 @@ PY_SRCS(
ydb/dbapi/cursor.py
ydb/dbapi/errors.py
ydb/default_pem.py
+ ydb/draft/__init__.py
+ ydb/draft/dynamic_config.py
ydb/driver.py
ydb/export.py
ydb/global_settings.py
diff --git a/contrib/python/ydb/py3/ydb/__init__.py b/contrib/python/ydb/py3/ydb/__init__.py
index 902b1e0850..8bfba3a902 100644
--- a/contrib/python/ydb/py3/ydb/__init__.py
+++ b/contrib/python/ydb/py3/ydb/__init__.py
@@ -18,6 +18,7 @@ from .scripting import * # noqa
from .import_client import * # noqa
from .tracing import * # noqa
from .topic import * # noqa
+from .draft import * # noqa
try:
import ydb.aio as aio # noqa
diff --git a/contrib/python/ydb/py3/ydb/_apis.py b/contrib/python/ydb/py3/ydb/_apis.py
index 924e14c1b6..9ad2a32f21 100644
--- a/contrib/python/ydb/py3/ydb/_apis.py
+++ b/contrib/python/ydb/py3/ydb/_apis.py
@@ -11,6 +11,10 @@ try:
ydb_topic_v1_pb2_grpc,
)
+ from ydb.public.api.grpc.draft import (
+ ydb_dynamic_config_v1_pb2_grpc,
+ )
+
from ydb.public.api.protos import (
ydb_status_codes_pb2,
ydb_discovery_pb2,
@@ -20,6 +24,10 @@ try:
ydb_operation_pb2,
ydb_common_pb2,
)
+
+ from ydb.public.api.protos.draft import (
+ ydb_dynamic_config_pb2,
+ )
except ImportError:
from contrib.ydb.public.api.grpc import (
ydb_cms_v1_pb2_grpc,
@@ -30,6 +38,10 @@ except ImportError:
ydb_topic_v1_pb2_grpc,
)
+ from contrib.ydb.public.api.grpc.draft import (
+ ydb_dynamic_config_v1_pb2_grpc,
+ )
+
from contrib.ydb.public.api.protos import (
ydb_status_codes_pb2,
ydb_discovery_pb2,
@@ -40,6 +52,10 @@ except ImportError:
ydb_common_pb2,
)
+ from contrib.ydb.public.api.protos.draft import (
+ ydb_dynamic_config_pb2,
+ )
+
StatusIds = ydb_status_codes_pb2.StatusIds
FeatureFlag = ydb_common_pb2.FeatureFlag
@@ -49,6 +65,7 @@ ydb_scheme = ydb_scheme_pb2
ydb_table = ydb_table_pb2
ydb_discovery = ydb_discovery_pb2
ydb_operation = ydb_operation_pb2
+ydb_dynamic_config = ydb_dynamic_config_pb2
class CmsService(object):
@@ -108,3 +125,12 @@ class TopicService(object):
DropTopic = "DropTopic"
StreamRead = "StreamRead"
StreamWrite = "StreamWrite"
+
+
+class DynamicConfigService(object):
+ Stub = ydb_dynamic_config_v1_pb2_grpc.DynamicConfigServiceStub
+
+ ReplaceConfig = "ReplaceConfig"
+ SetConfig = "SetConfig"
+ GetConfig = "GetConfig"
+ GetNodeLabels = "GetNodeLabels"
diff --git a/contrib/python/ydb/py3/ydb/draft/__init__.py b/contrib/python/ydb/py3/ydb/draft/__init__.py
new file mode 100644
index 0000000000..c34316f2c2
--- /dev/null
+++ b/contrib/python/ydb/py3/ydb/draft/__init__.py
@@ -0,0 +1 @@
+from .dynamic_config import * # noqa
diff --git a/contrib/python/ydb/py3/ydb/draft/dynamic_config.py b/contrib/python/ydb/py3/ydb/draft/dynamic_config.py
new file mode 100644
index 0000000000..afec19eca7
--- /dev/null
+++ b/contrib/python/ydb/py3/ydb/draft/dynamic_config.py
@@ -0,0 +1,173 @@
+import abc
+from abc import abstractmethod
+from .. import issues, operation, _apis
+
+
+class IDynamicConfigClient(abc.ABC):
+ @abstractmethod
+ def __init__(self, driver):
+ pass
+
+ @abstractmethod
+ def replace_config(self, config, dry_run, allow_unknown_fields, settings):
+ pass
+
+ @abstractmethod
+ def set_config(self, config, dry_run, allow_unknown_fields, settings):
+ pass
+
+ @abstractmethod
+ def get_config(self, settings):
+ pass
+
+ @abstractmethod
+ def get_node_labels(self, node_id, settings):
+ pass
+
+
+class DynamicConfig(object):
+ __slots__ = ("version", "cluster", "config")
+
+ def __init__(self, version, cluster, config, *args, **kwargs):
+ self.version = version
+ self.cluster = cluster
+ self.config = config
+
+
+class NodeLabels(object):
+ __slots__ = "labels"
+
+ def __init__(self, labels, *args, **kwargs):
+ self.labels = labels
+
+
+def _replace_config_request_factory(config, dry_run, allow_unknown_fields):
+ request = _apis.ydb_dynamic_config.ReplaceConfigRequest()
+ request.config = config
+ request.dry_run = dry_run
+ request.allow_unknown_fields = allow_unknown_fields
+ return request
+
+
+def _set_config_request_factory(config, dry_run, allow_unknown_fields):
+ request = _apis.ydb_dynamic_config.SetConfigRequest()
+ request.config = config
+ request.dry_run = dry_run
+ request.allow_unknown_fields = allow_unknown_fields
+ return request
+
+
+def _get_config_request_factory():
+ request = _apis.ydb_dynamic_config.GetConfigRequest()
+ return request
+
+
+def _get_node_labels_request_factory(node_id):
+ request = _apis.ydb_dynamic_config.GetNodeLabelsRequest()
+ request.node_id = node_id
+ return request
+
+
+def _wrap_dynamic_config(config_pb, dynamic_config_cls=None, *args, **kwargs):
+ dynamic_config_cls = DynamicConfig if dynamic_config_cls is None else dynamic_config_cls
+ return dynamic_config_cls(config_pb.identity.version, config_pb.identity.cluster, config_pb.config, *args, **kwargs)
+
+
+def _wrap_get_config_response(rpc_state, response):
+ issues._process_response(response.operation)
+ message = _apis.ydb_dynamic_config.GetConfigResult()
+ response.operation.result.Unpack(message)
+ return _wrap_dynamic_config(message)
+
+
+def _wrap_node_labels(labels_pb, node_labels_cls=None, *args, **kwargs):
+ node_labels_cls = NodeLabels if node_labels_cls is None else node_labels_cls
+ return node_labels_cls(dict([(entry.label, entry.value) for entry in labels_pb.labels]), *args, **kwargs)
+
+
+def _wrap_get_node_labels_response(rpc_state, response):
+ issues._process_response(response.operation)
+ message = _apis.ydb_dynamic_config.GetNodeLabelsResult()
+ response.operation.result.Unpack(message)
+ return _wrap_node_labels(message)
+
+
+class BaseDynamicConfigClient(IDynamicConfigClient):
+ __slots__ = ("_driver",)
+
+ def __init__(self, driver):
+ self._driver = driver
+
+ def replace_config(self, config, dry_run, allow_unknown_fields, settings=None):
+ return self._driver(
+ _replace_config_request_factory(config, dry_run, allow_unknown_fields),
+ _apis.DynamicConfigService.Stub,
+ _apis.DynamicConfigService.ReplaceConfig,
+ operation.Operation,
+ settings,
+ )
+
+ def set_config(self, config, dry_run, allow_unknown_fields, settings=None):
+ return self._driver(
+ _set_config_request_factory(config, dry_run, allow_unknown_fields),
+ _apis.DynamicConfigService.Stub,
+ _apis.DynamicConfigService.SetConfig,
+ operation.Operation,
+ settings,
+ )
+
+ def get_config(self, settings=None):
+ return self._driver(
+ _get_config_request_factory(),
+ _apis.DynamicConfigService.Stub,
+ _apis.DynamicConfigService.GetConfig,
+ _wrap_get_config_response,
+ settings,
+ )
+
+ def get_node_labels(self, node_id, settings=None):
+ return self._driver(
+ _get_node_labels_request_factory(node_id),
+ _apis.DynamicConfigService.Stub,
+ _apis.DynamicConfigService.GetNodeLabels,
+ _wrap_get_node_labels_response,
+ settings,
+ )
+
+
+class DynamicConfigClient(BaseDynamicConfigClient):
+ def async_replace_config(self, config, dry_run, allow_unknown_fields, settings=None):
+ return self._driver.future(
+ _replace_config_request_factory(config, dry_run, allow_unknown_fields),
+ _apis.DynamicConfigService.Stub,
+ _apis.DynamicConfigService.ReplaceConfig,
+ operation.Operation,
+ settings,
+ )
+
+ def async_set_config(self, config, dry_run, allow_unknown_fields, settings=None):
+ return self._driver.future(
+ _set_config_request_factory(config, dry_run, allow_unknown_fields),
+ _apis.DynamicConfigService.Stub,
+ _apis.DynamicConfigService.SetConfig,
+ operation.Operation,
+ settings,
+ )
+
+ def async_get_config(self, settings=None):
+ return self._driver.future(
+ _get_config_request_factory(),
+ _apis.DynamicConfigService.Stub,
+ _apis.DynamicConfigService.GetConfig,
+ _wrap_get_config_response,
+ settings,
+ )
+
+ def async_get_node_labels(self, node_id, settings=None):
+ return self._driver.future(
+ _get_node_labels_request_factory(node_id),
+ _apis.DynamicConfigService.Stub,
+ _apis.DynamicConfigService.GetNodeLabels,
+ _wrap_get_node_labels_response,
+ settings,
+ )
diff --git a/contrib/python/ydb/py3/ydb/ydb_version.py b/contrib/python/ydb/py3/ydb/ydb_version.py
index 709cb0a9e5..8173e1e609 100644
--- a/contrib/python/ydb/py3/ydb/ydb_version.py
+++ b/contrib/python/ydb/py3/ydb/ydb_version.py
@@ -1 +1 @@
-VERSION = "3.7.0"
+VERSION = "3.8.0"