Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-aioftp for openSUSE:Factory 
checked in at 2026-11-01 22:24:38
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-aioftp (Old)
 and      /work/SRC/openSUSE:Factory/.python-aioftp.new.1255 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-aioftp"

Sun Nov  1 22:24:38 2026 rev:16 rq:1394280 version:0.28.3

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-aioftp/python-aioftp.changes      
2025-11-13 17:31:05.736599624 +0100
+++ /work/SRC/openSUSE:Factory/.python-aioftp.new.1255/python-aioftp.changes    
2026-11-01 22:26:01.530491269 +0100
@@ -1,0 +2,12 @@
+Sun Oct 25 11:57:07 UTC 2026 - Dirk Müller <[email protected]>
+
+- update to 0.28.3:
+  * client is_dir should treat cdir and pdir as a directory too,
+    according to RFC3659 (fixes #211)
+  * apply connection_timeout to passive connections
+  * add trust_server_pasv_ipv4_address option with default to
+    False to avoid possible ipv4 spoofing in server response
+  * add system_type parameter to server
+  * add welcome_message parameter for a server
+
+-------------------------------------------------------------------

Old:
----
  aioftp-0.27.2.tar.gz

New:
----
  aioftp-0.28.3.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-aioftp.spec ++++++
--- /var/tmp/diff_new_pack.pTTb9M/_old  2026-11-01 22:26:02.135516351 +0100
+++ /var/tmp/diff_new_pack.pTTb9M/_new  2026-11-01 22:26:02.137516433 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package python-aioftp
 #
-# Copyright (c) 2025 SUSE LLC
+# Copyright (c) 2026 SUSE LLC and contributors
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -18,7 +18,7 @@
 
 %{?sle15_python_module_pythons}
 Name:           python-aioftp
-Version:        0.27.2
+Version:        0.28.3
 Release:        0
 Summary:        FTP client/server for asyncio
 License:        Apache-2.0

++++++ aioftp-0.27.2.tar.gz -> aioftp-0.28.3.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/aioftp-0.27.2/PKG-INFO new/aioftp-0.28.3/PKG-INFO
--- old/aioftp-0.27.2/PKG-INFO  2025-09-24 23:36:06.265699900 +0200
+++ new/aioftp-0.28.3/PKG-INFO  2026-09-19 16:24:16.943065000 +0200
@@ -1,8 +1,8 @@
 Metadata-Version: 2.4
 Name: aioftp
-Version: 0.27.2
+Version: 0.28.3
 Summary: ftp client/server for asyncio
-Author: yieyu, rsichnyi, jw4js, oleksandr-kuzmenko, ndhansen, modelmat, greut, 
PonyPC, jacobtomlinson, bachya, CrafterKolyan, jkr78, sakosha
+Author: yieyu, rsichnyi, jw4js, oleksandr-kuzmenko, ndhansen, modelmat, greut, 
PonyPC, jacobtomlinson, bachya, CrafterKolyan, jkr78, sakosha, rwakulszowa
 Author-email: pohmelie <[email protected]>, asvetlov 
<[email protected]>, decaz <[email protected]>, janneronkko 
<[email protected]>, thirtyseven <[email protected]>, ported-pw 
<[email protected]>, Olegt0rr <[email protected]>, michalc <[email protected]>, 
ch3pjw <[email protected]>, puddly <[email protected]>, AMDmi3 
<[email protected]>, webknjaz <webknjaz+github/[email protected]>, rcfox 
<[email protected]>, bellini666 <[email protected]>
 License:                                  Apache License
                                    Version 2.0, January 2004
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/aioftp-0.27.2/history.rst 
new/aioftp-0.28.3/history.rst
--- old/aioftp-0.27.2/history.rst       2025-09-24 23:36:02.000000000 +0200
+++ new/aioftp-0.28.3/history.rst       2026-09-19 16:24:13.827084000 +0200
@@ -1,4 +1,22 @@
-x.x.x (xxxx-xx-xx)
+0.28.3 (2026-09-19)
+-------------------
+- client `is_dir` should treat `cdir` and `pdir` as a directory too, according 
to RFC3659 (fixes #211)
+
+0.28.2 (2026-09-19)
+-------------------
+- apply `connection_timeout` to passive connections (#212)
+Thanks to `Cycloctane <https://github.com/Cycloctane>`_
+
+0.28.1 (2026-09-19)
+-------------------
+- add `trust_server_pasv_ipv4_address` option with default to `False` to avoid 
possible ipv4 spoofing in server response
+- add `system_type` parameter to server (#208)
+Thanks to `rwakulszowa <https://github.com/rwakulszowa>`_
+
+0.28.0 (2026-08-05)
+-------------------
+- add `welcome_message` parameter for a server (#207)
+Thanks to `rwakulszowa <https://github.com/rwakulszowa>`_
 
 0.27.2 (2025-09-25)
 -------------------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/aioftp-0.27.2/pyproject.toml 
new/aioftp-0.28.3/pyproject.toml
--- old/aioftp-0.27.2/pyproject.toml    2025-09-24 23:36:02.000000000 +0200
+++ new/aioftp-0.28.3/pyproject.toml    2026-09-19 16:24:13.827084000 +0200
@@ -1,6 +1,6 @@
 [project]
 name = "aioftp"
-version = "0.27.2"
+version = "0.28.3"
 description = "ftp client/server for asyncio"
 readme = "README.rst"
 requires-python = ">= 3.10"
@@ -33,6 +33,7 @@
     {name = "rcfox", email="[email protected]"},
     {name = "bellini666", email="[email protected]"},
     {name = "sakosha"},
+    {name = "rwakulszowa"},
 ]
 classifiers = [
     "Programming Language :: Python",
@@ -83,6 +84,7 @@
 line-length = 120
 target-version = "py310"
 lint.select = ["E", "W", "F", "Q", "UP", "I", "ASYNC"]
+lint.ignore = ["ASYNC240"]
 src = ["src"]
 exclude = ["ftpbench.py"]
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/aioftp-0.27.2/src/aioftp/client.py 
new/aioftp-0.28.3/src/aioftp/client.py
--- old/aioftp-0.27.2/src/aioftp/client.py      2025-09-24 23:36:02.000000000 
+0200
+++ new/aioftp-0.28.3/src/aioftp/client.py      2026-09-19 16:24:13.828139800 
+0200
@@ -201,6 +201,7 @@
         parse_list_line_custom: ParseListLineCustomCallable | None = None,
         parse_list_line_custom_first: bool = True,
         passive_commands: tuple[str, ...] = ("epsv", "pasv"),
+        trust_server_pasv_ipv4_address: bool = False,
         **siosocks_asyncio_kwargs: Any,
     ):
         self.socket_timeout = socket_timeout
@@ -217,6 +218,7 @@
         self.parse_list_line_custom = parse_list_line_custom
         self.parse_list_line_custom_first = parse_list_line_custom_first
         self._passive_commands = passive_commands
+        self.trust_server_pasv_ipv4_address = trust_server_pasv_ipv4_address
         self._siosocks_asyncio_kwargs = siosocks_asyncio_kwargs
 
     async def _open_connection(self, host: str, port: int) -> 
tuple[asyncio.StreamReader, asyncio.StreamWriter]:
@@ -229,21 +231,21 @@
                     context=ssl_object.context,
                     session=ssl_object.session,
                 )
-        connection: tuple[asyncio.StreamReader, asyncio.StreamWriter] = await 
open_connection(
-            host,
-            port,
-            ssl=ssl_resolved,
-            **self._siosocks_asyncio_kwargs,
+        connection: tuple[asyncio.StreamReader, asyncio.StreamWriter] = await 
asyncio.wait_for(
+            open_connection(
+                host,
+                port,
+                ssl=ssl_resolved,
+                **self._siosocks_asyncio_kwargs,
+            ),
+            self.connection_timeout,
         )
         return connection
 
     async def connect(self, host: str, port: int = DEFAULT_PORT) -> None:
         self.server_host = host
         self.server_port = port
-        reader, writer = await asyncio.wait_for(
-            self._open_connection(host, port),
-            self.connection_timeout,
-        )
+        reader, writer = await self._open_connection(host, port)
         self._stream = ThrottleStreamIO(
             reader,
             writer,
@@ -1051,7 +1053,7 @@
         :rtype: :py:class:`bool`
         """
         info = await self.stat(path)
-        return info["type"] == "dir"
+        return info["type"] in ("dir", "cdir", "pdir")
 
     async def exists(self, path: PathLike) -> bool:
         """
@@ -1319,9 +1321,12 @@
         ip, port = self.parse_epsv_response(info[-1])
         return ip, port
 
-    async def _do_pasv(self) -> tuple[str, int]:
+    async def _do_pasv(self) -> tuple[str | None, int]:
         code, info = await self.command("PASV", "227")
+        ip: str | None
         ip, port = self.parse_pasv_response(info[-1])
+        if not self.trust_server_pasv_ipv4_address:
+            ip = None
         return ip, port
 
     async def get_passive_connection(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/aioftp-0.27.2/src/aioftp/server.py 
new/aioftp-0.28.3/src/aioftp/server.py
--- old/aioftp-0.27.2/src/aioftp/server.py      2025-09-24 23:36:02.000000000 
+0200
+++ new/aioftp-0.28.3/src/aioftp/server.py      2026-09-19 16:24:13.828139800 
+0200
@@ -676,6 +676,12 @@
         to enable TLS over the accepted connections.
         Please look :py:meth:`asyncio.loop.create_server` docs.
     :type ssl: :py:class:`ssl.SSLContext`
+
+    :param welcome_message: welcome message for new connections
+    :type welcome_message: :py:class:`str`
+
+    :param system_type: identifier of the OS running the server
+    :type system_type: :py:class:`str`
     """
 
     def __init__(
@@ -697,6 +703,8 @@
         data_ports: Iterable[int] | None = None,
         encoding: str = "utf-8",
         ssl: ssl.SSLContext | None = None,
+        welcome_message: str = "welcome",
+        system_type: str = "UNIX Type: L8",
     ) -> None:
         self.block_size = block_size
         self.socket_timeout = socket_timeout
@@ -729,6 +737,8 @@
         self.throttle_per_user: dict[User | None, StreamThrottle] = {}
         self.encoding = encoding
         self.ssl = ssl
+        self.welcome_message = welcome_message
+        self.system_type = system_type
         self.commands_mapping: dict[
             str,
             Callable[[Connection, str], Awaitable[bool]] | 
Callable[[Connection, str | PurePosixPath], Awaitable[bool]],
@@ -1098,7 +1108,7 @@
         if self.available_connections.locked():
             ok, code, info = False, "421", "Too many connections"
         else:
-            ok, code, info = True, "220", "welcome"
+            ok, code, info = True, "220", self.welcome_message
             connection.acquired = True
             self.available_connections.acquire()
         connection.response(code, info)
@@ -1612,6 +1622,6 @@
         return True
 
     async def syst(self, connection: Connection, rest: str) -> bool:
-        """Return system type (always returns UNIX type: L8)."""
-        connection.response("215", "UNIX Type: L8")
+        """Return system type."""
+        connection.response("215", self.system_type)
         return True
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/aioftp-0.27.2/src/aioftp.egg-info/PKG-INFO 
new/aioftp-0.28.3/src/aioftp.egg-info/PKG-INFO
--- old/aioftp-0.27.2/src/aioftp.egg-info/PKG-INFO      2025-09-24 
23:36:06.000000000 +0200
+++ new/aioftp-0.28.3/src/aioftp.egg-info/PKG-INFO      2026-09-19 
16:24:16.924065000 +0200
@@ -1,8 +1,8 @@
 Metadata-Version: 2.4
 Name: aioftp
-Version: 0.27.2
+Version: 0.28.3
 Summary: ftp client/server for asyncio
-Author: yieyu, rsichnyi, jw4js, oleksandr-kuzmenko, ndhansen, modelmat, greut, 
PonyPC, jacobtomlinson, bachya, CrafterKolyan, jkr78, sakosha
+Author: yieyu, rsichnyi, jw4js, oleksandr-kuzmenko, ndhansen, modelmat, greut, 
PonyPC, jacobtomlinson, bachya, CrafterKolyan, jkr78, sakosha, rwakulszowa
 Author-email: pohmelie <[email protected]>, asvetlov 
<[email protected]>, decaz <[email protected]>, janneronkko 
<[email protected]>, thirtyseven <[email protected]>, ported-pw 
<[email protected]>, Olegt0rr <[email protected]>, michalc <[email protected]>, 
ch3pjw <[email protected]>, puddly <[email protected]>, AMDmi3 
<[email protected]>, webknjaz <webknjaz+github/[email protected]>, rcfox 
<[email protected]>, bellini666 <[email protected]>
 License:                                  Apache License
                                    Version 2.0, January 2004
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/aioftp-0.27.2/tests/test_connection.py 
new/aioftp-0.28.3/tests/test_connection.py
--- old/aioftp-0.27.2/tests/test_connection.py  2025-09-24 23:36:02.000000000 
+0200
+++ new/aioftp-0.28.3/tests/test_connection.py  2026-09-19 16:24:13.829216700 
+0200
@@ -129,7 +129,7 @@
 
 
 @pytest.mark.asyncio
-async def test_pasv_connection_pasv_forced_response_address(pair_factory, 
Server):
+async def test_pasv_connection_pasv_forced_response_address(pair_factory, 
Client, Server):
     def ipv4_used():
         try:
             ipaddress.IPv4Address(pair.host)
@@ -140,6 +140,7 @@
     # using TEST-NET-1 address
     ipv4_address = "192.0.2.1"
     async with pair_factory(
+        client=Client(trust_server_pasv_ipv4_address=True),
         server=Server(ipv4_pasv_forced_response_address=ipv4_address),
     ) as pair:
         assert pair.server.ipv4_pasv_forced_response_address == ipv4_address
@@ -294,3 +295,42 @@
                 pair.server.server_port,
             )
             await pair.client.login()
+
+
[email protected]
+async def test_welcome_message(pair_factory, Server):
+    welcome_message = "Welcome to the FTP server!"
+    async with pair_factory(
+        server=Server(welcome_message=welcome_message),
+        connected=False,
+    ) as pair:
+        lines = await pair.client.connect(
+            pair.server.server_host,
+            pair.server.server_port,
+        )
+        assert lines == [" " + welcome_message]
+
+
[email protected]
+async def test_system_type(pair_factory, Server):
+    system_type = "My custom OS"
+    async with pair_factory(
+        server=Server(system_type=system_type),
+    ) as pair:
+        resp = await pair.client.command("SYST", expected_codes=(215,))
+        assert resp == ("215", [" " + system_type])
+
+
[email protected]
+async def test_client_timeout_passive_connection(pair_factory, Client, 
monkeypatch):
+    open_connection = asyncio.open_connection
+
+    async def slow_open_connection(host, port, **kwargs):
+        await asyncio.sleep(1)
+        return await open_connection(host, port, **kwargs)
+
+    async with pair_factory(Client(connection_timeout=0.5), logged=True) as 
pair:
+        with monkeypatch.context() as m:
+            m.setattr("asyncio.open_connection", slow_open_connection)
+            with pytest.raises(asyncio.TimeoutError):
+                await pair.client.get_passive_connection()

Reply via email to