From faec437d163d8015fd5e0da74381c190fa45c298 Mon Sep 17 00:00:00 2001 From: robot-piglet Date: Wed, 31 Jul 2024 19:34:56 +0300 Subject: Intermediate changes --- contrib/python/importlib-resources/ya.make | 3 +++ 1 file changed, 3 insertions(+) (limited to 'contrib/python') diff --git a/contrib/python/importlib-resources/ya.make b/contrib/python/importlib-resources/ya.make index 21d607abef0..c7ba0d70fcb 100644 --- a/contrib/python/importlib-resources/ya.make +++ b/contrib/python/importlib-resources/ya.make @@ -2,6 +2,9 @@ PY23_LIBRARY() LICENSE(Apache-2.0) +# The code is not taken from upstream. An analogue of version 1.0.2 has been implemented. See CONTRIB-1203 +VERSION(1.0.2) + PY_SRCS( TOP_LEVEL importlib_resources/__init__.py -- cgit v1.3 From 226ad6e44ddaecc763a95f179974da04b9c9fa83 Mon Sep 17 00:00:00 2001 From: robot-piglet Date: Thu, 1 Aug 2024 09:58:13 +0300 Subject: Intermediate changes --- contrib/libs/backtrace/README.md | 12 +++++++++++- contrib/libs/backtrace/ya.make | 4 ++-- contrib/python/pytest-lazy-fixtures/.dist-info/METADATA | 10 +++------- contrib/python/pytest-lazy-fixtures/README.md | 8 ++------ .../pytest-lazy-fixtures/pytest_lazy_fixtures/loader.py | 2 +- .../pytest-lazy-fixtures/pytest_lazy_fixtures/plugin.py | 8 +------- contrib/python/pytest-lazy-fixtures/ya.make | 2 +- 7 files changed, 21 insertions(+), 25 deletions(-) (limited to 'contrib/python') diff --git a/contrib/libs/backtrace/README.md b/contrib/libs/backtrace/README.md index c82834d174d..d1807842cce 100644 --- a/contrib/libs/backtrace/README.md +++ b/contrib/libs/backtrace/README.md @@ -10,8 +10,18 @@ The libbacktrace library may be linked into a program or library and used to produce symbolic backtraces. Sample uses would be to print a detailed backtrace when an error occurs or to gather detailed profiling information. + In general the functions provided by this library are async-signal-safe, meaning that they may be safely called from a signal handler. +That said, on systems that use `dl_iterate_phdr`, such as GNU/Linux, +gitthe first call to a libbacktrace function will call `dl_iterate_phdr`, +which is not in general async-signal-safe. Therefore, programs +that call libbacktrace from a signal handler should ensure that they +make an initial call from outside of a signal handler. +Similar considerations apply when arranging to call libbacktrace +from within malloc; `dl_iterate_phdr` can also call malloc, +so make an initial call to a libbacktrace function outside of +malloc before trying to call libbacktrace functions within malloc. The libbacktrace library is provided under a BSD license. See the source files for the exact license text. @@ -25,7 +35,7 @@ will work. See the source file backtrace-supported.h.in for the macros that it defines. -As of October 2020, libbacktrace supports ELF, PE/COFF, Mach-O, and +As of July 2024, libbacktrace supports ELF, PE/COFF, Mach-O, and XCOFF executables with DWARF debugging information. In other words, it supports GNU/Linux, *BSD, macOS, Windows, and AIX. The library is written to make it straightforward to add support for diff --git a/contrib/libs/backtrace/ya.make b/contrib/libs/backtrace/ya.make index 202f54991f2..d8d066df2c7 100644 --- a/contrib/libs/backtrace/ya.make +++ b/contrib/libs/backtrace/ya.make @@ -6,9 +6,9 @@ LICENSE(BSD-3-Clause) LICENSE_TEXTS(.yandex_meta/licenses.list.txt) -VERSION(2024-07-16) +VERSION(2024-07-18) -ORIGINAL_SOURCE(https://github.com/ianlancetaylor/libbacktrace/archive/1dd5c408fe6f5d9bccf870ec4e0e4bcabeb0664e.tar.gz) +ORIGINAL_SOURCE(https://github.com/ianlancetaylor/libbacktrace/archive/8e32931a4fe98b9bc955cb97b4702123b204f139.tar.gz) ADDINCL( contrib/libs/backtrace diff --git a/contrib/python/pytest-lazy-fixtures/.dist-info/METADATA b/contrib/python/pytest-lazy-fixtures/.dist-info/METADATA index 260a9b18ccf..e03b9014b7d 100644 --- a/contrib/python/pytest-lazy-fixtures/.dist-info/METADATA +++ b/contrib/python/pytest-lazy-fixtures/.dist-info/METADATA @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: pytest-lazy-fixtures -Version: 1.0.7 +Version: 1.1.0 Summary: Allows you to use fixtures in @pytest.mark.parametrize. Home-page: https://github.com/dev-petrov/pytest-lazy-fixtures License: MIT @@ -43,7 +43,7 @@ pip install pytest-lazy-fixtures ## Usage -To use your fixtures inside `@pytest.mark.parametrize` you can use `lf` (`lazy_fixture`) or `pytest.lazy_fixtures`. +To use your fixtures inside `@pytest.mark.parametrize` you can use `lf` (`lazy_fixture`). ```python import pytest @@ -54,10 +54,6 @@ def one(): return 1 @pytest.mark.parametrize('arg1,arg2', [('val1', lf('one'))]) -def test_func(arg1, arg2): - assert arg2 == 1 - -@pytest.mark.parametrize('arg1,arg2', [('val1', pytest.lazy_fixtures('one'))]) def test_func(arg1, arg2): assert arg2 == 1 ``` @@ -96,7 +92,7 @@ def test_func(arg1, arg2): assert arg2 == 1 ``` -And there is some useful wrapper called `lfc` (`lazy_fixture_callable`) or `pytest.lazy_fixtures_callable`. +And there is some useful wrapper called `lfc` (`lazy_fixture_callable`). It can work with any callable and your fixtures, e.g. ```python diff --git a/contrib/python/pytest-lazy-fixtures/README.md b/contrib/python/pytest-lazy-fixtures/README.md index 6c13ec033a7..ba6ff870da3 100644 --- a/contrib/python/pytest-lazy-fixtures/README.md +++ b/contrib/python/pytest-lazy-fixtures/README.md @@ -22,7 +22,7 @@ pip install pytest-lazy-fixtures ## Usage -To use your fixtures inside `@pytest.mark.parametrize` you can use `lf` (`lazy_fixture`) or `pytest.lazy_fixtures`. +To use your fixtures inside `@pytest.mark.parametrize` you can use `lf` (`lazy_fixture`). ```python import pytest @@ -33,10 +33,6 @@ def one(): return 1 @pytest.mark.parametrize('arg1,arg2', [('val1', lf('one'))]) -def test_func(arg1, arg2): - assert arg2 == 1 - -@pytest.mark.parametrize('arg1,arg2', [('val1', pytest.lazy_fixtures('one'))]) def test_func(arg1, arg2): assert arg2 == 1 ``` @@ -75,7 +71,7 @@ def test_func(arg1, arg2): assert arg2 == 1 ``` -And there is some useful wrapper called `lfc` (`lazy_fixture_callable`) or `pytest.lazy_fixtures_callable`. +And there is some useful wrapper called `lfc` (`lazy_fixture_callable`). It can work with any callable and your fixtures, e.g. ```python diff --git a/contrib/python/pytest-lazy-fixtures/pytest_lazy_fixtures/loader.py b/contrib/python/pytest-lazy-fixtures/pytest_lazy_fixtures/loader.py index 3c675c2aaf1..d2d39ff4f80 100644 --- a/contrib/python/pytest-lazy-fixtures/pytest_lazy_fixtures/loader.py +++ b/contrib/python/pytest-lazy-fixtures/pytest_lazy_fixtures/loader.py @@ -14,7 +14,7 @@ def load_lazy_fixtures(value, request: pytest.FixtureRequest): return value.load_fixture(request) # we need to check exact type if type(value) is dict: # noqa: E721 - return {key: load_lazy_fixtures(value, request) for key, value in value.items()} + return {load_lazy_fixtures(key, request): load_lazy_fixtures(value, request) for key, value in value.items()} # we need to check exact type elif type(value) in {list, tuple, set}: return type(value)([load_lazy_fixtures(value, request) for value in value]) diff --git a/contrib/python/pytest-lazy-fixtures/pytest_lazy_fixtures/plugin.py b/contrib/python/pytest-lazy-fixtures/pytest_lazy_fixtures/plugin.py index de7d75a4f79..f3475e199c8 100644 --- a/contrib/python/pytest-lazy-fixtures/pytest_lazy_fixtures/plugin.py +++ b/contrib/python/pytest-lazy-fixtures/pytest_lazy_fixtures/plugin.py @@ -1,16 +1,10 @@ import pytest -from .lazy_fixture import LazyFixtureWrapper, lf -from .lazy_fixture_callable import lfc +from .lazy_fixture import LazyFixtureWrapper from .loader import load_lazy_fixtures from .normalizer import normalize_metafunc_calls -def pytest_configure(): - pytest.lazy_fixtures = lf - pytest.lazy_fixtures_callable = lfc - - @pytest.hookimpl(tryfirst=True) def pytest_fixture_setup(fixturedef, request): val = getattr(request, "param", None) diff --git a/contrib/python/pytest-lazy-fixtures/ya.make b/contrib/python/pytest-lazy-fixtures/ya.make index b672f39330f..47d86e8e021 100644 --- a/contrib/python/pytest-lazy-fixtures/ya.make +++ b/contrib/python/pytest-lazy-fixtures/ya.make @@ -2,7 +2,7 @@ PY3_LIBRARY() -VERSION(1.0.7) +VERSION(1.1.0) LICENSE(MIT) -- cgit v1.3 From 8ca35a5a3ec2486b6905e4f1e55ab10872752ab2 Mon Sep 17 00:00:00 2001 From: robot-piglet Date: Mon, 5 Aug 2024 09:59:58 +0300 Subject: Intermediate changes --- contrib/python/pure-eval/.dist-info/METADATA | 14 ++++++-------- contrib/python/pure-eval/README.md | 2 +- contrib/python/pure-eval/pure_eval/__init__.py | 9 +++++++++ contrib/python/pure-eval/pure_eval/my_getattr_static.py | 6 ++++-- contrib/python/pure-eval/pure_eval/utils.py | 7 ++++++- contrib/python/pure-eval/pure_eval/version.py | 2 +- contrib/python/pure-eval/ya.make | 2 +- 7 files changed, 28 insertions(+), 14 deletions(-) (limited to 'contrib/python') diff --git a/contrib/python/pure-eval/.dist-info/METADATA b/contrib/python/pure-eval/.dist-info/METADATA index 931f69c3484..1f086de3a8a 100644 --- a/contrib/python/pure-eval/.dist-info/METADATA +++ b/contrib/python/pure-eval/.dist-info/METADATA @@ -1,19 +1,19 @@ Metadata-Version: 2.1 -Name: pure-eval -Version: 0.2.2 +Name: pure_eval +Version: 0.2.3 Summary: Safely evaluate AST nodes without side effects Home-page: http://github.com/alexmojaki/pure_eval Author: Alex Hall Author-email: alex.mojaki@gmail.com License: MIT -Platform: UNKNOWN Classifier: Intended Audience :: Developers -Classifier: Programming Language :: Python :: 3.5 -Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: 3.8 Classifier: Programming Language :: Python :: 3.9 Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 +Classifier: Programming Language :: Python :: 3.13 Classifier: License :: OSI Approved :: MIT License Classifier: Operating System :: OS Independent Description-Content-Type: text/markdown @@ -23,7 +23,7 @@ Requires-Dist: pytest ; extra == 'tests' # `pure_eval` -[![Build Status](https://travis-ci.org/alexmojaki/pure_eval.svg?branch=master)](https://travis-ci.org/alexmojaki/pure_eval) [![Coverage Status](https://coveralls.io/repos/github/alexmojaki/pure_eval/badge.svg?branch=master)](https://coveralls.io/github/alexmojaki/pure_eval?branch=master) [![Supports Python versions 3.5+](https://img.shields.io/pypi/pyversions/pure_eval.svg)](https://pypi.python.org/pypi/pure_eval) +[![Build Status](https://travis-ci.org/alexmojaki/pure_eval.svg?branch=master)](https://travis-ci.org/alexmojaki/pure_eval) [![Coverage Status](https://coveralls.io/repos/github/alexmojaki/pure_eval/badge.svg?branch=master)](https://coveralls.io/github/alexmojaki/pure_eval?branch=master) [![Supports Python versions 3.7+](https://img.shields.io/pypi/pyversions/pure_eval.svg)](https://pypi.python.org/pypi/pure_eval) This is a Python package that lets you safely evaluate certain AST nodes without triggering arbitrary code that may have unwanted side effects. @@ -225,5 +225,3 @@ d = {1: 2} y = 2 d[x] = 2 ``` - - diff --git a/contrib/python/pure-eval/README.md b/contrib/python/pure-eval/README.md index a4edbfc0a57..3506b333988 100644 --- a/contrib/python/pure-eval/README.md +++ b/contrib/python/pure-eval/README.md @@ -1,6 +1,6 @@ # `pure_eval` -[![Build Status](https://travis-ci.org/alexmojaki/pure_eval.svg?branch=master)](https://travis-ci.org/alexmojaki/pure_eval) [![Coverage Status](https://coveralls.io/repos/github/alexmojaki/pure_eval/badge.svg?branch=master)](https://coveralls.io/github/alexmojaki/pure_eval?branch=master) [![Supports Python versions 3.5+](https://img.shields.io/pypi/pyversions/pure_eval.svg)](https://pypi.python.org/pypi/pure_eval) +[![Build Status](https://travis-ci.org/alexmojaki/pure_eval.svg?branch=master)](https://travis-ci.org/alexmojaki/pure_eval) [![Coverage Status](https://coveralls.io/repos/github/alexmojaki/pure_eval/badge.svg?branch=master)](https://coveralls.io/github/alexmojaki/pure_eval?branch=master) [![Supports Python versions 3.7+](https://img.shields.io/pypi/pyversions/pure_eval.svg)](https://pypi.python.org/pypi/pure_eval) This is a Python package that lets you safely evaluate certain AST nodes without triggering arbitrary code that may have unwanted side effects. diff --git a/contrib/python/pure-eval/pure_eval/__init__.py b/contrib/python/pure-eval/pure_eval/__init__.py index 0040e318a6e..ec4ba735030 100644 --- a/contrib/python/pure-eval/pure_eval/__init__.py +++ b/contrib/python/pure-eval/pure_eval/__init__.py @@ -6,3 +6,12 @@ try: except ImportError: # version.py is auto-generated with the git tag when building __version__ = "???" + +__all__ = [ + "Evaluator", + "CannotEval", + "group_expressions", + "is_expression_interesting", + "getattr_static", + "__version__", +] diff --git a/contrib/python/pure-eval/pure_eval/my_getattr_static.py b/contrib/python/pure-eval/pure_eval/my_getattr_static.py index c750b1acc3f..5490b90adec 100644 --- a/contrib/python/pure-eval/pure_eval/my_getattr_static.py +++ b/contrib/python/pure-eval/pure_eval/my_getattr_static.py @@ -79,8 +79,10 @@ def getattr_static(obj, attr): klass_result = _check_class(klass, attr) if instance_result is not _sentinel and klass_result is not _sentinel: - if (_check_class(type(klass_result), '__get__') is not _sentinel and - _check_class(type(klass_result), '__set__') is not _sentinel): + if _check_class(type(klass_result), "__get__") is not _sentinel and ( + _check_class(type(klass_result), "__set__") is not _sentinel + or _check_class(type(klass_result), "__delete__") is not _sentinel + ): return _resolve_descriptor(klass_result, obj, klass) if instance_result is not _sentinel: diff --git a/contrib/python/pure-eval/pure_eval/utils.py b/contrib/python/pure-eval/pure_eval/utils.py index a8a37302daa..19ead658506 100644 --- a/contrib/python/pure-eval/pure_eval/utils.py +++ b/contrib/python/pure-eval/pure_eval/utils.py @@ -184,7 +184,12 @@ def copy_ast_without_context(x): if field != 'ctx' if hasattr(x, field) } - return type(x)(**kwargs) + a = type(x)(**kwargs) + if hasattr(a, 'ctx'): + # Python 3.13.0b2+ defaults to Load when we don't pass ctx + # https://github.com/python/cpython/pull/118871 + del a.ctx + return a elif isinstance(x, list): return list(map(copy_ast_without_context, x)) else: diff --git a/contrib/python/pure-eval/pure_eval/version.py b/contrib/python/pure-eval/pure_eval/version.py index 9dd16a34511..db9cf742db5 100644 --- a/contrib/python/pure-eval/pure_eval/version.py +++ b/contrib/python/pure-eval/pure_eval/version.py @@ -1 +1 @@ -__version__ = '0.2.2' \ No newline at end of file +__version__ = '0.2.3' \ No newline at end of file diff --git a/contrib/python/pure-eval/ya.make b/contrib/python/pure-eval/ya.make index 9d3cdb4c6da..b42f4018d61 100644 --- a/contrib/python/pure-eval/ya.make +++ b/contrib/python/pure-eval/ya.make @@ -2,7 +2,7 @@ PY3_LIBRARY() -VERSION(0.2.2) +VERSION(0.2.3) LICENSE(MIT) -- cgit v1.3 From 636037ad08e5e0ea28bb4f7eaa1d8bc414c3a038 Mon Sep 17 00:00:00 2001 From: robot-piglet Date: Mon, 5 Aug 2024 14:45:45 +0300 Subject: Intermediate changes --- contrib/libs/cxxsupp/libcxxmsvc/include/bitset | 2 +- contrib/python/certifi/py2/ya.make | 2 ++ contrib/python/certifi/py3/ya.make | 2 ++ 3 files changed, 5 insertions(+), 1 deletion(-) (limited to 'contrib/python') diff --git a/contrib/libs/cxxsupp/libcxxmsvc/include/bitset b/contrib/libs/cxxsupp/libcxxmsvc/include/bitset index d5c42991d9f..c85a280fdfb 100644 --- a/contrib/libs/cxxsupp/libcxxmsvc/include/bitset +++ b/contrib/libs/cxxsupp/libcxxmsvc/include/bitset @@ -387,7 +387,7 @@ __bitset<_N_words, _Size>::to_ullong(true_type, true_type) const { unsigned long long __r = __first_[0]; for (size_t __i = 1; __i < sizeof(unsigned long long) / sizeof(__storage_type); ++__i) - __r |= static_cast(__first_[__i]) << (sizeof(__storage_type) * CHAR_BIT); + __r |= static_cast(__first_[__i]) << (sizeof(__storage_type) * CHAR_BIT * __i); return __r; } diff --git a/contrib/python/certifi/py2/ya.make b/contrib/python/certifi/py2/ya.make index 274da44efc0..27aa0018f46 100644 --- a/contrib/python/certifi/py2/ya.make +++ b/contrib/python/certifi/py2/ya.make @@ -2,6 +2,8 @@ PY2_LIBRARY() LICENSE(Service-Py23-Proxy) +VERSION(Service-no-external-sources) + PEERDIR( library/python/certifi ) diff --git a/contrib/python/certifi/py3/ya.make b/contrib/python/certifi/py3/ya.make index fa3aa2c9d01..e841bd82d54 100644 --- a/contrib/python/certifi/py3/ya.make +++ b/contrib/python/certifi/py3/ya.make @@ -2,6 +2,8 @@ PY3_LIBRARY() LICENSE(Service-Py23-Proxy) +VERSION(Service-no-external-sources) + PEERDIR( library/python/certifi ) -- cgit v1.3 From 957f0c255bd884c03bf673d354346180583537bb Mon Sep 17 00:00:00 2001 From: robot-piglet Date: Tue, 6 Aug 2024 08:17:05 +0300 Subject: Intermediate changes --- contrib/python/hypothesis/py3/.dist-info/METADATA | 10 +++++----- contrib/python/hypothesis/py3/_hypothesis_pytestplugin.py | 6 ++---- .../py3/hypothesis/internal/conjecture/junkdrawer.py | 6 +++++- contrib/python/hypothesis/py3/hypothesis/reporting.py | 13 ++----------- contrib/python/hypothesis/py3/hypothesis/version.py | 2 +- contrib/python/hypothesis/py3/ya.make | 2 +- contrib/python/pytest-lazy-fixtures/.dist-info/METADATA | 2 +- .../pytest-lazy-fixtures/pytest_lazy_fixtures/normalizer.py | 7 ++++--- contrib/python/pytest-lazy-fixtures/ya.make | 2 +- 9 files changed, 22 insertions(+), 28 deletions(-) (limited to 'contrib/python') diff --git a/contrib/python/hypothesis/py3/.dist-info/METADATA b/contrib/python/hypothesis/py3/.dist-info/METADATA index ffee48a82f0..223aafcb694 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.108.2 +Version: 6.108.4 Summary: A library for property-based testing Home-page: https://hypothesis.works Author: David R. MacIver and Zac Hatfield-Dodds @@ -41,10 +41,10 @@ Requires-Dist: exceptiongroup >=1.0.0 ; python_version < "3.11" Provides-Extra: all Requires-Dist: black >=19.10b0 ; extra == 'all' Requires-Dist: click >=7.0 ; extra == 'all' -Requires-Dist: crosshair-tool >=0.0.61 ; extra == 'all' +Requires-Dist: crosshair-tool >=0.0.63 ; extra == 'all' Requires-Dist: django >=3.2 ; extra == 'all' Requires-Dist: dpcontracts >=0.4 ; extra == 'all' -Requires-Dist: hypothesis-crosshair >=0.0.7 ; extra == 'all' +Requires-Dist: hypothesis-crosshair >=0.0.9 ; extra == 'all' Requires-Dist: lark >=0.10.1 ; extra == 'all' Requires-Dist: libcst >=0.3.16 ; extra == 'all' Requires-Dist: numpy >=1.17.3 ; extra == 'all' @@ -63,8 +63,8 @@ Requires-Dist: rich >=9.0.0 ; extra == 'cli' Provides-Extra: codemods Requires-Dist: libcst >=0.3.16 ; extra == 'codemods' Provides-Extra: crosshair -Requires-Dist: hypothesis-crosshair >=0.0.7 ; extra == 'crosshair' -Requires-Dist: crosshair-tool >=0.0.61 ; extra == 'crosshair' +Requires-Dist: hypothesis-crosshair >=0.0.9 ; extra == 'crosshair' +Requires-Dist: crosshair-tool >=0.0.63 ; extra == 'crosshair' Provides-Extra: dateutil Requires-Dist: python-dateutil >=1.4 ; extra == 'dateutil' Provides-Extra: django diff --git a/contrib/python/hypothesis/py3/_hypothesis_pytestplugin.py b/contrib/python/hypothesis/py3/_hypothesis_pytestplugin.py index e82b528bb53..9df7817c68c 100644 --- a/contrib/python/hypothesis/py3/_hypothesis_pytestplugin.py +++ b/contrib/python/hypothesis/py3/_hypothesis_pytestplugin.py @@ -309,7 +309,7 @@ else: with current_pytest_item.with_value(item): yield if store.results: - item.hypothesis_report_information = list(store.results) + item.hypothesis_report_information = "\n".join(store.results) def _stash_get(config, key, default): if hasattr(config, "stash"): @@ -325,9 +325,7 @@ else: def pytest_runtest_makereport(item, call): report = (yield).get_result() if hasattr(item, "hypothesis_report_information"): - report.sections.append( - ("Hypothesis", "\n".join(item.hypothesis_report_information)) - ) + report.sections.append(("Hypothesis", item.hypothesis_report_information)) if report.when != "teardown": return diff --git a/contrib/python/hypothesis/py3/hypothesis/internal/conjecture/junkdrawer.py b/contrib/python/hypothesis/py3/hypothesis/internal/conjecture/junkdrawer.py index 7dbab5b9717..4465f59e5c4 100644 --- a/contrib/python/hypothesis/py3/hypothesis/internal/conjecture/junkdrawer.py +++ b/contrib/python/hypothesis/py3/hypothesis/internal/conjecture/junkdrawer.py @@ -421,6 +421,10 @@ _gc_initialized = False _gc_start = 0 _gc_cumulative_time = 0 +# Since gc_callback potentially runs in test context, and perf_counter +# might be monkeypatched, we store a reference to the real one. +_perf_counter = time.perf_counter + def gc_cumulative_time() -> float: global _gc_initialized @@ -430,7 +434,7 @@ def gc_cumulative_time() -> float: def gc_callback(phase, info): global _gc_start, _gc_cumulative_time try: - now = time.perf_counter() + now = _perf_counter() if phase == "start": _gc_start = now elif phase == "stop" and _gc_start > 0: diff --git a/contrib/python/hypothesis/py3/hypothesis/reporting.py b/contrib/python/hypothesis/py3/hypothesis/reporting.py index a0f300b2bcb..19073c5aff2 100644 --- a/contrib/python/hypothesis/py3/hypothesis/reporting.py +++ b/contrib/python/hypothesis/py3/hypothesis/reporting.py @@ -8,8 +8,6 @@ # 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 - from hypothesis._settings import Verbosity, settings from hypothesis.internal.compat import escape_unicode_characters from hypothesis.utils.dynamicvariables import DynamicVariable @@ -37,14 +35,6 @@ def current_verbosity(): return settings.default.verbosity -def to_text(textish): - if inspect.isfunction(textish): - textish = textish() - if isinstance(textish, bytes): - textish = textish.decode() - return textish - - def verbose_report(text): if current_verbosity() >= Verbosity.verbose: base_report(text) @@ -61,4 +51,5 @@ def report(text): def base_report(text): - current_reporter()(to_text(text)) + assert isinstance(text, str), f"unexpected non-str {text=}" + current_reporter()(text) diff --git a/contrib/python/hypothesis/py3/hypothesis/version.py b/contrib/python/hypothesis/py3/hypothesis/version.py index 4858f7fb0ca..29e2144b92a 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, 108, 2) +__version_info__ = (6, 108, 4) __version__ = ".".join(map(str, __version_info__)) diff --git a/contrib/python/hypothesis/py3/ya.make b/contrib/python/hypothesis/py3/ya.make index 63eb354c8e2..4efa89329dd 100644 --- a/contrib/python/hypothesis/py3/ya.make +++ b/contrib/python/hypothesis/py3/ya.make @@ -2,7 +2,7 @@ PY3_LIBRARY() -VERSION(6.108.2) +VERSION(6.108.4) LICENSE(MPL-2.0) diff --git a/contrib/python/pytest-lazy-fixtures/.dist-info/METADATA b/contrib/python/pytest-lazy-fixtures/.dist-info/METADATA index e03b9014b7d..8b36c5866f6 100644 --- a/contrib/python/pytest-lazy-fixtures/.dist-info/METADATA +++ b/contrib/python/pytest-lazy-fixtures/.dist-info/METADATA @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: pytest-lazy-fixtures -Version: 1.1.0 +Version: 1.1.1 Summary: Allows you to use fixtures in @pytest.mark.parametrize. Home-page: https://github.com/dev-petrov/pytest-lazy-fixtures License: MIT diff --git a/contrib/python/pytest-lazy-fixtures/pytest_lazy_fixtures/normalizer.py b/contrib/python/pytest-lazy-fixtures/pytest_lazy_fixtures/normalizer.py index fdbfe86402b..db4cfa8b00b 100644 --- a/contrib/python/pytest-lazy-fixtures/pytest_lazy_fixtures/normalizer.py +++ b/contrib/python/pytest-lazy-fixtures/pytest_lazy_fixtures/normalizer.py @@ -64,14 +64,15 @@ def _normalize_call(callspec, metafunc, used_keys): fm = metafunc.config.pluginmanager.get_plugin("funcmanage") used_keys = used_keys or set() - valtype_keys = callspec.params.keys() - used_keys + params = callspec.params.copy() if pytest.version_tuple >= (8, 0, 0) else {**callspec.params, **callspec.funcargs} + valtype_keys = params.keys() - used_keys for arg in valtype_keys: - value = callspec.params[arg] + value = params[arg] fixturenames_closure, arg2fixturedefs = _get_fixturenames_closure_and_arg2fixturedefs(fm, metafunc, value) if fixturenames_closure and arg2fixturedefs: - extra_fixturenames = [fname for fname in fixturenames_closure if fname not in callspec.params] + extra_fixturenames = [fname for fname in fixturenames_closure if fname not in params] newmetafunc = _copy_metafunc(metafunc) newmetafunc.fixturenames = extra_fixturenames diff --git a/contrib/python/pytest-lazy-fixtures/ya.make b/contrib/python/pytest-lazy-fixtures/ya.make index 47d86e8e021..43c43a87f9d 100644 --- a/contrib/python/pytest-lazy-fixtures/ya.make +++ b/contrib/python/pytest-lazy-fixtures/ya.make @@ -2,7 +2,7 @@ PY3_LIBRARY() -VERSION(1.1.0) +VERSION(1.1.1) LICENSE(MIT) -- cgit v1.3 From 4f495b080a6a0f72c77fa503b9f4a1b357969037 Mon Sep 17 00:00:00 2001 From: rekby Date: Tue, 6 Aug 2024 16:45:38 +0300 Subject: Export python mergedeep library to in github.com/ydb-platform/ydb d57ca70b751f8907c3621fa2935e0a9fcdba7972 --- contrib/python/mergedeep/.dist-info/METADATA | 154 ++++++++ contrib/python/mergedeep/.dist-info/top_level.txt | 1 + contrib/python/mergedeep/.yandex_meta/yamaker.yaml | 2 + contrib/python/mergedeep/LICENSE | 21 ++ contrib/python/mergedeep/README.md | 133 +++++++ contrib/python/mergedeep/mergedeep/__init__.py | 5 + contrib/python/mergedeep/mergedeep/mergedeep.py | 100 ++++++ .../python/mergedeep/mergedeep/test_mergedeep.py | 397 +++++++++++++++++++++ contrib/python/mergedeep/tests/ya.make | 17 + contrib/python/mergedeep/ya.make | 29 ++ 10 files changed, 859 insertions(+) create mode 100644 contrib/python/mergedeep/.dist-info/METADATA create mode 100644 contrib/python/mergedeep/.dist-info/top_level.txt create mode 100644 contrib/python/mergedeep/.yandex_meta/yamaker.yaml create mode 100644 contrib/python/mergedeep/LICENSE create mode 100644 contrib/python/mergedeep/README.md create mode 100644 contrib/python/mergedeep/mergedeep/__init__.py create mode 100644 contrib/python/mergedeep/mergedeep/mergedeep.py create mode 100644 contrib/python/mergedeep/mergedeep/test_mergedeep.py create mode 100644 contrib/python/mergedeep/tests/ya.make create mode 100644 contrib/python/mergedeep/ya.make (limited to 'contrib/python') diff --git a/contrib/python/mergedeep/.dist-info/METADATA b/contrib/python/mergedeep/.dist-info/METADATA new file mode 100644 index 00000000000..23452d786be --- /dev/null +++ b/contrib/python/mergedeep/.dist-info/METADATA @@ -0,0 +1,154 @@ +Metadata-Version: 2.1 +Name: mergedeep +Version: 1.3.4 +Summary: A deep merge function for 🐍. +Home-page: https://github.com/clarketm/mergedeep +Author: Travis Clarke +Author-email: travis.m.clarke@gmail.com +License: UNKNOWN +Platform: UNKNOWN +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: License :: OSI Approved :: MIT License +Classifier: Operating System :: OS Independent +Requires-Python: >=3.6 +Description-Content-Type: text/markdown + +# [mergedeep](https://mergedeep.readthedocs.io/en/latest/) + +[![PyPi release](https://img.shields.io/pypi/v/mergedeep.svg)](https://pypi.org/project/mergedeep/) +[![PyPi versions](https://img.shields.io/pypi/pyversions/mergedeep.svg)](https://pypi.org/project/mergedeep/) +[![Downloads](https://pepy.tech/badge/mergedeep)](https://pepy.tech/project/mergedeep) +[![Conda Version](https://img.shields.io/conda/vn/conda-forge/mergedeep.svg)](https://anaconda.org/conda-forge/mergedeep) +[![Conda Downloads](https://img.shields.io/conda/dn/conda-forge/mergedeep.svg)](https://anaconda.org/conda-forge/mergedeep) +[![Documentation Status](https://readthedocs.org/projects/mergedeep/badge/?version=latest)](https://mergedeep.readthedocs.io/en/latest/?badge=latest) + +A deep merge function for 🐍. + +[Check out the mergedeep docs](https://mergedeep.readthedocs.io/en/latest/) + +## Installation + +```bash +$ pip install mergedeep +``` + +## Usage + +```text +merge(destination: MutableMapping, *sources: Mapping, strategy: Strategy = Strategy.REPLACE) -> MutableMapping +``` + +Deep merge without mutating the source dicts. + +```python3 +from mergedeep import merge + +a = {"keyA": 1} +b = {"keyB": {"sub1": 10}} +c = {"keyB": {"sub2": 20}} + +merged = merge({}, a, b, c) + +print(merged) +# {"keyA": 1, "keyB": {"sub1": 10, "sub2": 20}} +``` + +Deep merge into an existing dict. +```python3 +from mergedeep import merge + +a = {"keyA": 1} +b = {"keyB": {"sub1": 10}} +c = {"keyB": {"sub2": 20}} + +merge(a, b, c) + +print(a) +# {"keyA": 1, "keyB": {"sub1": 10, "sub2": 20}} +``` + +### Merge strategies: + +1. Replace (*default*) + +> `Strategy.REPLACE` + +```python3 +# When `destination` and `source` keys are the same, replace the `destination` value with one from `source` (default). + +# Note: with multiple sources, the `last` (i.e. rightmost) source value will be what appears in the merged result. + +from mergedeep import merge, Strategy + +dst = {"key": [1, 2]} +src = {"key": [3, 4]} + +merge(dst, src, strategy=Strategy.REPLACE) +# same as: merge(dst, src) + +print(dst) +# {"key": [3, 4]} +``` + +2. Additive + +> `Strategy.ADDITIVE` + +```python3 +# When `destination` and `source` values are both the same additive collection type, extend `destination` by adding values from `source`. +# Additive collection types include: `list`, `tuple`, `set`, and `Counter` + +# Note: if the values are not additive collections of the same type, then fallback to a `REPLACE` merge. + +from mergedeep import merge, Strategy + +dst = {"key": [1, 2], "count": Counter({"a": 1, "b": 1})} +src = {"key": [3, 4], "count": Counter({"a": 1, "c": 1})} + +merge(dst, src, strategy=Strategy.ADDITIVE) + +print(dst) +# {"key": [1, 2, 3, 4], "count": Counter({"a": 2, "b": 1, "c": 1})} +``` + +3. Typesafe replace + +> `Strategy.TYPESAFE_REPLACE` or `Strategy.TYPESAFE` + +```python3 +# When `destination` and `source` values are of different types, raise `TypeError`. Otherwise, perform a `REPLACE` merge. + +from mergedeep import merge, Strategy + +dst = {"key": [1, 2]} +src = {"key": {3, 4}} + +merge(dst, src, strategy=Strategy.TYPESAFE_REPLACE) # same as: `Strategy.TYPESAFE` +# TypeError: destination type: differs from source type: for key: "key" +``` + +4. Typesafe additive + +> `Strategy.TYPESAFE_ADDITIVE` + +```python3 +# When `destination` and `source` values are of different types, raise `TypeError`. Otherwise, perform a `ADDITIVE` merge. + +from mergedeep import merge, Strategy + +dst = {"key": [1, 2]} +src = {"key": {3, 4}} + +merge(dst, src, strategy=Strategy.TYPESAFE_ADDITIVE) +# TypeError: destination type: differs from source type: for key: "key" +``` + +## License + +MIT © [**Travis Clarke**](https://blog.travismclarke.com/) + + diff --git a/contrib/python/mergedeep/.dist-info/top_level.txt b/contrib/python/mergedeep/.dist-info/top_level.txt new file mode 100644 index 00000000000..5413932b268 --- /dev/null +++ b/contrib/python/mergedeep/.dist-info/top_level.txt @@ -0,0 +1 @@ +mergedeep diff --git a/contrib/python/mergedeep/.yandex_meta/yamaker.yaml b/contrib/python/mergedeep/.yandex_meta/yamaker.yaml new file mode 100644 index 00000000000..b88229ef483 --- /dev/null +++ b/contrib/python/mergedeep/.yandex_meta/yamaker.yaml @@ -0,0 +1,2 @@ +mark_as_tests: + - mergedeep/test_mergedeep.py diff --git a/contrib/python/mergedeep/LICENSE b/contrib/python/mergedeep/LICENSE new file mode 100644 index 00000000000..45c64408162 --- /dev/null +++ b/contrib/python/mergedeep/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2019 Travis Clarke (https://www.travismclarke.com/) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/contrib/python/mergedeep/README.md b/contrib/python/mergedeep/README.md new file mode 100644 index 00000000000..86322730cd9 --- /dev/null +++ b/contrib/python/mergedeep/README.md @@ -0,0 +1,133 @@ +# [mergedeep](https://mergedeep.readthedocs.io/en/latest/) + +[![PyPi release](https://img.shields.io/pypi/v/mergedeep.svg)](https://pypi.org/project/mergedeep/) +[![PyPi versions](https://img.shields.io/pypi/pyversions/mergedeep.svg)](https://pypi.org/project/mergedeep/) +[![Downloads](https://pepy.tech/badge/mergedeep)](https://pepy.tech/project/mergedeep) +[![Conda Version](https://img.shields.io/conda/vn/conda-forge/mergedeep.svg)](https://anaconda.org/conda-forge/mergedeep) +[![Conda Downloads](https://img.shields.io/conda/dn/conda-forge/mergedeep.svg)](https://anaconda.org/conda-forge/mergedeep) +[![Documentation Status](https://readthedocs.org/projects/mergedeep/badge/?version=latest)](https://mergedeep.readthedocs.io/en/latest/?badge=latest) + +A deep merge function for 🐍. + +[Check out the mergedeep docs](https://mergedeep.readthedocs.io/en/latest/) + +## Installation + +```bash +$ pip install mergedeep +``` + +## Usage + +```text +merge(destination: MutableMapping, *sources: Mapping, strategy: Strategy = Strategy.REPLACE) -> MutableMapping +``` + +Deep merge without mutating the source dicts. + +```python3 +from mergedeep import merge + +a = {"keyA": 1} +b = {"keyB": {"sub1": 10}} +c = {"keyB": {"sub2": 20}} + +merged = merge({}, a, b, c) + +print(merged) +# {"keyA": 1, "keyB": {"sub1": 10, "sub2": 20}} +``` + +Deep merge into an existing dict. +```python3 +from mergedeep import merge + +a = {"keyA": 1} +b = {"keyB": {"sub1": 10}} +c = {"keyB": {"sub2": 20}} + +merge(a, b, c) + +print(a) +# {"keyA": 1, "keyB": {"sub1": 10, "sub2": 20}} +``` + +### Merge strategies: + +1. Replace (*default*) + +> `Strategy.REPLACE` + +```python3 +# When `destination` and `source` keys are the same, replace the `destination` value with one from `source` (default). + +# Note: with multiple sources, the `last` (i.e. rightmost) source value will be what appears in the merged result. + +from mergedeep import merge, Strategy + +dst = {"key": [1, 2]} +src = {"key": [3, 4]} + +merge(dst, src, strategy=Strategy.REPLACE) +# same as: merge(dst, src) + +print(dst) +# {"key": [3, 4]} +``` + +2. Additive + +> `Strategy.ADDITIVE` + +```python3 +# When `destination` and `source` values are both the same additive collection type, extend `destination` by adding values from `source`. +# Additive collection types include: `list`, `tuple`, `set`, and `Counter` + +# Note: if the values are not additive collections of the same type, then fallback to a `REPLACE` merge. + +from mergedeep import merge, Strategy + +dst = {"key": [1, 2], "count": Counter({"a": 1, "b": 1})} +src = {"key": [3, 4], "count": Counter({"a": 1, "c": 1})} + +merge(dst, src, strategy=Strategy.ADDITIVE) + +print(dst) +# {"key": [1, 2, 3, 4], "count": Counter({"a": 2, "b": 1, "c": 1})} +``` + +3. Typesafe replace + +> `Strategy.TYPESAFE_REPLACE` or `Strategy.TYPESAFE` + +```python3 +# When `destination` and `source` values are of different types, raise `TypeError`. Otherwise, perform a `REPLACE` merge. + +from mergedeep import merge, Strategy + +dst = {"key": [1, 2]} +src = {"key": {3, 4}} + +merge(dst, src, strategy=Strategy.TYPESAFE_REPLACE) # same as: `Strategy.TYPESAFE` +# TypeError: destination type: differs from source type: for key: "key" +``` + +4. Typesafe additive + +> `Strategy.TYPESAFE_ADDITIVE` + +```python3 +# When `destination` and `source` values are of different types, raise `TypeError`. Otherwise, perform a `ADDITIVE` merge. + +from mergedeep import merge, Strategy + +dst = {"key": [1, 2]} +src = {"key": {3, 4}} + +merge(dst, src, strategy=Strategy.TYPESAFE_ADDITIVE) +# TypeError: destination type: differs from source type: for key: "key" +``` + +## License + +MIT © [**Travis Clarke**](https://blog.travismclarke.com/) diff --git a/contrib/python/mergedeep/mergedeep/__init__.py b/contrib/python/mergedeep/mergedeep/__init__.py new file mode 100644 index 00000000000..92d12f6c949 --- /dev/null +++ b/contrib/python/mergedeep/mergedeep/__init__.py @@ -0,0 +1,5 @@ +__version__ = "1.3.4" + +from mergedeep.mergedeep import merge, Strategy + +__all__ = ["merge", "Strategy"] diff --git a/contrib/python/mergedeep/mergedeep/mergedeep.py b/contrib/python/mergedeep/mergedeep/mergedeep.py new file mode 100644 index 00000000000..6dda8e82f38 --- /dev/null +++ b/contrib/python/mergedeep/mergedeep/mergedeep.py @@ -0,0 +1,100 @@ +from collections import Counter +from collections.abc import Mapping +from copy import deepcopy +from enum import Enum +from functools import reduce, partial +from typing import MutableMapping + + +class Strategy(Enum): + # Replace `destination` item with one from `source` (default). + REPLACE = 0 + # Combine `list`, `tuple`, `set`, or `Counter` types into one collection. + ADDITIVE = 1 + # Alias to: `TYPESAFE_REPLACE` + TYPESAFE = 2 + # Raise `TypeError` when `destination` and `source` types differ. Otherwise, perform a `REPLACE` merge. + TYPESAFE_REPLACE = 3 + # Raise `TypeError` when `destination` and `source` types differ. Otherwise, perform a `ADDITIVE` merge. + TYPESAFE_ADDITIVE = 4 + + +def _handle_merge_replace(destination, source, key): + if isinstance(destination[key], Counter) and isinstance(source[key], Counter): + # Merge both destination and source `Counter` as if they were a standard dict. + _deepmerge(destination[key], source[key]) + else: + # If a key exists in both objects and the values are `different`, the value from the `source` object will be used. + destination[key] = deepcopy(source[key]) + + +def _handle_merge_additive(destination, source, key): + # Values are combined into one long collection. + if isinstance(destination[key], list) and isinstance(source[key], list): + # Extend destination if both destination and source are `list` type. + destination[key].extend(deepcopy(source[key])) + elif isinstance(destination[key], set) and isinstance(source[key], set): + # Update destination if both destination and source are `set` type. + destination[key].update(deepcopy(source[key])) + elif isinstance(destination[key], tuple) and isinstance(source[key], tuple): + # Update destination if both destination and source are `tuple` type. + destination[key] = destination[key] + deepcopy(source[key]) + elif isinstance(destination[key], Counter) and isinstance(source[key], Counter): + # Update destination if both destination and source are `Counter` type. + destination[key].update(deepcopy(source[key])) + else: + _handle_merge[Strategy.REPLACE](destination, source, key) + + +def _handle_merge_typesafe(destination, source, key, strategy): + # Raise a TypeError if the destination and source types differ. + if type(destination[key]) is not type(source[key]): + raise TypeError( + f'destination type: {type(destination[key])} differs from source type: {type(source[key])} for key: "{key}"' + ) + else: + _handle_merge[strategy](destination, source, key) + + +_handle_merge = { + Strategy.REPLACE: _handle_merge_replace, + Strategy.ADDITIVE: _handle_merge_additive, + Strategy.TYPESAFE: partial(_handle_merge_typesafe, strategy=Strategy.REPLACE), + Strategy.TYPESAFE_REPLACE: partial(_handle_merge_typesafe, strategy=Strategy.REPLACE), + Strategy.TYPESAFE_ADDITIVE: partial(_handle_merge_typesafe, strategy=Strategy.ADDITIVE), +} + + +def _is_recursive_merge(a, b): + both_mapping = isinstance(a, Mapping) and isinstance(b, Mapping) + both_counter = isinstance(a, Counter) and isinstance(b, Counter) + return both_mapping and not both_counter + + +def _deepmerge(dst, src, strategy=Strategy.REPLACE): + for key in src: + if key in dst: + if _is_recursive_merge(dst[key], src[key]): + # If the key for both `dst` and `src` are both Mapping types (e.g. dict), then recurse. + _deepmerge(dst[key], src[key], strategy) + elif dst[key] is src[key]: + # If a key exists in both objects and the values are `same`, the value from the `dst` object will be used. + pass + else: + _handle_merge.get(strategy)(dst, src, key) + else: + # If the key exists only in `src`, the value from the `src` object will be used. + dst[key] = deepcopy(src[key]) + return dst + + +def merge(destination: MutableMapping, *sources: Mapping, strategy: Strategy = Strategy.REPLACE) -> MutableMapping: + """ + A deep merge function for 🐍. + + :param destination: The destination mapping. + :param sources: The source mappings. + :param strategy: The merge strategy. + :return: + """ + return reduce(partial(_deepmerge, strategy=strategy), sources, destination) diff --git a/contrib/python/mergedeep/mergedeep/test_mergedeep.py b/contrib/python/mergedeep/mergedeep/test_mergedeep.py new file mode 100644 index 00000000000..ef397288350 --- /dev/null +++ b/contrib/python/mergedeep/mergedeep/test_mergedeep.py @@ -0,0 +1,397 @@ +"""mergedeep test module""" +import inspect +import unittest +from collections import Counter +from copy import deepcopy + +from mergedeep import merge, Strategy + + +class test_mergedeep(unittest.TestCase): + """mergedeep function tests.""" + + ############################################################################################################################## + # REPLACE + ############################################################################################################################## + + def test_should_merge_3_dicts_into_new_dict_using_replace_strategy_and_only_mutate_target(self,): + expected = { + "a": {"b": {"c": 5, "_c": 15}, "B": {"C": 10}}, + "d": 3, + "e": {1: 2, "a": {"f": 2}}, + "f": [4, 5, 6], + "g": (100, 200), + "h": Counter({"a": 5, "b": 1, "c": 1}), + "i": 2, + "j": Counter({"z": 2}), + "z": Counter({"a": 2}), + } + + a = { + "a": {"b": {"c": 5}}, + "d": 1, + "e": {2: 3}, + "f": [1, 2, 3], + "g": (2, 4, 6), + "h": Counter({"a": 1, "b": 1}), + "j": 1, + } + a_copy = deepcopy(a) + + b = { + "a": {"B": {"C": 10}}, + "d": 2, + "e": 2, + "f": [4, 5, 6], + "g": (100, 200), + "h": Counter({"a": 5, "c": 1}), + "i": Counter({"a": 1}), + "z": Counter({"a": 2}), + } + b_copy = deepcopy(b) + + c = { + "a": {"b": {"_c": 15}}, + "d": 3, + "e": {1: 2, "a": {"f": 2}}, + "i": 2, + "j": Counter({"z": 2}), + "z": Counter({"a": 2}), + } + c_copy = deepcopy(c) + + actual = merge({}, a, b, c, strategy=Strategy.REPLACE) + + self.assertEqual(actual, expected) + self.assertEqual(a, a_copy) + self.assertEqual(b, b_copy) + self.assertEqual(c, c_copy) + + def test_should_merge_2_dicts_into_existing_dict_using_replace_strategy_and_only_mutate_target(self,): + expected = { + "a": {"b": {"c": 5, "_c": 15}, "B": {"C": 10}}, + "d": 3, + "e": {1: 2, "a": {"f": 2}}, + "f": [4, 5, 6], + "g": (100, 200), + "h": Counter({"a": 1, "b": 1, "c": 1}), + "i": 2, + "j": Counter({"z": 2}), + } + + a = { + "a": {"b": {"c": 5}}, + "d": 1, + "e": {2: 3}, + "f": [1, 2, 3], + "g": (2, 4, 6), + "h": Counter({"a": 1, "b": 1}), + "j": 1, + } + a_copy = deepcopy(a) + + b = { + "a": {"B": {"C": 10}}, + "d": 2, + "e": 2, + "f": [4, 5, 6], + "g": (100, 200), + "h": Counter({"a": 1, "c": 1}), + "i": Counter({"a": 1}), + } + b_copy = deepcopy(b) + + c = {"a": {"b": {"_c": 15}}, "d": 3, "e": {1: 2, "a": {"f": 2}}, "i": 2, "j": Counter({"z": 2})} + c_copy = deepcopy(c) + + actual = merge(a, b, c, strategy=Strategy.REPLACE) + + self.assertEqual(actual, expected) + self.assertEqual(actual, a) + self.assertNotEqual(a, a_copy) + self.assertEqual(b, b_copy) + self.assertEqual(c, c_copy) + + def test_should_have_default_strategy_of_replace(self): + func_spec = inspect.getfullargspec(merge) + default_strategy = Strategy.REPLACE + + self.assertEqual(func_spec.kwonlydefaults.get("strategy"), default_strategy) + + # mock_merge.method.assert_called_with(target, source, strategy=Strategy.REPLACE) + + ############################################################################################################################## + # ADDITIVE + ############################################################################################################################## + + def test_should_merge_3_dicts_into_new_dict_using_additive_strategy_on_lists_and_only_mutate_target(self,): + expected = { + "a": {"b": {"c": 5, "_c": 15}, "B": {"C": 10}}, + "d": 3, + "e": {1: 2, "a": {"f": 2}}, + "f": [1, 2, 3, 4, 5, 6], + } + + a = {"a": {"b": {"c": 5}}, "d": 1, "e": {2: 3}, "f": [1, 2, 3]} + a_copy = deepcopy(a) + + b = {"a": {"B": {"C": 10}}, "d": 2, "e": 2, "f": [4, 5, 6]} + b_copy = deepcopy(b) + + c = {"a": {"b": {"_c": 15}}, "d": 3, "e": {1: 2, "a": {"f": 2}}} + c_copy = deepcopy(c) + + actual = merge({}, a, b, c, strategy=Strategy.ADDITIVE) + + self.assertEqual(actual, expected) + self.assertEqual(a, a_copy) + self.assertEqual(b, b_copy) + self.assertEqual(c, c_copy) + + def test_should_merge_3_dicts_into_new_dict_using_additive_strategy_on_sets_and_only_mutate_target(self,): + expected = { + "a": {"b": {"c": 5, "_c": 15}, "B": {"C": 10}}, + "d": 3, + "e": {1: 2, "a": {"f": 2}}, + "f": {1, 2, 3, 4, 5, 6}, + } + + a = {"a": {"b": {"c": 5}}, "d": 1, "e": {2: 3}, "f": {1, 2, 3}} + a_copy = deepcopy(a) + + b = {"a": {"B": {"C": 10}}, "d": 2, "e": 2, "f": {4, 5, 6}} + b_copy = deepcopy(b) + + c = {"a": {"b": {"_c": 15}}, "d": 3, "e": {1: 2, "a": {"f": 2}}} + c_copy = deepcopy(c) + + actual = merge({}, a, b, c, strategy=Strategy.ADDITIVE) + + self.assertEqual(actual, expected) + self.assertEqual(a, a_copy) + self.assertEqual(b, b_copy) + self.assertEqual(c, c_copy) + + def test_should_merge_3_dicts_into_new_dict_using_additive_strategy_on_tuples_and_only_mutate_target(self,): + expected = { + "a": {"b": {"c": 5, "_c": 15}, "B": {"C": 10}}, + "d": 3, + "e": {1: 2, "a": {"f": 2}}, + "f": (1, 2, 3, 4, 5, 6), + } + + a = {"a": {"b": {"c": 5}}, "d": 1, "e": {2: 3}, "f": (1, 2, 3)} + a_copy = deepcopy(a) + + b = {"a": {"B": {"C": 10}}, "d": 2, "e": 2, "f": (4, 5, 6)} + b_copy = deepcopy(b) + + c = {"a": {"b": {"_c": 15}}, "d": 3, "e": {1: 2, "a": {"f": 2}}} + c_copy = deepcopy(c) + + actual = merge({}, a, b, c, strategy=Strategy.ADDITIVE) + + self.assertEqual(actual, expected) + self.assertEqual(a, a_copy) + self.assertEqual(b, b_copy) + self.assertEqual(c, c_copy) + + def test_should_merge_3_dicts_into_new_dict_using_additive_strategy_on_counters_and_only_mutate_target(self,): + expected = { + "a": {"b": {"c": 5, "_c": 15}, "B": {"C": 10}}, + "d": 3, + "e": {1: 2, "a": {"f": 2}}, + "f": Counter({"a": 2, "c": 1, "b": 1}), + "i": 2, + "j": Counter({"z": 2}), + "z": Counter({"a": 4}), + } + + a = { + "a": {"b": {"c": 5}}, + "d": 1, + "e": {2: 3}, + "f": Counter({"a": 1, "c": 1}), + "i": Counter({"f": 9}), + "j": Counter({"a": 1, "z": 4}), + } + a_copy = deepcopy(a) + + b = { + "a": {"B": {"C": 10}}, + "d": 2, + "e": 2, + "f": Counter({"a": 1, "b": 1}), + "j": [1, 2, 3], + "z": Counter({"a": 2}), + } + b_copy = deepcopy(b) + + c = { + "a": {"b": {"_c": 15}}, + "d": 3, + "e": {1: 2, "a": {"f": 2}}, + "i": 2, + "j": Counter({"z": 2}), + "z": Counter({"a": 2}), + } + c_copy = deepcopy(c) + + actual = merge({}, a, b, c, strategy=Strategy.ADDITIVE) + + self.assertEqual(actual, expected) + self.assertEqual(a, a_copy) + self.assertEqual(b, b_copy) + self.assertEqual(c, c_copy) + + def test_should_not_copy_references(self): + before = 1 + after = 99 + + o1 = {"key1": before} + o2 = {"key2": before} + + expected = {"list": deepcopy([o1, o2]), "tuple": deepcopy((o1, o2))} + + a = {"list": [o1], "tuple": (o1,)} + b = {"list": [o2], "tuple": (o2,)} + + actual = merge({}, a, b, strategy=Strategy.ADDITIVE) + + o1["key1"] = after + o2["key2"] = after + + self.assertEqual(actual, expected) + + # Copied dicts should `not` mutate + self.assertEqual(actual["list"][0]["key1"], before) + self.assertEqual(actual["list"][1]["key2"], before) + self.assertEqual(actual["tuple"][0]["key1"], before) + self.assertEqual(actual["tuple"][1]["key2"], before) + + # Non-copied dicts should mutate + self.assertEqual(a["list"][0]["key1"], after) + self.assertEqual(b["list"][0]["key2"], after) + self.assertEqual(a["tuple"][0]["key1"], after) + self.assertEqual(b["tuple"][0]["key2"], after) + + ############################################################################################################################## + # TYPESAFE + # TYPESAFE_REPLACE + ############################################################################################################################## + + def test_should_raise_TypeError_using_typesafe_strategy_if_types_differ(self): + a = {"a": {"b": {"c": 5}}, "d": 1, "e": {2: 3}, "f": [1, 2, 3]} + b = {"a": {"B": {"C": 10}}, "d": 2, "e": 2, "f": [4, 5, 6]} + c = {"a": {"b": {"_c": 15}}, "d": 3, "e": {1: 2, "a": {"f": 2}}} + + with self.assertRaises(TypeError): + merge({}, a, b, c, strategy=Strategy.TYPESAFE) + + def test_should_raise_TypeError_using_typesafe_replace_strategy_if_types_differ(self,): + a = {"a": {"b": {"c": 5}}, "d": 1, "e": {2: 3}, "f": [1, 2, 3]} + b = {"a": {"B": {"C": 10}}, "d": 2, "e": 2, "f": [4, 5, 6]} + c = {"a": {"b": {"_c": 15}}, "d": 3, "e": {1: 2, "a": {"f": 2}}} + + with self.assertRaises(TypeError): + merge({}, a, b, c, strategy=Strategy.TYPESAFE_REPLACE) + + def test_should_merge_3_dicts_into_new_dict_using_typesafe_strategy_and_only_mutate_target_if_types_are_compatible( + self, + ): + expected = { + "a": {"b": {"c": 5, "_c": 15}, "B": {"C": 10}}, + "d": 3, + "f": [4, 5, 6], + "g": {2, 3, 4}, + "h": (1, 3), + "z": Counter({"a": 1, "b": 1, "c": 1}), + } + + a = {"a": {"b": {"c": 5}}, "d": 1, "f": [1, 2, 3], "g": {1, 2, 3}, "z": Counter({"a": 1, "b": 1})} + a_copy = deepcopy(a) + + b = {"a": {"B": {"C": 10}}, "d": 2, "f": [4, 5, 6], "g": {2, 3, 4}, "h": (1,)} + b_copy = deepcopy(b) + + c = {"a": {"b": {"_c": 15}}, "d": 3, "h": (1, 3), "z": Counter({"a": 1, "c": 1})} + c_copy = deepcopy(c) + + actual = merge({}, a, b, c, strategy=Strategy.TYPESAFE) + + self.assertEqual(actual, expected) + self.assertEqual(a, a_copy) + self.assertEqual(b, b_copy) + self.assertEqual(c, c_copy) + + def test_should_merge_3_dicts_into_new_dict_using_typesafe_replace_strategy_and_only_mutate_target_if_types_are_compatible( + self, + ): + expected = { + "a": {"b": {"c": 5, "_c": 15}, "B": {"C": 10}}, + "d": 3, + "f": [4, 5, 6], + "g": {2, 3, 4}, + "h": (1, 3), + "z": Counter({"a": 1, "b": 1, "c": 1}), + } + + a = {"a": {"b": {"c": 5}}, "d": 1, "f": [1, 2, 3], "g": {1, 2, 3}, "z": Counter({"a": 1, "b": 1})} + a_copy = deepcopy(a) + + b = {"a": {"B": {"C": 10}}, "d": 2, "f": [4, 5, 6], "g": {2, 3, 4}, "h": (1,)} + b_copy = deepcopy(b) + + c = {"a": {"b": {"_c": 15}}, "d": 3, "h": (1, 3), "z": Counter({"a": 1, "c": 1})} + c_copy = deepcopy(c) + + actual = merge({}, a, b, c, strategy=Strategy.TYPESAFE_REPLACE) + + self.assertEqual(actual, expected) + self.assertEqual(a, a_copy) + self.assertEqual(b, b_copy) + self.assertEqual(c, c_copy) + + ############################################################################################################################## + # TYPESAFE_ADDITIVE + ############################################################################################################################## + + def test_should_raise_TypeError_using_typesafe_additive_strategy_if_types_differ(self,): + a = {"a": {"b": {"c": 5}}, "d": 1, "e": {2: 3}, "f": [1, 2, 3]} + b = {"a": {"B": {"C": 10}}, "d": 2, "e": 2, "f": [4, 5, 6]} + c = {"a": {"b": {"_c": 15}}, "d": 3, "e": {1: 2, "a": {"f": 2}}} + + with self.assertRaises(TypeError): + merge({}, a, b, c, strategy=Strategy.TYPESAFE_ADDITIVE) + + def test_should_merge_3_dicts_into_new_dict_using_typesafe_additive_strategy_and_only_mutate_target_if_types_are_compatible( + self, + ): + expected = { + "a": {"b": {"c": 5, "_c": 15}, "B": {"C": 10}}, + "d": 3, + "f": [1, 2, 3, 4, 5, 6], + "g": {1, 2, 3, 4}, + "h": (1, 1, 3), + "z": Counter({"a": 2, "b": 1, "c": 1}), + } + + a = {"a": {"b": {"c": 5}}, "d": 1, "f": [1, 2, 3], "g": {1, 2, 3}, "z": Counter({"a": 1, "b": 1})} + a_copy = deepcopy(a) + + b = {"a": {"B": {"C": 10}}, "d": 2, "f": [4, 5, 6], "g": {2, 3, 4}, "h": (1,)} + b_copy = deepcopy(b) + + c = {"a": {"b": {"_c": 15}}, "d": 3, "h": (1, 3), "z": Counter({"a": 1, "c": 1})} + c_copy = deepcopy(c) + + actual = merge({}, a, b, c, strategy=Strategy.TYPESAFE_ADDITIVE) + + self.assertEqual(actual, expected) + self.assertEqual(a, a_copy) + self.assertEqual(b, b_copy) + self.assertEqual(c, c_copy) + + +if __name__ == "__main__": + unittest.main() diff --git a/contrib/python/mergedeep/tests/ya.make b/contrib/python/mergedeep/tests/ya.make new file mode 100644 index 00000000000..a0a227f788e --- /dev/null +++ b/contrib/python/mergedeep/tests/ya.make @@ -0,0 +1,17 @@ +PY3TEST() + +SUBSCRIBER(g:python-contrib) + +PEERDIR( + contrib/python/mergedeep +) + +SRCDIR(contrib/python/mergedeep/mergedeep) + +TEST_SRCS( + test_mergedeep.py +) + +NO_LINT() + +END() diff --git a/contrib/python/mergedeep/ya.make b/contrib/python/mergedeep/ya.make new file mode 100644 index 00000000000..ec7f03aaf4a --- /dev/null +++ b/contrib/python/mergedeep/ya.make @@ -0,0 +1,29 @@ +# Generated by devtools/yamaker (pypi). + +PY3_LIBRARY() + +SUBSCRIBER(g:python-contrib) + +VERSION(1.3.4) + +LICENSE(MIT) + +NO_LINT() + +PY_SRCS( + TOP_LEVEL + mergedeep/__init__.py + mergedeep/mergedeep.py +) + +RESOURCE_FILES( + PREFIX contrib/python/mergedeep/ + .dist-info/METADATA + .dist-info/top_level.txt +) + +END() + +RECURSE_FOR_TESTS( + tests +) -- cgit v1.3 From dacef943277fa7047bdfbbe942c90bcebdbfe791 Mon Sep 17 00:00:00 2001 From: robot-piglet Date: Wed, 7 Aug 2024 10:37:11 +0300 Subject: Intermediate changes --- .../importlib-metadata/py3/.dist-info/METADATA | 4 +- .../py3/importlib_metadata/__init__.py | 14 +++- .../py3/importlib_metadata/_itertools.py | 98 ++++++++++++++++++++++ contrib/python/importlib-metadata/py3/ya.make | 2 +- 4 files changed, 113 insertions(+), 5 deletions(-) (limited to 'contrib/python') diff --git a/contrib/python/importlib-metadata/py3/.dist-info/METADATA b/contrib/python/importlib-metadata/py3/.dist-info/METADATA index d7dd4a31a2e..691fb545bff 100644 --- a/contrib/python/importlib-metadata/py3/.dist-info/METADATA +++ b/contrib/python/importlib-metadata/py3/.dist-info/METADATA @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: importlib_metadata -Version: 8.0.0 +Version: 8.1.0 Summary: Read metadata from Python packages Author-email: "Jason R. Coombs" Project-URL: Source, https://github.com/python/importlib_metadata @@ -28,13 +28,13 @@ Requires-Dist: pytest-checkdocs >=2.4 ; extra == 'test' Requires-Dist: pytest-cov ; extra == 'test' Requires-Dist: pytest-mypy ; extra == 'test' Requires-Dist: pytest-enabler >=2.2 ; extra == 'test' -Requires-Dist: pytest-ruff >=0.2.1 ; extra == 'test' Requires-Dist: packaging ; extra == 'test' Requires-Dist: pyfakefs ; extra == 'test' Requires-Dist: flufl.flake8 ; extra == 'test' Requires-Dist: pytest-perf >=0.9.2 ; extra == 'test' Requires-Dist: jaraco.test >=5.4 ; extra == 'test' Requires-Dist: importlib-resources >=1.3 ; (python_version < "3.9") and extra == 'test' +Requires-Dist: pytest-ruff >=0.2.1 ; (sys_platform != "cygwin") and extra == 'test' .. image:: https://img.shields.io/pypi/v/importlib_metadata.svg :target: https://pypi.org/project/importlib_metadata diff --git a/contrib/python/importlib-metadata/py3/importlib_metadata/__init__.py b/contrib/python/importlib-metadata/py3/importlib_metadata/__init__.py index 6147ca9f5e7..c9730079926 100644 --- a/contrib/python/importlib-metadata/py3/importlib_metadata/__init__.py +++ b/contrib/python/importlib-metadata/py3/importlib_metadata/__init__.py @@ -24,7 +24,7 @@ from ._compat import ( install, ) from ._functools import method_cache, pass_none -from ._itertools import always_iterable, unique_everseen +from ._itertools import always_iterable, bucket, unique_everseen from ._meta import PackageMetadata, SimplePath from contextlib import suppress @@ -393,7 +393,7 @@ class Distribution(metaclass=abc.ABCMeta): if not name: raise ValueError("A distribution name is required.") try: - return next(iter(cls.discover(name=name))) + return next(iter(cls._prefer_valid(cls.discover(name=name)))) except StopIteration: raise PackageNotFoundError(name) @@ -417,6 +417,16 @@ class Distribution(metaclass=abc.ABCMeta): resolver(context) for resolver in cls._discover_resolvers() ) + @staticmethod + def _prefer_valid(dists: Iterable[Distribution]) -> Iterable[Distribution]: + """ + Prefer (move to the front) distributions that have metadata. + + Ref python/importlib_resources#489. + """ + buckets = bucket(dists, lambda dist: bool(dist.metadata)) + return itertools.chain(buckets[True], buckets[False]) + @staticmethod def at(path: str | os.PathLike[str]) -> Distribution: """Return a Distribution for the indicated metadata path. diff --git a/contrib/python/importlib-metadata/py3/importlib_metadata/_itertools.py b/contrib/python/importlib-metadata/py3/importlib_metadata/_itertools.py index d4ca9b9140e..79d37198ce7 100644 --- a/contrib/python/importlib-metadata/py3/importlib_metadata/_itertools.py +++ b/contrib/python/importlib-metadata/py3/importlib_metadata/_itertools.py @@ -1,3 +1,4 @@ +from collections import defaultdict, deque from itertools import filterfalse @@ -71,3 +72,100 @@ def always_iterable(obj, base_type=(str, bytes)): return iter(obj) except TypeError: return iter((obj,)) + + +# Copied from more_itertools 10.3 +class bucket: + """Wrap *iterable* and return an object that buckets the iterable into + child iterables based on a *key* function. + + >>> iterable = ['a1', 'b1', 'c1', 'a2', 'b2', 'c2', 'b3'] + >>> s = bucket(iterable, key=lambda x: x[0]) # Bucket by 1st character + >>> sorted(list(s)) # Get the keys + ['a', 'b', 'c'] + >>> a_iterable = s['a'] + >>> next(a_iterable) + 'a1' + >>> next(a_iterable) + 'a2' + >>> list(s['b']) + ['b1', 'b2', 'b3'] + + The original iterable will be advanced and its items will be cached until + they are used by the child iterables. This may require significant storage. + + By default, attempting to select a bucket to which no items belong will + exhaust the iterable and cache all values. + If you specify a *validator* function, selected buckets will instead be + checked against it. + + >>> from itertools import count + >>> it = count(1, 2) # Infinite sequence of odd numbers + >>> key = lambda x: x % 10 # Bucket by last digit + >>> validator = lambda x: x in {1, 3, 5, 7, 9} # Odd digits only + >>> s = bucket(it, key=key, validator=validator) + >>> 2 in s + False + >>> list(s[2]) + [] + + """ + + def __init__(self, iterable, key, validator=None): + self._it = iter(iterable) + self._key = key + self._cache = defaultdict(deque) + self._validator = validator or (lambda x: True) + + def __contains__(self, value): + if not self._validator(value): + return False + + try: + item = next(self[value]) + except StopIteration: + return False + else: + self._cache[value].appendleft(item) + + return True + + def _get_values(self, value): + """ + Helper to yield items from the parent iterator that match *value*. + Items that don't match are stored in the local cache as they + are encountered. + """ + while True: + # If we've cached some items that match the target value, emit + # the first one and evict it from the cache. + if self._cache[value]: + yield self._cache[value].popleft() + # Otherwise we need to advance the parent iterator to search for + # a matching item, caching the rest. + else: + while True: + try: + item = next(self._it) + except StopIteration: + return + item_value = self._key(item) + if item_value == value: + yield item + break + elif self._validator(item_value): + self._cache[item_value].append(item) + + def __iter__(self): + for item in self._it: + item_value = self._key(item) + if self._validator(item_value): + self._cache[item_value].append(item) + + yield from self._cache.keys() + + def __getitem__(self, value): + if not self._validator(value): + return iter(()) + + return self._get_values(value) diff --git a/contrib/python/importlib-metadata/py3/ya.make b/contrib/python/importlib-metadata/py3/ya.make index ad2a140f18c..8e7b3102b36 100644 --- a/contrib/python/importlib-metadata/py3/ya.make +++ b/contrib/python/importlib-metadata/py3/ya.make @@ -2,7 +2,7 @@ PY3_LIBRARY() -VERSION(8.0.0) +VERSION(8.1.0) LICENSE(Apache-2.0) -- cgit v1.3