diff --git a/.gitignore b/.gitignore index 67956048c..fd6c19909 100644 --- a/.gitignore +++ b/.gitignore @@ -54,7 +54,7 @@ coverage.xml *.pot # Sphinx documentation -docs/_build/ +sphinx/_build/ # OS hidden files .DS_Store diff --git a/CHANGES/template.jinja b/.towncrier.md.jinja similarity index 57% rename from CHANGES/template.jinja rename to .towncrier.md.jinja index 659c5f400..5c08f3495 100644 --- a/CHANGES/template.jinja +++ b/.towncrier.md.jinja @@ -1,20 +1,17 @@ {% for section, _ in sections.items() %} -{% set underline = underlines[0] %}{% if section %}{{section}} -{{ underline * section|length }}{% set underline = underlines[1] %} -{% endif %} +{%- if section %}{{section}}{% endif -%} + {% if sections[section] %} {% for category, val in definitions.items() if category in sections[section]%} -{{ definitions[category]['name'] }} -{{ underline * definitions[category]['name']|length }} +### {{ definitions[category]['name'] }} {% if definitions[category]['showcontent'] %} {% for text, values in sections[section][category].items() %} -- {{ text }} - (see {{ values|join(',\n ') }}); +- {{ values|join(', ') }} {{ text }} {% endfor %} {% else %} -- {{ sections[section][category]['']|join(',\n ') }}; +- {{ sections[section][category]['']|join(', ') }} {% endif %} {% if sections[section][category]|length == 0 %} @@ -22,10 +19,10 @@ No significant changes. {% else %} {% endif %} + {% endfor %} {% else %} No significant changes. - {% endif %} {% endfor %} diff --git a/CHANGES.md b/CHANGES.md new file mode 100644 index 000000000..4438d32a3 --- /dev/null +++ b/CHANGES.md @@ -0,0 +1,523 @@ +# Changes + +## 1.3.1 (2019-12-02) + +### Bugfixes + +- Fix transaction data decoding + (see [#657](https://github.com/aio-libs/aioredis/issues/657)) +- Fix duplicate calls to `pool.wait_closed()` upon `create_pool()` exception. + (see [#671](https://github.com/aio-libs/aioredis/issues/671)) + +### Deprecations and Removals + +- Drop explicit loop requirement in API. + Deprecate `loop` argument. + Throw warning in Python 3.8+ if explicit `loop` is passed to methods. + (see [#666](https://github.com/aio-libs/aioredis/issues/666)) + +### Misc + +- [#643](https://github.com/aio-libs/aioredis/issues/643), + [#646](https://github.com/aio-libs/aioredis/issues/646), + [#648](https://github.com/aio-libs/aioredis/issues/648) + +## 1.3.0 (2019-09-24) + +### Features + +- Added `xdel` and `xtrim` method which missed in `commands/streams.py` & also added unit test code for them + (see [#438](https://github.com/aio-libs/aioredis/issues/438)) + - Add `count` argument to `spop` command + (see [#485](https://github.com/aio-libs/aioredis/issues/485)) + - Add support for `zpopmax` and `zpopmin` redis commands + (see [#550](https://github.com/aio-libs/aioredis/issues/550)) + - Add `towncrier`: change notes are now stored in `CHANGES.txt` + (see [#576](https://github.com/aio-libs/aioredis/issues/576)) + - Type hints for the library + (see [#584](https://github.com/aio-libs/aioredis/issues/584)) + - A few additions to the sorted set commands: + + - the blocking pop commands: `BZPOPMAX` and `BZPOPMIN` + + - the `CH` and `INCR` options of the `ZADD` command + + (see [#618](https://github.com/aio-libs/aioredis/issues/618)) + - Added `no_ack` parameter to `xread_group` streams method in `commands/streams.py` + (see [#625](https://github.com/aio-libs/aioredis/issues/625)) + +### Bugfixes + +- Fix for sensitive logging + (see [#459](https://github.com/aio-libs/aioredis/issues/459)) + - Fix slow memory leak in `wait_closed` implementation + (see [#498](https://github.com/aio-libs/aioredis/issues/498)) + - Fix handling of instances were Redis returns null fields for a stream message (see + [#605](https://github.com/aio-libs/aioredis/issues/605)) + +### Improved Documentation + +- Rewrite "Getting started" documentation. + (see [#641](https://github.com/aio-libs/aioredis/issues/641)) + +### Misc + +- [#585](https://github.com/aio-libs/aioredis/issues/585), + [#611](https://github.com/aio-libs/aioredis/issues/611), + [#612](https://github.com/aio-libs/aioredis/issues/612), + [#619](https://github.com/aio-libs/aioredis/issues/619), + [#620](https://github.com/aio-libs/aioredis/issues/620), + [#642](https://github.com/aio-libs/aioredis/issues/642) + +## 1.2.0 (2018-10-24) + + +### Features + +- Implemented new Stream command support + (see [#299](https://github.com/aio-libs/aioredis/pull/299)) +- Reduce `encode_command()` cost about 60% + (see [#397](https://github.com/aio-libs/aioredis/pull/397)) + +### Bugfixes + +- Fix pipeline commands buffering was causing multiple `sendto` syscalls + (see [#464](https://github.com/aio-libs/aioredis/pull/464) + and [#473](https://github.com/aio-libs/aioredis/pull/473)) +- Python 3.7 compatibility fixes + (see [#426](https://github.com/aio-libs/aioredis/pull/426)) +- Fix typos in documentation + (see [#400](https://github.com/aio-libs/aioredis/pull/400)) +- Fix `INFO` command result parsing + (see [#405](https://github.com/aio-libs/aioredis/pull/405)) +- Fix bug in `ConnectionsPool._drop_closed` method + (see [#461](https://github.com/aio-libs/aioredis/pull/461)) + +### Miscellaneous + +- Update dependencies versions +- Multiple tests improvements +## 1.1.0 (2018-02-16) + + +### Features + +- Implement new commands: `wait`, `touch`, `swapdb`, `unlink` + (see [#376](https://github.com/aio-libs/aioredis/pull/376)) +- Add `async_op` argument to `flushall` and `flushdb` commands + (see [#364](https://github.com/aio-libs/aioredis/pull/364), + and [#370](https://github.com/aio-libs/aioredis/pull/370)) + +### Bugfixes + +- **Important!** Fix Sentinel sentinel client with pool `minsize` + greater than 1 + (see [#380](https://github.com/aio-libs/aioredis/pull/380)) +- Fix `SentinelPool.discover_timeout` usage + (see [#379](https://github.com/aio-libs/aioredis/pull/379)) +- Fix `Receiver` hang on disconnect + (see [#354](https://github.com/aio-libs/aioredis/pull/354), + and [#366](https://github.com/aio-libs/aioredis/pull/366)) +- Fix an issue with `subscribe`/`psubscribe` with empty pool + (see [#351](https://github.com/aio-libs/aioredis/pull/351), + and [#355](https://github.com/aio-libs/aioredis/pull/355)) +- Fix an issue when `StreamReader`'s feed_data is called before set_parser + (see [#347](https://github.com/aio-libs/aioredis/pull/347)) + +### Miscellaneous + +- Update dependencies versions +- Multiple test fixes + +## 1.0.0 (2017-11-17) + + +### Features + +- **Important!** Drop Python 3.3, 3.4 support (see [#321](https://github.com/aio-libs/aioredis/pull/321), + [#323](https://github.com/aio-libs/aioredis/pull/323) + and [#326](https://github.com/aio-libs/aioredis/pull/326)) +- **Important!** Connections pool has been refactored; now `create_redis` + function will yield `Redis` instance instead of `RedisPool` + (see [#129](https://github.com/aio-libs/aioredis/pull/129)) +- **Important!** Change sorted set commands reply format: + return list of tuples instead of plain list for commands + accepting `withscores` argument + (see [#334](https://github.com/aio-libs/aioredis/pull/334)) +- **Important!** Change `hscan` command reply format: + return list of tuples instead of mixed key-value list + (see [#335](https://github.com/aio-libs/aioredis/pull/335)) +- Implement Redis URI support as supported `address` argument value + (see [#322](https://github.com/aio-libs/aioredis/pull/322)) +- Dropped `create_reconnecting_redis`, `create_redis_pool` should be + used instead +- Implement custom `StreamReader` + (see [#273](https://github.com/aio-libs/aioredis/pull/273)) +- Implement Sentinel support + (see [#181](https://github.com/aio-libs/aioredis/pull/181)) +- Implement pure-python parser + (see [#212](https://github.com/aio-libs/aioredis/pull/212)) +- Add `migrate_keys` command + (see [#187](https://github.com/aio-libs/aioredis/pull/187)) +- Add `zrevrangebylex` command + (see [#201](https://github.com/aio-libs/aioredis/pull/201)) +- Add `command`, `command_count`, `command_getkeys` and + `command_info` commands + (see [#229](https://github.com/aio-libs/aioredis/pull/229)) +- Add `ping` support in pubsub connection + (see [#264](https://github.com/aio-libs/aioredis/pull/264)) +- Add `exist` parameter to `zadd` command + (see [#288](https://github.com/aio-libs/aioredis/pull/288)) +- Add `MaxClientsError` and implement `ReplyError` specialization + (see [#325](https://github.com/aio-libs/aioredis/pull/325)) +- Add `encoding` parameter to sorted set commands + (see [#289](https://github.com/aio-libs/aioredis/pull/289)) + +### Bugfixes + +- Fix `CancelledError` in `conn._reader_task` + (see [#301](https://github.com/aio-libs/aioredis/pull/301)) +- Fix pending commands cancellation with `CancelledError`, + use explicit exception instead of calling `cancel()` method + (see [#316](https://github.com/aio-libs/aioredis/pull/316)) +- Correct error message on Sentinel discovery of master/slave with password + (see [#327](https://github.com/aio-libs/aioredis/pull/327)) +- Fix `bytearray` support as command argument + (see [#329](https://github.com/aio-libs/aioredis/pull/329)) +- Fix critical bug in patched asyncio.Lock + (see [#256](https://github.com/aio-libs/aioredis/pull/256)) +- Fix Multi/Exec transaction canceled error + (see [#225](https://github.com/aio-libs/aioredis/pull/225)) +- Add missing arguments to `create_redis` and `create_redis_pool` +- Fix deprecation warning + (see [#191](https://github.com/aio-libs/aioredis/pull/191)) +- Make correct `__aiter__()` + (see [#192](https://github.com/aio-libs/aioredis/pull/192)) +- Backward compatibility fix for `with (yield from pool) as conn:` + (see [#205](https://github.com/aio-libs/aioredis/pull/205)) +- Fixed pubsub receiver stop() + (see [#211](https://github.com/aio-libs/aioredis/pull/211)) + +### Miscellaneous + +- Multiple test fixes +- Add PyPy3 to build matrix +- Update dependencies versions +- Add missing Python 3.6 classifier + +## 0.3.5 (2017-11-08) + + +### Bugfixes + +- Fix for indistinguishable futures cancellation with + `asyncio.CancelledError` + (see [#316](https://github.com/aio-libs/aioredis/pull/316)), + cherry-picked from master + +## 0.3.4 (2017-10-25) + + +### Bugfixes + +- Fix time command result decoding when using connection-wide encoding setting + (see [#266](https://github.com/aio-libs/aioredis/pull/266)) + +## 0.3.3 (2017-06-30) + + +### Bugfixes + +- Critical bug fixed in patched asyncio.Lock + (see [#256](https://github.com/aio-libs/aioredis/pull/256)) + +## 0.3.2 (2017-06-21) + + +### Features + +- Added `zrevrangebylex` command + (see [#201](https://github.com/aio-libs/aioredis/pull/201)), + cherry-picked from master +- Add connection timeout + (see [#221](https://github.com/aio-libs/aioredis/pull/221)), + cherry-picked from master +### Bugfixes + +- Fixed pool close warning + (see [#239](https://github.com/aio-libs/aioredis/pull/239) + and [#236](https://github.com/aio-libs/aioredis/issues/236)), + cherry-picked from master +- Fixed asyncio Lock deadlock issue + (see [#231](https://github.com/aio-libs/aioredis/issues/231) + and [#241](https://github.com/aio-libs/aioredis/pull/241)) + +## 0.3.1 (2017-05-09) + + +### Bugfixes + +- Fix pubsub Receiver missing iter() method + (see [#203](https://github.com/aio-libs/aioredis/issues/203)) + +## 0.3.0 (2017-01-11) + + +### Features + +- Pub/Sub connection commands accept `Channel` instances + (see [#168](https://github.com/aio-libs/aioredis/pull/168)) +- Implement new Pub/Sub MPSC (multi-producers, single-consumer) Queue -- + `aioredis.pubsub.Receiver` + (see [#176](https://github.com/aio-libs/aioredis/pull/176)) +- Add `aioredis.abc` module providing abstract base classes + defining interface for basic lib components (see [#176](https://github.com/aio-libs/aioredis/pull/176)) +- Implement Geo commands support + (see [#177](https://github.com/aio-libs/aioredis/pull/177) + and [#179](https://github.com/aio-libs/aioredis/pull/179)) + +### Bugfixes + +- Minor tests fixes +### Miscellaneous + +- Update examples and docs to use `async`/`await` syntax + also keeping `yield from` examples for history + (see [#173](https://github.com/aio-libs/aioredis/pull/173)) +- Reflow Travis CI configuration; add Python 3.6 section + (see [#170](https://github.com/aio-libs/aioredis/pull/170)) +- Add AppVeyor integration to run tests on Windows + (see [#180](https://github.com/aio-libs/aioredis/pull/180)) +- Update multiple development requirements + +## 0.2.9 (2016-10-24) + + +### Features + +- Allow multiple keys in `EXISTS` command + (see [#156](https://github.com/aio-libs/aioredis/issues/156) + and [#157](https://github.com/aio-libs/aioredis/issues/157)) + +### Bugfixes + +- Close RedisPool when connection to Redis failed + (see [#136](https://github.com/aio-libs/aioredis/issues/136)) +- Add simple `INFO` command argument validation + (see [#140](https://github.com/aio-libs/aioredis/issues/140)) +- Remove invalid uses of `next()` + +### Miscellaneous + +- Update devel.rst docs; update Pub/Sub Channel docs (cross-refs) +- Update MANIFEST.in to include docs, examples and tests in source bundle + +## 0.2.8 (2016-07-22) + + +### Features + +- Add `hmset_dict` command + (see [#130](https://github.com/aio-libs/aioredis/issues/130)) +- Add `RedisConnection.address` property +- RedisPool `minsize`/`maxsize` must not be `None` +- Implement `close()`/`wait_closed()`/`closed` interface for pool + (see [#128](https://github.com/aio-libs/aioredis/issues/128)) + +### Bugfixes + +- Add test for `hstrlen` +- Test fixes + +### Miscellaneous + +- Enable Redis 3.2.0 on Travis +- Add spell checking when building docs + (see [#132](https://github.com/aio-libs/aioredis/issues/132)) +- Documentation updated + +## 0.2.7 (2016-05-27) + + +- `create_pool()` minsize default value changed to 1 +- Fixed cancellation of wait_closed + (see [#118](https://github.com/aio-libs/aioredis/issues/118)) +- Fixed `time()` conversion to float + (see [#126](https://github.com/aio-libs/aioredis/issues/126)) +- Fixed `hmset()` method to return bool instead of `b'OK'` + (see [#12)) +- Fixed multi/exec + watch issue (changed watch variable was causing + `tr.execute()` to fail) + (see [#121](https://github.com/aio-libs/aioredis/issues/121)) +- Replace `asyncio.Future` uses with utility method + (get ready to Python 3.5.2 `loop.create_future()`) +- Tests switched from unittest to pytest (see [#12)) +- Documentation updates + +## 0.2.6 (2016-03-30) + + +- Fixed Multi/Exec transactions cancellation issue + (see [#110](https://github.com/aio-libs/aioredis/issues/110) + and [#114](https://github.com/aio-libs/aioredis/issues/114)) +- Fixed Pub/Sub subscribe concurrency issue + (see [#113](https://github.com/aio-libs/aioredis/issues/113) + and [#115](https://github.com/aio-libs/aioredis/issues/115)) +- Add SSL/TLS support + (see [#116](https://github.com/aio-libs/aioredis/issues/116)) +- `aioredis.ConnectionClosedError` raised in `execute_pubsub` as well + (see [#108](https://github.com/aio-libs/aioredis/issues/108)) +- `Redis.slaveof()` method signature changed: now to disable + replication one should call `redis.slaveof(None)` instead of `redis.slaveof()` +- More tests added + +## 0.2.5 (2016-03-02) + + +- Close all Pub/Sub channels on connection close + (see [#88](https://github.com/aio-libs/aioredis/issues/88)) +- Add `iter()` method to `aioredis.Channel` allowing to use it + with `async for` + (see [#89](https://github.com/aio-libs/aioredis/issues/89)) +- Inline code samples in docs made runnable and downloadable + (see [#92](https://github.com/aio-libs/aioredis/issues/92)) +- Python 3.5 examples converted to use `async`/`await` syntax + (see [#93](https://github.com/aio-libs/aioredis/issues/93)) +- Fix Multi/Exec to honor encoding parameter + (see [#94](https://github.com/aio-libs/aioredis/issues/94) + and [#97](https://github.com/aio-libs/aioredis/issues/97)) +- Add debug message in `create_connection` + (see [#90](https://github.com/aio-libs/aioredis/issues/90)) +- Replace `asyncio.async` calls with wrapper that respects asyncio version + (see [#101](https://github.com/aio-libs/aioredis/issues/101)) +- Use NODELAY option for TCP sockets + (see [#105](https://github.com/aio-libs/aioredis/issues/105)) +- New `aioredis.ConnectionClosedError` exception added. Raised if + connection to Redis server is lost + (see [#108](https://github.com/aio-libs/aioredis/issues/108) + and [#109](https://github.com/aio-libs/aioredis/issues/109)) +- Fix RedisPool to close and drop connection in subscribe mode on release +- Fix `aioredis.util.decode` to recursively decode list responses +- More examples added and docs updated +- Add google groups link to README +- Bump year in LICENSE and docs + +## 0.2.4 (2015-10-13) + + +- Python 3.5 `async` support: + + - New scan commands API (`iscan`, `izscan`, `ihscan`) + - Pool made awaitable (allowing `with await pool: ...` and `async + with pool.get() as conn:` constructs) +- Fixed dropping closed connections from free pool + (see [#83](https://github.com/aio-libs/aioredis/issues/83)) +- Docs updated + +## 0.2.3 (2015-08-14) + + +- Redis cluster support work in progress +- Fixed pool issue causing pool growth over max size & `acquire` call hangs + (see [#71](https://github.com/aio-libs/aioredis/issues/71)) +- `info` server command result parsing implemented +- Fixed behavior of util functions + (see [#70](https://github.com/aio-libs/aioredis/issues/70)) +- `hstrlen` command added +- Few fixes in examples +- Few fixes in documentation + +## 0.2.2 (2015-07-07) + + +- Decoding data with `encoding` parameter now takes into account + list (array) replies + (see [#68](https://github.com/aio-libs/aioredis/pull/68)) +- `encoding` parameter added to following commands: + + - generic commands: keys, randomkey + - hash commands: hgetall, hkeys, hmget, hvals + - list commands: blpop, brpop, brpoplpush, lindex, lpop, lrange, rpop, rpoplpush + - set commands: smembers, spop, srandmember + - string commands: getrange, getset, mget +- Backward incompatibility: + + `ltrim` command now returns bool value instead of 'OK' +- Tests updated + +## 0.2.1 (2015-07-06) + + +- Logging added (aioredis.log module) +- Fixed issue with `wait_message` in pub/sub + (see [#66](https://github.com/aio-libs/aioredis/issues/66)) + +## 0.2.0 (2015-06-04) + + +- Pub/Sub support added +- Fix in `zrevrangebyscore` command + (see [#62](https://github.com/aio-libs/aioredis/pull/62)) +- Fixes/tests/docs + +## 0.1.5 (2014-12-09) + + +- AutoConnector added +- wait_closed method added for clean connections shutdown +- `zscore` command fixed +- Test fixes + +## 0.1.4 (2014-09-22) + + +- Dropped following Redis methods -- `Redis.multi()`, + `Redis.exec()`, `Redis.discard()` +- `Redis.multi_exec` hack'ish property removed +- `Redis.multi_exec()` method added +- High-level commands implemented: + + - generic commands (tests) + - transactions commands (api stabilization). + +- Backward incompatibilities: + + - Following sorted set commands' API changed: + + `zcount`, `zrangebyscore`, `zremrangebyscore`, `zrevrangebyscore` + - set string command' API changed + + +## 0.1.3 (2014-08-08) + + +- RedisConnection.execute refactored to support commands pipelining + (see [#33](http://github.com/aio-libs/aioredis/issues/33)) +- Several fixes +- WIP on transactions and commands interface +- High-level commands implemented and tested: + + - hash commands - hyperloglog commands - set commands - scripting commands - string commands - list commands + +## 0.1.2 (2014-07-31) + + +- `create_connection`, `create_pool`, `create_redis` functions updated: + db and password arguments made keyword-only + (see [#26](http://github.com/aio-libs/aioredis/issues/26)) +- Fixed transaction handling + (see [#32](http://github.com/aio-libs/aioredis/issues/32)) +- Response decoding + (see [#16](http://github.com/aio-libs/aioredis/issues/16)) + +## 0.1.1 (2014-07-07) + + +- Transactions support (in connection, high-level commands have some issues) +- Docs & tests updated. + + +## 0.1.0 (2014-06-24) + + +- Initial release- RedisConnection implemented- RedisPool implemented- Docs for RedisConnection & RedisPool- WIP on high-level API. diff --git a/CHANGES.txt b/CHANGES.txt deleted file mode 100644 index cf031ac97..000000000 --- a/CHANGES.txt +++ /dev/null @@ -1,686 +0,0 @@ -Changes -------- - -.. towncrier release notes start - -1.3.1 (2019-12-02) -^^^^^^^^^^^^^^^^^^ -Bugfixes -~~~~~~~~ - -- Fix transaction data decoding - (see `#657 `_); -- Fix duplicate calls to ``pool.wait_closed()`` upon ``create_pool()`` exception. - (see `#671 `_); - -Deprecations and Removals -~~~~~~~~~~~~~~~~~~~~~~~~~ - -- Drop explicit loop requirement in API. - Deprecate ``loop`` argument. - Throw warning in Python 3.8+ if explicit ``loop`` is passed to methods. - (see `#666 `_); - -Misc -~~~~ - -- `#643 `_, - `#646 `_, - `#648 `_; - - -1.3.0 (2019-09-24) -^^^^^^^^^^^^^^^^^^ -Features -~~~~~~~~ - -- Added ``xdel`` and ``xtrim`` method which missed in ``commands/streams.py`` & also added unit test code for them - (see `#438 `_); -- Add ``count`` argument to ``spop`` command - (see `#485 `_); -- Add support for ``zpopmax`` and ``zpopmin`` redis commands - (see `#550 `_); -- Add ``towncrier``: change notes are now stored in ``CHANGES.txt`` - (see `#576 `_); -- Type hints for the library - (see `#584 `_); -- A few additions to the sorted set commands: - - - the blocking pop commands: ``BZPOPMAX`` and ``BZPOPMIN`` - - - the ``CH`` and ``INCR`` options of the ``ZADD`` command - - (see `#618 `_); -- Added ``no_ack`` parameter to ``xread_group`` streams method in ``commands/streams.py`` - (see `#625 `_); - -Bugfixes -~~~~~~~~ - -- Fix for sensitive logging - (see `#459 `_); -- Fix slow memory leak in ``wait_closed`` implementation - (see `#498 `_); -- Fix handling of instances were Redis returns null fields for a stream message - (see `#605 `_); - -Improved Documentation -~~~~~~~~~~~~~~~~~~~~~~ - -- Rewrite "Getting started" documentation. - (see `#641 `_); - -Misc -~~~~ - -- `#585 `_, - `#611 `_, - `#612 `_, - `#619 `_, - `#620 `_, - `#642 `_; - - -1.2.0 (2018-10-24) -^^^^^^^^^^^^^^^^^^ - -**NEW**: - -* Implemented new Stream command support - (see `#299 `_); - -* Reduce ``encode_command()`` cost about 60% - (see `#397 `_); - - -**FIX**: - -* Fix pipeline commands buffering was causing multiple ``sendto`` syscalls - (see `#464 `_ - and `#473 `_); - -* Python 3.7 compatibility fixes - (see `#426 `_); - -* Fix typos in documentation - (see `#400 `_); - -* Fix ``INFO`` command result parsing - (see `#405 `_); - -* Fix bug in ``ConnectionsPool._drop_closed`` method - (see `#461 `_); - -**MISC**: - -* Update dependencies versions; - -* Multiple tests improvements; - -1.1.0 (2018-02-16) -^^^^^^^^^^^^^^^^^^ - -**NEW**: - -* Implement new commands: ``wait``, ``touch``, ``swapdb``, ``unlink`` - (see `#376 `_); - -* Add ``async_op`` argument to ``flushall`` and ``flushdb`` commands - (see `#364 `_, - and `#370 `_); - -**FIX**: - -* **Important!** Fix Sentinel sentinel client with pool ``minsize`` - greater than 1 - (see `#380 `_); - -* Fix ``SentinelPool.discover_timeout`` usage - (see `#379 `_); - -* Fix ``Receiver`` hang on disconnect - (see `#354 `_, - and `#366 `_); - -* Fix an issue with ``subscribe``/``psubscribe`` with empty pool - (see `#351 `_, - and `#355 `_); - -* Fix an issue when ``StreamReader``'s feed_data is called before set_parser - (see `#347 `_); - -**MISC**: - -* Update dependencies versions; - -* Multiple test fixes; - - -1.0.0 (2017-11-17) -^^^^^^^^^^^^^^^^^^ - -**NEW**: - -* **Important!** Drop Python 3.3, 3.4 support; - (see `#321 `_, - `#323 `_ - and `#326 `_); - -* **Important!** Connections pool has been refactored; now ``create_redis`` - function will yield ``Redis`` instance instead of ``RedisPool`` - (see `#129 `_); - -* **Important!** Change sorted set commands reply format: - return list of tuples instead of plain list for commands - accepting ``withscores`` argument - (see `#334 `_); - -* **Important!** Change ``hscan`` command reply format: - return list of tuples instead of mixed key-value list - (see `#335 `_); - -* Implement Redis URI support as supported ``address`` argument value - (see `#322 `_); - -* Dropped ``create_reconnecting_redis``, ``create_redis_pool`` should be - used instead; - -* Implement custom ``StreamReader`` - (see `#273 `_); - -* Implement Sentinel support - (see `#181 `_); - -* Implement pure-python parser - (see `#212 `_); - -* Add ``migrate_keys`` command - (see `#187 `_); - -* Add ``zrevrangebylex`` command - (see `#201 `_); - -* Add ``command``, ``command_count``, ``command_getkeys`` and - ``command_info`` commands - (see `#229 `_); - -* Add ``ping`` support in pubsub connection - (see `#264 `_); - -* Add ``exist`` parameter to ``zadd`` command - (see `#288 `_); - -* Add ``MaxClientsError`` and implement ``ReplyError`` specialization - (see `#325 `_); - -* Add ``encoding`` parameter to sorted set commands - (see `#289 `_); - -**FIX**: - -* Fix ``CancelledError`` in ``conn._reader_task`` - (see `#301 `_); - -* Fix pending commands cancellation with ``CancelledError``, - use explicit exception instead of calling ``cancel()`` method - (see `#316 `_); - -* Correct error message on Sentinel discovery of master/slave with password - (see `#327 `_); - -* Fix ``bytearray`` support as command argument - (see `#329 `_); - -* Fix critical bug in patched asyncio.Lock - (see `#256 `_); - -* Fix Multi/Exec transaction canceled error - (see `#225 `_); - -* Add missing arguments to ``create_redis`` and ``create_redis_pool``; - -* Fix deprecation warning - (see `#191 `_); - -* Make correct ``__aiter__()`` - (see `#192 `_); - -* Backward compatibility fix for ``with (yield from pool) as conn:`` - (see `#205 `_); - -* Fixed pubsub receiver stop() - (see `#211 `_); - -**MISC**: - -* Multiple test fixes; - -* Add PyPy3 to build matrix; - -* Update dependencies versions; - -* Add missing Python 3.6 classifier; - - -0.3.5 (2017-11-08) -^^^^^^^^^^^^^^^^^^ - -**FIX**: - -* Fix for indistinguishable futures cancellation with - ``asyncio.CancelledError`` - (see `#316 `_), - cherry-picked from master; - - -0.3.4 (2017-10-25) -^^^^^^^^^^^^^^^^^^ - -**FIX**: - -* Fix time command result decoding when using connection-wide encoding setting - (see `#266 `_); - - -0.3.3 (2017-06-30) -^^^^^^^^^^^^^^^^^^ - -**FIX**: - -* Critical bug fixed in patched asyncio.Lock - (see `#256 `_); - - -0.3.2 (2017-06-21) -^^^^^^^^^^^^^^^^^^ - -**NEW**: - -* Added ``zrevrangebylex`` command - (see `#201 `_), - cherry-picked from master; - -* Add connection timeout - (see `#221 `_), - cherry-picked from master; - -**FIX**: - -* Fixed pool close warning - (see `#239 `_ - and `#236 `_), - cherry-picked from master; - -* Fixed asyncio Lock deadlock issue - (see `#231 `_ - and `#241 `_); - - -0.3.1 (2017-05-09) -^^^^^^^^^^^^^^^^^^ - -**FIX**: - -* Fix pubsub Receiver missing iter() method - (see `#203 `_); - - -0.3.0 (2017-01-11) -^^^^^^^^^^^^^^^^^^ - -**NEW**: - -* Pub/Sub connection commands accept ``Channel`` instances - (see `#168 `_); - -* Implement new Pub/Sub MPSC (multi-producers, single-consumer) Queue -- - ``aioredis.pubsub.Receiver`` - (see `#176 `_); - -* Add ``aioredis.abc`` module providing abstract base classes - defining interface for basic lib components; - (see `#176 `_); - -* Implement Geo commands support - (see `#177 `_ - and `#179 `_); - -**FIX**: - -* Minor tests fixes; - -**MISC**: - -* Update examples and docs to use ``async``/``await`` syntax - also keeping ``yield from`` examples for history - (see `#173 `_); - -* Reflow Travis CI configuration; add Python 3.6 section - (see `#170 `_); - -* Add AppVeyor integration to run tests on Windows - (see `#180 `_); - -* Update multiple development requirements; - - -0.2.9 (2016-10-24) -^^^^^^^^^^^^^^^^^^ - -**NEW**: - -* Allow multiple keys in ``EXISTS`` command - (see `#156 `_ - and `#157 `_); - -**FIX**: - -* Close RedisPool when connection to Redis failed - (see `#136 `_); - -* Add simple ``INFO`` command argument validation - (see `#140 `_); - -* Remove invalid uses of ``next()`` - -**MISC**: - -* Update devel.rst docs; update Pub/Sub Channel docs (cross-refs); - -* Update MANIFEST.in to include docs, examples and tests in source bundle; - - -0.2.8 (2016-07-22) -^^^^^^^^^^^^^^^^^^ - -**NEW**: - -* Add ``hmset_dict`` command - (see `#130 `_); - -* Add ``RedisConnection.address`` property; - -* RedisPool ``minsize``/``maxsize`` must not be ``None``; - -* Implement ``close()``/``wait_closed()``/``closed`` interface for pool - (see `#128 `_); - -**FIX**: - -* Add test for ``hstrlen``; - -* Test fixes - -**MISC**: - -* Enable Redis 3.2.0 on Travis; - -* Add spell checking when building docs - (see `#132 `_); - -* Documentation updated; - - -0.2.7 (2016-05-27) -^^^^^^^^^^^^^^^^^^ - -* ``create_pool()`` minsize default value changed to 1; - -* Fixed cancellation of wait_closed - (see `#118 `_); - -* Fixed ``time()`` conversion to float - (see `#126 `_); - -* Fixed ``hmset()`` method to return bool instead of ``b'OK'`` - (see `#126`_); - -* Fixed multi/exec + watch issue (changed watch variable was causing - ``tr.execute()`` to fail) - (see `#121 `_); - -* Replace ``asyncio.Future`` uses with utility method - (get ready to Python 3.5.2 ``loop.create_future()``); - -* Tests switched from unittest to pytest (see `#126`_); - -* Documentation updates; - - -0.2.6 (2016-03-30) -^^^^^^^^^^^^^^^^^^ - -* Fixed Multi/Exec transactions cancellation issue - (see `#110 `_ - and `#114 `_); - -* Fixed Pub/Sub subscribe concurrency issue - (see `#113 `_ - and `#115 `_); - -* Add SSL/TLS support - (see `#116 `_); - -* ``aioredis.ConnectionClosedError`` raised in ``execute_pubsub`` as well - (see `#108 `_); - -* ``Redis.slaveof()`` method signature changed: now to disable - replication one should call ``redis.slaveof(None)`` instead of ``redis.slaveof()``; - -* More tests added; - - -0.2.5 (2016-03-02) -^^^^^^^^^^^^^^^^^^ - -* Close all Pub/Sub channels on connection close - (see `#88 `_); - -* Add ``iter()`` method to ``aioredis.Channel`` allowing to use it - with ``async for`` - (see `#89 `_); - -* Inline code samples in docs made runnable and downloadable - (see `#92 `_); - -* Python 3.5 examples converted to use ``async``/``await`` syntax - (see `#93 `_); - -* Fix Multi/Exec to honor encoding parameter - (see `#94 `_ - and `#97 `_); - -* Add debug message in ``create_connection`` - (see `#90 `_); - -* Replace ``asyncio.async`` calls with wrapper that respects asyncio version - (see `#101 `_); - -* Use NODELAY option for TCP sockets - (see `#105 `_); - -* New ``aioredis.ConnectionClosedError`` exception added. Raised if - connection to Redis server is lost - (see `#108 `_ - and `#109 `_); - -* Fix RedisPool to close and drop connection in subscribe mode on release; - -* Fix ``aioredis.util.decode`` to recursively decode list responses; - -* More examples added and docs updated; - -* Add google groups link to README; - -* Bump year in LICENSE and docs; - - -0.2.4 (2015-10-13) -^^^^^^^^^^^^^^^^^^ - -* Python 3.5 ``async`` support: - - - New scan commands API (``iscan``, ``izscan``, ``ihscan``); - - - Pool made awaitable (allowing ``with await pool: ...`` and ``async - with pool.get() as conn:`` constructs); - -* Fixed dropping closed connections from free pool - (see `#83 `_); - -* Docs updated; - - -0.2.3 (2015-08-14) -^^^^^^^^^^^^^^^^^^ - -* Redis cluster support work in progress; - -* Fixed pool issue causing pool growth over max size & ``acquire`` call hangs - (see `#71 `_); - -* ``info`` server command result parsing implemented; - -* Fixed behavior of util functions - (see `#70 `_); - -* ``hstrlen`` command added; - -* Few fixes in examples; - -* Few fixes in documentation; - - -0.2.2 (2015-07-07) -^^^^^^^^^^^^^^^^^^ - -* Decoding data with ``encoding`` parameter now takes into account - list (array) replies - (see `#68 `_); - -* ``encoding`` parameter added to following commands: - - - generic commands: keys, randomkey; - - - hash commands: hgetall, hkeys, hmget, hvals; - - - list commands: blpop, brpop, brpoplpush, lindex, lpop, lrange, rpop, rpoplpush; - - - set commands: smembers, spop, srandmember; - - - string commands: getrange, getset, mget; - -* Backward incompatibility: - - ``ltrim`` command now returns bool value instead of 'OK'; - -* Tests updated; - - -0.2.1 (2015-07-06) -^^^^^^^^^^^^^^^^^^ - -* Logging added (aioredis.log module); - -* Fixed issue with ``wait_message`` in pub/sub - (see `#66 `_); - - -0.2.0 (2015-06-04) -^^^^^^^^^^^^^^^^^^ - -* Pub/Sub support added; - -* Fix in ``zrevrangebyscore`` command - (see `#62 `_); - -* Fixes/tests/docs; - - -0.1.5 (2014-12-09) -^^^^^^^^^^^^^^^^^^ - -* AutoConnector added; - -* wait_closed method added for clean connections shutdown; - -* ``zscore`` command fixed; - -* Test fixes; - - -0.1.4 (2014-09-22) -^^^^^^^^^^^^^^^^^^ - -* Dropped following Redis methods -- ``Redis.multi()``, - ``Redis.exec()``, ``Redis.discard()``; - -* ``Redis.multi_exec`` hack'ish property removed; - -* ``Redis.multi_exec()`` method added; - -* High-level commands implemented: - - * generic commands (tests); - - * transactions commands (api stabilization). - -* Backward incompatibilities: - - * Following sorted set commands' API changed: - - ``zcount``, ``zrangebyscore``, ``zremrangebyscore``, ``zrevrangebyscore``; - - * set string command' API changed; - - - -0.1.3 (2014-08-08) -^^^^^^^^^^^^^^^^^^ - -* RedisConnection.execute refactored to support commands pipelining - (see `#33 `_); - -* Several fixes; - -* WIP on transactions and commands interface; - -* High-level commands implemented and tested: - - * hash commands; - * hyperloglog commands; - * set commands; - * scripting commands; - * string commands; - * list commands; - - -0.1.2 (2014-07-31) -^^^^^^^^^^^^^^^^^^ - -* ``create_connection``, ``create_pool``, ``create_redis`` functions updated: - db and password arguments made keyword-only - (see `#26 `_); - -* Fixed transaction handling - (see `#32 `_); - -* Response decoding - (see `#16 `_); - - -0.1.1 (2014-07-07) -^^^^^^^^^^^^^^^^^^ - -* Transactions support (in connection, high-level commands have some issues); -* Docs & tests updated. - - -0.1.0 (2014-06-24) -^^^^^^^^^^^^^^^^^^ - -* Initial release; -* RedisConnection implemented; -* RedisPool implemented; -* Docs for RedisConnection & RedisPool; -* WIP on high-level API. diff --git a/CHANGES/655.doc b/CHANGES/655.doc deleted file mode 100644 index 4fc69cd73..000000000 --- a/CHANGES/655.doc +++ /dev/null @@ -1 +0,0 @@ -Added example of using blocking commands such as "brpop" diff --git a/CHANGES/705.bugfix b/CHANGES/705.bugfix deleted file mode 100644 index 7f8242424..000000000 --- a/CHANGES/705.bugfix +++ /dev/null @@ -1 +0,0 @@ -Add support for mapping with multiple field/value pairs to hset(). diff --git a/CHANGES/705.removal b/CHANGES/705.removal deleted file mode 100644 index 80af98a6c..000000000 --- a/CHANGES/705.removal +++ /dev/null @@ -1 +0,0 @@ -Deprecate hmset() and hmset_dict(), use hset() instead. diff --git a/CHANGES/708.bugfix b/CHANGES/708.bugfix deleted file mode 100644 index b0841850f..000000000 --- a/CHANGES/708.bugfix +++ /dev/null @@ -1 +0,0 @@ -Support multiple ids in stream `xdel` function. diff --git a/CHANGES/713.feature b/CHANGES/713.feature deleted file mode 100644 index 6f9967482..000000000 --- a/CHANGES/713.feature +++ /dev/null @@ -1 +0,0 @@ -Add support for client name in Connection/Pool objects to be set automatically upon connecting. diff --git a/CHANGES/723.bugfix b/CHANGES/723.bugfix deleted file mode 100644 index 4fa9cefde..000000000 --- a/CHANGES/723.bugfix +++ /dev/null @@ -1 +0,0 @@ -Revert fix to handling of instances where Redis returns null fields for a stream message. Nil values will now be returned. diff --git a/CHANGES/726.bugfix b/CHANGES/726.bugfix deleted file mode 100644 index 57390e4f2..000000000 --- a/CHANGES/726.bugfix +++ /dev/null @@ -1 +0,0 @@ -Fix "'NoneType' object is not iterable" when iterating over self._waiters. diff --git a/CHANGES/784.feature b/CHANGES/784.feature deleted file mode 100644 index d22395bda..000000000 --- a/CHANGES/784.feature +++ /dev/null @@ -1 +0,0 @@ -Z*LEX functions no longer take `include_min`/`include_max`, and the user must prefix the bounds with `[` or `(`, as per the [redis command](https://redis.io/commands/zrangebylex#how-to-specify-intervals). diff --git a/CHANGES/802.bugfix b/CHANGES/802.bugfix deleted file mode 100644 index 4d971493f..000000000 --- a/CHANGES/802.bugfix +++ /dev/null @@ -1 +0,0 @@ -Fix multiple acquire airedis.locks.Lock (see https://bugs.python.org/issue32734) diff --git a/CHANGES/824.feature b/CHANGES/824.feature deleted file mode 100644 index 34ecd8e8d..000000000 --- a/CHANGES/824.feature +++ /dev/null @@ -1 +0,0 @@ -Drop Python 3.5 support. diff --git a/CHANGES/825.misc b/CHANGES/825.misc deleted file mode 100644 index 5dfe59be2..000000000 --- a/CHANGES/825.misc +++ /dev/null @@ -1 +0,0 @@ -Reformat code with black. diff --git a/CHANGES/826.misc b/CHANGES/826.misc deleted file mode 100644 index b527d5742..000000000 --- a/CHANGES/826.misc +++ /dev/null @@ -1 +0,0 @@ -Set up pre-commit hooks and lint/re-format source. diff --git a/CHANGES/840.misc b/CHANGES/840.misc deleted file mode 100644 index 8f4055888..000000000 --- a/CHANGES/840.misc +++ /dev/null @@ -1 +0,0 @@ -Use modern pytest paradigms, update dependencies, and updates for flake8. diff --git a/CHANGES/850.misc b/CHANGES/850.misc deleted file mode 100644 index bcaf14249..000000000 --- a/CHANGES/850.misc +++ /dev/null @@ -1 +0,0 @@ -Add pip install -e . to developer instructions. diff --git a/CHANGES/855.feature b/CHANGES/855.feature deleted file mode 100644 index 5cf630642..000000000 --- a/CHANGES/855.feature +++ /dev/null @@ -1 +0,0 @@ -Add support for passing TYPE argument to the SCAN command. diff --git a/CHANGES/876.bugfix b/CHANGES/876.bugfix deleted file mode 100644 index 9148c081e..000000000 --- a/CHANGES/876.bugfix +++ /dev/null @@ -1 +0,0 @@ -Fix pool hang when pubsub connection died. diff --git a/CHANGES/899.doc b/CHANGES/899.doc deleted file mode 100644 index 1033b723d..000000000 --- a/CHANGES/899.doc +++ /dev/null @@ -1 +0,0 @@ -Fix pubsub example using PSUBSCRIBE to work as advertised. diff --git a/CHANGES/908.bugfix b/CHANGES/908.bugfix deleted file mode 100644 index 588bf8db7..000000000 --- a/CHANGES/908.bugfix +++ /dev/null @@ -1 +0,0 @@ -corrected error message in incrbyfloat. diff --git a/CHANGES/931.feature b/CHANGES/931.feature new file mode 100644 index 000000000..fa8c56bdd --- /dev/null +++ b/CHANGES/931.feature @@ -0,0 +1 @@ +Port redis-py's client implementation to aioredis. diff --git a/LICENSE b/LICENSE index 35a984bbc..4d8920e89 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,7 @@ The MIT License (MIT) Copyright (c) 2014-2017 Alexey Popravka +Copyright (c) 2021 Sean Stewart Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/Makefile b/Makefile index d39a0833d..75e61f0d7 100644 --- a/Makefile +++ b/Makefile @@ -5,16 +5,13 @@ MYPY ?= mypy # Python implementation PYTHON_IMPL = $(shell $(PYTHON) -c "import sys; print(sys.implementation.name)") -EXAMPLES = $(sort $(wildcard examples/*.py examples/*/*.py)) +EXAMPLES = $(sort $(wildcard docs/examples/*.py docs/examples/*/*.py)) -.PHONY: all lint init-hooks doc man-doc spelling test cov dist devel clean mypy +.PHONY: all lint init-hooks doc spelling test cov dist devel clean mypy all: aioredis.egg-info lint doc cov doc: spelling - $(MAKE) -C docs html - @echo "open file://`pwd`/docs/_build/html/index.html" -man-doc: spelling - $(MAKE) -C docs man + mkdocs build spelling: @echo "Running spelling check" $(MAKE) -C docs spelling @@ -28,11 +25,11 @@ test: cov coverage: $(PYTEST) --cov -dist: clean man-doc +dist: clean $(PYTHON) setup.py sdist bdist_wheel clean: - -rm -r docs/_build + -rm -r docs/build -rm -r build dist aioredis.egg-info init-hooks: diff --git a/README.md b/README.md new file mode 100644 index 000000000..fa9aa75ff --- /dev/null +++ b/README.md @@ -0,0 +1,57 @@ +# aioredis + +asyncio (3156) Redis client library. + +The library is intended to provide simple and clear interface to Redis +based on asyncio. + +## Features + +| Feature | Supported | +|:-----------------------------|:----------------------| +| hiredis parser | :white_check_mark: | +| Pure-python parser | :white_check_mark: | +| Low-level & High-level APIs | :white_check_mark: | +| Pipelining support | :white_check_mark: | +| Multi/Exec support | :white_check_mark: | +| Connections Pool | :white_check_mark: | +| Pub/Sub support | :white_check_mark: | +| Sentinel support | :white_check_mark: | +| ACL support | :white_check_mark: | +| Streams support | :white_check_mark: | +| Redis Cluster support | :no_entry_sign: | +| Tested Python versions | 3.6, 3.7, 3.8, 3.9 | +| Tested for Redis servers | 5.0, 6.0 | +| Support for dev Redis server | through low-level API | + + +## Installation + +The easiest way to install aioredis is by using the package on PyPi: + + pip install aioredis + +## Requirements + +- Python 3.6+ +- hiredis + +## Benchmarks + +Benchmarks can be found here: + + +## Contribute + +- Issue Tracker: +- Google Group: \#!forum/aio-libs +- Gitter: +- Source Code: +- Contributor's guide: devel + +Feel free to file an issue or make pull request if you find any bugs or +have some suggestions for library improvement. + +## License + +The aioredis is offered under a [MIT License](license.md). diff --git a/README.rst b/README.rst deleted file mode 100644 index 5cc871a41..000000000 --- a/README.rst +++ /dev/null @@ -1,128 +0,0 @@ -aioredis -======== - -asyncio (PEP 3156) Redis client library. - -.. image:: https://travis-ci.com/aio-libs/aioredis.svg?branch=master - :target: https://travis-ci.com/aio-libs/aioredis - - -.. image:: https://codecov.io/gh/aio-libs/aioredis/branch/master/graph/badge.svg - :target: https://codecov.io/gh/aio-libs/aioredis - -Features --------- - -================================ ============================== -hiredis_ parser Yes -Pure-python parser Yes -Low-level & High-level APIs Yes -Connections Pool Yes -Pipelining support Yes -Pub/Sub support Yes -SSL/TLS support Yes -Sentinel support Yes -Redis Cluster support WIP -Trollius (python 2.7) No -Tested CPython versions `3.6, 3.7, 3.8 `_ [1]_ [2]_ -Tested PyPy3 versions `pypy3.6-7.1.1 `_ -Tested for Redis server `2.6, 2.8, 3.0, 3.2, 4.0 5.0 `_ -Support for dev Redis server through low-level API -================================ ============================== - -.. [1] For Python 3.3, 3.4 support use aioredis v0.3. -.. [2] For Python 3.5 support use aioredis v1.2. - -Documentation -------------- - -http://aioredis.readthedocs.io/ - -Usage example -------------- - -Simple high-level interface with connections pool: - -.. code:: python - - import asyncio - import aioredis - - async def go(): - redis = await aioredis.create_redis_pool( - 'redis://localhost') - await redis.set('my-key', 'value') - val = await redis.get('my-key', encoding='utf-8') - print(val) - redis.close() - await redis.wait_closed() - - asyncio.run(go()) - # will print 'value' - -Using a pool among multiple coroutine calls: - -.. code:: python - - import asyncio - import string - - import aioredis - - async def go(r, key, value): - await r.set(key, value) - val = await r.get(key) - print(f"Got {key} -> {val}") - - async def main(loop): - r = await aioredis.create_redis_pool( - "redis://localhost", minsize=5, maxsize=10, loop=loop - ) - try: - return await asyncio.gather( - *( - go(r, i, j) - for i, j in zip(string.ascii_uppercase, string.ascii_lowercase) - ), - return_exceptions=True, - ) - finally: - r.close() - await r.wait_closed() - - if __name__ == "__main__": - loop = asyncio.get_event_loop() - res = loop.run_until_complete(main(loop)) - -Requirements ------------- - -* Python_ 3.6+ -* hiredis_ - -.. note:: - - hiredis is preferred requirement. - Pure-python protocol parser is implemented as well and can be used - through ``parser`` parameter. - -Benchmarks ----------- - -Benchmarks can be found here: https://github.com/popravich/python-redis-benchmark - -Discussion list ---------------- - -*aio-libs* google group: https://groups.google.com/forum/#!forum/aio-libs - -Or gitter room: https://gitter.im/aio-libs/Lobby - -License -------- - -The aioredis is offered under MIT license. - -.. _Python: https://www.python.org -.. _hiredis: https://pypi.python.org/pypi/hiredis -.. _travis: https://travis-ci.com/aio-libs/aioredis diff --git a/aioredis/__init__.py b/aioredis/__init__.py index 12da3e8e9..063d7201d 100644 --- a/aioredis/__init__.py +++ b/aioredis/__init__.py @@ -31,7 +31,7 @@ def int_or_str(value): return value -__version__ = "3.5.3" +__version__ = "2.0.0" VERSION = tuple(map(int_or_str, __version__.split("."))) __all__ = [ diff --git a/aioredis/client.py b/aioredis/client.py index 4528327e1..43e43ca45 100644 --- a/aioredis/client.py +++ b/aioredis/client.py @@ -4267,7 +4267,7 @@ def __del__(self): loop.create_task(self.reset()) else: loop.run_until_complete(self.reset()) - super().close() + super().__del__() except Exception: pass diff --git a/aioredis/connection.py b/aioredis/connection.py index f2e91f825..6cdf55193 100644 --- a/aioredis/connection.py +++ b/aioredis/connection.py @@ -1414,7 +1414,7 @@ async def disconnect(self, inuse_connections: bool = True): Disconnects connections in the pool If ``inuse_connections`` is True, disconnect connections that are - current in use, potentially by other threads. Otherwise only disconnect + current in use, potentially by other tasks. Otherwise only disconnect connections that are idle in the pool. """ self._checkpid() diff --git a/docs/Makefile b/docs/Makefile deleted file mode 100644 index 02b17eb9d..000000000 --- a/docs/Makefile +++ /dev/null @@ -1,183 +0,0 @@ -# Makefile for Sphinx documentation -# - -# You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = sphinx-build -PAPER = -BUILDDIR = _build - -# User-friendly check for sphinx-build -ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) -$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) -endif - -# Internal variables. -PAPEROPT_a4 = -D latex_paper_size=a4 -PAPEROPT_letter = -D latex_paper_size=letter -ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . -# the i18n builder cannot share the environment and doctrees with the others -I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . - -.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext - -help: - @echo "Please use \`make ' where is one of" - @echo " html to make standalone HTML files" - @echo " dirhtml to make HTML files named index.html in directories" - @echo " singlehtml to make a single large HTML file" - @echo " pickle to make pickle files" - @echo " json to make JSON files" - @echo " htmlhelp to make HTML files and a HTML help project" - @echo " qthelp to make HTML files and a qthelp project" - @echo " devhelp to make HTML files and a Devhelp project" - @echo " epub to make an epub" - @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" - @echo " latexpdf to make LaTeX files and run them through pdflatex" - @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" - @echo " text to make text files" - @echo " man to make manual pages" - @echo " texinfo to make Texinfo files" - @echo " info to make Texinfo files and run them through makeinfo" - @echo " gettext to make PO message catalogs" - @echo " changes to make an overview of all changed/added/deprecated items" - @echo " xml to make Docutils-native XML files" - @echo " pseudoxml to make pseudoxml-XML files for display purposes" - @echo " linkcheck to check all external links for integrity" - @echo " doctest to run all doctests embedded in the documentation (if enabled)" - -clean: - rm -rf $(BUILDDIR)/* - -html: - $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." - -dirhtml: - $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." - -singlehtml: - $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml - @echo - @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." - -pickle: - $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle - @echo - @echo "Build finished; now you can process the pickle files." - -json: - $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json - @echo - @echo "Build finished; now you can process the JSON files." - -htmlhelp: - $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp - @echo - @echo "Build finished; now you can run HTML Help Workshop with the" \ - ".hhp project file in $(BUILDDIR)/htmlhelp." - -qthelp: - $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp - @echo - @echo "Build finished; now you can run "qcollectiongenerator" with the" \ - ".qhcp project file in $(BUILDDIR)/qthelp, like this:" - @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/aioredis.qhcp" - @echo "To view the help file:" - @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/aioredis.qhc" - -devhelp: - $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp - @echo - @echo "Build finished." - @echo "To view the help file:" - @echo "# mkdir -p $$HOME/.local/share/devhelp/aioredis" - @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/aioredis" - @echo "# devhelp" - -epub: - $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub - @echo - @echo "Build finished. The epub file is in $(BUILDDIR)/epub." - -latex: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo - @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." - @echo "Run \`make' in that directory to run these through (pdf)latex" \ - "(use \`make latexpdf' here to do that automatically)." - -latexpdf: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo "Running LaTeX files through pdflatex..." - $(MAKE) -C $(BUILDDIR)/latex all-pdf - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." - -latexpdfja: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo "Running LaTeX files through platex and dvipdfmx..." - $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." - -text: - $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text - @echo - @echo "Build finished. The text files are in $(BUILDDIR)/text." - -man: - $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man - @echo - @echo "Build finished. The manual pages are in $(BUILDDIR)/man." - -texinfo: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo - @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." - @echo "Run \`make' in that directory to run these through makeinfo" \ - "(use \`make info' here to do that automatically)." - -info: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo "Running Texinfo files through makeinfo..." - make -C $(BUILDDIR)/texinfo info - @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." - -gettext: - $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale - @echo - @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." - -changes: - $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes - @echo - @echo "The overview file is in $(BUILDDIR)/changes." - -linkcheck: - $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck - @echo - @echo "Link check complete; look for any errors in the above output " \ - "or in $(BUILDDIR)/linkcheck/output.txt." - -doctest: - $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest - @echo "Testing of doctests in the sources finished, look at the " \ - "results in $(BUILDDIR)/doctest/output.txt." - -xml: - $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml - @echo - @echo "Build finished. The XML files are in $(BUILDDIR)/xml." - -pseudoxml: - $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml - @echo - @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." - - -spelling: - $(SPHINXBUILD) -b spelling $(ALLSPHINXOPTS) $(BUILDDIR)/spelling || \ - (cat $(BUILDDIR)/spelling/output.txt; false) - test ! -s $(BUILDDIR)/spelling/output.txt diff --git a/docs/_templates/layout.html b/docs/_templates/layout.html deleted file mode 100644 index d0514f5cb..000000000 --- a/docs/_templates/layout.html +++ /dev/null @@ -1,23 +0,0 @@ -{% extends "!layout.html" %} - -{% block sidebartitle %} - - {{ super() }} - - {% if github_user and github_repo %} - {% set travis_url = "https://travis-ci.com/{}/{}".format(github_user, github_repo) %} -
-
- -
-
-
- - - -
- {% endif %} - -{% endblock %} diff --git a/docs/abc.rst b/docs/abc.rst deleted file mode 100644 index 91a00a095..000000000 --- a/docs/abc.rst +++ /dev/null @@ -1,20 +0,0 @@ -.. module:: aioredis.abc - -:mod:`aioredis.abc` --- Interfaces Reference -============================================ - -This module defines several abstract classes that must be used -when implementing custom connection managers or other features. - - -.. autoclass:: AbcConnection - :show-inheritance: - :members: - -.. autoclass:: AbcPool - :show-inheritance: - :members: - -.. autoclass:: AbcChannel - :show-inheritance: - :members: diff --git a/docs/api/high-level.md b/docs/api/high-level.md new file mode 100644 index 000000000..93a95b788 --- /dev/null +++ b/docs/api/high-level.md @@ -0,0 +1,17 @@ +# High Level APIs + +## Exceptions + +::: aioredis.exceptions + +## Client + +::: aioredis.client + +## Lock + +::: aioredis.lock + +## Sentinel + +::: aioredis.sentinel diff --git a/docs/api/low-level.md b/docs/api/low-level.md new file mode 100644 index 000000000..74fa204d7 --- /dev/null +++ b/docs/api/low-level.md @@ -0,0 +1,9 @@ +# Low Level APIs + +## Connection + +::: aioredis.connection + +## Utils + +::: aioredis.utils diff --git a/docs/api_reference.rst b/docs/api_reference.rst deleted file mode 100644 index 091eae97c..000000000 --- a/docs/api_reference.rst +++ /dev/null @@ -1,844 +0,0 @@ -:mod:`aioredis` --- API Reference -================================= - -.. highlight:: python3 -.. module:: aioredis - - -.. _aioredis-connection: - -Connection ----------- - -Redis Connection is the core function of the library. -Connection instances can be used as is or through -:ref:`pool` or :ref:`high-level API`. - -Connection usage is as simple as: - -.. code:: python - - import asyncio - import aioredis - - async def connect_uri(): - conn = await aioredis.create_connection( - 'redis://localhost/0') - val = await conn.execute('GET', 'my-key') - - async def connect_tcp(): - conn = await aioredis.create_connection( - ('localhost', 6379)) - val = await conn.execute('GET', 'my-key') - - async def connect_unixsocket(): - conn = await aioredis.create_connection( - '/path/to/redis/socket') - # or uri 'unix:///path/to/redis/socket?db=1' - val = await conn.execute('GET', 'my-key') - - asyncio.get_event_loop().run_until_complete(connect_tcp()) - asyncio.get_event_loop().run_until_complete(connect_unixsocket()) - - -.. cofunction:: create_connection(address, \*, db=0, password=None, ssl=None,\ - encoding=None, parser=None,\ - timeout=None, connection_cls=None, name=None) - - Creates Redis connection. - - .. versionchanged:: v0.3.1 - ``timeout`` argument added. - - .. versionchanged:: v1.0 - ``parser`` argument added. - - .. deprecated:: v1.3.1 - ``loop`` argument deprecated for Python 3.8 compatibility. - - :param address: An address where to connect. - Can be one of the following: - - * a Redis URI --- ``"redis://host:6379/0?encoding=utf-8"``; - ``"redis://:password@host:6379/0?encoding=utf-8"``; - - * a (host, port) tuple --- ``('localhost', 6379)``; - - * or a unix domain socket path string --- ``"/path/to/redis.sock"``. - :type address: tuple or str - - :param int db: Redis database index to switch to when connected. - - :param password: Password to use if redis server instance requires - authorization. - :type password: str or None - - :param ssl: SSL context that is passed through to - :func:`asyncio.BaseEventLoop.create_connection`. - :type ssl: :class:`ssl.SSLContext` or True or None - - :param encoding: Codec to use for response decoding. - :type encoding: str or None - - :param parser: Protocol parser class. Can be used to set custom protocol - reader; expected same interface as :class:`hiredis.Reader`. - :type parser: callable or None - - :param timeout: Max time to open a connection, otherwise - raise :exc:`asyncio.TimeoutError` exception. - ``None`` by default - :type timeout: float greater than 0 or None - - :param connection_cls: Custom connection class. ``None`` by default. - :type connection_cls: :class:`abc.AbcConnection` or None - - :param name: Client name to set upon connecting. - :type name: str or None - - :return: :class:`RedisConnection` instance. - - -.. class:: RedisConnection - - Bases: :class:`abc.AbcConnection` - - Redis connection interface. - - .. attribute:: address - - Redis server address; either IP-port tuple or unix socket str (*read-only*). - IP is either IPv4 or IPv6 depending on resolved host part in initial address. - - .. versionadded:: v0.2.8 - - .. attribute:: db - - Current database index (*read-only*). - - .. attribute:: encoding - - Current codec for response decoding (*read-only*). - - .. attribute:: closed - - Set to ``True`` if connection is closed (*read-only*). - - .. attribute:: in_transaction - - Set to ``True`` when MULTI command was issued (*read-only*). - - .. attribute:: pubsub_channels - - *Read-only* dict with subscribed channels. - Keys are bytes, values are :class:`~aioredis.Channel` instances. - - .. attribute:: pubsub_patterns - - *Read-only* dict with subscribed patterns. - Keys are bytes, values are :class:`~aioredis.Channel` instances. - - .. attribute:: in_pubsub - - Indicates that connection is in PUB/SUB mode. - Provides the number of subscribed channels. *Read-only*. - - - .. method:: execute(command, \*args, encoding=_NOTSET) - - Execute Redis command. - - The method is **not a coroutine** itself but instead it - writes to underlying transport and returns a :class:`asyncio.Future` - waiting for result. - - :param command: Command to execute - :type command: str, bytes, bytearray - - :param encoding: Keyword-only argument for overriding response decoding. - By default will use connection-wide encoding. - May be set to None to skip response decoding. - :type encoding: str or None - - :raise TypeError: When any of arguments is None or - can not be encoded as bytes. - :raise aioredis.ReplyError: For redis error replies. - :raise aioredis.ProtocolError: When response can not be decoded - and/or connection is broken. - - :return: Returns bytes or int reply (or str if encoding was set) - - - .. method:: execute_pubsub(command, \*channels_or_patterns) - - Method to execute Pub/Sub commands. - The method is not a coroutine itself but returns a :func:`asyncio.gather()` - coroutine. - Method also accept :class:`aioredis.Channel` instances as command - arguments:: - - >>> ch1 = Channel('A', is_pattern=False) - >>> await conn.execute_pubsub('subscribe', ch1) - [[b'subscribe', b'A', 1]] - - .. versionchanged:: v0.3 - The method accept :class:`~aioredis.Channel` instances. - - :param command: One of the following Pub/Sub commands: - ``subscribe``, ``unsubscribe``, - ``psubscribe``, ``punsubscribe``. - :type command: str, bytes, bytearray - - :param \*channels_or_patterns: Channels or patterns to subscribe connection - to or unsubscribe from. - At least one channel/pattern is required. - - :return: Returns a list of subscribe/unsubscribe messages, - ex:: - - >>> await conn.execute_pubsub('subscribe', 'A', 'B') - [[b'subscribe', b'A', 1], [b'subscribe', b'B', 2]] - - - .. method:: close() - - Closes connection. - - Mark connection as closed and schedule cleanup procedure. - - All pending commands will be canceled with - :exc:`ConnectionForcedCloseError`. - - - .. method:: wait_closed() - - Coroutine waiting for connection to get closed. - - - .. method:: select(db) - - Changes current db index to new one. - - :param int db: New redis database index. - - :raise TypeError: When ``db`` parameter is not int. - :raise ValueError: When ``db`` parameter is less than 0. - - :return True: Always returns True or raises exception. - - - .. method:: auth(password) - - Send AUTH command. - - :param str password: Plain-text password - - :return bool: True if redis replied with 'OK'. - - ----- - -.. _aioredis-pool: - -Connections Pool ----------------- - -The library provides connections pool. The basic usage is as follows: - -.. code:: python - - import aioredis - - async def sample_pool(): - pool = await aioredis.create_pool('redis://localhost') - val = await pool.execute('get', 'my-key') - - -.. _aioredis-create_pool: - -.. function:: create_pool(address, \*, db=0, password=None, ssl=None, \ - encoding=None, minsize=1, maxsize=10, \ - parser=None, \ - create_connection_timeout=None, \ - pool_cls=None, connection_cls=None, name=None) - - A :ref:`coroutine` that instantiates a pool of - :class:`~.RedisConnection`. - - .. versionchanged:: v0.2.7 - ``minsize`` default value changed from 10 to 1. - - .. versionchanged:: v0.2.8 - Disallow arbitrary ConnectionsPool maxsize. - - .. deprecated:: v0.2.9 - *commands_factory* argument is deprecated and will be removed in *v1.0*. - - .. versionchanged:: v0.3.2 - ``create_connection_timeout`` argument added. - - .. versionchanged: v1.0 - ``commands_factory`` argument has been dropped. - - .. versionadded:: v1.0 - ``parser``, ``pool_cls`` and ``connection_cls`` arguments added. - - .. deprecated:: v1.3.1 - ``loop`` argument deprecated for Python 3.8 compatibility. - - :param address: An address where to connect. - Can be one of the following: - - * a Redis URI --- ``"redis://host:6379/0?encoding=utf-8"``; - - * a (host, port) tuple --- ``('localhost', 6379)``; - - * or a unix domain socket path string --- ``"/path/to/redis.sock"``. - :type address: tuple or str - - :param int db: Redis database index to switch to when connected. - - :param password: Password to use if redis server instance requires - authorization. - :type password: str or None - - :param ssl: SSL context that is passed through to - :func:`asyncio.BaseEventLoop.create_connection`. - :type ssl: :class:`ssl.SSLContext` or True or None - - :param encoding: Codec to use for response decoding. - :type encoding: str or None - - :param int minsize: Minimum number of free connection to create in pool. - ``1`` by default. - - :param int maxsize: Maximum number of connection to keep in pool. - ``10`` by default. - Must be greater than ``0``. ``None`` is disallowed. - - :param parser: Protocol parser class. Can be used to set custom protocol - reader; expected same interface as :class:`hiredis.Reader`. - :type parser: callable or None - - :param create_connection_timeout: Max time to open a connection, - otherwise raise an :exc:`asyncio.TimeoutError`. ``None`` by default. - :type create_connection_timeout: float greater than 0 or None - - :param pool_cls: Can be used to instantiate custom pool class. - This argument **must be** a subclass of :class:`~aioredis.abc.AbcPool`. - :type pool_cls: aioredis.abc.AbcPool - - :param connection_cls: Can be used to make pool instantiate custom - connection classes. This argument **must be** a subclass of - :class:`~aioredis.abc.AbcConnection`. - :type connection_cls: aioredis.abc.AbcConnection - - :param name: Client name to set upon connecting. - :type name: str or None - - :return: :class:`ConnectionsPool` instance. - - -.. class:: ConnectionsPool - - Bases: :class:`abc.AbcPool` - - Redis connections pool. - - .. attribute:: minsize - - A minimum size of the pool (*read-only*). - - .. attribute:: maxsize - - A maximum size of the pool (*read-only*). - - .. attribute:: size - - Current pool size --- number of free and used connections (*read-only*). - - .. attribute:: freesize - - Current number of free connections (*read-only*). - - .. attribute:: db - - Currently selected db index (*read-only*). - - .. attribute:: encoding - - Current codec for response decoding (*read-only*). - - .. attribute:: closed - - ``True`` if pool is closed. - - .. versionadded:: v0.2.8 - - .. method:: execute(command, \*args, \**kwargs) - - Execute Redis command in a free connection and return - :class:`asyncio.Future` waiting for result. - - This method tries to pick a free connection from pool and send - command through it at once (keeping pipelining feature provided - by :meth:`aioredis.RedisConnection.execute`). - If no connection is found --- returns coroutine waiting for free - connection to execute command. - - .. versionadded:: v1.0 - - .. method:: execute_pubsub(command, \*channels) - - Execute Redis (p)subscribe/(p)unsubscribe command. - - ``ConnectionsPool`` picks separate free connection for pub/sub - and uses it until pool is closed or connection is disconnected - (unsubscribing from all channels/pattern will leave connection - locked for pub/sub use). - - There is no auto-reconnect for Pub/Sub connection as this will - hide from user messages loss. - - Has similar to :meth:`execute` behavior, ie: tries to pick free - connection from pool and switch it to pub/sub mode; or fallback - to coroutine waiting for free connection and repeating operation. - - .. versionadded:: v1.0 - - .. method:: get_connection(command, args=()) - - Gets free connection from pool returning tuple of (connection, address). - - If no free connection is found -- None is returned in place of connection. - - :rtype: tuple(:class:`RedisConnection` or None, str) - - .. versionadded:: v1.0 - - .. comethod:: clear() - - Closes and removes all free connections in the pool. - - .. comethod:: select(db) - - Changes db index for all free connections in the pool. - - :param int db: New database index. - - .. comethod:: acquire(command=None, args=()) - - Acquires a connection from *free pool*. Creates new connection if needed. - - :param command: reserved for future. - :param args: reserved for future. - :raises aioredis.PoolClosedError: if pool is already closed - - .. method:: release(conn) - - Returns used connection back into pool. - - When returned connection has db index that differs from one in pool - the connection will be dropped. - When queue of free connections is full the connection will be dropped. - - .. note:: This method is **not a coroutine**. - - :param aioredis.RedisConnection conn: A RedisConnection instance. - - .. method:: close() - - Close all free and in-progress connections and mark pool as closed. - - .. versionadded:: v0.2.8 - - .. comethod:: wait_closed() - - Wait until pool gets closed (when all connections are closed). - - .. versionadded:: v0.2.8 - ----- - -.. _aioredis-exceptions: - -Exceptions ----------- - -.. exception:: RedisError - - :Bases: :exc:`Exception` - - Base exception class for aioredis exceptions. - -.. exception:: ProtocolError - - :Bases: :exc:`RedisError` - - Raised when protocol error occurs. - When this type of exception is raised connection must be considered - broken and must be closed. - -.. exception:: ReplyError - - :Bases: :exc:`RedisError` - - Raised for Redis :term:`error replies`. - -.. exception:: MaxClientsError - - :Bases: :exc:`ReplyError` - - Raised when maximum number of clients has been reached - (Redis server configured value). - -.. exception:: AuthError - - :Bases: :exc:`ReplyError` - - Raised when authentication errors occur. - -.. exception:: ConnectionClosedError - - :Bases: :exc:`RedisError` - - Raised if connection to server was lost/closed. - -.. exception:: ConnectionForcedCloseError - - :Bases: :exc:`ConnectionClosedError` - - Raised if connection was closed with :func:`RedisConnection.close` method. - -.. exception:: PipelineError - - :Bases: :exc:`RedisError` - - Raised from :meth:`~.commands.TransactionsCommandsMixin.pipeline` - if any pipelined command raised error. - -.. exception:: MultiExecError - - :Bases: :exc:`PipelineError` - - Same as :exc:`~.PipelineError` but raised when executing multi_exec - block. - -.. exception:: WatchVariableError - - :Bases: :exc:`MultiExecError` - - Raised if watched variable changed (EXEC returns None). - Subclass of :exc:`~.MultiExecError`. - -.. exception:: ChannelClosedError - - :Bases: :exc:`RedisError` - - Raised from :meth:`aioredis.Channel.get` when Pub/Sub channel is - unsubscribed and messages queue is empty. - -.. exception:: PoolClosedError - - :Bases: :exc:`RedisError` - - Raised from :meth:`aioredis.ConnectionsPool.acquire` - when pool is already closed. - -.. exception:: ReadOnlyError - - :Bases: :exc:`RedisError` - - Raised from slave when read-only mode is enabled. - -.. exception:: MasterNotFoundError - - :Bases: :exc:`RedisError` - - Raised by Sentinel client if it can not find requested master. - -.. exception:: SlaveNotFoundError - - :Bases: :exc:`RedisError` - - Raised by Sentinel client if it can not find requested slave. - -.. exception:: MasterReplyError - - :Bases: :exc:`RedisError` - - Raised if establishing connection to master failed with ``RedisError``, - for instance because of required or wrong authentication. - -.. exception:: SlaveReplyError - - :Bases: :exc:`RedisError` - - Raised if establishing connection to slave failed with ``RedisError``, - for instance because of required or wrong authentication. - -Exceptions Hierarchy -~~~~~~~~~~~~~~~~~~~~ - -.. code-block:: guess - - Exception - RedisError - ProtocolError - ReplyError - MaxClientsError - AuthError - PipelineError - MultiExecError - WatchVariableError - ChannelClosedError - ConnectionClosedError - ConnectionForcedCloseError - PoolClosedError - ReadOnlyError - MasterNotFoundError - SlaveNotFoundError - MasterReplyError - SlaveReplyError - - ----- - -.. _aioredis-channel: - -Pub/Sub Channel object ----------------------- - -`Channel` object is a wrapper around queue for storing received pub/sub messages. - - -.. class:: Channel(name, is_pattern) - - Bases: :class:`abc.AbcChannel` - - Object representing Pub/Sub messages queue. - It's basically a wrapper around :class:`asyncio.Queue`. - - .. attribute:: name - - Holds encoded channel/pattern name. - - .. attribute:: is_pattern - - Set to True for pattern channels. - - .. attribute:: is_active - - Set to True if there are messages in queue and connection is still - subscribed to this channel. - - .. comethod:: get(\*, encoding=None, decoder=None) - - Coroutine that waits for and returns a message. - - Return value is message received or ``None`` signifying that channel has - been unsubscribed and no more messages will be received. - - :param str encoding: If not None used to decode resulting bytes message. - - :param callable decoder: If specified used to decode message, - ex. :func:`json.loads()` - - :raise aioredis.ChannelClosedError: If channel is unsubscribed and - has no more messages. - - .. method:: get_json(\*, encoding="utf-8") - - Shortcut to ``get(encoding="utf-8", decoder=json.loads)`` - - .. comethod:: wait_message() - - Waits for message to become available in channel - or channel is closed (unsubscribed). - - Main idea is to use it in loops: - - >>> ch = redis.channels['channel:1'] - >>> while await ch.wait_message(): - ... msg = await ch.get() - - :rtype: bool - - .. comethod:: iter(, \*, encoding=None, decoder=None) - :async-for: - :coroutine: - - Same as :meth:`~.get` method but it is a native coroutine. - - Usage example:: - - >>> async for msg in ch.iter(): - ... print(msg) - - .. versionadded:: 0.2.5 - - ----- - -.. _aioredis-redis: - -Commands Interface ------------------- - -The library provides high-level API implementing simple interface -to Redis commands. - -The usage is as simple as: - -.. code:: python - - import aioredis - - # Create Redis client bound to single non-reconnecting connection. - async def single_connection(): - redis = await aioredis.create_redis( - 'redis://localhost') - val = await redis.get('my-key') - - # Create Redis client bound to connections pool. - async def pool_of_connections(): - redis = await aioredis.create_redis_pool( - 'redis://localhost') - val = await redis.get('my-key') - - # we can also use pub/sub as underlying pool - # has several free connections: - ch1, ch2 = await redis.subscribe('chan:1', 'chan:2') - # publish using free connection - await redis.publish('chan:1', 'Hello') - await ch1.get() - -For commands reference --- -see :ref:`commands mixins reference `. - - -.. cofunction:: create_redis(address, \*, db=0, password=None, ssl=None,\ - encoding=None, commands_factory=Redis,\ - parser=None, timeout=None,\ - connection_cls=None) - - This :ref:`coroutine` creates high-level Redis - interface instance bound to single Redis connection - (without auto-reconnect). - - .. versionadded:: v1.0 - ``parser``, ``timeout`` and ``connection_cls`` arguments added. - - .. deprecated:: v1.3.1 - ``loop`` argument deprecated for Python 3.8 compatibility. - - See also :class:`~aioredis.RedisConnection` for parameters description. - - :param address: An address where to connect. Can be a (host, port) tuple, - unix domain socket path string or a Redis URI string. - :type address: tuple or str - - :param int db: Redis database index to switch to when connected. - - :param password: Password to use if Redis server instance requires - authorization. - :type password: str or bytes or None - - :param ssl: SSL context that is passed through to - :func:`asyncio.BaseEventLoop.create_connection`. - :type ssl: :class:`ssl.SSLContext` or True or None - - :param encoding: Codec to use for response decoding. - :type encoding: str or None - - :param commands_factory: A factory accepting single parameter -- - object implementing :class:`~abc.AbcConnection` - and returning an instance providing - high-level interface to Redis. :class:`Redis` by default. - :type commands_factory: callable - - :param parser: Protocol parser class. Can be used to set custom protocol - reader; expected same interface as :class:`hiredis.Reader`. - :type parser: callable or None - - :param timeout: Max time to open a connection, otherwise - raise :exc:`asyncio.TimeoutError` exception. - ``None`` by default - :type timeout: float greater than 0 or None - - :param connection_cls: Can be used to instantiate custom - connection class. This argument **must be** a subclass of - :class:`~aioredis.abc.AbcConnection`. - :type connection_cls: aioredis.abc.AbcConnection - - :returns: Redis client (result of ``commands_factory`` call), - :class:`Redis` by default. - - -.. cofunction:: create_redis_pool(address, \*, db=0, password=None, ssl=None,\ - encoding=None, commands_factory=Redis,\ - minsize=1, maxsize=10,\ - parser=None, timeout=None,\ - pool_cls=None, connection_cls=None,\ - ) - - This :ref:`coroutine` create high-level Redis client instance - bound to connections pool (this allows auto-reconnect and simple pub/sub - use). - - See also :class:`~aioredis.ConnectionsPool` for parameters description. - - .. versionchanged:: v1.0 - ``parser``, ``timeout``, ``pool_cls`` and ``connection_cls`` - arguments added. - - .. deprecated:: v1.3.1 - ``loop`` argument deprecated for Python 3.8 compatibility. - - :param address: An address where to connect. Can be a (host, port) tuple, - unix domain socket path string or a Redis URI string. - :type address: tuple or str - - :param int db: Redis database index to switch to when connected. - :param password: Password to use if Redis server instance requires - authorization. - :type password: str or bytes or None - - :param ssl: SSL context that is passed through to - :func:`asyncio.BaseEventLoop.create_connection`. - :type ssl: :class:`ssl.SSLContext` or True or None - - :param encoding: Codec to use for response decoding. - :type encoding: str or None - - :param commands_factory: A factory accepting single parameter -- - object implementing :class:`~abc.AbcConnection` interface - and returning an instance providing - high-level interface to Redis. :class:`Redis` by default. - :type commands_factory: callable - - :param int minsize: Minimum number of connections to initialize - and keep in pool. Default is 1. - - :param int maxsize: Maximum number of connections that can be created - in pool. Default is 10. - - :param parser: Protocol parser class. Can be used to set custom protocol - reader; expected same interface as :class:`hiredis.Reader`. - :type parser: callable or None - - :param timeout: Max time to open a connection, otherwise - raise :exc:`asyncio.TimeoutError` exception. - ``None`` by default - :type timeout: float greater than 0 or None - - :param pool_cls: Can be used to instantiate custom pool class. - This argument **must be** a subclass of :class:`~aioredis.abc.AbcPool`. - :type pool_cls: aioredis.abc.AbcPool - - :param connection_cls: Can be used to make pool instantiate custom - connection classes. This argument **must be** a subclass of - :class:`~aioredis.abc.AbcConnection`. - :type connection_cls: aioredis.abc.AbcConnection - - :returns: Redis client (result of ``commands_factory`` call), - :class:`Redis` by default. diff --git a/docs/changes.md b/docs/changes.md new file mode 100644 index 000000000..e0818b74c --- /dev/null +++ b/docs/changes.md @@ -0,0 +1,520 @@ +# Changes + +## 1.3.1 (2019-12-02) + +### Bugfixes + +- Fix transaction data decoding + (see [#657](https://github.com/aio-libs/aioredis/issues/657)) +- Fix duplicate calls to `pool.wait_closed()` upon `create_pool()` exception. + (see [#671](https://github.com/aio-libs/aioredis/issues/671)) + +### Deprecations and Removals + +- Drop explicit loop requirement in API. + Deprecate `loop` argument. + Throw warning in Python 3.8+ if explicit `loop` is passed to methods. + (see [#666](https://github.com/aio-libs/aioredis/issues/666)) + +### Misc + +- [#643](https://github.com/aio-libs/aioredis/issues/643), + [#646](https://github.com/aio-libs/aioredis/issues/646), + [#648](https://github.com/aio-libs/aioredis/issues/648) + +## 1.3.0 (2019-09-24) + +### Features + +- Added `xdel` and `xtrim` method which missed in `commands/streams.py` & also added unit test code for them + (see [#438](https://github.com/aio-libs/aioredis/issues/438)) +- Add `count` argument to `spop` command + (see [#485](https://github.com/aio-libs/aioredis/issues/485)) +- Add support for `zpopmax` and `zpopmin` redis commands + (see [#550](https://github.com/aio-libs/aioredis/issues/550)) +- Add `towncrier`: change notes are now stored in `CHANGES.txt` + (see [#576](https://github.com/aio-libs/aioredis/issues/576)) +- Type hints for the library + (see [#584](https://github.com/aio-libs/aioredis/issues/584)) +- A few additions to the sorted set commands: +- the blocking pop commands: `BZPOPMAX` and `BZPOPMIN` +- the `CH` and `INCR` options of the `ZADD` command + (see [#618](https://github.com/aio-libs/aioredis/issues/618)) +- Added `no_ack` parameter to `xread_group` streams method in `commands/streams.py` + (see [#625](https://github.com/aio-libs/aioredis/issues/625)) + +### Bugfixes + +- Fix for sensitive logging + (see [#459](https://github.com/aio-libs/aioredis/issues/459)) +- Fix slow memory leak in `wait_closed` implementation + (see [#498](https://github.com/aio-libs/aioredis/issues/498)) +- Fix handling of instances were Redis returns null fields for a stream message (see + [#605](https://github.com/aio-libs/aioredis/issues/605)) + +### Improved Documentation + +- Rewrite "Getting started" documentation. + (see [#641](https://github.com/aio-libs/aioredis/issues/641)) + +### Misc + +- [#585](https://github.com/aio-libs/aioredis/issues/585), + [#611](https://github.com/aio-libs/aioredis/issues/611), + [#612](https://github.com/aio-libs/aioredis/issues/612), + [#619](https://github.com/aio-libs/aioredis/issues/619), + [#620](https://github.com/aio-libs/aioredis/issues/620), + [#642](https://github.com/aio-libs/aioredis/issues/642) + +## 1.2.0 (2018-10-24) + + +### Features + +- Implemented new Stream command support + (see [#299](https://github.com/aio-libs/aioredis/pull/299)) +- Reduce `encode_command()` cost about 60% + (see [#397](https://github.com/aio-libs/aioredis/pull/397)) + +### Bugfixes + +- Fix pipeline commands buffering was causing multiple `sendto` syscalls + (see [#464](https://github.com/aio-libs/aioredis/pull/464) + and [#473](https://github.com/aio-libs/aioredis/pull/473)) +- Python 3.7 compatibility fixes + (see [#426](https://github.com/aio-libs/aioredis/pull/426)) +- Fix typos in documentation + (see [#400](https://github.com/aio-libs/aioredis/pull/400)) +- Fix `INFO` command result parsing + (see [#405](https://github.com/aio-libs/aioredis/pull/405)) +- Fix bug in `ConnectionsPool._drop_closed` method + (see [#461](https://github.com/aio-libs/aioredis/pull/461)) + +### Miscellaneous + +- Update dependencies versions +- Multiple tests improvements +## 1.1.0 (2018-02-16) + + +### Features + +- Implement new commands: `wait`, `touch`, `swapdb`, `unlink` + (see [#376](https://github.com/aio-libs/aioredis/pull/376)) +- Add `async_op` argument to `flushall` and `flushdb` commands + (see [#364](https://github.com/aio-libs/aioredis/pull/364), + and [#370](https://github.com/aio-libs/aioredis/pull/370)) + +### Bugfixes + +- **Important!** Fix Sentinel sentinel client with pool `minsize` + greater than 1 + (see [#380](https://github.com/aio-libs/aioredis/pull/380)) +- Fix `SentinelPool.discover_timeout` usage + (see [#379](https://github.com/aio-libs/aioredis/pull/379)) +- Fix `Receiver` hang on disconnect + (see [#354](https://github.com/aio-libs/aioredis/pull/354), + and [#366](https://github.com/aio-libs/aioredis/pull/366)) +- Fix an issue with `subscribe`/`psubscribe` with empty pool + (see [#351](https://github.com/aio-libs/aioredis/pull/351), + and [#355](https://github.com/aio-libs/aioredis/pull/355)) +- Fix an issue when `StreamReader`'s feed_data is called before set_parser + (see [#347](https://github.com/aio-libs/aioredis/pull/347)) + +### Miscellaneous + +- Update dependencies versions +- Multiple test fixes + +## 1.0.0 (2017-11-17) + + +### Features + +- **Important!** Drop Python 3.3, 3.4 support (see [#321](https://github.com/aio-libs/aioredis/pull/321), + [#323](https://github.com/aio-libs/aioredis/pull/323) + and [#326](https://github.com/aio-libs/aioredis/pull/326)) +- **Important!** Connections pool has been refactored; now `create_redis` + function will yield `Redis` instance instead of `RedisPool` + (see [#129](https://github.com/aio-libs/aioredis/pull/129)) +- **Important!** Change sorted set commands reply format: + return list of tuples instead of plain list for commands + accepting `withscores` argument + (see [#334](https://github.com/aio-libs/aioredis/pull/334)) +- **Important!** Change `hscan` command reply format: + return list of tuples instead of mixed key-value list + (see [#335](https://github.com/aio-libs/aioredis/pull/335)) +- Implement Redis URI support as supported `address` argument value + (see [#322](https://github.com/aio-libs/aioredis/pull/322)) +- Dropped `create_reconnecting_redis`, `create_redis_pool` should be + used instead +- Implement custom `StreamReader` + (see [#273](https://github.com/aio-libs/aioredis/pull/273)) +- Implement Sentinel support + (see [#181](https://github.com/aio-libs/aioredis/pull/181)) +- Implement pure-python parser + (see [#212](https://github.com/aio-libs/aioredis/pull/212)) +- Add `migrate_keys` command + (see [#187](https://github.com/aio-libs/aioredis/pull/187)) +- Add `zrevrangebylex` command + (see [#201](https://github.com/aio-libs/aioredis/pull/201)) +- Add `command`, `command_count`, `command_getkeys` and + `command_info` commands + (see [#229](https://github.com/aio-libs/aioredis/pull/229)) +- Add `ping` support in pubsub connection + (see [#264](https://github.com/aio-libs/aioredis/pull/264)) +- Add `exist` parameter to `zadd` command + (see [#288](https://github.com/aio-libs/aioredis/pull/288)) +- Add `MaxClientsError` and implement `ReplyError` specialization + (see [#325](https://github.com/aio-libs/aioredis/pull/325)) +- Add `encoding` parameter to sorted set commands + (see [#289](https://github.com/aio-libs/aioredis/pull/289)) + +### Bugfixes + +- Fix `CancelledError` in `conn._reader_task` + (see [#301](https://github.com/aio-libs/aioredis/pull/301)) +- Fix pending commands cancellation with `CancelledError`, + use explicit exception instead of calling `cancel()` method + (see [#316](https://github.com/aio-libs/aioredis/pull/316)) +- Correct error message on Sentinel discovery of master/slave with password + (see [#327](https://github.com/aio-libs/aioredis/pull/327)) +- Fix `bytearray` support as command argument + (see [#329](https://github.com/aio-libs/aioredis/pull/329)) +- Fix critical bug in patched asyncio.Lock + (see [#256](https://github.com/aio-libs/aioredis/pull/256)) +- Fix Multi/Exec transaction canceled error + (see [#225](https://github.com/aio-libs/aioredis/pull/225)) +- Add missing arguments to `create_redis` and `create_redis_pool` +- Fix deprecation warning + (see [#191](https://github.com/aio-libs/aioredis/pull/191)) +- Make correct `__aiter__()` + (see [#192](https://github.com/aio-libs/aioredis/pull/192)) +- Backward compatibility fix for `with (yield from pool) as conn:` + (see [#205](https://github.com/aio-libs/aioredis/pull/205)) +- Fixed pubsub receiver stop() + (see [#211](https://github.com/aio-libs/aioredis/pull/211)) + +### Miscellaneous + +- Multiple test fixes +- Add PyPy3 to build matrix +- Update dependencies versions +- Add missing Python 3.6 classifier + +## 0.3.5 (2017-11-08) + + +### Bugfixes + +- Fix for indistinguishable futures cancellation with + `asyncio.CancelledError` + (see [#316](https://github.com/aio-libs/aioredis/pull/316)), + cherry-picked from master + +## 0.3.4 (2017-10-25) + + +### Bugfixes + +- Fix time command result decoding when using connection-wide encoding setting + (see [#266](https://github.com/aio-libs/aioredis/pull/266)) + +## 0.3.3 (2017-06-30) + + +### Bugfixes + +- Critical bug fixed in patched asyncio.Lock + (see [#256](https://github.com/aio-libs/aioredis/pull/256)) + +## 0.3.2 (2017-06-21) + + +### Features + +- Added `zrevrangebylex` command + (see [#201](https://github.com/aio-libs/aioredis/pull/201)), + cherry-picked from master +- Add connection timeout + (see [#221](https://github.com/aio-libs/aioredis/pull/221)), + cherry-picked from master +### Bugfixes + +- Fixed pool close warning + (see [#239](https://github.com/aio-libs/aioredis/pull/239) + and [#236](https://github.com/aio-libs/aioredis/issues/236)), + cherry-picked from master +- Fixed asyncio Lock deadlock issue + (see [#231](https://github.com/aio-libs/aioredis/issues/231) + and [#241](https://github.com/aio-libs/aioredis/pull/241)) + +## 0.3.1 (2017-05-09) + + +### Bugfixes + +- Fix pubsub Receiver missing iter() method + (see [#203](https://github.com/aio-libs/aioredis/issues/203)) + +## 0.3.0 (2017-01-11) + + +### Features + +- Pub/Sub connection commands accept `Channel` instances + (see [#168](https://github.com/aio-libs/aioredis/pull/168)) +- Implement new Pub/Sub MPSC (multi-producers, single-consumer) Queue -- + `aioredis.pubsub.Receiver` + (see [#176](https://github.com/aio-libs/aioredis/pull/176)) +- Add `aioredis.abc` module providing abstract base classes + defining interface for basic lib components (see [#176](https://github.com/aio-libs/aioredis/pull/176)) +- Implement Geo commands support + (see [#177](https://github.com/aio-libs/aioredis/pull/177) + and [#179](https://github.com/aio-libs/aioredis/pull/179)) + +### Bugfixes + +- Minor tests fixes +### Miscellaneous + +- Update examples and docs to use `async`/`await` syntax + also keeping `yield from` examples for history + (see [#173](https://github.com/aio-libs/aioredis/pull/173)) +- Reflow Travis CI configuration; add Python 3.6 section + (see [#170](https://github.com/aio-libs/aioredis/pull/170)) +- Add AppVeyor integration to run tests on Windows + (see [#180](https://github.com/aio-libs/aioredis/pull/180)) +- Update multiple development requirements + +## 0.2.9 (2016-10-24) + + +### Features + +- Allow multiple keys in `EXISTS` command + (see [#156](https://github.com/aio-libs/aioredis/issues/156) + and [#157](https://github.com/aio-libs/aioredis/issues/157)) + +### Bugfixes + +- Close RedisPool when connection to Redis failed + (see [#136](https://github.com/aio-libs/aioredis/issues/136)) +- Add simple `INFO` command argument validation + (see [#140](https://github.com/aio-libs/aioredis/issues/140)) +- Remove invalid uses of `next()` + +### Miscellaneous + +- Update devel.rst docs; update Pub/Sub Channel docs (cross-refs) +- Update MANIFEST.in to include docs, examples and tests in source bundle + +## 0.2.8 (2016-07-22) + + +### Features + +- Add `hmset_dict` command + (see [#130](https://github.com/aio-libs/aioredis/issues/130)) +- Add `RedisConnection.address` property +- RedisPool `minsize`/`maxsize` must not be `None` +- Implement `close()`/`wait_closed()`/`closed` interface for pool + (see [#128](https://github.com/aio-libs/aioredis/issues/128)) + +### Bugfixes + +- Add test for `hstrlen` +- Test fixes + +### Miscellaneous + +- Enable Redis 3.2.0 on Travis +- Add spell checking when building docs + (see [#132](https://github.com/aio-libs/aioredis/issues/132)) +- Documentation updated + +## 0.2.7 (2016-05-27) + + +- `create_pool()` minsize default value changed to 1 +- Fixed cancellation of wait_closed + (see [#118](https://github.com/aio-libs/aioredis/issues/118)) +- Fixed `time()` conversion to float + (see [#126](https://github.com/aio-libs/aioredis/issues/126)) +- Fixed `hmset()` method to return bool instead of `b'OK'` + (see [#12)) +- Fixed multi/exec + watch issue (changed watch variable was causing + `tr.execute()` to fail) + (see [#121](https://github.com/aio-libs/aioredis/issues/121)) +- Replace `asyncio.Future` uses with utility method + (get ready to Python 3.5.2 `loop.create_future()`) +- Tests switched from unittest to pytest (see [#12)) +- Documentation updates + +## 0.2.6 (2016-03-30) + + +- Fixed Multi/Exec transactions cancellation issue + (see [#110](https://github.com/aio-libs/aioredis/issues/110) + and [#114](https://github.com/aio-libs/aioredis/issues/114)) +- Fixed Pub/Sub subscribe concurrency issue + (see [#113](https://github.com/aio-libs/aioredis/issues/113) + and [#115](https://github.com/aio-libs/aioredis/issues/115)) +- Add SSL/TLS support + (see [#116](https://github.com/aio-libs/aioredis/issues/116)) +- `aioredis.ConnectionClosedError` raised in `execute_pubsub` as well + (see [#108](https://github.com/aio-libs/aioredis/issues/108)) +- `Redis.slaveof()` method signature changed: now to disable + replication one should call `redis.slaveof(None)` instead of `redis.slaveof()` +- More tests added + +## 0.2.5 (2016-03-02) + + +- Close all Pub/Sub channels on connection close + (see [#88](https://github.com/aio-libs/aioredis/issues/88)) +- Add `iter()` method to `aioredis.Channel` allowing to use it + with `async for` + (see [#89](https://github.com/aio-libs/aioredis/issues/89)) +- Inline code samples in docs made runnable and downloadable + (see [#92](https://github.com/aio-libs/aioredis/issues/92)) +- Python 3.5 examples converted to use `async`/`await` syntax + (see [#93](https://github.com/aio-libs/aioredis/issues/93)) +- Fix Multi/Exec to honor encoding parameter + (see [#94](https://github.com/aio-libs/aioredis/issues/94) + and [#97](https://github.com/aio-libs/aioredis/issues/97)) +- Add debug message in `create_connection` + (see [#90](https://github.com/aio-libs/aioredis/issues/90)) +- Replace `asyncio.async` calls with wrapper that respects asyncio version + (see [#101](https://github.com/aio-libs/aioredis/issues/101)) +- Use NODELAY option for TCP sockets + (see [#105](https://github.com/aio-libs/aioredis/issues/105)) +- New `aioredis.ConnectionClosedError` exception added. Raised if + connection to Redis server is lost + (see [#108](https://github.com/aio-libs/aioredis/issues/108) + and [#109](https://github.com/aio-libs/aioredis/issues/109)) +- Fix RedisPool to close and drop connection in subscribe mode on release +- Fix `aioredis.util.decode` to recursively decode list responses +- More examples added and docs updated +- Add google groups link to README +- Bump year in LICENSE and docs + +## 0.2.4 (2015-10-13) + + +- Python 3.5 `async` support: + + - New scan commands API (`iscan`, `izscan`, `ihscan`) + - Pool made awaitable (allowing `with await pool: ...` and `async + with pool.get() as conn:` constructs) +- Fixed dropping closed connections from free pool + (see [#83](https://github.com/aio-libs/aioredis/issues/83)) +- Docs updated + +## 0.2.3 (2015-08-14) + + +- Redis cluster support work in progress +- Fixed pool issue causing pool growth over max size & `acquire` call hangs + (see [#71](https://github.com/aio-libs/aioredis/issues/71)) +- `info` server command result parsing implemented +- Fixed behavior of util functions + (see [#70](https://github.com/aio-libs/aioredis/issues/70)) +- `hstrlen` command added +- Few fixes in examples +- Few fixes in documentation + +## 0.2.2 (2015-07-07) + + +- Decoding data with `encoding` parameter now takes into account + list (array) replies + (see [#68](https://github.com/aio-libs/aioredis/pull/68)) +- `encoding` parameter added to following commands: + + - generic commands: keys, randomkey + - hash commands: hgetall, hkeys, hmget, hvals + - list commands: blpop, brpop, brpoplpush, lindex, lpop, lrange, rpop, rpoplpush + - set commands: smembers, spop, srandmember + - string commands: getrange, getset, mget +- Backward incompatibility: + + `ltrim` command now returns bool value instead of 'OK' +- Tests updated + +## 0.2.1 (2015-07-06) + + +- Logging added (aioredis.log module) +- Fixed issue with `wait_message` in pub/sub + (see [#66](https://github.com/aio-libs/aioredis/issues/66)) + +## 0.2.0 (2015-06-04) + + +- Pub/Sub support added +- Fix in `zrevrangebyscore` command + (see [#62](https://github.com/aio-libs/aioredis/pull/62)) +- Fixes/tests/docs + +## 0.1.5 (2014-12-09) + + +- AutoConnector added +- wait_closed method added for clean connections shutdown +- `zscore` command fixed +- Test fixes + +## 0.1.4 (2014-09-22) + + +- Dropped following Redis methods -- `Redis.multi()`, + `Redis.exec()`, `Redis.discard()` +- `Redis.multi_exec` hack'ish property removed +- `Redis.multi_exec()` method added +- High-level commands implemented: + + - generic commands (tests) + - transactions commands (api stabilization). + +- Backward incompatibilities: + + - Following sorted set commands' API changed: + + `zcount`, `zrangebyscore`, `zremrangebyscore`, `zrevrangebyscore` + - set string command' API changed + + +## 0.1.3 (2014-08-08) + + +- RedisConnection.execute refactored to support commands pipelining + (see [#33](http://github.com/aio-libs/aioredis/issues/33)) +- Several fixes +- WIP on transactions and commands interface +- High-level commands implemented and tested: + + - hash commands - hyperloglog commands - set commands - scripting commands - string commands - list commands + +## 0.1.2 (2014-07-31) + + +- `create_connection`, `create_pool`, `create_redis` functions updated: + db and password arguments made keyword-only + (see [#26](http://github.com/aio-libs/aioredis/issues/26)) +- Fixed transaction handling + (see [#32](http://github.com/aio-libs/aioredis/issues/32)) +- Response decoding + (see [#16](http://github.com/aio-libs/aioredis/issues/16)) + +## 0.1.1 (2014-07-07) + + +- Transactions support (in connection, high-level commands have some issues) +- Docs & tests updated. + + +## 0.1.0 (2014-06-24) + + +- Initial release- RedisConnection implemented- RedisPool implemented- Docs for RedisConnection & RedisPool- WIP on high-level API. diff --git a/docs/conf.py b/docs/conf.py deleted file mode 100644 index 916ed1333..000000000 --- a/docs/conf.py +++ /dev/null @@ -1,292 +0,0 @@ -#!/usr/bin/env python3 -# -# aioredis documentation build configuration file, created by -# sphinx-quickstart on Thu Jun 12 22:57:11 2014. -# -# This file is execfile()d with the current directory set to its -# containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -import os -import sys - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -# sys.path.insert(0, os.path.abspath('.')) -sys.path.insert(0, os.path.join(os.path.abspath("."), "..")) - -# -- General configuration ------------------------------------------------ - -# If your documentation needs a minimal Sphinx version, state it here. -# needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = [ - "sphinx.ext.intersphinx", - "sphinx.ext.autodoc", - "sphinxcontrib.asyncio", - "sphinxcontrib.spelling", -] - -spelling_lang = "en_US" -spelling_word_list_filename = "spelling_wordlist.txt" -spelling_ignore_pypi_package_names = False -spelling_ignore_wiki_words = False -spelling_ignore_acronyms = False -spelling_ignore_python_builtins = False -spelling_ignore_importable_modules = False - -# Add any paths that contain templates here, relative to this directory. -templates_path = ["_templates"] - -# The suffix of source filenames. -source_suffix = ".rst" - -# The encoding of source files. -# source_encoding = 'utf-8-sig' - -# The master toctree document. -master_doc = "index" - -# General information about the project. -project = "aioredis" -copyright = "2014-2019, Alexey Popravka" - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# -# The short X.Y version. -version = "1.3" -# The full version, including alpha/beta/rc tags. -release = "1.3.0" - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -# language = None - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -# today = '' -# Else, today_fmt is used as the format for a strftime call. -# today_fmt = '%B %d, %Y' - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -exclude_patterns = ["_build"] - -# The reST default role (used for this markup: `text`) to use for all -# documents. -# default_role = None - -# If true, '()' will be appended to :func: etc. cross-reference text. -# add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -# add_module_names = True - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -# show_authors = False - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = "sphinx" - -# A list of ignored prefixes for module index sorting. -# modindex_common_prefix = [] - -# If true, keep warnings as "system message" paragraphs in the built documents. -# keep_warnings = False - - -# -- Options for HTML output ---------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -html_theme = "default" - -on_rtd = os.environ.get("READTHEDOCS", None) == "True" - -if not on_rtd: # only import and set the theme if we're building docs locally - try: - import sphinx_rtd_theme - except ImportError: - pass - else: - html_theme = "sphinx_rtd_theme" - html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] - -html_context = { - "github_user": "aio-libs", - "github_repo": "aioredis", -} - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -# html_theme_options = {} - -# Add any paths that contain custom themes here, relative to this directory. -# html_theme_path = [] - -# The name for this set of Sphinx documents. If None, it defaults to -# " v documentation". -# html_title = None - -# A shorter title for the navigation bar. Default is the same as html_title. -# html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -# html_logo = None - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -# html_favicon = None - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ["_static"] - -# Add any extra paths that contain custom files (such as robots.txt or -# .htaccess) here, relative to this directory. These files are copied -# directly to the root of the documentation. -# html_extra_path = [] - -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. -# html_last_updated_fmt = '%b %d, %Y' - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -# html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -# html_sidebars = {} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -# html_additional_pages = {} - -# If false, no module index is generated. -# html_domain_indices = True - -# If false, no index is generated. -# html_use_index = True - -# If true, the index is split into individual pages for each letter. -# html_split_index = False - -# If true, links to the reST sources are added to the pages. -# html_show_sourcelink = True - -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -# html_show_sphinx = True - -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -# html_show_copyright = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -# html_use_opensearch = '' - -# This is the file name suffix for HTML files (e.g. ".xhtml"). -# html_file_suffix = None - -# Output file base name for HTML help builder. -htmlhelp_basename = "aioredisdoc" - - -# -- Options for LaTeX output --------------------------------------------- - -latex_elements = { - # The paper size ('letterpaper' or 'a4paper'). - #'papersize': 'letterpaper', - # The font size ('10pt', '11pt' or '12pt'). - #'pointsize': '10pt', - # Additional stuff for the LaTeX preamble. - #'preamble': '', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, -# author, documentclass [howto, manual, or own class]). -latex_documents = [ - ("index", "aioredis.tex", "aioredis Documentation", "Alexey Popravka", "manual"), -] - -# The name of an image file (relative to this directory) to place at the top of -# the title page. -# latex_logo = None - -# For "manual" documents, if this is true, then toplevel headings are parts, -# not chapters. -# latex_use_parts = False - -# If true, show page references after internal links. -# latex_show_pagerefs = False - -# If true, show URL addresses after external links. -# latex_show_urls = False - -# Documents to append as an appendix to all manuals. -# latex_appendices = [] - -# If false, no module index is generated. -# latex_domain_indices = True - - -# -- Options for manual page output --------------------------------------- - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [("index", "aioredis", "aioredis Documentation", ["Alexey Popravka"], 1)] - -# If true, show URL addresses after external links. -# man_show_urls = False - - -# -- Options for Texinfo output ------------------------------------------- - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - ( - "index", - "aioredis", - "aioredis Documentation", - "Alexey Popravka", - "aioredis", - "One line description of project.", - "Miscellaneous", - ), -] - -# Documents to append as an appendix to all manuals. -# texinfo_appendices = [] - -# If false, no module index is generated. -# texinfo_domain_indices = True - -# How to display URL addresses: 'footnote', 'no', or 'inline'. -# texinfo_show_urls = 'footnote' - -# If true, do not generate a @detailmenu in the "Top" node's menu. -# texinfo_no_detailmenu = False - - -# Example configuration for intersphinx: refer to the Python standard library. -intersphinx_mapping = {"http://docs.python.org/3": None} diff --git a/docs/devel.md b/docs/devel.md new file mode 100644 index 000000000..c47781ada --- /dev/null +++ b/docs/devel.md @@ -0,0 +1,111 @@ +# Contributing + +To start contributing you must read all the following. + +First you must fork/clone repo from +[github](https://github.com/aio-libs/aioredis): + + $ git clone git@github.com:aio-libs/aioredis.git + +Next, you should install all python dependencies, it is as easy as +running single command: + + $ make devel + +this command will install: + +- `mkdocs` for building documentation; +- `pytest` for running tests; +- `flake8` and `black` for code linting; +- and few other packages. + +Make sure you have provided a `towncrier` note. Just add short +description running following commands: + + $ echo "Short description" > CHANGES/filename.type + +This will create new file in `CHANGES` directory. Filename should +consist of the ticket ID or other unique identifier. Five default types +are: + +- .feature - signifying new feature +- .bugfix - signifying a bug fix +- .doc - documentation improvement +- .removal - deprecation or removal of public API +- .misc - a ticket has been closed, but not in interest of users + +You can check if everything is correct by typing: + + $ towncrier --draft + +To produce the news file: + + $ towncrier + +## Submissions + +Starting with v2.0, aioredis is a running, *asyncio-native port of redis-py*. When +submitting a change, if we find it is the result of an issue with the source +implementation, then we may redirect your change to that library to be triaged and +merged there first. + +In general, updates to the high-level Redis client will likely be re-routed via +redis-py, while changes to the lower-level connection client will likely be accepted +directly. + +## Code style + +Code **must** be pep8 compliant. + +You can check it with following command: + + $ make lint + +## Running tests + +You can run tests in any of the following ways: + + # first install aioredis (must use -e for tests to work) + $ pip install -e . + + # will run tests in a verbose mode + $ make test + # or + $ pytest + + # or with particular Redis server + $ pytest --redis-url=redis://localhost:6379/2 tests/errors_test.py + + # will run tests with coverage report + $ make cov + # or + $ pytest --cov + +### Different Redis server versions + +To run tests against different Redis versions, you must have them installed on your host +machine and running. Then you can pass an explicit url to the tests with `--redis-url`: + + $ pytest --redis-url=redis://localhost:6379/2 + +### UVLoop + +To run tests with uvloop: + + $ pip install uvloop + $ pytest --uvloop + +## Writing tests + +aioredis uses pytest. + +Tests are located under `/tests` directory. + +### Redis Version Tests Helpers + +In `tests.conftest` there are `@skip_if_server_version_*` decorators which will +automatically skip tests if the server version doesn't meet the required version +specification. If you're adding support for a new feature of Redis, then this is a good +tool to use. + +--8<-- "includes/glossary.md" diff --git a/docs/devel.rst b/docs/devel.rst deleted file mode 100644 index 67bea6f94..000000000 --- a/docs/devel.rst +++ /dev/null @@ -1,228 +0,0 @@ -.. highlight:: bash - -.. _github: https://github.com/aio-libs/aioredis - -Contributing -============ - -To start contributing you must read all the following. - -First you must fork/clone repo from `github`_:: - - $ git clone git@github.com:aio-libs/aioredis.git - -Next, you should install all python dependencies, it is as easy as running -single command:: - - $ make devel - -this command will install: - -* ``sphinx`` for building documentation; -* ``pytest`` for running tests; -* ``flake8`` for code linting; -* and few other packages. - -Make sure you have provided a ``towncrier`` note. -Just add short description running following commands:: - - $ echo "Short description" > CHANGES/filename.type - -This will create new file in ``CHANGES`` directory. -Filename should consist of the ticket ID or other unique identifier. -Five default types are: - -* .feature - signifying new feature -* .bugfix - signifying a bug fix -* .doc - documentation improvement -* .removal - deprecation or removal of public API -* .misc - a ticket has been closed, but not in interest of users - -You can check if everything is correct by typing:: - - $ towncrier --draft - -To produce the news file:: - - $ towncrier - -Code style ----------- - -Code **must** be pep8 compliant. - -You can check it with following command:: - - $ make flake - - -Running tests -------------- - -You can run tests in any of the following ways:: - - # first install aioredis (must use -e for tests to work) - $ pip install -e . - - # will run tests in a verbose mode - $ make test - # or - $ pytest - - # or with particular Redis server - $ pytest --redis-server=/usr/local/bin/redis-server tests/errors_test.py - - # will run tests with coverage report - $ make cov - # or - $ pytest --cov - -SSL tests -~~~~~~~~~ - -Running SSL tests requires following additional programs to be installed: - -* ``openssl`` -- to generate test key and certificate; - -* ``socat`` -- to make SSL proxy; - -To install these on Ubuntu and generate test key & certificate run:: - - $ sudo apt-get install socat openssl - $ make certificate - -Different Redis server versions -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -To run tests against different redises use ``--redis-server`` command line -option:: - - $ pytest --redis-server=/path/to/custom/redis-server - -UVLoop -~~~~~~ - -To run tests with :term:`uvloop`:: - - $ pip install uvloop - $ pytest --uvloop - - -Writing tests -------------- - -:mod:`aioredis` uses :term:`pytest` tool. - -Tests are located under ``/tests`` directory. - - -Fixtures -~~~~~~~~ - -There is a number of fixtures that can be used to write tests: - - -.. attribute:: loop - - Current event loop used for test. - This is a function-scope fixture. - Using this fixture will always create new event loop and - set global one to None. - - .. code-block:: python - - def test_with_loop(loop): - @asyncio.coroutine - def do_something(): - pass - loop.run_until_complete(do_something()) - -.. function:: unused_port() - - Finds and returns free TCP port. - - .. code-block:: python - - def test_bind(unused_port): - port = unused_port() - assert 1024 < port <= 65535 - -.. cofunction:: create_connection(\*args, \**kw) - - Wrapper around :func:`aioredis.create_connection`. - Only difference is that it registers connection to be closed after test case, - so you should not be worried about unclosed connections. - -.. cofunction:: create_redis(\*args, \**kw) - - Wrapper around :func:`aioredis.create_redis`. - -.. cofunction:: create_pool(\*args, \**kw) - - Wrapper around :func:`aioredis.create_pool`. - -.. attribute:: redis - - Redis client instance. - -.. attribute:: pool - - RedisPool instance. - -.. attribute:: server - - Redis server instance info. Namedtuple with following properties: - - name - server instance name. - - port - Bind port. - - unixsocket - Bind unixsocket path. - - version - Redis server version tuple. - -.. attribute:: serverB - - Second predefined Redis server instance info. - -.. function:: start_server(name) - - Start Redis server instance. - Redis instances are cached by name. - - :return: server info tuple, see :attr:`server`. - :rtype: tuple - -.. function:: ssl_proxy(unsecure_port) - - Start SSL proxy. - - :param int unsecure_port: Redis server instance port - :return: secure_port and ssl_context pair - :rtype: tuple - - -``redis_version`` tests helper -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -In ``tests`` directory there is a :mod:`_testutils` module with a simple -helper --- :func:`redis_version` --- a function that add a pytest mark to a test -allowing to run it with requested Redis server versions. - -.. function:: _testutils.redis_version(\*version, reason) - - Marks test with minimum redis version to run. - - Example: - - .. code-block:: python - - from _testutil import redis_version - - @redis_version(3, 2, 0, reason="HSTRLEN new in redis 3.2.0") - def test_hstrlen(redis): - pass diff --git a/docs/examples.md b/docs/examples.md new file mode 100644 index 000000000..7a23eaa7a --- /dev/null +++ b/docs/examples.md @@ -0,0 +1,61 @@ +# Recipes + +Below are some useful patterns and starter scripts to get you familiar with aioredis's +interface. + +## High-level Client (Commands) + +```python +--8<-- "examples/commands.py" +``` + + +## Transactions (Pipeline + Multi/Exec) + +```python +--8<-- "examples/transaction.py" +``` + +## Pub/Sub + +```python +--8<-- "examples/pool_pubsub.py" +``` + + +## SCAN + +```python +--8<-- "examples/scan.py" +``` + + +## Redis Sentinel Client + +```python +--8<-- "examples/sentinel.py" +``` + + +## Low-level Connection Usage + +```python +--8<-- "examples/connection.py" +``` + + +## Connection Pooling + +```python +--8<-- "examples/pool.py" +``` + + +## Blocking Commands + +```python +--8<-- "examples/blocking.py" +``` + + +--8<-- "includes/glossary.md" diff --git a/docs/examples.rst b/docs/examples.rst deleted file mode 100644 index 0a2678cf2..000000000 --- a/docs/examples.rst +++ /dev/null @@ -1,72 +0,0 @@ -Examples of aioredis usage -========================== - -Below is a list of examples from `aioredis/examples -`_ -(see for more). - -Every example is a correct python program that can be executed. - - -Commands example -~~~~~~~~~~~~~~~~ - -:download:`get source code<../examples/commands.py>` - -.. literalinclude:: ../examples/commands.py - - -Transaction example -~~~~~~~~~~~~~~~~~~~ - -:download:`get source code<../examples/transaction.py>` - -.. literalinclude:: ../examples/transaction.py - - -Pub/Sub example -~~~~~~~~~~~~~~~ - -:download:`get source code<../examples/pubsub.py>` - -.. literalinclude:: ../examples/pubsub.py - - -Scan command example -~~~~~~~~~~~~~~~~~~~~ - -:download:`get source code<../examples/scan.py>` - -.. literalinclude:: ../examples/scan.py - - -Sentinel client -~~~~~~~~~~~~~~~ - -:download:`get source code<../examples/sentinel.py>` - -.. literalinclude:: ../examples/sentinel.py - -.. _aioredis-examples-simple: - -Low-level connection usage example -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -:download:`get source code<../examples/connection.py>` - -.. literalinclude:: ../examples/connection.py - - -Connections pool example -~~~~~~~~~~~~~~~~~~~~~~~~ - -:download:`get source code<../examples/pool.py>` - -.. literalinclude:: ../examples/pool.py - - -Blocking command example - -:download:`get source code<../examples/blocking.py>` - -.. literalinclude:: ../examples/blocking.py diff --git a/examples/blocking.py b/docs/examples/blocking.py similarity index 100% rename from examples/blocking.py rename to docs/examples/blocking.py diff --git a/examples/commands.py b/docs/examples/commands.py similarity index 100% rename from examples/commands.py rename to docs/examples/commands.py diff --git a/docs/examples/connection.py b/docs/examples/connection.py new file mode 100644 index 000000000..6ba93733d --- /dev/null +++ b/docs/examples/connection.py @@ -0,0 +1,43 @@ +import asyncio + +import aioredis + + +async def main(): + # Create a redis client bound to a connection pool. + redis = aioredis.from_url( + "redis://localhost", encoding="utf-8", decode_responses=True + ) + # get a redis client bound to a single connection. + async with redis.client() as conn: + ok = await conn.execute_command("set", "my-key", "some value") + assert ok is True + + str_value = await conn.execute_command("get", "my-key") + assert str_value == "some value" + + print("str value:", str_value) + # The connection is automatically release to the pool + + +async def main_single(): + # Create a redis client with only a single connection. + redis = aioredis.Redis( + host="localhost", + encoding="utf-8", + decode_responses=True, + single_connection_client=True, + ) + ok = await redis.execute_command("set", "my-key", "some value") + assert ok is True + + str_value = await redis.execute_command("get", "my-key") + assert str_value == "some value" + + print("str value:", str_value) + # the connection is automatically closed by GC. + + +if __name__ == "__main__": + asyncio.run(main()) + asyncio.run(main_single()) diff --git a/examples/getting_started/00_connect.py b/docs/examples/getting_started/00_connect.py similarity index 76% rename from examples/getting_started/00_connect.py rename to docs/examples/getting_started/00_connect.py index 3e4824db3..5cbff5501 100644 --- a/examples/getting_started/00_connect.py +++ b/docs/examples/getting_started/00_connect.py @@ -4,7 +4,7 @@ async def main(): - redis = await aioredis.from_url("redis://localhost") + redis = aioredis.from_url("redis://localhost") await redis.set("my-key", "value") value = await redis.get("my-key", encoding="utf-8") print(value) diff --git a/examples/getting_started/01_decoding.py b/docs/examples/getting_started/01_decoding.py similarity index 100% rename from examples/getting_started/01_decoding.py rename to docs/examples/getting_started/01_decoding.py diff --git a/examples/getting_started/02_decoding.py b/docs/examples/getting_started/02_decoding.py similarity index 100% rename from examples/getting_started/02_decoding.py rename to docs/examples/getting_started/02_decoding.py diff --git a/docs/examples/getting_started/03_multiexec.py b/docs/examples/getting_started/03_multiexec.py new file mode 100644 index 000000000..f4fc87472 --- /dev/null +++ b/docs/examples/getting_started/03_multiexec.py @@ -0,0 +1,14 @@ +import asyncio + +import aioredis + + +async def main(): + redis = await aioredis.from_url("redis://localhost") + async with redis.pipeline(transaction=True) as pipe: + ok1, ok2 = await (pipe.set("key1", "value1").set("key2", "value2").execute()) + assert ok1 + assert ok2 + + +asyncio.run(main()) diff --git a/examples/getting_started/04_pubsub.py b/docs/examples/getting_started/04_pubsub.py similarity index 100% rename from examples/getting_started/04_pubsub.py rename to docs/examples/getting_started/04_pubsub.py diff --git a/examples/getting_started/05_pubsub.py b/docs/examples/getting_started/05_pubsub.py similarity index 100% rename from examples/getting_started/05_pubsub.py rename to docs/examples/getting_started/05_pubsub.py diff --git a/examples/getting_started/06_sentinel.py b/docs/examples/getting_started/06_sentinel.py similarity index 100% rename from examples/getting_started/06_sentinel.py rename to docs/examples/getting_started/06_sentinel.py diff --git a/examples/pipeline.py b/docs/examples/pipeline.py similarity index 100% rename from examples/pipeline.py rename to docs/examples/pipeline.py diff --git a/docs/examples/pool.py b/docs/examples/pool.py new file mode 100644 index 000000000..9265af58e --- /dev/null +++ b/docs/examples/pool.py @@ -0,0 +1,23 @@ +import asyncio + +import aioredis + + +async def main(): + redis = aioredis.from_url("redis://localhost", max_connections=10) + await redis.execute_command("set", "my-key", "value") + val = await redis.execute_command("get", "my-key") + print("raw value:", val) + + +async def main_pool(): + pool = aioredis.ConnectionPool.from_url("redis://localhost", max_connections=10) + redis = aioredis.Redis(connection_pool=pool) + await redis.execute_command("set", "my-key", "value") + val = await redis.execute_command("get", "my-key") + print("raw value:", val) + + +if __name__ == "__main__": + asyncio.run(main()) + asyncio.run(main_pool()) diff --git a/examples/pool_pubsub.py b/docs/examples/pool_pubsub.py similarity index 100% rename from examples/pool_pubsub.py rename to docs/examples/pool_pubsub.py diff --git a/examples/redis-sentinel.conf b/docs/examples/redis-sentinel.conf similarity index 100% rename from examples/redis-sentinel.conf rename to docs/examples/redis-sentinel.conf diff --git a/examples/redis.conf b/docs/examples/redis.conf similarity index 100% rename from examples/redis.conf rename to docs/examples/redis.conf diff --git a/examples/scan.py b/docs/examples/scan.py similarity index 100% rename from examples/scan.py rename to docs/examples/scan.py diff --git a/examples/sentinel.py b/docs/examples/sentinel.py similarity index 100% rename from examples/sentinel.py rename to docs/examples/sentinel.py diff --git a/examples/transaction.py b/docs/examples/transaction.py similarity index 100% rename from examples/transaction.py rename to docs/examples/transaction.py diff --git a/docs/getting-started.md b/docs/getting-started.md new file mode 100644 index 000000000..46339a607 --- /dev/null +++ b/docs/getting-started.md @@ -0,0 +1,154 @@ +# Getting Started + +## Installation + +```shell +pip install aioredis +``` + +This will install `aioredis`, alongside `hiredis` and `async-timeout`. + +### Without Dependencies + +If you find yourself in a situation where you cannot support `hiredis` in your +application, you can install aioredis without that dependency: + +```shell +pip install --no-deps aioredis async-timeout +``` + +### Installing from Git + +```shell +pip install git+https://github.com/aio-libs/aioredis@master#egg=aioredis +``` + + +## Connecting + +```python +--8<-- "examples/getting_started/00_connect.py" +``` + +`aioredis.from_url` creates a Redis client backed by a pool of connections. The only +required argument is the URL, which should be string representing a TCP or UNIX socket +address. + +See the [high-level](api/high-level.md) API reference for a full list of supported +commands. + +### Connecting to a Specific Database + +There are two ways to specify a database index to set your connection pool to: + +1. Pass the index in as a keyward argument when initializing the client + ```python + import aioredis + + redis = await aioredis.from_url("redis://localhost", db=1) + ``` + +2. Pass the index as a path component in the URI + ```python + import aioredis + + redis = await aioredis.from_url("redis://localhost/1") + ``` + +!!! note + + DB index specified in URI will take precedence over + ``db`` keyword argument. + +### Connecting to an ACL-Protected Redis Instance + +Similarly, the username/password can be specified via a keyword argument or via the URI. +The values in the URI will always take precedence. + +1. Via keyword-arguments: + ```python + import aioredis + + redis = await aioredis.from_url( + "redis://localhost", username="user", password="sEcRet" + ) + ``` + +2. Via the AUTH section of the URI: + ```python + import aioredis + + redis = await aioredis.from_url("redis://user:sEcRet@localhost/") + ``` + + +## Response Decoding +By default `aioredis` will return `bytes` for most Redis commands that return string +replies. Redis error replies are known to be valid UTF-8 strings so error messages are +decoded automatically. + +If you know that data in Redis is valid string you can tell `aioredis` to decode result +by passing `decode_responses=True` in a command call: + +```python +--8<-- "examples/getting_started/01_decoding.py" +``` + +By default, `aioredis` will automatically decode lists, hashes, sets, etc: + +```python +--8<-- "examples/getting_started/02_decoding.py" +``` + +## Transactions (Multi/Exec) + +```python +--8<-- "examples/getting_started/03_multiexec.py" +``` + +The `aioredis.Redis.pipeline` will return a `aioredis.Pipeline` object, which will +buffer all commands in-memory and compile them into batches using the +[Redis Bulk String](https://redis.io/topics/protocol) protocol. Additionally, each +command will return the Pipeline instance, allowing you to chain your commands, +i.e., `p.set('foo', 1).set('bar', 2).mget('foo', 'bar')`. + +The commands will not be reflected in Redis until `execute()` is called & awaited. + +Usually, when performing a bulk operation, taking advantage of a "transaction" (e.g., +Multi/Exec) is to be desired, as it will also add a layer of atomicity to your bulk +operation. + + +## Pub/Sub Mode + +`aioredis` provides support for Redis Publish/Subscribe messaging. + +Subscribing to specific channels: + +```python +--8<-- "examples/getting_started/04_pubsub.py" +``` + +Subscribing to channels matching a glob-style pattern: + +```python +--8<-- "examples/getting_started/05_pubsub.py" +``` + +## Redis Sentinel Client + +```python +--8<-- "examples/getting_started/06_sentinel.py" +``` + +The Sentinel client requires a list of Redis Sentinel addresses to connect to and start +discovering services. + +Calling `aioredis.sentinel.Sentinel.master_for` or +`aioredis.sentinel.Sentinel.slave_for` methods will return Redis clients connected to +specified services monitored by Sentinel. + +Sentinel client will detect failover and reconnect Redis clients automatically. + + +--8<-- "includes/glossary.md" diff --git a/docs/glossary.rst b/docs/glossary.rst deleted file mode 100644 index 49427db7e..000000000 --- a/docs/glossary.rst +++ /dev/null @@ -1,37 +0,0 @@ -.. _glossary: - -Glossary -======== - - -.. glossary:: - :sorted: - - asyncio - - Reference implementation of :pep:`3156` - - See https://pypi.python.org/pypi/asyncio - - hiredis - - Python extension that wraps protocol parsing code in `hiredis`_. - - See https://pypi.python.org/pypi/hiredis - - error replies - - Redis server replies that start with - (minus) char. - Usually starts with ``-ERR``. - - pytest - - A mature full-featured Python testing tool. - See http://pytest.org/latest/ - - uvloop - - Is an ultra fast implementation of asyncio event loop on top of libuv. - See https://github.com/MagicStack/uvloop - -.. _hiredis: https://github.com/redis/hiredis diff --git a/docs/includes/glossary.md b/docs/includes/glossary.md new file mode 100644 index 000000000..ce7bfabc8 --- /dev/null +++ b/docs/includes/glossary.md @@ -0,0 +1,17 @@ +*[PEP 3156]: Asynchronous IO. See https://www.python.org/dev/peps/pep-3156/. + +*[asyncio]: Reference implementation of PEP 3156. + +*[hiredis]: Python extension that wraps protocol parsing code in `hiredis`. + +*[error replies]: Redis server replies that start with `-` (minus) char (`-ERR`). + +*[pytest]: A mature full-featured Python testing tool. See http://pytest.org/latest/. + +*[uvloop]: An ultra fast implementation of asyncio event loop on top of libuv. + +*[redis-py]: The official Python interface to the Redis key-value store. + +*[UNIX]: unix://var/run/redis.sock + +*[TCP]: redis://redis-host-or-ip:6379/1 diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 000000000..fa9aa75ff --- /dev/null +++ b/docs/index.md @@ -0,0 +1,57 @@ +# aioredis + +asyncio (3156) Redis client library. + +The library is intended to provide simple and clear interface to Redis +based on asyncio. + +## Features + +| Feature | Supported | +|:-----------------------------|:----------------------| +| hiredis parser | :white_check_mark: | +| Pure-python parser | :white_check_mark: | +| Low-level & High-level APIs | :white_check_mark: | +| Pipelining support | :white_check_mark: | +| Multi/Exec support | :white_check_mark: | +| Connections Pool | :white_check_mark: | +| Pub/Sub support | :white_check_mark: | +| Sentinel support | :white_check_mark: | +| ACL support | :white_check_mark: | +| Streams support | :white_check_mark: | +| Redis Cluster support | :no_entry_sign: | +| Tested Python versions | 3.6, 3.7, 3.8, 3.9 | +| Tested for Redis servers | 5.0, 6.0 | +| Support for dev Redis server | through low-level API | + + +## Installation + +The easiest way to install aioredis is by using the package on PyPi: + + pip install aioredis + +## Requirements + +- Python 3.6+ +- hiredis + +## Benchmarks + +Benchmarks can be found here: + + +## Contribute + +- Issue Tracker: +- Google Group: \#!forum/aio-libs +- Gitter: +- Source Code: +- Contributor's guide: devel + +Feel free to file an issue or make pull request if you find any bugs or +have some suggestions for library improvement. + +## License + +The aioredis is offered under a [MIT License](license.md). diff --git a/docs/index.rst b/docs/index.rst deleted file mode 100644 index cd992efe3..000000000 --- a/docs/index.rst +++ /dev/null @@ -1,103 +0,0 @@ -.. aioredis documentation master file, created by - sphinx-quickstart on Thu Jun 12 22:57:11 2014. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - -aioredis -======== - -asyncio (:pep:`3156`) Redis client library. - -The library is intended to provide simple and clear interface to Redis -based on :term:`asyncio`. - - -Features --------- - -================================ ============================== -:term:`hiredis` parser Yes -Pure-python parser Yes -Low-level & High-level APIs Yes -Connections Pool Yes -Pipelining support Yes -Pub/Sub support Yes -Sentinel support Yes -Redis Cluster support WIP -Trollius (python 2.7) No -Tested CPython versions `3.6, 3.7, 3.8 `_ [1]_ -Tested PyPy3 versions `pypy3.6-7.1.1, pypy3.6-7.2.0 `_ -Tested for Redis server `2.6, 2.8, 3.0, 3.2, 4.0 5.0 `_ -Support for dev Redis server through low-level API -================================ ============================== - -.. [1] For Python 3.5 support use aioredis v1.x. For Python 3.3, 3.4 support use aioredis v0.3. - -Installation ------------- - -The easiest way to install aioredis is by using the package on PyPi:: - - pip install aioredis - -Requirements ------------- - -- Python 3.6+ -- :term:`hiredis` - -Benchmarks ----------- - -Benchmarks can be found here: https://github.com/popravich/python-redis-benchmark - -Contribute ----------- - -- Issue Tracker: https://github.com/aio-libs/aioredis/issues -- Google Group: https://groups.google.com/forum/#!forum/aio-libs -- Gitter: https://gitter.im/aio-libs/Lobby -- Source Code: https://github.com/aio-libs/aioredis -- Contributor's guide: :doc:`devel` - -Feel free to file an issue or make pull request if you find any bugs or have -some suggestions for library improvement. - -License -------- - -The aioredis is offered under `MIT license`_. - ----- - -Contents -======== - -.. toctree:: - :maxdepth: 3 - - start - api_reference - mixins - abc - mpsc - sentinel - examples - devel - migration - releases - glossary - -.. :: - todo insert after start - advanced - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` - -.. _MIT license: https://github.com/aio-libs/aioredis/blob/master/LICENSE -.. _travis: https://travis-ci.com/aio-libs/aioredis diff --git a/docs/license.md b/docs/license.md new file mode 100644 index 000000000..4d8920e89 --- /dev/null +++ b/docs/license.md @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2014-2017 Alexey Popravka +Copyright (c) 2021 Sean Stewart + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/docs/migration.md b/docs/migration.md new file mode 100644 index 000000000..ea847c9b5 --- /dev/null +++ b/docs/migration.md @@ -0,0 +1,119 @@ +# Migrating to v2.0 + +## TL;DR + +aioredis v2.0 is now a completely compliant asyncio-native implementation of redis-py. +The entire core and public API has been re-written to follow redis-py's implementation +as closely as possible. This means there are some major changes to the connection +interface, but we now have an interface that is completely consistent across the two +libraries, so porting from redis-py to aioredis should (in theory) be as easy as +changing some imports and adding `await` statements where needed. + +## Motivations + +As of December, 2019, this library had been abandoned. The code had grown stale, issues +were piling up, and we were rapidly becoming out-of-date with Redis's own feature-set. +In light of this, the decision was made to ensure that the barrier to support for +potential maintainers or contributors would be minimized. A running port of redis-py +accomplishes this. + +Additionally, embracing redis-py as the de-facto implementation lowers the barrier to +entry for new adopters, as the interface is now nearly identical. + +## Connecting to Redis + +Connecting to redis is no longer done by calling `await aioredis.create_pool(...)`. +Instead, the default mode of initialization is the same as redis-py: + +```python +--8<-- "examples/commands.py" +``` + +As you can see, the `from_url(...)` methods are not coroutine functions. This is because +connections are created lazily rather than pre-filled, in keeping with the pattern +established in redis-py. If you have a need to establish a connection immediately, you +can use `aioredis.Reds.ping` to fetch a connection and ping your redis instance. + +## Pipelines and Transactions (Multi/Exec) + + +In the previous implementation, Pipeline was essentially an abstraction over +`asyncio.gather`. Every command set to the Pipeline was immediately pushed to Redis in +its own task. + +This had a few surprising side-effects: + + +1. aioredis Pipelines where much slower that redis-py Pipelines. +2. An exception in one command didn't necessarily halt execution of the Pipeline. +3. We weren't taking full advantage of Redis's Multi/Bulk protocol. +4. We could potentially overload Redis with too many individual commands at once. + +The `aioredis.Pipeline` is now fully compliant with the original redis-py +implementation: + +```python +--8<-- "examples/getting_started/03_multiexec.py" +``` + +```python +--8<-- "examples/transaction.py" +``` + +## Cleaning Up + +You may have noticed in the examples above that we don't explicitly close our +connections when the main function exits. This is because, again like redis-py, our +clients and connections have implemented `__del__` methods, so will attempt to +automatically clean up any open connections when garbage-collected. + +If, however, you find you need to manage your connections lifecycle yourself, you can +do so like this: + + +```python +import asyncio +import aioredis + + +async def main(): + pool = aioredis.ConnectionPool.from_url( + "redis://localhost", decode_responses=True + ) + meanings = aioredis.Redis(connection_pool=pool) + try: + await meanings.set("life", 42) + print(f"The answer: {await meanings.get('life')}") + finally: + await pool.disconnect() + + +if __name__ == "__main__": + asyncio.run(main()) +``` + + +## What's New + +aioredis is now *fully compliant* with Redis 6.0 including: + +1. ACL/RBAC +2. Full PubSub support (2.8.0) + +Some of these features were partially implemented or implemented with many known issues, +but are now considered stable. + + +## What's Gone + +We no longer ship with a `Channel` abstraction over PubSub. This implementation was +buggy and not well understood. Additionally, there is no such abstraction in our source +implementation (redis-py). + + +## Next Steps + +You're encouraged to review our Getting Started page, API docs, and Examples page to get +up-to-date on the latest aioredis implementation. + +--8<-- "includes/glossary.md" diff --git a/docs/migration.rst b/docs/migration.rst deleted file mode 100644 index 4d33ef449..000000000 --- a/docs/migration.rst +++ /dev/null @@ -1,238 +0,0 @@ -Migrating from v0.3 to v1.0 -=========================== - -.. contents:: API changes and backward incompatible changes: - :local: - ----- - -aioredis.create_pool --------------------- - -:func:`~aioredis.create_pool` now returns :class:`~aioredis.ConnectionsPool` -instead of ``RedisPool``. - -This means that pool now operates with :class:`~aioredis.RedisConnection` -objects and not :class:`~aioredis.Redis`. - -+--------+--------------------------------------------------------------------+ -| | .. code-block:: python3 | -| v0.3 | :emphasize-lines: 5 | -| | | -| | pool = await aioredis.create_pool(('localhost', 6379)) | -| | | -| | with await pool as redis: | -| | # calling methods of Redis class | -| | await redis.lpush('list-key', 'item1', 'item2') | -| | | -+--------+--------------------------------------------------------------------+ -| | .. code-block:: python3 | -| v1.0 | :emphasize-lines: 5 | -| | | -| | pool = await aioredis.create_pool(('localhost', 6379)) | -| | | -| | with await pool as conn: | -| | # calling conn.lpush will raise AttributeError exception | -| | await conn.execute('lpush', 'list-key', 'item1', 'item2') | -| | | -+--------+--------------------------------------------------------------------+ - - -aioredis.create_reconnecting_redis ----------------------------------- - -:func:`~aioredis.create_reconnecting_redis` has been dropped. - -:func:`~aioredis.create_redis_pool` can be used instead of former function. - -+--------+--------------------------------------------------------------------+ -| | .. code-block:: python3 | -| v0.3 | :emphasize-lines: 1 | -| | | -| | redis = await aioredis.create_reconnecting_redis( | -| | ('localhost', 6379)) | -| | | -| | await redis.lpush('list-key', 'item1', 'item2') | -| | | -+--------+--------------------------------------------------------------------+ -| | .. code-block:: python3 | -| v1.0 | :emphasize-lines: 1 | -| | | -| | redis = await aioredis.create_redis_pool( | -| | ('localhost', 6379)) | -| | | -| | await redis.lpush('list-key', 'item1', 'item2') | -| | | -+--------+--------------------------------------------------------------------+ - -``create_redis_pool`` returns :class:`~aioredis.Redis` initialized with -``ConnectionsPool`` which is responsible for reconnecting to server. - -Also ``create_reconnecting_redis`` was patching the ``RedisConnection`` and -breaking ``closed`` property (it was always ``True``). - - -aioredis.Redis --------------- - -:class:`~aioredis.Redis` class now operates with objects implementing -:class:`aioredis.abc.AbcConnection` interface. -:class:`~aioredis.RedisConnection` and :class:`~aioredis.ConnectionsPool` are -both implementing ``AbcConnection`` so it is become possible to use same API -when working with either single connection or connections pool. - -+--------+--------------------------------------------------------------------+ -| | .. code-block:: python3 | -| v0.3 | :emphasize-lines: 5 | -| | | -| | redis = await aioredis.create_redis(('localhost', 6379)) | -| | await redis.lpush('list-key', 'item1', 'item2') | -| | | -| | pool = await aioredis.create_pool(('localhost', 6379)) | -| | redis = await pool.acquire() # get Redis object | -| | await redis.lpush('list-key', 'item1', 'item2') | -| | | -+--------+--------------------------------------------------------------------+ -| | .. code-block:: python3 | -| v1.0 | :emphasize-lines: 2,5 | -| | | -| | redis = await aioredis.create_redis(('localhost', 6379)) | -| | await redis.lpush('list-key', 'item1', 'item2') | -| | | -| | redis = await aioredis.create_redis_pool(('localhost', 6379)) | -| | await redis.lpush('list-key', 'item1', 'item2') | -| | | -+--------+--------------------------------------------------------------------+ - -Blocking operations and connection sharing ------------------------------------------- - -Current implementation of ``ConnectionsPool`` by default **execute -every command on random connection**. The *Pros* of this is that it allowed -implementing ``AbcConnection`` interface and hide pool inside ``Redis`` class, -and also keep pipelining feature (like RedisConnection.execute). -The *Cons* of this is that **different tasks may use same connection and block -it** with some long-running command. - -We can call it **Shared Mode** --- commands are sent to random connections -in pool without need to lock [connection]: - -.. code-block:: python3 - - redis = await aioredis.create_redis_pool( - ('localhost', 6379), - minsize=1, - maxsize=1) - - async def task(): - # Shared mode - await redis.set('key', 'val') - - asyncio.ensure_future(task()) - asyncio.ensure_future(task()) - # Both tasks will send commands through same connection - # without acquiring (locking) it first. - -Blocking operations (like ``blpop``, ``brpop`` or long-running LUA scripts) -in **shared mode** mode will block connection and thus may lead to whole -program malfunction. - -This *blocking* issue can be easily solved by using exclusive connection -for such operations: - -.. code-block:: python3 - :emphasize-lines: 8 - - redis = await aioredis.create_redis_pool( - ('localhost', 6379), - minsize=1, - maxsize=1) - - async def task(): - # Exclusive mode - with await redis as r: - await r.set('key', 'val') - asyncio.ensure_future(task()) - asyncio.ensure_future(task()) - # Both tasks will first acquire connection. - -We can call this **Exclusive Mode** --- context manager is used to -acquire (lock) exclusive connection from pool and send all commands through it. - -.. note:: This technique is similar to v0.3 pool usage: - - .. code-block:: python3 - - # in aioredis v0.3 - pool = await aioredis.create_pool(('localhost', 6379)) - with await pool as redis: - # Redis is bound to exclusive connection - redis.set('key', 'val') - - -Sorted set commands return values ---------------------------------- - -Sorted set commands (like ``zrange``, ``zrevrange`` and others) that accept -``withscores`` argument now **return list of tuples** instead of plain list. - -+--------+--------------------------------------------------------------------+ -| | .. code-block:: python3 | -| v0.3 | :emphasize-lines: 4,7-8 | -| | | -| | redis = await aioredis.create_redis(('localhost', 6379)) | -| | await redis.zadd('zset-key', 1, 'one', 2, 'two') | -| | res = await redis.zrange('zset-key', withscores=True) | -| | assert res == [b'one', 1, b'two', 2] | -| | | -| | # not an easy way to make a dict | -| | it = iter(res) | -| | assert dict(zip(it, it)) == {b'one': 1, b'two': 2} | -| | | -+--------+--------------------------------------------------------------------+ -| | .. code-block:: python3 | -| v1.0 | :emphasize-lines: 4,7 | -| | | -| | redis = await aioredis.create_redis(('localhost', 6379)) | -| | await redis.zadd('zset-key', 1, 'one', 2, 'two') | -| | res = await redis.zrange('zset-key', withscores=True) | -| | assert res == [(b'one', 1), (b'two', 2)] | -| | | -| | # now its easier to make a dict of it | -| | assert dict(res) == {b'one': 1, b'two': 2} | -| | | -+--------+--------------------------------------------------------------------+ - - -Hash ``hscan`` command now returns list of tuples -------------------------------------------------- - -``hscan`` updated to return a list of tuples instead of plain -mixed key/value list. - -+--------+--------------------------------------------------------------------+ -| | .. code-block:: python3 | -| v0.3 | :emphasize-lines: 4,7-8 | -| | | -| | redis = await aioredis.create_redis(('localhost', 6379)) | -| | await redis.hmset('hash', 'one', 1, 'two', 2) | -| | cur, data = await redis.hscan('hash') | -| | assert data == [b'one', b'1', b'two', b'2'] | -| | | -| | # not an easy way to make a dict | -| | it = iter(data) | -| | assert dict(zip(it, it)) == {b'one': b'1', b'two': b'2'} | -| | | -+--------+--------------------------------------------------------------------+ -| | .. code-block:: python3 | -| v1.0 | :emphasize-lines: 4,7 | -| | | -| | redis = await aioredis.create_redis(('localhost', 6379)) | -| | await redis.hmset('hash', 'one', 1, 'two', 2) | -| | cur, data = await redis.hscan('hash') | -| | assert data == [(b'one', b'1'), (b'two', b'2')] | -| | | -| | # now its easier to make a dict of it | -| | assert dict(data) == {b'one': b'1': b'two': b'2'} | -| | | -+--------+--------------------------------------------------------------------+ diff --git a/docs/mixins.rst b/docs/mixins.rst deleted file mode 100644 index 8c239d3fa..000000000 --- a/docs/mixins.rst +++ /dev/null @@ -1,218 +0,0 @@ -.. _aioredis-commands: - -:class:`aioredis.Redis` --- Commands Mixins Reference -===================================================== - -.. module:: aioredis.commands - -This section contains reference for mixins implementing Redis commands. - -Descriptions are taken from ``docstrings`` so may not contain proper markup. - - -.. autoclass:: aioredis.Redis - :members: - - :param pool_or_conn: Can be either :class:`~aioredis.RedisConnection` - or :class:`~aioredis.ConnectionsPool`. - :type pool_or_conn: :class:`~aioredis.abc.AbcConnection` - -Generic commands ----------------- - -.. autoclass:: GenericCommandsMixin - :members: - - -Geo commands ------------- - -.. versionadded:: v0.3.0 - -.. autoclass:: GeoCommandsMixin - :members: - -Geo commands result wrappers -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. class:: GeoPoint(longitude, latitude) - - Bases: :class:`tuple` - - Named tuple representing result returned by ``GEOPOS`` and ``GEORADIUS`` - commands. - - :param float longitude: longitude value. - :param float latitude: latitude value. - -.. class:: GeoMember(member, dist, hash, coord) - - Bases: :class:`tuple` - - Named tuple representing result returned by ``GEORADIUS`` and - ``GEORADIUSBYMEMBER`` commands. - - :param member: Value of geo sorted set item; - :type member: str or bytes - - :param dist: Distance in units passed to call. - :class:`None` if ``with_dist`` was not set - in :meth:`~GeoCommandsMixin.georadius` call. - :type dist: None or float - - :param hash: Geo-hash represented as number. - :class:`None` if ``with_hash`` - was not in :meth:`~GeoCommandsMixin.georadius` call. - :type hash: None or int - - :param coord: Coordinate of geospatial index member. - :class:`None` if ``with_coord`` was not set - in :meth:`~GeoCommandsMixin.georadius` call. - :type coord: None or GeoPoint - - -Strings commands ----------------- - -.. autoclass:: StringCommandsMixin - :members: - -Hash commands -------------- - -.. autoclass:: HashCommandsMixin - :members: - -List commands -------------- - -.. autoclass:: ListCommandsMixin - :members: - -Set commands ------------- - -.. autoclass:: SetCommandsMixin - :members: - -Sorted Set commands -------------------- - -.. autoclass:: SortedSetCommandsMixin - :members: - -Server commands ---------------- - -.. autoclass:: ServerCommandsMixin - :members: - -HyperLogLog commands --------------------- - -.. autoclass:: HyperLogLogCommandsMixin - :members: - -Transaction commands --------------------- - -.. autoclass:: TransactionsCommandsMixin - :members: - -.. class:: Pipeline(connection, commands_factory=lambda conn: conn) - - Commands pipeline. - - Buffers commands for execution in bulk. - - This class implements `__getattr__` method allowing to call methods - on instance created with ``commands_factory``. - - .. deprecated:: v1.3.1 - ``loop`` argument deprecated for Python 3.8 compatibility. - - :param connection: Redis connection - :type connection: aioredis.RedisConnection - - :param callable commands_factory: Commands factory to get methods from. - - .. comethod:: execute(\*, return_exceptions=False) - - Executes all buffered commands and returns result. - - Any exception that is raised by any command is caught and - raised later when processing results. - - If ``return_exceptions`` is set to ``True`` then all collected errors - are returned in resulting list otherwise single - :exc:`aioredis.PipelineError` exception is raised - (containing all collected errors). - - :param bool return_exceptions: Raise or return exceptions. - - :raise aioredis.PipelineError: Raised when any command caused error. - -.. class:: MultiExec(connection, commands_factory=lambda conn: conn) - - Bases: :class:`~Pipeline`. - - Multi/Exec pipeline wrapper. - - See :class:`~Pipeline` for parameters description. - - .. deprecated:: v1.3.1 - ``loop`` argument deprecated for Python 3.8 compatibility. - - .. comethod:: execute(\*, return_exceptions=False) - - Executes all buffered commands and returns result. - - see :meth:`Pipeline.execute` for details. - - :param bool return_exceptions: Raise or return exceptions. - - :raise aioredis.MultiExecError: Raised instead of :exc:`aioredis.PipelineError` - :raise aioredis.WatchVariableError: If watched variable is changed - -Scripting commands ------------------- - -.. autoclass:: ScriptingCommandsMixin - :members: - -Server commands ---------------- - -.. autoclass:: ServerCommandsMixin - :members: - - -Pub/Sub commands ----------------- - -Also see :ref:`aioredis.Channel`. - -.. autoclass:: PubSubCommandsMixin - :members: - - -Cluster commands ----------------- - -.. warning:: - Current release (|release|) of the library **does not support** - `Redis Cluster`_ in a full manner. - It provides only several API methods which may be changed in future. - -.. _Redis Cluster: http://redis.io/topics/cluster-tutorial - -.. :: - .. autoclass:: ClusterCommandsMixin - :members: - - -Streams commands ----------------- - -.. autoclass:: StreamCommandsMixin - :members: diff --git a/docs/mpsc.rst b/docs/mpsc.rst deleted file mode 100644 index 6e1f7c402..000000000 --- a/docs/mpsc.rst +++ /dev/null @@ -1,34 +0,0 @@ -.. module:: aioredis.pubsub - -:mod:`aioredis.pubsub` --- Pub/Sub Tools Reference -================================================== - -Module provides a Pub/Sub listener interface implementing -multi-producers, single-consumer queue pattern. - - -.. autoclass:: Receiver - :members: - - .. warning:: - - Currently subscriptions implementation has few issues that will - be solved eventually, but until then developer must be aware of the - following: - - * Single ``Receiver`` instance can not be shared between two (or more) - connections (or client instances) because any of them can close - ``_Sender``. - - * Several ``Receiver`` instances can not subscribe to the same - channel or pattern. This is a flaw in subscription mode implementation: - subsequent subscriptions to some channel always return first-created - Channel object. - - -.. autoclass:: _Sender - - Bases: :class:`aioredis.abc.AbcChannel` - - **Not to be used directly**, returned by :meth:`Receiver.channel` or - :meth:`Receiver.pattern()` calls. diff --git a/docs/releases.rst b/docs/releases.rst deleted file mode 100644 index 5020c0b52..000000000 --- a/docs/releases.rst +++ /dev/null @@ -1,5 +0,0 @@ -Releases -======== - -.. include:: ../CHANGES.txt - :start-line: 2 diff --git a/docs/requirements.txt b/docs/requirements.txt index e7a486523..b474f26c8 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,6 +1,5 @@ -pyenchant==3.2.0 -sphinx==3.5.1 -sphinx-rtd-theme==0.5.1 -sphinxcontrib-asyncio==0.3.0 -sphinxcontrib-spelling==7.1.0 -towncrier==19.2.0 +mkdocs==1.1.2 +mkdocs-awesome-pages-plugin==2.5.0 +mkdocs-material==7.0.5 +mkdocs-material-extensions==1.0.1 +pydoc-markdown==3.10.0 diff --git a/docs/sentinel.rst b/docs/sentinel.rst deleted file mode 100644 index 78b69d55c..000000000 --- a/docs/sentinel.rst +++ /dev/null @@ -1,265 +0,0 @@ -.. highlight:: python3 -.. module:: aioredis.sentinel - -:mod:`aioredis.sentinel` --- Sentinel Client Reference -====================================================== - -This section contains reference for Redis Sentinel client. - -Sample usage: - -.. code:: python - - import aioredis - - sentinel = await aioredis.create_sentinel( - [('sentinel.host1', 26379), ('sentinel.host2', 26379)]) - - redis = sentinel.master_for('mymaster') - assert await redis.set('key', 'value') - assert await redis.get('key', encoding='utf-8') == 'value' - - # redis client will reconnect/reconfigure automatically - # by sentinel client instance - -``RedisSentinel`` ------------------ - -.. corofunction:: create_sentinel(sentinels, \*, db=None, password=None,\ - encoding=None, minsize=1, maxsize=10,\ - ssl=None, parser=None,\ - ) - - Creates Redis Sentinel client. - - .. deprecated:: v1.3.1 - ``loop`` argument deprecated for Python 3.8 compatibility. - - :param sentinels: A list of Sentinel node addresses. - :type sentinels: list[tuple] - - :param int db: Redis database index to select for every master/slave - connections. - - :param password: Password to use if Redis server instance requires - authorization. - :type password: str or bytes or None - - :param encoding: Codec to use for response decoding. - :type encoding: str or None - - :param int minsize: Minimum number of connections (to master or slave) - to initialize and keep in pool. Default is 1. - - :param int maxsize: Maximum number of connections (to master or slave) - that can be created in pool. Default is 10. - - :param ssl: SSL context that is passed through to - :func:`asyncio.BaseEventLoop.create_connection`. - :type ssl: :class:`ssl.SSLContext` or True or None - - :param parser: Protocol parser class. Can be used to set custom protocol - reader; expected same interface as :class:`hiredis.Reader`. - :type parser: callable or None - - :rtype: RedisSentinel - - -.. class:: RedisSentinel - - Redis Sentinel client. - - The class provides interface to Redis Sentinel commands as well as - few methods to acquire managed Redis clients, see below. - - .. attribute:: closed - - ``True`` if client is closed. - - .. method:: master_for(name) - - Get :class:`~.Redis` client to named master. - The client is instantiated with special connections pool which - is controlled by :class:`SentinelPool`. - **This method is not a coroutine.** - - :param str name: Service name. - - :rtype: aioredis.Redis - - .. method:: slave_for(name) - - Get :class:`~.Redis` client to named slave. - The client is instantiated with special connections pool which - is controlled by :class:`SentinelPool`. - **This method is not a coroutine.** - - :param str name: Service name. - - :rtype: aioredis.Redis - - .. method:: execute(command, \*args, \**kwargs) - - Execute Sentinel command. Every command is prefixed with ``SENTINEL`` - automatically. - - :rtype: asyncio.Future - - .. comethod:: ping() - - Send PING to Sentinel instance. - Currently the ping command will be sent to first sentinel in pool, - this may change in future. - - .. method:: master(name) - - Returns a dictionary containing the specified master's state. - Please refer to Redis documentation for more info on returned data. - - :rtype: asyncio.Future - - .. method:: master_address(name) - - Returns a ``(host, port)`` pair for the given service name. - - :rtype: asyncio.Future - - .. method:: masters() - - Returns a list of dictionaries containing all masters' states. - - :rtype: asyncio.Future - - .. method:: slaves(name) - - Returns a list of slaves for the given service name. - - :rtype: asyncio.Future - - .. method:: sentinels(name) - - Returns a list of Sentinels for the given service name. - - :rtype: asyncio.Future - - .. method:: monitor(name, ip, port, quorum) - - Add a new master to be monitored by this Sentinel. - - :param str name: Service name. - :param str ip: New node's IP address. - :param int port: Node's TCP port. - :param int quorum: Sentinel quorum. - - .. method:: remove(name) - - Remove a master from Sentinel's monitoring. - - :param str name: Service name - - .. method:: set(name, option, value) - - Set Sentinel monitoring parameter for a given master. - Please refer to Redis documentation for more info on options. - - :param str name: Master's name. - :param str option: Monitoring option name. - :param str value: Monitoring option value. - - .. method:: failover(name) - - Force a failover of a named master. - - :param str name: Master's name. - - .. method:: check_quorum(name) - - Check if the current Sentinel configuration is able - to reach the quorum needed to failover a master, - and the majority needed to authorize the failover. - - :param str name: Master's name. - - .. method:: close() - - Close all opened connections. - - .. comethod:: wait_closed() - - Wait until all connections are closed. - -``SentinelPool`` ----------------- - -.. warning:: - This API has not yet stabilized and may change in future releases. - -.. cofunction:: create_sentinel_pool(sentinels, \*, db=None, password=None,\ - encoding=None, minsize=1, maxsize=10,\ - ssl=None, parser=None, loop=None) - - Creates Sentinel connections pool. - - -.. class:: SentinelPool - - Sentinel connections pool. - - This pool manages both sentinel connections and Redis master/slave - connections. - - .. attribute:: closed - - ``True`` if pool and all connections are closed. - - .. method:: master_for(name) - - Returns a managed connections pool for requested service name. - - :param str name: Service name. - - :rtype: ``ManagedPool`` - - .. method:: slave_for(name) - - Returns a managed connections pool for requested service name. - - :param str name: Service name. - - :rtype: ``ManagedPool`` - - .. method:: execute(command, \*args, \**kwargs) - - Execute Sentinel command. - - .. comethod:: discover(timeout=0.2) - - Discover Sentinels and all monitored services within given timeout. - - This will reset internal state of this pool. - - .. comethod:: discover_master(service, timeout) - - Perform named master discovery. - - :param str service: Service name. - :param float timeout: Operation timeout - - :rtype: aioredis.RedisConnection - - .. comethod:: discover_slave(service, timeout) - - Perform slave discovery. - - :param str service: Service name. - :param float timeout: Operation timeout - - :rtype: aioredis.RedisConnection - - .. method:: close() - - Close all controlled connections (both to sentinel and redis). - - .. comethod:: wait_closed() - - Wait until pool gets closed. diff --git a/docs/start.rst b/docs/start.rst deleted file mode 100644 index ebe87f3d1..000000000 --- a/docs/start.rst +++ /dev/null @@ -1,222 +0,0 @@ -.. highlight:: python3 -.. module:: aioredis.commands - -Getting started -=============== - -Installation ------------- - -.. code-block:: bash - - $ pip install aioredis - -This will install aioredis along with its dependencies: - -* hiredis protocol parser; - -* async-timeout --- used in Sentinel client. - -Without dependencies -~~~~~~~~~~~~~~~~~~~~ - -In some cases [1]_ you might need to install :mod:`aioredis` without ``hiredis``, -it is achievable with the following command: - -.. code-block:: bash - - $ pip install --no-deps aioredis async-timeout - -Installing latest version from Git -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code-block:: bash - - $ pip install git+https://github.com/aio-libs/aioredis@master#egg=aioredis - -Connecting ----------- - -:download:`get source code<../examples/getting_started/00_connect.py>` - -.. literalinclude:: ../examples/getting_started/00_connect.py - :language: python3 - -:func:`aioredis.create_redis_pool` creates a Redis client backed by a pool of -connections. The only required argument is the address of Redis server. -Redis server address can be either host and port tuple -(ex: ``('localhost', 6379)``), or a string which will be parsed into -TCP or UNIX socket address (ex: ``'unix://var/run/redis.sock'``, -``'//var/run/redis.sock'``, ``redis://redis-host-or-ip:6379/1``). - -Closing the client. Calling ``redis.close()`` and then ``redis.wait_closed()`` -is strongly encouraged as these methods will shutdown all open connections -and cleanup resources. - -See the :doc:`commands reference ` for the full list of supported commands. - -Connecting to specific DB -~~~~~~~~~~~~~~~~~~~~~~~~~ - -There are several ways you can specify database index to select on connection: - -#. explicitly pass db index as ``db`` argument: - - .. code-block:: python - - redis = await aioredis.create_redis_pool( - 'redis://localhost', db=1) - -#. pass db index in URI as path component: - - .. code-block:: python - - redis = await aioredis.create_redis_pool( - 'redis://localhost/2') - - .. note:: - - DB index specified in URI will take precedence over - ``db`` keyword argument. - -#. call :meth:`~aioredis.Redis.select` method: - - .. code-block:: python - - redis = await aioredis.create_redis_pool( - 'redis://localhost/') - await redis.select(3) - - -Connecting to password-protected Redis instance -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The password can be specified either in keyword argument or in address URI: - -.. code-block:: python - - redis = await aioredis.create_redis_pool( - 'redis://localhost', password='sEcRet') - - redis = await aioredis.create_redis_pool( - 'redis://:sEcRet@localhost/') - - redis = await aioredis.create_redis_pool( - 'redis://localhost/?password=sEcRet') - -.. note:: - Password specified in URI will take precedence over password keyword. - - Also specifying both password as authentication component and - query parameter in URI is forbidden. - - .. code-block:: python - - # This will cause assertion error - await aioredis.create_redis_pool( - 'redis://:sEcRet@localhost/?password=SeCreT') - -Result messages decoding ------------------------- - -By default :mod:`aioredis` will return :class:`bytes` for most Redis -commands that return string replies. Redis error replies are known to be -valid UTF-8 strings so error messages are decoded automatically. - -If you know that data in Redis is valid string you can tell :mod:`aioredis` -to decode result by passing keyword-only argument ``encoding`` -in a command call: - -:download:`get source code<../examples/getting_started/01_decoding.py>` - -.. literalinclude:: ../examples/getting_started/01_decoding.py - :language: python3 - - -:mod:`aioredis` can decode messages for all Redis data types like -lists, hashes, sorted sets, etc: - -:download:`get source code<../examples/getting_started/02_decoding.py>` - -.. literalinclude:: ../examples/getting_started/02_decoding.py - :language: python3 - - -Multi/Exec transactions ------------------------ - -:download:`get source code<../examples/getting_started/03_multiexec.py>` - -.. literalinclude:: ../examples/getting_started/03_multiexec.py - :language: python3 - -:meth:`~TransactionsCommandsMixin.multi_exec` method creates and returns new -:class:`~aioredis.commands.MultiExec` object which is used for buffering commands and -then executing them inside MULTI/EXEC block. - -.. warning:: - - It is very important not to ``await`` buffered command - (ie ``tr.set('foo', '123')``) as it will block forever. - - The following code will block forever:: - - tr = redis.multi_exec() - await tr.incr('foo') # that's all. we've stuck! - - -Pub/Sub mode ------------- - -:mod:`aioredis` provides support for Redis Publish/Subscribe messaging. - -To start listening for messages you must call either -:meth:`~PubSubCommandsMixin.subscribe` or -:meth:`~PubSubCommandsMixin.psubscribe` method. -Both methods return list of :class:`~aioredis.Channel` objects representing -subscribed channels. - -Right after that the channel will receive and store messages -(the ``Channel`` object is basically a wrapper around :class:`asyncio.Queue`). -To read messages from channel you need to use :meth:`~aioredis.Channel.get` -or :meth:`~aioredis.Channel.get_json` coroutines. - -Example subscribing and reading channels: - -:download:`get source code<../examples/getting_started/04_pubsub.py>` - -.. literalinclude:: ../examples/getting_started/04_pubsub.py - :language: python3 - -Subscribing and reading patterns: - -:download:`get source code<../examples/getting_started/05_pubsub.py>` - -.. literalinclude:: ../examples/getting_started/05_pubsub.py - :language: python3 - -Sentinel client ---------------- - -:download:`get source code<../examples/getting_started/06_sentinel.py>` - -.. literalinclude:: ../examples/getting_started/06_sentinel.py - :language: python3 - -Sentinel client requires a list of Redis Sentinel addresses to connect to -and start discovering services. - -Calling :meth:`~aioredis.sentinel.SentinelPool.master_for` or -:meth:`~aioredis.sentinel.SentinelPool.slave_for` methods will return -Redis clients connected to specified services monitored by Sentinel. - -Sentinel client will detect failover and reconnect Redis clients automatically. - -See detailed reference :doc:`here ` - ----- - -.. [1] - Celery hiredis issues - (`#197 `_, - `#317 `_) diff --git a/docs/static/stylesheets/extra.css b/docs/static/stylesheets/extra.css new file mode 100644 index 000000000..bd5c8c930 --- /dev/null +++ b/docs/static/stylesheets/extra.css @@ -0,0 +1,6 @@ +/* Indentation. */ +div.doc-contents:not(.first) { + padding-left: 25px; + border-left: 4px solid rgba(230, 230, 230); + margin-bottom: 80px; +} diff --git a/examples/connection.py b/examples/connection.py deleted file mode 100644 index 35d916ce9..000000000 --- a/examples/connection.py +++ /dev/null @@ -1,22 +0,0 @@ -import asyncio - -import aioredis - - -async def main(): - redis = aioredis.from_url( - "redis://localhost", encoding="utf-8", decode_responses=True - ) - # get a redis client bound to a single connection. - async with redis.client() as conn: - ok = await conn.execute_command("set", "my-key", "some value") - assert ok is True - - str_value = await conn.execute_command("get", "my-key") - assert str_value == "some value" - - print("str value:", str_value) - - -if __name__ == "__main__": - asyncio.run(main()) diff --git a/examples/getting_started/03_multiexec.py b/examples/getting_started/03_multiexec.py deleted file mode 100644 index 7157cd269..000000000 --- a/examples/getting_started/03_multiexec.py +++ /dev/null @@ -1,24 +0,0 @@ -import asyncio - -import aioredis -from aioredis.utils import pipeline - - -async def main(): - redis = await aioredis.from_url("redis://localhost") - async with redis.pipeline(transaction=True) as pipe: - ok1, ok2 = await (pipe.set("key1", "value1").set("key2", "value2").execute()) - assert ok1 - assert ok2 - - -async def main2(): - redis = await aioredis.Redis.from_url("redis://localhost", decode_responses=True) - async with pipeline(redis) as pipe: - pipe.set("key1", "value1").set("key2", "value2") - assert await redis.get("key1", "value1") - assert await redis.get("key2", "value2") - - -asyncio.run(main()) -asyncio.run(main2()) diff --git a/examples/pool.py b/examples/pool.py deleted file mode 100644 index e5dfa0703..000000000 --- a/examples/pool.py +++ /dev/null @@ -1,14 +0,0 @@ -import asyncio - -import aioredis - - -async def main(): - redis = aioredis.from_url("redis://localhost", max_connections=10) - await redis.execute_command("set", "my-key", "value") - val = await redis.execute_command("get", "my-key") - print("raw value:", val) - - -if __name__ == "__main__": - asyncio.run(main()) diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 000000000..521a156c7 --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,63 @@ +site_name: aioredis +site_author: Sean D Stewart +copyright: "Copyright © 2020 - 2021 Sean Stewart" +site_url: http://aioredis.readthedocs.io/ +repo_url: https://github.com/aio-libs/aioredis +repo_name: aio-libs/aioredis +theme: + name: "material" +nav: +- index.md +- getting-started.md +- examples.md +- migration.md +- devel.md +- 'API Reference': + - api/high-level.md + - api/low-level.md +- changes.md +- license.md +plugins: +- search +- mkdocstrings: + handlers: + python: + setup_commands: + - import sys + - sys.path.append("aioredis") + selection: + docstring_style: restructured-text + new_path_syntax: yes +- autorefs +markdown_extensions: +- toc: + permalink: true +- abbr +- smarty +- admonition +- footnotes +- codehilite +- pymdownx.arithmatex +- pymdownx.inlinehilite +- pymdownx.superfences +- pymdownx.betterem: + smart_enable: all +- pymdownx.caret +- pymdownx.critic +- pymdownx.details +- pymdownx.emoji +- pymdownx.magiclink +- pymdownx.mark +- pymdownx.smartsymbols +- pymdownx.tasklist: + custom_checkbox: true +- pymdownx.tilde +- pymdownx.snippets: + check_paths: true + base_path: docs +extra: + social: + - icon: "fontawesome/brands/github-alt" + link: "https://github.com/aio-libs/aioredis" +extra_css: +- static/stylesheets/extra.css diff --git a/pyproject.toml b/pyproject.toml index 5108f0dd8..8cf41afa9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,10 +1,8 @@ [tool.towncrier] -package = "aioredis" +filename = "docs/changelog.md" directory = "CHANGES/" -filename = "CHANGES.txt" -title_format = "{version} ({project_date})" - -underlines = [ '^', '~', '"' ] - -issue_format = "`#{issue} `_" -template = "CHANGES/template.jinja" +start_string = "# Changelog\n" +issue_format = "[#{issue}](https://gitlab.com/group/project/-/issues/{issue})" +underlines = ["", ""] +template = ".towncrier.md.jinja" +title_format = "## [{version}] - {project_date}" diff --git a/setup.py b/setup.py index 208108d3f..ada0b1e80 100644 --- a/setup.py +++ b/setup.py @@ -40,11 +40,10 @@ def read_version(): name="aioredis", version=read_version(), description=("asyncio (PEP 3156) Redis support"), - long_description="\n\n".join((read("README.rst"), read("CHANGES.txt"))), + long_description="\n\n".join((read("README.md"), read("CHANGES.md"))), + long_description_content_type="text/markdown", classifiers=classifiers, platforms=["POSIX"], - author="Alexey Popravka", - author_email="alexey.popravka@horsedevel.com", url="https://github.com/aio-libs/aioredis", license="MIT", packages=find_packages(exclude=["tests"]),