Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-avro for openSUSE:Factory checked in at 2024-08-27 19:39:11 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-avro (Old) and /work/SRC/openSUSE:Factory/.python-avro.new.2698 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-avro" Tue Aug 27 19:39:11 2024 rev:16 rq:1196150 version:1.12.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-avro/python-avro.changes 2024-03-07 18:32:50.204586527 +0100 +++ /work/SRC/openSUSE:Factory/.python-avro.new.2698/python-avro.changes 2024-08-27 19:39:29.764875317 +0200 @@ -1,0 +2,25 @@ +Tue Aug 27 05:24:30 UTC 2024 - Steve Kowalik <steven.kowa...@suse.com> + +- Update to 1.12.0: + * Bug fixes: + + [AVRO-1318]: Python schema should store fingerprints + + [AVRO-3622]: Python compatibility check fails if record with and + without namespace are compared + + [AVRO-3659]: Typo in python example + + [AVRO-3667]: [Python] Python 3.10 CI test fails since a while + + [AVRO-3669]: Missing py.typed file + + [AVRO-3861]: [Build] Add RAT exclusions for python docs + + [AVRO-3866]: [Build][Python] Files are leftover after a build + * Improvements: + + [AVRO-312]: Generate documentation for Python with Sphinx + + [AVRO-1938]: Python support for generating canonical forms of schema + + [AVRO-3879]: [Build][Python] Fix ./build.sh clean to remove the + generated Python documents + + [AVRO-3977]: Fix failing typecheck in Python 3.12 + * Tests: + + [AVRO-3696]: [Python] Replace tox-wheel with upstream tox 4 + * Tasks: + + [AVRO-3808]: Drop support for Python 3.6, add Pypy 3.8-3.10 +- Switch to pyproject and pyunittest macros. + +------------------------------------------------------------------- Old: ---- avro-1.11.3.tar.gz New: ---- avro-1.12.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-avro.spec ++++++ --- /var/tmp/diff_new_pack.Hk36Fy/_old 2024-08-27 19:39:30.472905288 +0200 +++ /var/tmp/diff_new_pack.Hk36Fy/_new 2024-08-27 19:39:30.472905288 +0200 @@ -18,22 +18,20 @@ %{?sle15_python_module_pythons} Name: python-avro -Version: 1.11.3 +Version: 1.12.0 Release: 0 Summary: A serialization and RPC framework for Python License: Apache-2.0 -Group: Development/Languages/Python URL: https://avro.apache.org/ Source: https://files.pythonhosted.org/packages/source/a/avro/avro-%{version}.tar.gz -BuildRequires: %{python_module pytest} +BuildRequires: %{python_module base >= 3.7} +BuildRequires: %{python_module pip} BuildRequires: %{python_module setuptools} +BuildRequires: %{python_module wheel} BuildRequires: fdupes BuildRequires: python-rpm-macros Requires(post): update-alternatives Requires(postun): update-alternatives -Requires: python-Twisted -Requires: python-zope.interface -Suggests: python-python-snappy BuildArch: noarch %python_subpackages @@ -46,17 +44,17 @@ sed -i '1{\@^#!/usr/bin/env python@d}' avro/*.py avro/tether/*.py avro/test/*.py %build -%python_build +%pyproject_wheel %install -%python_install +%pyproject_install %python_clone -a %{buildroot}%{_bindir}/avro %python_expand %fdupes %{buildroot}%{$python_sitelib} %check -# test_server_with_path: tries to connect to apache.org -# test_minimum_speed is not stable in OBS -%pytest -k "not test_server_with_path and not test_minimum_speed" +# Only contains test_server_with_path; tries to connect to apache.org +rm avro/test/test_ipc.py +%pyunittest discover -v %post %python_install_alternative avro @@ -67,5 +65,5 @@ %files %{python_files} %python_alternative %{_bindir}/avro %{python_sitelib}/avro -%{python_sitelib}/avro-%{version}-py*.egg-info +%{python_sitelib}/avro-%{version}.dist-info ++++++ avro-1.11.3.tar.gz -> avro-1.12.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/avro-1.11.3/PKG-INFO new/avro-1.12.0/PKG-INFO --- old/avro-1.11.3/PKG-INFO 2023-09-25 18:36:57.003240300 +0200 +++ new/avro-1.12.0/PKG-INFO 2024-08-05 14:11:22.501020000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: avro -Version: 1.11.3 +Version: 1.12.0 Summary: Avro is a serialization and RPC framework. Home-page: https://avro.apache.org/ Author: Apache Avro @@ -8,14 +8,13 @@ License: Apache License 2.0 Keywords: avro,serialization,rpc Classifier: License :: OSI Approved :: Apache Software License -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: Development Status :: 5 - Production/Stable -Requires-Python: >=3.6 +Requires-Python: >=3.7 Description-Content-Type: text/markdown License-File: avro/LICENSE Requires-Dist: typing-extensions; python_version < "3.8" @@ -41,4 +40,4 @@ ### License, Credits and Acknowledgements -License, credits and acknowledgements are maintained in the [LICENSE.txt](https://github.com/apache/avro/blob/master/LICENSE.txt) and [NOTICE.txt](https://github.com/apache/avro/blob/master/NOTICE.txt) in the source code repository. Those files are also included with the installed package. +License, credits and acknowledgements are maintained in the [LICENSE.txt](https://github.com/apache/avro/blob/main/LICENSE.txt) and [NOTICE.txt](https://github.com/apache/avro/blob/main/NOTICE.txt) in the source code repository. Those files are also included with the installed package. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/avro-1.11.3/README.md new/avro-1.12.0/README.md --- old/avro-1.11.3/README.md 2022-02-23 17:45:22.000000000 +0100 +++ new/avro-1.12.0/README.md 2024-07-25 21:23:22.000000000 +0200 @@ -15,4 +15,4 @@ ### License, Credits and Acknowledgements -License, credits and acknowledgements are maintained in the [LICENSE.txt](https://github.com/apache/avro/blob/master/LICENSE.txt) and [NOTICE.txt](https://github.com/apache/avro/blob/master/NOTICE.txt) in the source code repository. Those files are also included with the installed package. +License, credits and acknowledgements are maintained in the [LICENSE.txt](https://github.com/apache/avro/blob/main/LICENSE.txt) and [NOTICE.txt](https://github.com/apache/avro/blob/main/NOTICE.txt) in the source code repository. Those files are also included with the installed package. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/avro-1.11.3/avro/VERSION.txt new/avro-1.12.0/avro/VERSION.txt --- old/avro-1.11.3/avro/VERSION.txt 2023-09-15 19:47:40.000000000 +0200 +++ new/avro-1.12.0/avro/VERSION.txt 2024-07-26 09:46:35.000000000 +0200 @@ -1 +1 @@ -1.11.3 \ No newline at end of file +1.12.0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/avro-1.11.3/avro/datafile.py new/avro-1.12.0/avro/datafile.py --- old/avro-1.11.3/avro/datafile.py 2023-09-14 17:42:29.000000000 +0200 +++ new/avro-1.12.0/avro/datafile.py 2024-07-25 21:23:22.000000000 +0200 @@ -26,7 +26,7 @@ import json import warnings from types import TracebackType -from typing import IO, AnyStr, BinaryIO, MutableMapping, Optional, Type, cast +from typing import IO, AnyStr, MutableMapping, Optional, Type, cast import avro.codecs import avro.errors diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/avro-1.11.3/avro/io.py new/avro-1.12.0/avro/io.py --- old/avro-1.11.3/avro/io.py 2023-09-14 17:42:29.000000000 +0200 +++ new/avro-1.12.0/avro/io.py 2024-07-25 21:23:22.000000000 +0200 @@ -89,17 +89,7 @@ import decimal import struct import warnings -from typing import ( - IO, - Deque, - Generator, - Iterable, - List, - Mapping, - Optional, - Sequence, - Union, -) +from typing import IO, Generator, Iterable, List, Mapping, Optional, Sequence, Union import avro.constants import avro.errors @@ -266,7 +256,7 @@ """ A float is written as 4 bytes. The float is converted into a 32-bit integer using a method equivalent to - Java's floatToIntBits and then encoded in little-endian format. + Java's floatToRawIntBits and then encoded in little-endian format. """ return float(STRUCT_FLOAT.unpack(self.read(4))[0]) @@ -274,7 +264,7 @@ """ A double is written as 8 bytes. The double is converted into a 64-bit integer using a method equivalent to - Java's doubleToLongBits and then encoded in little-endian format. + Java's doubleToRawLongBits and then encoded in little-endian format. """ return float(STRUCT_DOUBLE.unpack(self.read(8))[0]) @@ -435,7 +425,6 @@ """ null is written as zero bytes """ - pass def write_boolean(self, datum: bool) -> None: """ @@ -464,7 +453,7 @@ """ A float is written as 4 bytes. The float is converted into a 32-bit integer using a method equivalent to - Java's floatToIntBits and then encoded in little-endian format. + Java's floatToRawIntBits and then encoded in little-endian format. """ self.write(STRUCT_FLOAT.pack(datum)) @@ -472,7 +461,7 @@ """ A double is written as 8 bytes. The double is converted into a 64-bit integer using a method equivalent to - Java's doubleToLongBits and then encoded in little-endian format. + Java's doubleToRawLongBits and then encoded in little-endian format. """ self.write(STRUCT_DOUBLE.pack(datum)) @@ -810,7 +799,7 @@ while block_count != 0: if block_count < 0: block_count = -block_count - block_size = decoder.read_long() + decoder.skip_long() for i in range(block_count): read_items.append(self.read_data(writers_schema.items, readers_schema.items, decoder)) block_count = decoder.read_long() @@ -847,7 +836,7 @@ while block_count != 0: if block_count < 0: block_count = -block_count - block_size = decoder.read_long() + decoder.skip_long() for i in range(block_count): key = decoder.read_utf8() read_items[key] = self.read_data(writers_schema.values, readers_schema.values, decoder) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/avro-1.11.3/avro/ipc.py new/avro-1.12.0/avro/ipc.py --- old/avro-1.11.3/avro/ipc.py 2023-09-14 17:42:29.000000000 +0200 +++ new/avro-1.12.0/avro/ipc.py 2024-07-25 21:23:22.000000000 +0200 @@ -77,27 +77,41 @@ self._send_protocol = None # read-only properties - local_protocol = property(lambda self: self._local_protocol) - transceiver = property(lambda self: self._transceiver) + @property + def local_protocol(self): + return self._local_protocol + + @property + def transceiver(self): + return self._transceiver # read/write properties - def set_remote_protocol(self, new_remote_protocol): + @property + def remote_protocol(self): + return self._remote_protocol + + @remote_protocol.setter + def remote_protocol(self, new_remote_protocol): self._remote_protocol = new_remote_protocol REMOTE_PROTOCOLS[self.transceiver.remote_name] = self.remote_protocol - remote_protocol = property(lambda self: self._remote_protocol, set_remote_protocol) + @property + def remote_hash(self): + return self._remote_hash - def set_remote_hash(self, new_remote_hash): + @remote_hash.setter + def remote_hash(self, new_remote_hash): self._remote_hash = new_remote_hash REMOTE_HASHES[self.transceiver.remote_name] = self.remote_hash - remote_hash = property(lambda self: self._remote_hash, set_remote_hash) + @property + def send_protocol(self): + return self._send_protocol - def set_send_protocol(self, new_send_protocol): + @send_protocol.setter + def send_protocol(self, new_send_protocol): self._send_protocol = new_send_protocol - send_protocol = property(lambda self: self._send_protocol, set_send_protocol) - def request(self, message_name, request_datum): """ Writes a request message and reads a response or error message. @@ -185,7 +199,7 @@ the error, serialized per the message's error union schema. """ # response metadata - response_metadata = META_READER.read(decoder) + META_READER.read(decoder) # remote response schema remote_message_schema = self.remote_protocol.messages.get(message_name) @@ -236,9 +250,17 @@ self.set_protocol_cache(self.local_hash, self.local_protocol) # read-only properties - local_protocol = property(lambda self: self._local_protocol) - local_hash = property(lambda self: self._local_hash) - protocol_cache = property(lambda self: self._protocol_cache) + @property + def local_protocol(self): + return self._local_protocol + + @property + def local_hash(self): + return self._local_hash + + @property + def protocol_cache(self): + return self._protocol_cache # utility functions to manipulate protocol cache def get_protocol_cache(self, hash): @@ -266,7 +288,7 @@ return buffer_writer.getvalue() # read request using remote protocol - request_metadata = META_READER.read(buffer_decoder) + META_READER.read(buffer_decoder) remote_message_name = buffer_decoder.read_utf8() # get remote and local request schemas so we can do @@ -342,9 +364,8 @@ def invoke(self, local_message, request): """ - Aactual work done by server: cf. handler in thrift. + Actual work done by server: cf. handler in thrift. """ - pass def read_request(self, writers_schema, readers_schema, decoder): datum_reader = avro.io.DatumReader(writers_schema, readers_schema) @@ -371,7 +392,9 @@ self._reader = reader # read-only properties - reader = property(lambda self: self._reader) + @property + def reader(self): + return self._reader def read_framed_message(self): message = [] @@ -401,7 +424,9 @@ self._writer = writer # read-only properties - writer = property(lambda self: self._writer) + @property + def writer(self): + return self._writer def write_framed_message(self, message): message_length = len(message) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/avro-1.11.3/avro/schema.py new/avro-1.12.0/avro/schema.py --- old/avro-1.11.3/avro/schema.py 2023-09-14 17:42:29.000000000 +0200 +++ new/avro-1.12.0/avro/schema.py 2024-07-25 21:23:22.000000000 +0200 @@ -50,6 +50,7 @@ from functools import reduce from pathlib import Path from typing import ( + Callable, FrozenSet, List, Mapping, @@ -62,7 +63,6 @@ import avro.constants import avro.errors -from avro.constants import NAMED_TYPES, PRIMITIVE_TYPES, VALID_TYPES from avro.name import Name, Names, validate_basename # @@ -197,9 +197,11 @@ return get_other_props(self.props, self._reserved_properties) -class EqualByJsonMixin: +class EqualByJsonMixin(collections.abc.Hashable): """A mixin that defines equality as equal if the json deserializations are equal.""" + fingerprint: Callable[..., bytes] + def __eq__(self, that: object) -> bool: try: that_obj = json.loads(str(that)) @@ -207,13 +209,29 @@ return False return cast(bool, json.loads(str(self)) == that_obj) + def __hash__(self) -> int: + """Make it so a schema can be in a set or a key in a dictionary. + + NB: Python has special rules for this method being defined in the same class as __eq__. + """ + return hash(self.fingerprint()) -class EqualByPropsMixin(PropertiesMixin): + +class EqualByPropsMixin(collections.abc.Hashable, PropertiesMixin): """A mixin that defines equality as equal if the props are equal.""" + fingerprint: Callable[..., bytes] + def __eq__(self, that: object) -> bool: return hasattr(that, "props") and self.props == getattr(that, "props") + def __hash__(self) -> int: + """Make it so a schema can be in a set or a key in a dictionary. + + NB: Python has special rules for this method being defined in the same class as __eq__. + """ + return hash(self.fingerprint()) + class CanonicalPropertiesMixin(PropertiesMixin): """A Mixin that provides canonical properties to Schema and Field types.""" @@ -232,7 +250,7 @@ def __init__(self, type_: str, other_props: Optional[Mapping[str, object]] = None, validate_names: bool = True) -> None: if not isinstance(type_, str): raise avro.errors.SchemaParseException("Schema type must be a string.") - if type_ not in VALID_TYPES: + if type_ not in avro.constants.VALID_TYPES: raise avro.errors.SchemaParseException(f"{type_} is not a valid type.") self.set_prop("type", type_) self.type = type_ @@ -355,9 +373,17 @@ return self.name if self.namespace == names.default_namespace else self.fullname # read-only properties - name = property(lambda self: self.get_prop("name")) - namespace = property(lambda self: self.get_prop("namespace")) - fullname = property(lambda self: self._fullname) + @property + def name(self): + return self.get_prop("name") + + @property + def namespace(self): + return self.get_prop("namespace") + + @property + def fullname(self): + return self._fullname # @@ -426,10 +452,21 @@ self.set_prop("doc", doc) # read-only properties - default = property(lambda self: self.get_prop("default")) - has_default = property(lambda self: self._has_default) - order = property(lambda self: self.get_prop("order")) - doc = property(lambda self: self.get_prop("doc")) + @property + def default(self): + return self.get_prop("default") + + @property + def has_default(self): + return self._has_default + + @property + def order(self): + return self.get_prop("order") + + @property + def doc(self): + return self.get_prop("doc") def __str__(self): return json.dumps(self.to_json()) @@ -472,7 +509,7 @@ def __init__(self, type, other_props=None): # Ensure valid ctor args - if type not in PRIMITIVE_TYPES: + if type not in avro.constants.PRIMITIVE_TYPES: raise avro.errors.AvroException(f"{type} is not a valid primitive type.") # Call parent ctor @@ -528,8 +565,13 @@ self.set_prop("scale", scale) # read-only properties - precision = property(lambda self: self.get_prop("precision")) - scale = property(lambda self: self.get_prop("scale")) + @property + def precision(self): + return self.get_prop("precision") + + @property + def scale(self): + return self.get_prop("scale") def to_json(self, names=None): return self.props @@ -556,7 +598,9 @@ self.set_prop("size", size) # read-only properties - size = property(lambda self: self.get_prop("size")) + @property + def size(self): + return self.get_prop("size") def match(self, writer): """Return True if the current schema (as reader) matches the writer schema. @@ -610,8 +654,13 @@ self.set_prop("scale", scale) # read-only properties - precision = property(lambda self: self.get_prop("precision")) - scale = property(lambda self: self.get_prop("scale")) + @property + def precision(self): + return self.get_prop("precision") + + @property + def scale(self): + return self.get_prop("scale") def to_json(self, names=None): return self.props @@ -666,7 +715,9 @@ return symbols raise Exception - doc = property(lambda self: self.get_prop("doc")) + @property + def doc(self): + return self.get_prop("doc") def match(self, writer): """Return True if the current schema (as reader) matches the writer schema. @@ -724,7 +775,9 @@ self.set_prop("items", items_schema) # read-only properties - items = property(lambda self: self.get_prop("items")) + @property + def items(self): + return self.get_prop("items") def match(self, writer): """Return True if the current schema (as reader) matches the writer schema. @@ -776,7 +829,9 @@ self.set_prop("values", values_schema) # read-only properties - values = property(lambda self: self.get_prop("values")) + @property + def values(self): + return self.get_prop("values") def match(self, writer): """Return True if the current schema (as reader) matches the writer schema. @@ -833,8 +888,8 @@ raise avro.errors.SchemaParseException(f"Union item must be a valid Avro schema: {e}") # check the new schema if ( - new_schema.type in VALID_TYPES - and new_schema.type not in NAMED_TYPES + new_schema.type in avro.constants.VALID_TYPES + and new_schema.type not in avro.constants.NAMED_TYPES and new_schema.type in [schema.type for schema in schema_objects] ): raise avro.errors.SchemaParseException(f"{new_schema.type} type already in Union") @@ -845,7 +900,9 @@ self._schemas = schema_objects # read-only properties - schemas = property(lambda self: self._schemas) + @property + def schemas(self): + return self._schemas def match(self, writer): """Return True if the current schema (as reader) matches the writer schema. @@ -871,9 +928,7 @@ def validate(self, datum): """Return the first branch schema of which datum is a valid example, else None.""" - for branch in self.schemas: - if branch.validate(datum) is not None: - return branch + return next((branch for branch in self.schemas if branch.validate(datum) is not None), None) class ErrorUnionSchema(UnionSchema): @@ -969,8 +1024,13 @@ names.default_namespace = old_default # read-only properties - fields = property(lambda self: self.get_prop("fields")) - doc = property(lambda self: self.get_prop("doc")) + @property + def fields(self): + return self.get_prop("fields") + + @property + def doc(self): + return self.get_prop("doc") @property def fields_dict(self): @@ -1199,7 +1259,7 @@ if logical_schema is not None: return cast(Schema, logical_schema) - if type_ in NAMED_TYPES: + if type_ in avro.constants.NAMED_TYPES: name = json_data.get("name") if not isinstance(name, str): raise avro.errors.SchemaParseException(f"Name {name} must be a string, but it is {type(name)}.") @@ -1229,10 +1289,10 @@ return RecordSchema(name, namespace, fields, names, type_, doc, other_props, validate_names) raise avro.errors.SchemaParseException(f"Unknown Named Type: {type_}") - if type_ in PRIMITIVE_TYPES: + if type_ in avro.constants.PRIMITIVE_TYPES: return PrimitiveSchema(type_, other_props) - if type_ in VALID_TYPES: + if type_ in avro.constants.VALID_TYPES: if type_ == "array": items = json_data.get("items") return ArraySchema(items, names, other_props, validate_names) @@ -1252,7 +1312,7 @@ elif isinstance(json_data, list): return UnionSchema(json_data, names, validate_names=validate_names) # JSON string (primitive) - elif json_data in PRIMITIVE_TYPES: + elif json_data in avro.constants.PRIMITIVE_TYPES: return PrimitiveSchema(json_data) # not for us! fail_msg = f"Could not make an Avro Schema object from {json_data}" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/avro-1.11.3/avro/test/gen_interop_data.py new/avro-1.12.0/avro/test/gen_interop_data.py --- old/avro-1.11.3/avro/test/gen_interop_data.py 2023-09-14 17:42:29.000000000 +0200 +++ new/avro-1.12.0/avro/test/gen_interop_data.py 2024-07-25 21:23:22.000000000 +0200 @@ -23,6 +23,7 @@ import io import json import os +from contextlib import closing from pathlib import Path from typing import IO, TextIO @@ -93,7 +94,8 @@ def main() -> int: args = _parse_args() - generate(args.schema_path, args.output_path) + with closing(args.output_path) as op: + generate(args.schema_path, op) return 0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/avro-1.11.3/avro/test/test_protocol.py new/avro-1.12.0/avro/test/test_protocol.py --- old/avro-1.11.3/avro/test/test_protocol.py 2023-09-14 17:42:29.000000000 +0200 +++ new/avro-1.12.0/avro/test/test_protocol.py 2024-07-25 21:23:22.000000000 +0200 @@ -392,7 +392,7 @@ self.assertEqual("com.acme.Greeting", proto.types[0].fullname) self.assertEqual("Greeting", proto.types[0].name) # but there shouldn't be 'namespace' rendered to json on the inner type - self.assertFalse("namespace" in proto.to_json()["types"][0]) + self.assertNotIn("namespace", proto.to_json()["types"][0]) class ProtocolParseTestCase(unittest.TestCase): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/avro-1.11.3/avro/test/test_schema.py new/avro-1.12.0/avro/test/test_schema.py --- old/avro-1.11.3/avro/test/test_schema.py 2023-09-14 17:42:29.000000000 +0200 +++ new/avro-1.12.0/avro/test/test_schema.py 2024-07-25 21:23:22.000000000 +0200 @@ -58,12 +58,12 @@ valid = False -PRIMITIVE_EXAMPLES = [InvalidTestSchema('"True"')] # type: List[TestSchema] +PRIMITIVE_EXAMPLES: List[TestSchema] = [InvalidTestSchema('"True"')] PRIMITIVE_EXAMPLES.append(InvalidTestSchema("True")) PRIMITIVE_EXAMPLES.append(InvalidTestSchema('{"no_type": "test"}')) PRIMITIVE_EXAMPLES.append(InvalidTestSchema('{"type": "panther"}')) -PRIMITIVE_EXAMPLES.extend([ValidTestSchema(f'"{t}"') for t in avro.schema.PRIMITIVE_TYPES]) -PRIMITIVE_EXAMPLES.extend([ValidTestSchema({"type": t}) for t in avro.schema.PRIMITIVE_TYPES]) +PRIMITIVE_EXAMPLES.extend([ValidTestSchema(f'"{t}"') for t in avro.constants.PRIMITIVE_TYPES]) +PRIMITIVE_EXAMPLES.extend([ValidTestSchema({"type": t}) for t in avro.constants.PRIMITIVE_TYPES]) FIXED_EXAMPLES = [ ValidTestSchema({"type": "fixed", "name": "Test", "size": 1}), @@ -890,6 +890,31 @@ self.test_schema.parse() +class HashableTestCase(unittest.TestCase): + """Ensure that Schema are hashable. + + While hashability is implemented with parsing canonical form fingerprinting, + this test should be kept distinct to avoid coupling.""" + + def __init__(self, test_schema): + """Ignore the normal signature for unittest.TestCase because we are generating + many test cases from this one class. This is safe as long as the autoloader + ignores this class. The autoloader will ignore this class as long as it has + no methods starting with `test_`. + """ + super().__init__("parse_and_hash") + self.test_schema = test_schema + + def parse_and_hash(self): + """Ensure that every schema can be hashed.""" + try: + hash(self.test_schema.parse()) + except TypeError as e: + if "unhashable type" in str(e): + self.fail(f"{self.test_schema} is not hashable") + raise + + class RoundTripParseTestCase(unittest.TestCase): """Enable generating round-trip parse test cases over all the valid test schema.""" @@ -1434,6 +1459,7 @@ suite.addTests(OtherAttributesTestCase(ex) for ex in OTHER_PROP_EXAMPLES) suite.addTests(loader.loadTestsFromTestCase(CanonicalFormTestCase)) suite.addTests(FingerprintTestCase(ex[0], ex[1]) for ex in FINGERPRINT_EXAMPLES) + suite.addTests(HashableTestCase(ex) for ex in VALID_EXAMPLES) return suite diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/avro-1.11.3/avro/test/test_tether_task.py new/avro-1.12.0/avro/test/test_tether_task.py --- old/avro-1.11.3/avro/test/test_tether_task.py 2023-09-14 17:42:29.000000000 +0200 +++ new/avro-1.12.0/avro/test/test_tether_task.py 2024-07-25 21:23:22.000000000 +0200 @@ -18,7 +18,6 @@ # limitations under the License. import io -import os import subprocess import sys import time diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/avro-1.11.3/avro/test/test_tether_task_runner.py new/avro-1.12.0/avro/test/test_tether_task_runner.py --- old/avro-1.11.3/avro/test/test_tether_task_runner.py 2023-09-14 17:42:29.000000000 +0200 +++ new/avro-1.12.0/avro/test/test_tether_task_runner.py 2024-07-25 21:23:22.000000000 +0200 @@ -19,7 +19,6 @@ import io import logging -import os import subprocess import sys import time @@ -47,7 +46,6 @@ pyfile = avro.test.mock_tether_parent.__file__ proc = subprocess.Popen([sys.executable, pyfile, "start_server", f"{parent_port}"]) - input_port = avro.tether.util.find_port() print(f"Mock server started process pid={proc.pid}") # Possible race condition? open tries to connect to the subprocess before the subprocess is fully started diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/avro-1.11.3/avro/test/test_tether_word_count.py new/avro-1.12.0/avro/test/test_tether_word_count.py --- old/avro-1.11.3/avro/test/test_tether_word_count.py 2022-02-23 17:45:22.000000000 +0100 +++ new/avro-1.12.0/avro/test/test_tether_word_count.py 2024-07-25 21:23:22.000000000 +0200 @@ -18,7 +18,6 @@ # limitations under the License. import collections -import distutils.spawn import os import platform import shutil @@ -80,13 +79,13 @@ telling you how to install java. This code does additional work around that to be completely automatic. """ - if platform.system() == "Darwin": - try: - output = subprocess.check_output("/usr/libexec/java_home", stderr=subprocess.STDOUT) - except subprocess.CalledProcessError as e: - output = e.output - return b"No Java runtime present" not in output - return bool(distutils.spawn.find_executable("java")) + if platform.system() != "Darwin": + return bool(shutil.which("java")) + try: + output = subprocess.check_output("/usr/libexec/java_home", stderr=subprocess.STDOUT) + except subprocess.CalledProcessError as e: + output = e.output + return b"No Java runtime present" not in output @unittest.skipUnless(_has_java(), "No Java runtime present") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/avro-1.11.3/avro/tether/__init__.py new/avro-1.12.0/avro/tether/__init__.py --- old/avro-1.11.3/avro/tether/__init__.py 2023-09-14 17:42:29.000000000 +0200 +++ new/avro-1.12.0/avro/tether/__init__.py 2024-07-25 21:23:22.000000000 +0200 @@ -27,3 +27,13 @@ ) from avro.tether.tether_task_runner import TaskRunner from avro.tether.util import find_port + +__all__ = ( + "HTTPRequestor", + "TaskRunner", + "TaskType", + "TetherTask", + "find_port", + "inputProtocol", + "outputProtocol", +) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/avro-1.11.3/avro/tether/tether_task.py new/avro-1.12.0/avro/tether/tether_task.py --- old/avro-1.11.3/avro/tether/tether_task.py 2023-09-14 17:42:29.000000000 +0200 +++ new/avro-1.12.0/avro/tether/tether_task.py 2024-07-25 21:23:22.000000000 +0200 @@ -285,7 +285,7 @@ try: inSchema = avro.schema.parse(inSchemaText) - outSchema = avro.schema.parse(outSchemaText) + avro.schema.parse(outSchemaText) if taskType == TaskType.MAP: self.inReader = avro.io.DatumReader(writers_schema=inSchema, readers_schema=self.inschema) @@ -299,7 +299,7 @@ # determine which fields in the input record are they keys for the reducer self._red_fkeys = [f.name for f in self.midschema.fields if not (f.order == "ignore")] - except Exception as e: + except Exception: estr = traceback.format_exc() self.fail(estr) @@ -345,7 +345,7 @@ self.reduceFlush(prev, self.outCollector) self.reduce(self.midRecord, self.outCollector) - except Exception as e: + except Exception: estr = traceback.format_exc() self.log.warning("failing: %s", estr) self.fail(estr) @@ -357,7 +357,7 @@ if (self.taskType == TaskType.REDUCE) and not (self.midRecord is None): try: self.reduceFlush(self.midRecord, self.outCollector) - except Exception as e: + except Exception: estr = traceback.format_exc() self.log.warning("failing: %s", estr) self.fail(estr) @@ -430,7 +430,7 @@ try: self.outputClient.request("fail", {"message": message}) - except Exception as e: + except Exception: self.log.exception("TetherTask.fail: an exception occured while trying to send the fail message to the output server.") self.close() @@ -441,7 +441,7 @@ try: self.clienTransciever.close() - except Exception as e: + except Exception: # ignore exceptions pass diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/avro-1.11.3/avro/tether/tether_task_runner.py new/avro-1.12.0/avro/tether/tether_task_runner.py --- old/avro-1.11.3/avro/tether/tether_task_runner.py 2023-09-14 17:42:29.000000000 +0200 +++ new/avro-1.12.0/avro/tether/tether_task_runner.py 2024-07-25 21:23:22.000000000 +0200 @@ -66,7 +66,7 @@ self.log.info("TetherTaskRunner: Received partitions") try: self.task.partitions = request["partitions"] - except Exception as e: + except Exception: self.log.error("Exception occured while processing the partitions message: Message:\n%s", traceback.format_exc()) raise elif message.name == "input": diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/avro-1.11.3/avro/utils.py new/avro-1.12.0/avro/utils.py --- old/avro-1.11.3/avro/utils.py 2023-09-14 17:42:29.000000000 +0200 +++ new/avro-1.12.0/avro/utils.py 2024-07-25 21:23:22.000000000 +0200 @@ -36,3 +36,5 @@ randbytes = getattr(random, "randbytes", _randbytes) + +__all__ = ("randbytes", "TypedDict") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/avro-1.11.3/avro.egg-info/PKG-INFO new/avro-1.12.0/avro.egg-info/PKG-INFO --- old/avro-1.11.3/avro.egg-info/PKG-INFO 2023-09-25 18:36:56.000000000 +0200 +++ new/avro-1.12.0/avro.egg-info/PKG-INFO 2024-08-05 14:11:22.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: avro -Version: 1.11.3 +Version: 1.12.0 Summary: Avro is a serialization and RPC framework. Home-page: https://avro.apache.org/ Author: Apache Avro @@ -8,14 +8,13 @@ License: Apache License 2.0 Keywords: avro,serialization,rpc Classifier: License :: OSI Approved :: Apache Software License -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: Development Status :: 5 - Production/Stable -Requires-Python: >=3.6 +Requires-Python: >=3.7 Description-Content-Type: text/markdown License-File: avro/LICENSE Requires-Dist: typing-extensions; python_version < "3.8" @@ -41,4 +40,4 @@ ### License, Credits and Acknowledgements -License, credits and acknowledgements are maintained in the [LICENSE.txt](https://github.com/apache/avro/blob/master/LICENSE.txt) and [NOTICE.txt](https://github.com/apache/avro/blob/master/NOTICE.txt) in the source code repository. Those files are also included with the installed package. +License, credits and acknowledgements are maintained in the [LICENSE.txt](https://github.com/apache/avro/blob/main/LICENSE.txt) and [NOTICE.txt](https://github.com/apache/avro/blob/main/NOTICE.txt) in the source code repository. Those files are also included with the installed package. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/avro-1.11.3/pyproject.toml new/avro-1.12.0/pyproject.toml --- old/avro-1.11.3/pyproject.toml 2023-09-14 17:42:29.000000000 +0200 +++ new/avro-1.12.0/pyproject.toml 2024-07-25 21:23:22.000000000 +0200 @@ -25,3 +25,12 @@ [tool.isort] profile = 'black' + +[tool.autoflake] +expand-star-imports = true +recursive = true +# Put a name in __all_ to explicitly export something a module imports. +# This is clearer and will keep autoflake from trying to remove it. +remove-all-unused-imports = true +remove-duplicate-keys = true +remove-unused-variables = true diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/avro-1.11.3/setup.cfg new/avro-1.12.0/setup.cfg --- old/avro-1.11.3/setup.cfg 2023-09-25 18:36:57.003240300 +0200 +++ new/avro-1.12.0/setup.cfg 2024-08-05 14:11:22.501452400 +0200 @@ -15,7 +15,6 @@ license = Apache License 2.0 classifiers = License :: OSI Approved :: Apache Software License - Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 @@ -39,7 +38,7 @@ install_requires = typing-extensions;python_version<"3.8" zip_safe = true -python_requires = >=3.6 +python_requires = >=3.7 [options.entry_points] console_scripts = @@ -64,6 +63,9 @@ [aliases] dist = sdist --dist-dir ../../dist/py +[flake8] +max-line-length = 150 + [egg_info] tag_build = tag_date = 0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/avro-1.11.3/setup.py new/avro-1.12.0/setup.py --- old/avro-1.11.3/setup.py 2023-09-14 17:42:29.000000000 +0200 +++ new/avro-1.12.0/setup.py 2024-07-25 21:23:22.000000000 +0200 @@ -19,9 +19,7 @@ import distutils.errors -import glob import os -import subprocess import setuptools # type: ignore