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
 

Reply via email to