diff options
author | Innokentii Mokin <innokentii@ydb.tech> | 2024-01-27 10:01:54 +0000 |
---|---|---|
committer | Innokentii Mokin <innokentii@ydb.tech> | 2024-01-27 10:01:54 +0000 |
commit | 621e3d86c4e02bf3c88bb68e5aba5856fbf0185d (patch) | |
tree | 2d517d0985015d27ce6862003509de502be44ccc /contrib/python | |
parent | a7dad28338e49d920879eb2b3e728ee6dd166b6e (diff) | |
parent | 00b9982cd019afca788639aa8279f2dc1f342383 (diff) | |
download | ydb-621e3d86c4e02bf3c88bb68e5aba5856fbf0185d.tar.gz |
Merge branch 'mergelibs11' into main
Diffstat (limited to 'contrib/python')
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="<?>"' 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" |