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 2021-11-08 17:24:13 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-aioftp (Old) and /work/SRC/openSUSE:Factory/.python-aioftp.new.1890 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-aioftp" Mon Nov 8 17:24:13 2021 rev:5 rq:929836 version:0.19.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-aioftp/python-aioftp.changes 2021-01-27 18:57:26.856360302 +0100 +++ /work/SRC/openSUSE:Factory/.python-aioftp.new.1890/python-aioftp.changes 2021-11-08 17:25:00.220725594 +0100 @@ -1,0 +2,7 @@ +Wed Nov 3 09:47:36 UTC 2021 - John Paul Adrian Glaubitz <adrian.glaub...@suse.com> + +- Update to 0.19.0 + * add client connection timeout + * remove explicit coroutine passing to `asyncio.wait` + +------------------------------------------------------------------- Old: ---- aioftp-0.18.1.tar.gz New: ---- aioftp-0.19.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-aioftp.spec ++++++ --- /var/tmp/diff_new_pack.u8nZmr/_old 2021-11-08 17:25:00.712725917 +0100 +++ /var/tmp/diff_new_pack.u8nZmr/_new 2021-11-08 17:25:00.712725917 +0100 @@ -20,7 +20,7 @@ %define skip_python2 1 %define skip_python36 1 Name: python-aioftp -Version: 0.18.1 +Version: 0.19.0 Release: 0 Summary: FTP client/server for asyncio License: Apache-2.0 ++++++ aioftp-0.18.1.tar.gz -> aioftp-0.19.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aioftp-0.18.1/PKG-INFO new/aioftp-0.19.0/PKG-INFO --- old/aioftp-0.18.1/PKG-INFO 2020-10-03 13:45:39.000000000 +0200 +++ new/aioftp-0.19.0/PKG-INFO 2021-10-26 21:52:54.011503000 +0200 @@ -1,163 +1,11 @@ Metadata-Version: 2.1 Name: aioftp -Version: 0.18.1 +Version: 0.19.0 Summary: ftp client/server for asyncio Home-page: https://github.com/aio-libs/aioftp Author: pohmelie Author-email: multisosnoo...@gmail.com License: Apache-2.0 -Description: .. aioftp documentation master file, created by - sphinx-quickstart on Fri Apr 17 16:21:03 2015. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - - aioftp - ====== - - .. image:: https://travis-ci.com/aio-libs/aioftp.svg?branch=master - :target: https://travis-ci.com/aio-libs/aioftp - :alt: Travis status for master branch - - .. image:: https://codecov.io/gh/aio-libs/aioftp/branch/master/graph/badge.svg - :target: https://codecov.io/gh/aio-libs/aioftp - - .. image:: https://img.shields.io/pypi/v/aioftp.svg - :target: https://pypi.python.org/pypi/aioftp - - .. image:: https://img.shields.io/pypi/pyversions/aioftp.svg - :target: https://pypi.python.org/pypi/aioftp - - .. image:: https://pepy.tech/badge/aioftp/month - :target: https://pypi.python.org/pypi/aioftp - - ftp client/server for asyncio (http://aioftp.readthedocs.org) - - .. _GitHub: https://github.com/aio-libs/aioftp - - Features - -------- - - - Simple. - - Extensible. - - Client socks proxy via `siosocks <https://github.com/pohmelie/siosocks>`_ - (`pip install aioftp[socks]`). - - Goals - ----- - - - Minimum usable core. - - Do not use deprecated or overridden commands and features (if possible). - - Very high level api. - - Client use this commands: USER, PASS, ACCT, PWD, CWD, CDUP, MKD, RMD, MLSD, - MLST, RNFR, RNTO, DELE, STOR, APPE, RETR, TYPE, PASV, ABOR, QUIT, REST, LIST - (as fallback) - - Server support this commands: USER, PASS, QUIT, PWD, CWD, CDUP, MKD, RMD, MLSD, - LIST (but it's not recommended to use it, cause it has no standard format), - MLST, RNFR, RNTO, DELE, STOR, RETR, TYPE ("I" and "A"), PASV, ABOR, APPE, REST - - This subsets are enough for 99% of tasks, but if you need something, then you - can easily extend current set of commands. - - Server benchmark - ---------------- - - Compared with `pyftpdlib <https://github.com/giampaolo/pyftpdlib>`_ and - checked with its ftpbench script. - - aioftp 0.8.0 - - :: - - STOR (client -> server) 284.95 MB/sec - RETR (server -> client) 408.44 MB/sec - 200 concurrent clients (connect, login) 0.18 secs - STOR (1 file with 200 idle clients) 287.52 MB/sec - RETR (1 file with 200 idle clients) 382.05 MB/sec - 200 concurrent clients (RETR 10.0M file) 13.33 secs - 200 concurrent clients (STOR 10.0M file) 12.56 secs - 200 concurrent clients (QUIT) 0.03 secs - - pyftpdlib 1.5.2 - - :: - - STOR (client -> server) 1235.56 MB/sec - RETR (server -> client) 3960.21 MB/sec - 200 concurrent clients (connect, login) 0.06 secs - STOR (1 file with 200 idle clients) 1208.58 MB/sec - RETR (1 file with 200 idle clients) 3496.03 MB/sec - 200 concurrent clients (RETR 10.0M file) 0.55 secs - 200 concurrent clients (STOR 10.0M file) 1.46 secs - 200 concurrent clients (QUIT) 0.02 secs - - Dependencies - ------------ - - - Python 3.7+ - - 0.13.0 is the last version which supports python 3.5.3+ - - 0.16.1 is the last version which supports python 3.6+ - - License - ------- - - aioftp is offered under the Apache 2 license. - - Library installation - -------------------- - - :: - - pip install aioftp - - Getting started - --------------- - - Client example - - .. code-block:: python - - import asyncio - import aioftp - - - async def get_mp3(host, port, login, password): - async with aioftp.Client.context(host, port, login, password) as client: - for path, info in (await client.list(recursive=True)): - if info["type"] == "file" and path.suffix == ".mp3": - await client.download(path) - - - tasks = ( - get_mp3("server1.com", 21, "login", "password"), - get_mp3("server2.com", 21, "login", "password"), - get_mp3("server3.com", 21, "login", "password"), - ) - asyncio.run(asyncio.wait(tasks)) - - Server example - - .. code-block:: python - - import asyncio - import aioftp - - - async def main(): - server = aioftp.Server([user], path_io_factory=path_io_factory) - await server.run() - - asyncio.run(main()) - - Or just use simple server - - .. code-block:: shell - - python -m aioftp --help - Platform: UNKNOWN Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 @@ -166,3 +14,165 @@ Requires-Python: >=3.7 Provides-Extra: socks Provides-Extra: tests +License-File: license.txt + +.. aioftp documentation master file, created by + sphinx-quickstart on Fri Apr 17 16:21:03 2015. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +aioftp +====== + +.. image:: https://github.com/aio-libs/aioftp/actions/workflows/ci.yml/badge.svg?branch=master + :target: https://github.com/aio-libs/aioftp/actions/workflows/ci.yml + :alt: Github actions tests for master branch + +.. image:: https://github.com/aio-libs/aioftp/actions/workflows/cd.yml/badge.svg?branch=master + :target: https://github.com/aio-libs/aioftp/actions/workflows/cd.yml + :alt: Github actions deploy to pypi for master branch + +.. image:: https://codecov.io/gh/aio-libs/aioftp/branch/master/graph/badge.svg + :target: https://codecov.io/gh/aio-libs/aioftp + +.. image:: https://img.shields.io/pypi/v/aioftp.svg + :target: https://pypi.python.org/pypi/aioftp + +.. image:: https://img.shields.io/pypi/pyversions/aioftp.svg + :target: https://pypi.python.org/pypi/aioftp + +.. image:: https://pepy.tech/badge/aioftp/month + :target: https://pypi.python.org/pypi/aioftp + +ftp client/server for asyncio (http://aioftp.readthedocs.org) + +.. _GitHub: https://github.com/aio-libs/aioftp + +Features +-------- + +- Simple. +- Extensible. +- Client socks proxy via `siosocks <https://github.com/pohmelie/siosocks>`_ + (`pip install aioftp[socks]`). + +Goals +----- + +- Minimum usable core. +- Do not use deprecated or overridden commands and features (if possible). +- Very high level api. + +Client use this commands: USER, PASS, ACCT, PWD, CWD, CDUP, MKD, RMD, MLSD, +MLST, RNFR, RNTO, DELE, STOR, APPE, RETR, TYPE, PASV, ABOR, QUIT, REST, LIST +(as fallback) + +Server support this commands: USER, PASS, QUIT, PWD, CWD, CDUP, MKD, RMD, MLSD, +LIST (but it's not recommended to use it, cause it has no standard format), +MLST, RNFR, RNTO, DELE, STOR, RETR, TYPE ("I" and "A"), PASV, ABOR, APPE, REST + +This subsets are enough for 99% of tasks, but if you need something, then you +can easily extend current set of commands. + +Server benchmark +---------------- + +Compared with `pyftpdlib <https://github.com/giampaolo/pyftpdlib>`_ and +checked with its ftpbench script. + +aioftp 0.8.0 + +:: + + STOR (client -> server) 284.95 MB/sec + RETR (server -> client) 408.44 MB/sec + 200 concurrent clients (connect, login) 0.18 secs + STOR (1 file with 200 idle clients) 287.52 MB/sec + RETR (1 file with 200 idle clients) 382.05 MB/sec + 200 concurrent clients (RETR 10.0M file) 13.33 secs + 200 concurrent clients (STOR 10.0M file) 12.56 secs + 200 concurrent clients (QUIT) 0.03 secs + +pyftpdlib 1.5.2 + +:: + + STOR (client -> server) 1235.56 MB/sec + RETR (server -> client) 3960.21 MB/sec + 200 concurrent clients (connect, login) 0.06 secs + STOR (1 file with 200 idle clients) 1208.58 MB/sec + RETR (1 file with 200 idle clients) 3496.03 MB/sec + 200 concurrent clients (RETR 10.0M file) 0.55 secs + 200 concurrent clients (STOR 10.0M file) 1.46 secs + 200 concurrent clients (QUIT) 0.02 secs + +Dependencies +------------ + +- Python 3.7+ + +0.13.0 is the last version which supports python 3.5.3+ + +0.16.1 is the last version which supports python 3.6+ + +License +------- + +aioftp is offered under the Apache 2 license. + +Library installation +-------------------- + +:: + + pip install aioftp + +Getting started +--------------- + +Client example + +.. code-block:: python + + import asyncio + import aioftp + + + async def get_mp3(host, port, login, password): + async with aioftp.Client.context(host, port, login, password) as client: + for path, info in (await client.list(recursive=True)): + if info["type"] == "file" and path.suffix == ".mp3": + await client.download(path) + + + async def main(): + tasks = [ + asyncio.create_task(get_mp3("server1.com", 21, "login", "password")), + asyncio.create_task(get_mp3("server2.com", 21, "login", "password")), + asyncio.create_task(get_mp3("server3.com", 21, "login", "password")), + ] + await asyncio.wait(tasks) + + asyncio.run(main()) + +Server example + +.. code-block:: python + + import asyncio + import aioftp + + + async def main(): + server = aioftp.Server([user], path_io_factory=path_io_factory) + await server.run() + + asyncio.run(main()) + +Or just use simple server + +.. code-block:: shell + + python -m aioftp --help + + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aioftp-0.18.1/README.rst new/aioftp-0.19.0/README.rst --- old/aioftp-0.18.1/README.rst 2020-10-03 13:45:24.000000000 +0200 +++ new/aioftp-0.19.0/README.rst 2021-10-26 21:52:45.000000000 +0200 @@ -6,9 +6,13 @@ aioftp ====== -.. image:: https://travis-ci.com/aio-libs/aioftp.svg?branch=master - :target: https://travis-ci.com/aio-libs/aioftp - :alt: Travis status for master branch +.. image:: https://github.com/aio-libs/aioftp/actions/workflows/ci.yml/badge.svg?branch=master + :target: https://github.com/aio-libs/aioftp/actions/workflows/ci.yml + :alt: Github actions tests for master branch + +.. image:: https://github.com/aio-libs/aioftp/actions/workflows/cd.yml/badge.svg?branch=master + :target: https://github.com/aio-libs/aioftp/actions/workflows/cd.yml + :alt: Github actions deploy to pypi for master branch .. image:: https://codecov.io/gh/aio-libs/aioftp/branch/master/graph/badge.svg :target: https://codecov.io/gh/aio-libs/aioftp @@ -123,12 +127,15 @@ await client.download(path) - tasks = ( - get_mp3("server1.com", 21, "login", "password"), - get_mp3("server2.com", 21, "login", "password"), - get_mp3("server3.com", 21, "login", "password"), - ) - asyncio.run(asyncio.wait(tasks)) + async def main(): + tasks = [ + asyncio.create_task(get_mp3("server1.com", 21, "login", "password")), + asyncio.create_task(get_mp3("server2.com", 21, "login", "password")), + asyncio.create_task(get_mp3("server3.com", 21, "login", "password")), + ] + await asyncio.wait(tasks) + + asyncio.run(main()) Server example diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aioftp-0.18.1/aioftp/__init__.py new/aioftp-0.19.0/aioftp/__init__.py --- old/aioftp-0.18.1/aioftp/__init__.py 2020-10-03 13:45:24.000000000 +0200 +++ new/aioftp-0.19.0/aioftp/__init__.py 2021-10-26 21:52:45.000000000 +0200 @@ -7,7 +7,7 @@ from .pathio import * from .server import * -__version__ = "0.18.1" +__version__ = "0.19.0" version = tuple(map(int, __version__.split("."))) __all__ = ( diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aioftp-0.18.1/aioftp/client.py new/aioftp-0.19.0/aioftp/client.py --- old/aioftp-0.18.1/aioftp/client.py 2020-10-03 13:45:24.000000000 +0200 +++ new/aioftp-0.19.0/aioftp/client.py 2021-10-26 21:52:45.000000000 +0200 @@ -1,3 +1,4 @@ +import asyncio import calendar import collections import contextlib @@ -105,12 +106,15 @@ class BaseClient: - def __init__(self, *, socket_timeout=None, + def __init__(self, *, + socket_timeout=None, + connection_timeout=None, read_speed_limit=None, write_speed_limit=None, path_timeout=None, path_io_factory=pathio.PathIO, encoding="utf-8", ssl=None, parse_list_line_custom=None, passive_commands=("epsv", "pasv"), **siosocks_asyncio_kwargs): self.socket_timeout = socket_timeout + self.connection_timeout = connection_timeout self.throttle = StreamThrottle.from_limits( read_speed_limit, write_speed_limit, @@ -128,7 +132,10 @@ async def connect(self, host, port=DEFAULT_PORT): self.server_host = host self.server_port = port - reader, writer = await self._open_connection(host, port) + reader, writer = await asyncio.wait_for( + self._open_connection(host, port), + self.connection_timeout, + ) self.stream = ThrottleStreamIO( reader, writer, @@ -557,6 +564,9 @@ :param socket_timeout: timeout for read operations :type socket_timeout: :py:class:`float`, :py:class:`int` or `None` + :param connection_timeout: timeout for connection + :type connection_timeout: :py:class:`float`, :py:class:`int` or `None` + :param read_speed_limit: download speed limit in bytes per second :type server_to_client_speed_limit: :py:class:`int` or `None` diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aioftp-0.18.1/aioftp/common.py new/aioftp-0.19.0/aioftp/common.py --- old/aioftp-0.18.1/aioftp/common.py 2020-10-03 13:45:24.000000000 +0200 +++ new/aioftp-0.19.0/aioftp/common.py 2021-10-26 21:52:45.000000000 +0200 @@ -473,13 +473,13 @@ :param name: name of throttle to acquire ("read" or "write") :type name: :py:class:`str` """ - waiters = [] + tasks = [] for throttle in self.throttles.values(): curr_throttle = getattr(throttle, name) if curr_throttle.limit: - waiters.append(curr_throttle.wait()) - if waiters: - await asyncio.wait(waiters) + tasks.append(asyncio.create_task(curr_throttle.wait())) + if tasks: + await asyncio.wait(tasks) def append(self, name, data, start): """ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aioftp-0.18.1/aioftp/server.py new/aioftp-0.19.0/aioftp/server.py --- old/aioftp-0.18.1/aioftp/server.py 2020-10-03 13:45:24.000000000 +0200 +++ new/aioftp-0.19.0/aioftp/server.py 2021-10-26 21:52:45.000000000 +0200 @@ -783,7 +783,7 @@ Shutdown the server and close all connections. """ self.server.close() - tasks = [self.server.wait_closed()] + tasks = [asyncio.create_task(self.server.wait_closed())] for connection in self.connections.values(): connection._dispatcher.cancel() tasks.append(connection._dispatcher) @@ -919,9 +919,9 @@ connection.path_io = self.path_io_factory(timeout=self.path_timeout, connection=connection) pending = { - self.greeting(connection, ""), - self.response_writer(stream, response_queue), - self.parse_command(stream), + asyncio.create_task(self.greeting(connection, "")), + asyncio.create_task(self.response_writer(stream, response_queue)), + asyncio.create_task(self.parse_command(stream)), } self.connections[key] = connection try: @@ -944,11 +944,15 @@ return # this is parse_command result elif isinstance(result, tuple): - pending.add(self.parse_command(stream)) + pending.add( + asyncio.create_task(self.parse_command(stream)) + ) cmd, rest = result f = self.commands_mapping.get(cmd) if f is not None: - pending.add(f(connection, rest)) + pending.add( + asyncio.create_task(f(connection, rest)) + ) if cmd not in ("retr", "stor", "appe"): connection.restart_offset = 0 else: @@ -963,9 +967,8 @@ tasks_to_wait = [] if not asyncio.get_running_loop().is_closed(): for task in pending | connection.extra_workers: - if isinstance(task, asyncio.Task): - task.cancel() - tasks_to_wait.append(task) + task.cancel() + tasks_to_wait.append(task) if connection.future.passive_server.done(): connection.passive_server.close() if self.available_data_ports is not None: @@ -977,7 +980,9 @@ if connection.acquired: self.available_connections.release() if connection.future.user.done(): - task = self.user_manager.notify_logout(connection.user) + task = asyncio.create_task( + self.user_manager.notify_logout(connection.user) + ) tasks_to_wait.append(task) self.connections.pop(key) if tasks_to_wait: @@ -1128,8 +1133,11 @@ } async def build_mlsx_string(self, connection, path): - stats = await connection.path_io.stat(path) - facts = self._build_mlsx_facts_from_stats(stats) + if not await connection.path_io.exists(path): + facts = {} + else: + stats = await connection.path_io.stat(path) + facts = self._build_mlsx_facts_from_stats(stats) if await connection.path_io.is_file(path): facts["Type"] = "file" elif await connection.path_io.is_dir(path): @@ -1169,7 +1177,7 @@ real_path, virtual_path = self.get_paths(connection, rest) coro = mlsd_worker(self, connection, rest) - task = asyncio.ensure_future(coro) + task = asyncio.create_task(coro) connection.extra_workers.add(task) connection.response("150", "mlsd transfer started") return True @@ -1227,7 +1235,7 @@ real_path, virtual_path = self.get_paths(connection, rest) coro = list_worker(self, connection, rest) - task = asyncio.ensure_future(coro) + task = asyncio.create_task(coro) connection.extra_workers.add(task) connection.response("150", "list transfer started") return True @@ -1305,7 +1313,7 @@ real_path, virtual_path = self.get_paths(connection, rest) if await connection.path_io.is_dir(real_path.parent): coro = stor_worker(self, connection, rest) - task = asyncio.ensure_future(coro) + task = asyncio.create_task(coro) connection.extra_workers.add(task) code, info = "150", "data transfer started" else: @@ -1342,7 +1350,7 @@ real_path, virtual_path = self.get_paths(connection, rest) coro = retr_worker(self, connection, rest) - task = asyncio.ensure_future(coro) + task = asyncio.create_task(coro) connection.extra_workers.add(task) connection.response("150", "data transfer started") return True diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aioftp-0.18.1/aioftp.egg-info/PKG-INFO new/aioftp-0.19.0/aioftp.egg-info/PKG-INFO --- old/aioftp-0.18.1/aioftp.egg-info/PKG-INFO 2020-10-03 13:45:39.000000000 +0200 +++ new/aioftp-0.19.0/aioftp.egg-info/PKG-INFO 2021-10-26 21:52:53.000000000 +0200 @@ -1,163 +1,11 @@ Metadata-Version: 2.1 Name: aioftp -Version: 0.18.1 +Version: 0.19.0 Summary: ftp client/server for asyncio Home-page: https://github.com/aio-libs/aioftp Author: pohmelie Author-email: multisosnoo...@gmail.com License: Apache-2.0 -Description: .. aioftp documentation master file, created by - sphinx-quickstart on Fri Apr 17 16:21:03 2015. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - - aioftp - ====== - - .. image:: https://travis-ci.com/aio-libs/aioftp.svg?branch=master - :target: https://travis-ci.com/aio-libs/aioftp - :alt: Travis status for master branch - - .. image:: https://codecov.io/gh/aio-libs/aioftp/branch/master/graph/badge.svg - :target: https://codecov.io/gh/aio-libs/aioftp - - .. image:: https://img.shields.io/pypi/v/aioftp.svg - :target: https://pypi.python.org/pypi/aioftp - - .. image:: https://img.shields.io/pypi/pyversions/aioftp.svg - :target: https://pypi.python.org/pypi/aioftp - - .. image:: https://pepy.tech/badge/aioftp/month - :target: https://pypi.python.org/pypi/aioftp - - ftp client/server for asyncio (http://aioftp.readthedocs.org) - - .. _GitHub: https://github.com/aio-libs/aioftp - - Features - -------- - - - Simple. - - Extensible. - - Client socks proxy via `siosocks <https://github.com/pohmelie/siosocks>`_ - (`pip install aioftp[socks]`). - - Goals - ----- - - - Minimum usable core. - - Do not use deprecated or overridden commands and features (if possible). - - Very high level api. - - Client use this commands: USER, PASS, ACCT, PWD, CWD, CDUP, MKD, RMD, MLSD, - MLST, RNFR, RNTO, DELE, STOR, APPE, RETR, TYPE, PASV, ABOR, QUIT, REST, LIST - (as fallback) - - Server support this commands: USER, PASS, QUIT, PWD, CWD, CDUP, MKD, RMD, MLSD, - LIST (but it's not recommended to use it, cause it has no standard format), - MLST, RNFR, RNTO, DELE, STOR, RETR, TYPE ("I" and "A"), PASV, ABOR, APPE, REST - - This subsets are enough for 99% of tasks, but if you need something, then you - can easily extend current set of commands. - - Server benchmark - ---------------- - - Compared with `pyftpdlib <https://github.com/giampaolo/pyftpdlib>`_ and - checked with its ftpbench script. - - aioftp 0.8.0 - - :: - - STOR (client -> server) 284.95 MB/sec - RETR (server -> client) 408.44 MB/sec - 200 concurrent clients (connect, login) 0.18 secs - STOR (1 file with 200 idle clients) 287.52 MB/sec - RETR (1 file with 200 idle clients) 382.05 MB/sec - 200 concurrent clients (RETR 10.0M file) 13.33 secs - 200 concurrent clients (STOR 10.0M file) 12.56 secs - 200 concurrent clients (QUIT) 0.03 secs - - pyftpdlib 1.5.2 - - :: - - STOR (client -> server) 1235.56 MB/sec - RETR (server -> client) 3960.21 MB/sec - 200 concurrent clients (connect, login) 0.06 secs - STOR (1 file with 200 idle clients) 1208.58 MB/sec - RETR (1 file with 200 idle clients) 3496.03 MB/sec - 200 concurrent clients (RETR 10.0M file) 0.55 secs - 200 concurrent clients (STOR 10.0M file) 1.46 secs - 200 concurrent clients (QUIT) 0.02 secs - - Dependencies - ------------ - - - Python 3.7+ - - 0.13.0 is the last version which supports python 3.5.3+ - - 0.16.1 is the last version which supports python 3.6+ - - License - ------- - - aioftp is offered under the Apache 2 license. - - Library installation - -------------------- - - :: - - pip install aioftp - - Getting started - --------------- - - Client example - - .. code-block:: python - - import asyncio - import aioftp - - - async def get_mp3(host, port, login, password): - async with aioftp.Client.context(host, port, login, password) as client: - for path, info in (await client.list(recursive=True)): - if info["type"] == "file" and path.suffix == ".mp3": - await client.download(path) - - - tasks = ( - get_mp3("server1.com", 21, "login", "password"), - get_mp3("server2.com", 21, "login", "password"), - get_mp3("server3.com", 21, "login", "password"), - ) - asyncio.run(asyncio.wait(tasks)) - - Server example - - .. code-block:: python - - import asyncio - import aioftp - - - async def main(): - server = aioftp.Server([user], path_io_factory=path_io_factory) - await server.run() - - asyncio.run(main()) - - Or just use simple server - - .. code-block:: shell - - python -m aioftp --help - Platform: UNKNOWN Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 @@ -166,3 +14,165 @@ Requires-Python: >=3.7 Provides-Extra: socks Provides-Extra: tests +License-File: license.txt + +.. aioftp documentation master file, created by + sphinx-quickstart on Fri Apr 17 16:21:03 2015. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +aioftp +====== + +.. image:: https://github.com/aio-libs/aioftp/actions/workflows/ci.yml/badge.svg?branch=master + :target: https://github.com/aio-libs/aioftp/actions/workflows/ci.yml + :alt: Github actions tests for master branch + +.. image:: https://github.com/aio-libs/aioftp/actions/workflows/cd.yml/badge.svg?branch=master + :target: https://github.com/aio-libs/aioftp/actions/workflows/cd.yml + :alt: Github actions deploy to pypi for master branch + +.. image:: https://codecov.io/gh/aio-libs/aioftp/branch/master/graph/badge.svg + :target: https://codecov.io/gh/aio-libs/aioftp + +.. image:: https://img.shields.io/pypi/v/aioftp.svg + :target: https://pypi.python.org/pypi/aioftp + +.. image:: https://img.shields.io/pypi/pyversions/aioftp.svg + :target: https://pypi.python.org/pypi/aioftp + +.. image:: https://pepy.tech/badge/aioftp/month + :target: https://pypi.python.org/pypi/aioftp + +ftp client/server for asyncio (http://aioftp.readthedocs.org) + +.. _GitHub: https://github.com/aio-libs/aioftp + +Features +-------- + +- Simple. +- Extensible. +- Client socks proxy via `siosocks <https://github.com/pohmelie/siosocks>`_ + (`pip install aioftp[socks]`). + +Goals +----- + +- Minimum usable core. +- Do not use deprecated or overridden commands and features (if possible). +- Very high level api. + +Client use this commands: USER, PASS, ACCT, PWD, CWD, CDUP, MKD, RMD, MLSD, +MLST, RNFR, RNTO, DELE, STOR, APPE, RETR, TYPE, PASV, ABOR, QUIT, REST, LIST +(as fallback) + +Server support this commands: USER, PASS, QUIT, PWD, CWD, CDUP, MKD, RMD, MLSD, +LIST (but it's not recommended to use it, cause it has no standard format), +MLST, RNFR, RNTO, DELE, STOR, RETR, TYPE ("I" and "A"), PASV, ABOR, APPE, REST + +This subsets are enough for 99% of tasks, but if you need something, then you +can easily extend current set of commands. + +Server benchmark +---------------- + +Compared with `pyftpdlib <https://github.com/giampaolo/pyftpdlib>`_ and +checked with its ftpbench script. + +aioftp 0.8.0 + +:: + + STOR (client -> server) 284.95 MB/sec + RETR (server -> client) 408.44 MB/sec + 200 concurrent clients (connect, login) 0.18 secs + STOR (1 file with 200 idle clients) 287.52 MB/sec + RETR (1 file with 200 idle clients) 382.05 MB/sec + 200 concurrent clients (RETR 10.0M file) 13.33 secs + 200 concurrent clients (STOR 10.0M file) 12.56 secs + 200 concurrent clients (QUIT) 0.03 secs + +pyftpdlib 1.5.2 + +:: + + STOR (client -> server) 1235.56 MB/sec + RETR (server -> client) 3960.21 MB/sec + 200 concurrent clients (connect, login) 0.06 secs + STOR (1 file with 200 idle clients) 1208.58 MB/sec + RETR (1 file with 200 idle clients) 3496.03 MB/sec + 200 concurrent clients (RETR 10.0M file) 0.55 secs + 200 concurrent clients (STOR 10.0M file) 1.46 secs + 200 concurrent clients (QUIT) 0.02 secs + +Dependencies +------------ + +- Python 3.7+ + +0.13.0 is the last version which supports python 3.5.3+ + +0.16.1 is the last version which supports python 3.6+ + +License +------- + +aioftp is offered under the Apache 2 license. + +Library installation +-------------------- + +:: + + pip install aioftp + +Getting started +--------------- + +Client example + +.. code-block:: python + + import asyncio + import aioftp + + + async def get_mp3(host, port, login, password): + async with aioftp.Client.context(host, port, login, password) as client: + for path, info in (await client.list(recursive=True)): + if info["type"] == "file" and path.suffix == ".mp3": + await client.download(path) + + + async def main(): + tasks = [ + asyncio.create_task(get_mp3("server1.com", 21, "login", "password")), + asyncio.create_task(get_mp3("server2.com", 21, "login", "password")), + asyncio.create_task(get_mp3("server3.com", 21, "login", "password")), + ] + await asyncio.wait(tasks) + + asyncio.run(main()) + +Server example + +.. code-block:: python + + import asyncio + import aioftp + + + async def main(): + server = aioftp.Server([user], path_io_factory=path_io_factory) + await server.run() + + asyncio.run(main()) + +Or just use simple server + +.. code-block:: shell + + python -m aioftp --help + + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aioftp-0.18.1/history.rst new/aioftp-0.19.0/history.rst --- old/aioftp-0.18.1/history.rst 2020-10-03 13:45:24.000000000 +0200 +++ new/aioftp-0.19.0/history.rst 2021-10-26 21:52:45.000000000 +0200 @@ -1,11 +1,19 @@ x.x.x (xx-xx-xxxx) ------------------ +0.19.0 (08-10-2021) +------------------ + +- add client connection timeout (#140) +- remove explicit coroutine passing to `asyncio.wait` (#134) +Thanks to `decaz <https://github.com/decaz>`_ + 0.18.1 (03-10-2020) ------------------ - sync tests with new `siosocks` (#127) - some docs fixes +- log level changes 0.18.0 (03-09-2020) ------------------