diff --git a/CHANGELOG.md b/CHANGELOG.md index ad8892e5..2c1397e2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,22 +37,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ConnectionPool updates information about each server state (RO/RW) on initial connect and then asynchronously in separate threads. Application retries must be written considering the asynchronous nature - of cluster state refresh. User does not need to use any synchronization + of cluster state refresh. The user does not need to use any synchronization mechanisms in requests, it's all handled with ConnectionPool methods. - ConnectionPool API is the same as a plain Connection API. - On each request, a connection is chosen to execute this request. - A connection is chosen based on a request mode: - * Mode.ANY chooses any instance. - * Mode.RW chooses an RW instance. - * Mode.RO chooses an RO instance. - * Mode.PREFER_RW chooses an RW instance, if possible, RO instance + ConnectionPool API is the same as the plain Connection API. + On each request, a connection is chosen to execute the request. + A connection is chosen based on the request mode: + * `Mode.ANY` chooses any instance. + * `Mode.RW` chooses an RW instance. + * `Mode.RO` chooses an RO instance. + * `Mode.PREFER_RW` chooses an RW instance, if possible, an RO instance otherwise. - * Mode.PREFER_RO chooses an RO instance, if possible, RW instance + * `Mode.PREFER_RO` chooses an RO instance, if possible, an RW instance otherwise. - All requests that are guaranteed to write (insert, replace, delete, - upsert, update) use RW mode by default. select uses ANY by default. You - can set the mode explicitly. call, eval, execute and ping requests + All requests that guarantee to write data (insert, replace, delete, + upsert, update) use the RW mode by default. + The select request uses `ANY` by default. You + can set the mode explicitly. The call, eval, execute, and ping requests require to set the mode explicitly. Example: @@ -69,14 +70,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ``` ### Changed -- **Breaking**: drop Python 2 support (PR #207). -- **Breaking**: change binary types encode/decode for Python 3 - to support working with varbinary (PR #211, #105). - With Python 2 the behavior of the connector remains the same. +- **Breaking change**: Python 2 support dropped (PR #207). +- **Breaking change**: `encode`/`decode` binary types for Python 3 changed + to support working with `varbinary` (PR #211, #105). + With Python 2, the behavior of the connector remains the same. Before this patch: - * encoding="utf-8" (default) + * `encoding="utf-8"` (default) | Python 3 | -> | Tarantool | -> | Python 3 | |----------|----|--------------------|----|----------| @@ -84,7 +85,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | bytes | -> | mp_str (string) | -> | str | | | | mp_bin (varbinary) | -> | bytes | - * encoding=None + * `encoding=None` | Python 3 | -> | Tarantool | -> | Python 3 | |----------|----|--------------------|----|----------| @@ -92,12 +93,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | str | -> | mp_str (string) | -> | bytes | | | | mp_bin (varbinary) | -> | bytes | - Using bytes as key was not supported by several methods (delete, - update, select). + Several method (delete, update, select) did not support + using `bytes` as key. After this patch: - * encoding="utf-8" (default) + * `encoding="utf-8"` (default) | Python 3 | -> | Tarantool | -> | Python 3 | |----------|----|--------------------|----|----------| @@ -112,13 +113,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | str | -> | mp_str (string) | -> | bytes | | | | mp_bin (varbinary) | -> | bytes | - Using bytes as key are now supported by all methods. + All methods now support using `bytes` as key. - Thus, encoding="utf-8" connection may be used to work with - utf-8 strings and varbinary and encodine=None connection - may be used to work with non-utf-8 strings. + Thus, an `encoding="utf-8"` connection may be used to work with + UTF-8 strings and `varbinary`, and an `encoding=None` connection + may be used to work with non-UTF-8 strings. -- Clarify license of the project (BSD-2-Clause) (PR #210, #197). +- Clarify the license of the project (BSD-2-Clause) (PR #210, #197). - Migrate CI to GitHub Actions (PR #213, PR #216, #182). - Various improvements and fixes in README (PR #210, PR #215). @@ -141,15 +142,15 @@ the dependency on the msgpack library. ### Added - Support msgpack 1.0.0 (#155, PR #173). -- SQL support (.execute() method) (#159, PR #161). -- Allow to receive a Tarantool tuple as a Python tuple, not a list, with - use_list=False connection option (#166, PR #161). +- SQL support (the method `.execute()`) (#159, PR #161). +- Allow receiving a Tarantool tuple as a Python tuple, not a list, with + the `use_list=False` connection option (#166, PR #161). - Support the Database API (PEP-0249) (PR #161). ### Changed - Various improvements in README (PR #147, PR #151, PR #180). ### Fixed -- Support encoding=None connections (PR #172). +- Support `encoding=None` connections (PR #172). - Various improvements and fixes in tests (8ff9a3f, bd37703, PR #165, #178, PR #179, PR #181). diff --git a/INSTALL b/INSTALL index f07c3c45..5d7089ac 100644 --- a/INSTALL +++ b/INSTALL @@ -1,17 +1,17 @@ Installing tarantool-python =========================== -The simplest (and recommended) way to install tarantool-python +Here is the simplest (and recommended) way to install tarantool-python. -using `pip`:: +Using `pip`:: $ pip install tarantool -or `easy_install`:: +Using `easy_install`:: $ easy_install tarantool -You can also download a source tarball and install the package using distutils script:: +You can also download the source tarball and install the package using distutils script:: # python setup.py install diff --git a/README.rst b/README.rst index a59dbf98..500e3a1d 100644 --- a/README.rst +++ b/README.rst @@ -14,35 +14,39 @@ This package is a pure-python client library for `Tarantool`_. .. image:: https://github.com/tarantool/tarantool-python/actions/workflows/testing.yml/badge.svg?branch=master :target: https://github.com/tarantool/tarantool-python/actions/workflows/testing.yml -Download and Install +Download and install -------------------- -The recommended way to install ``tarantool`` package is using PIP -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +With pip (recommended) +^^^^^^^^^^^^^^^^^^^^^^ -For Tarantool version < 1.6.0 you must get ``0.3.*`` connector version:: +The recommended way to install the ``tarantool`` package is using ``pip``. + +For Tarantool version < 1.6.0, get the ``0.3.*`` connector version:: $ pip install tarantool\<0.4 -For later Tarantool use version ``0.5.*`` connector version:: +For a later Tarantool version, get the ``0.5.*`` connector version:: $ pip install tarantool\>0.4 -You can also download zip archive, unpack it and run -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ZIP archive +^^^^^^^^^^^ -.. code-block:: console +You can also download zip archive, unpack it and run:: $ python setup.py install -To install development version of the package using pip -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Development version +^^^^^^^^^^^^^^^^^^^ + +You can also install the development version of the package using ``pip``. -For Tarantool version < 1.6.0 you must get ``stable`` branch:: +For Tarantool version < 1.6.0, get the ``stable`` branch:: $ pip install git+https://github.com/tarantool/tarantool-python.git@stable -For later Tarantool use ``master`` branch:: +For a later Tarantool version, use the ``master`` branch:: $ pip install git+https://github.com/tarantool/tarantool-python.git@master @@ -51,41 +55,42 @@ For later Tarantool use ``master`` branch:: What is Tarantool? ------------------ -`Tarantool`_ is a NoSQL database running inside a Lua program. It combines the -network programming power of Node.JS with data persistency capabilities of -Redis. It's open source, `BSD-2-Clause`_ licensed. +`Tarantool`_ is an in-memory NoSQL database with a Lua application server on board. +It combines the network programming power of Node.JS +with data persistency capabilities of Redis. +It's open-source, licensed under `BSD-2-Clause`_. Features -------- * ANSI SQL, including views, joins, referential and check constraints -* Lua packages for non-blocking I/O, fibers and HTTP -* MsgPack data format and MsgPack based client-server protocol +* Lua packages for non-blocking I/O, fibers, and HTTP +* MsgPack data format and MsgPack-based client-server protocol * Two data engines: - * memtx - the in-memory storage engine with optional persistence - * vinyl - the on-disk storage engine to use with large data sets + * memtx – in-memory storage engine with optional persistence + * vinyl – on-disk storage engine to use with larger data sets -* secondary key and index iterators support (can be non-unique and composite) -* multiple index types: HASH, BITSET, TREE, RTREE -* asynchronous master-master replication -* authentication and access control +* Secondary key and index iterator support (can be non-unique and composite) +* Multiple index types: HASH, BITSET, TREE, RTREE +* Asynchronous master-master replication +* Authentication and access control See More ^^^^^^^^ -* `Tarantool Homepage`_ -* `Tarantool at Github`_ -* `Tarantool User Guide`_ -* `Client-server Protocol Specification`_ +* `Tarantool homepage`_ +* `Tarantool on GitHub`_ +* `Tarantool documentation`_ +* `Client-server protocol specification`_ NOTE ^^^^ This driver is synchronous, so connection mustn't be shared between threads/processes. -Look at `asynctnt`_ for asynchronous Python driver based on asyncio. See -also the `feature comparison table`_. +If you're looking for an asynchronous Python driver based on ``asyncio``, +consider using `asynctnt`_ . See also the `feature comparison table`_. Run tests ^^^^^^^^^ @@ -98,10 +103,11 @@ On Linux: On Windows: -* Setup a Linux machine with installed tarantool (called ``remote`` later). -* (on ``remote``) Copy ``test/suites/lib/tarantool_python_ci.lua`` to +* Setup a Linux machine with Tarantool installed. + This machine will be referred to as ``remote`` in this instruction. +* (On ``remote``) Copy ``test/suites/lib/tarantool_python_ci.lua`` to ``/etc/tarantool/instances.available``. -* (on ``remote``) Run ``tarantoolctl start tarantool_python_ci``. +* (On ``remote``) Run ``tarantoolctl start tarantool_python_ci``. * Set the following environment variables: * ``REMOTE_TARANTOOL_HOST=...``, * ``REMOTE_TARANTOOL_CONSOLE_PORT=3302``. @@ -109,9 +115,9 @@ On Windows: .. _`Tarantool`: .. _`Tarantool Database`: -.. _`Tarantool Homepage`: https://tarantool.io -.. _`Tarantool at Github`: https://github.com/tarantool/tarantool -.. _`Tarantool User Guide`: https://www.tarantool.io/en/doc/latest/ +.. _`Tarantool homepage`: https://tarantool.io +.. _`Tarantool on GitHub`: https://github.com/tarantool/tarantool +.. _`Tarantool documentation`: https://www.tarantool.io/en/doc/latest/ .. _`Client-server protocol specification`: https://www.tarantool.io/en/doc/latest/dev_guide/internals/box_protocol/ .. _`BSD-2-Clause`: https://opensource.org/licenses/BSD-2-Clause .. _`asynctnt`: https://github.com/igorcoding/asynctnt diff --git a/doc/guide.en.rst b/doc/guide.en.rst index e30eac0f..d4d8aab9 100644 --- a/doc/guide.en.rst +++ b/doc/guide.en.rst @@ -9,14 +9,14 @@ Basic concepts Spaces ^^^^^^ -Spaces is a collections of tuples. +A space is a collection of tuples. Usually, tuples in one space represent objects of the same type, -although this is not necessary. +although not necessarily. -.. note:: The analogue of spaces is tables in traditional (SQL) databases. +.. note:: Spaces are analogous to tables in traditional (SQL) databases. Spaces have integer identifiers defined in the server configuration. -To access the space as a named object it is possible to use the method +One of the ways to access a space as a named object is by using the method :meth:`Connection.space() ` and an instance of :class:`~tarantool.space.Space`. @@ -29,16 +29,15 @@ Example:: Field types ^^^^^^^^^^^ -Three field types are supported in Tarantool: ``STR``, ``NUM`` and ``NUM64``. -These types are used only for index configuration -but not saved in tuple's data and not transferred between the client and server. +Three field types are supported in Tarantool: ``STR``, ``NUM``, and ``NUM64``. +These types are used only for index configuration. +They are neither saved in the tuple data nor transferred between the client and the server. Thus, from the client point of view, fields are raw byte arrays -without explicitly definde types. +without explicitly defined types. -It is much easier to use native types for python developer: +For a Python developer, it is much easier to use native types: ``int``, ``long``, ``unicode`` (``int`` and ``str`` for Python 3.x). -For raw binary data ``bytes`` should be used -(in this case the type casting is not performed). +For raw binary data, use ``bytes`` (in this case, type casting is not performed). Tarantool data types corresponds to the following Python types: • ``RAW`` - ``bytes`` @@ -46,13 +45,13 @@ Tarantool data types corresponds to the following Python types: • ``NUM`` - ``int`` • ``NUM64`` - ``int`` or ``long`` (``int`` for Python 3.x) -Please define spaces schema to enable automatic type casting: +To enable automatic type casting, please define a schema for the spaces: >>> import tarantool >>> schema = { 0: { # Space description 'name': 'users', # Space name - 'default_type': tarantool.STR, # Type that used to decode fields that are not listed below + 'default_type': tarantool.STR, # Type that is used to decode fields not listed below 'fields': { 0: ('numfield', tarantool.NUM), # (field name, field type) 1: ('num64field', tarantool.NUM64), @@ -69,23 +68,23 @@ Please define spaces schema to enable automatic type casting: } >>> connection = tarantool.connect(host = 'localhost', port=33013, schema = schema) >>> demo = connection.space('users') - >>> demo.insert((0, 12, u'this is unicode string')) + >>> demo.insert((0, 12, u'this is a unicode string')) >>> demo.select(0) - [(0, 12, u'this is unicode string')] + [(0, 12, u'this is a unicode string')] -As you can see, original "raw" fields were casted to native types as defined in the schema. +As you can see, original "raw" fields were cast to native types as defined in the schema. -Tarantool's tuple can contain any number of fields. -If some fields are not defined then ``default_type`` will be used. +A Tarantool tuple can contain any number of fields. +If some fields are not defined, then ``default_type`` will be used. -To prevent implicit type casting for strings use ``RAW`` type. +To prevent implicit type casting for strings, use the ``RAW`` type. Raw byte fields should be used if the application uses binary data -(eg, images or python objects packed with ``picke``). +(like images or Python objects packed with ``pickle``). -You can also specify schema for CALL results: +You can also specify a schema for CALL results: >>> ... - # Copy schema decription from 'users' space + # Copy schema decription from the 'users' space >>> connection.call("box.select", '0', '0', 0L, space_name='users'); [(0, 12, u'this is unicode string')] # Provide schema description explicitly @@ -98,7 +97,7 @@ You can also specify schema for CALL results: Python 2.6 adds :class:`bytes` as a synonym for the :class:`str` type, and it also supports the ``b''`` notation. -.. note:: **utf-8** allways used for type conversion between ``unicode`` and ``bytes`` +.. note:: **utf-8** is always used for type conversion between ``unicode`` and ``bytes``. @@ -111,21 +110,21 @@ Requests (:meth:`insert() `, :meth:`select() `) return a :class:`~tarantool.response.Response` instance. -Class :class:`~tarantool.response.Response` inherited from `list`, -so in fact response can be used as a list of a tuples. +The class :class:`~tarantool.response.Response` inherits from `list`, +so a response is, in fact, a list of tuples. -In addition :class:`~tarantool.response.Response` instance has the ``rowcount`` attribute. +In addition, a :class:`~tarantool.response.Response` instance has the ``rowcount`` attribute. The value of ``rowcount`` equals to the number of records affected by the request. -For example for :meth:`delete() ` -request ``rowcount`` is equals to ``1`` if record was deleted. +For example, for :meth:`delete() `, +the request ``rowcount`` equals to ``1`` if a record was deleted. -Connect to the server ---------------------- +Connect to a server +------------------- -To connect to the server it is required to use :meth:`tarantool.connect` method. -It returns an :class:`~tarantool.connection.Connection` instance. +To connect to a server, use the :meth:`tarantool.connect` method. +It returns a :class:`~tarantool.connection.Connection` instance. Example:: @@ -139,92 +138,91 @@ Example:: Data manipulation ----------------- -There are four basic operations supported by Tarantool: +Tarantool supports four basic operations: **insert**, **delete**, **update** and **select**. -.. Note:: НЕОБХОДИМО ОБЪЯСНИТЬ КАКИЕ ДАННЫЕ ИСПОЛЬЗУЮТСЯ ДЛЯ ПРИМЕРА - Inserting and replacing records ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -To insert or replace records :meth:`Space.insert() ` -method should be used:: +To insert or replace records, use the :meth:`Space.insert() ` +method. + +Example:: >>> user.insert((user_id, email, int(time.time()))) -The first element of the tuple is always its unique primary key. +The first element of a tuple is always its unique primary key. If an entry with the same key already exists, it will be replaced without any warning or error message. -.. note:: In case of ``insert`` request ``Response.rowcount`` is always equals to ``1`` +.. note:: For ``insert`` requests, ``Response.rowcount`` always equals ``1``. -Deleting Records +Deleting records ^^^^^^^^^^^^^^^^ -To delete records :meth:`Space.delete() ` -method should be used:: +To delete records, use the :meth:`Space.delete() ` method. + +Example:: >>> user.delete(primary_key) -.. note:: If the record was deleted ``Response.rowcount`` equals to ``1``. - If the record was not found ``Response.rowcount`` equals to ``0``. +.. note:: If the record was deleted, ``Response.rowcount`` equals ``1``. + If the record was not found, ``Response.rowcount`` equals ``0``. -Updating Records +Updating records ^^^^^^^^^^^^^^^^ -*Update* request in Tarantool allows to simultaneous and atomic update multiple -fields of a tuple. +An *update* request in Tarantool allows updating multiple +fields of a tuple simultaneously and atomically. -To update records :meth:`Space.update() ` -method should be used. +To update records, use the :meth:`Space.update() ` +method. Example:: >>> user.update(1001, [('=', 1, 'John'), ('=', 2, 'Smith')]) -In this example new values for fields ``1`` and ``2`` are assigned. +In this example, fields ``1`` and ``2`` are assigned new values. -:meth:`Space.update() ` method allows to change +The :meth:`Space.update() ` method allows changing multiple fields of the tuple at a time. -The following update operations are supported by Tarantool: +Tarantool supports the following update operations: • ``'='`` – assign new value to the field • ``'+'`` – add argument to the field (*both arguments are treated as signed 32-bit ints*) • ``'^'`` – bitwise AND (*only for 32-bit integers*) • ``'|'`` – bitwise XOR (*only for 32-bit integers*) • ``'&'`` – bitwise OR (*only for 32-bit integers*) - • ``'splice'`` – implementation of `Perl splice `_ function + • ``'splice'`` – implementation of `Perl splice `_ -.. note:: The zero (i.e. [0]) field of the tuple can not be updated, - because it is the primary key +.. note:: The 0th field of the tuple cannot be updated, because it is the primary key. -.. seealso:: See :meth:`Space.update() ` documentation for details +.. seealso:: See :meth:`Space.update() ` documentation for details. -.. warning:: ``'splice'`` operation is not implemented yet +.. warning:: The ``'splice'`` operation is not implemented yet. -Selecting Records +Selecting records ^^^^^^^^^^^^^^^^^ -To select records :meth:`Space.select() ` -method should be used. -*SELECT* query can return one or many records. +To select records, use the :meth:`Space.select() ` method. +A *SELECT* query can return one or many records. .. rubric:: Select by primary key -Select a record using its primary key ``3800``:: +Select a record using its primary key, ``3800``:: >>> world.select(3800) [(3800, u'USA', u'Texas', u'Dallas', 1188580)] -.. rubric:: Select using secondary index +.. rubric:: Select by a secondary index :: @@ -237,15 +235,15 @@ Select a record using its primary key ``3800``:: (3794, u'USA', u'California', u'Los Angeles', 3694820)] -Argument ``index = 1`` indicates that secondary index (``1``) should be used. +The argument ``index=1`` indicates that a secondary index (``1``) should be used. The primary key (``index=0``) is used by default. -.. note:: Secondary indexes must be explicitly declared in the server configuration +.. note:: Secondary indexes must be explicitly declared in the server configuration. -.. rubric:: Select records using several keys +.. rubric:: Select by several keys -.. note:: This conforms to ``where key in (k1, k2, k3...)`` +.. note:: This conforms to ``where key in (k1, k2, k3...)``. Select records with primary key values ``3800``, ``3805`` and ``3796``:: @@ -263,21 +261,20 @@ Select data on cities in Texas:: [(3800, u'USA', u'Texas', u'Dallas', 1188580), (3796, u'USA', u'Texas', u'Houston', 1953631)] -.. rubric:: Select records explicitly specifying field types +.. rubric:: Select records by explicitly specifying field types -Tarantool has no strict schema so all fields are raw binary byte arrays. -You can specify field types in the ``schema`` parameter to a connection. +Tarantool has no strict schema, so all fields are raw binary byte arrays. +You can specify field types in the ``schema`` parameter of the connection. Call server-side functions -------------------------- A server-side function written in Lua can select and modify data, -access configuration and perform administrative tasks. +access configuration, and perform administrative tasks. -To call stored function -:meth:`Connection.call() ` -method should be used. -Also, this method has an alias :meth:`Space.call() `. +To call a stored function, use the +:meth:`Connection.call() ` method. +(This method has an alias, :meth:`Space.call() `.) Example:: @@ -286,4 +283,4 @@ Example:: .. seealso:: - Tarantool/Box User Guide » `Writing stored procedures in Lua `_ + Tarantool documentation » `Insert one million tuples with a Lua stored procedure `_ diff --git a/doc/guide.ru.rst b/doc/guide.ru.rst index 31fedb94..4a7e7bcf 100644 --- a/doc/guide.ru.rst +++ b/doc/guide.ru.rst @@ -6,17 +6,17 @@ Базовые понятия --------------- -Пространства -^^^^^^^^^^^^ +Спейсы +^^^^^^ -Пространства в Tarantool — это коллекции кортежей. -Как правило, кортежи в пространстве представляют собой объекты одного типа, +Спейсы в Tarantool — это коллекции кортежей. +Как правило, кортежи в спейсе представляют собой объекты одного типа, хотя это и не обязательно. -.. note:: Аналог пространства — это таблица в традиционных (SQL) базах данных. +.. note:: Аналог спейса — таблица в традиционных (SQL) базах данных. -Пространства имеют целочисленные идентификаторы, которые задаются в конфигурации сервера. -Чтобы обращаться к пространству, как к именованному объекту, можно использовать метод +Спейсы имеют целочисленные идентификаторы, которые задаются в конфигурации сервера. +Чтобы обращаться к спейсу как к именованному объекту, можно использовать метод :meth:`Connection.space() ` и экземпляр класса :class:`~tarantool.space.Space`. @@ -32,7 +32,7 @@ Tarantool поддерживает три типа полей: ``STR``, ``NUM`` и ``NUM64``. Эти типы используются только при конфигурации индексов, но не сохраняются с данными кортежа и не передаются между сервером и клиентом. -Таким образом, с точки зрения клиента, поля кортежей являются просто байтовыми массивами +Таким образом, с точки зрения клиента, поля кортежей — это просто байтовые массивы без явно заданных типов. Для разработчика на Python намного удобнее использовать родные типы: @@ -51,7 +51,7 @@ Tarantool поддерживает три типа полей: ``STR``, ``NUM`` >>> schema = { 0: { # Space description 'name': 'users', # Space name - 'default_type': tarantool.STR, # Type that used to decode fields that are not listed below + 'default_type': tarantool.STR, # Type that is used to decode fields not listed below 'fields': { 0: ('user_id', tarantool.NUM), # (field name, field type) 1: ('num64field', tarantool.NUM64), @@ -68,17 +68,17 @@ Tarantool поддерживает три типа полей: ``STR``, ``NUM`` } >>> connection = tarantool.connect(host = 'localhost', port=33013, schema = schema) >>> demo = connection.space('users') - >>> demo.insert((0, 12, u'this is unicode string')) + >>> demo.insert((0, 12, u'this is a unicode string')) >>> demo.select(0) - [(0, 12, u'this is unicode string')] + [(0, 12, u'this is a unicode string')] Как видно из примера, все значения были преобразованы в Python-типы в соответствии со схемой. Кортеж Tarantool может содержать произвольное количество полей. -Если какие-то поля не объявлены в схеме, то ``default_type`` будет использован для конвертации. +Если какие-то поля не объявлены в схеме, то для конвертации будет использован ``default_type``. Поля с "сырыми" байтами следует использовать, если приложение работает с -двоичными данными (например, изображения или python-объекты, сохраненные с помощью ``picke``). +двоичными данными (например, с изображениями или Python-объектами, сохраненными с помощью ``pickle``). Возможно также указать тип для CALL запросов: @@ -96,7 +96,7 @@ Tarantool поддерживает три типа полей: ``STR``, ``NUM`` Python 2.6 добавляет синоним :class:`bytes` к типу :class:`str` (также поддерживается синтаксис ``b''``). -.. note:: Для преобразования между ``bytes`` и ``unicode`` всегда используется **utf-8** +.. note:: Для преобразования между ``bytes`` и ``unicode`` всегда используется **utf-8**. @@ -140,8 +140,6 @@ Tarantool поддерживает три типа полей: ``STR``, ``NUM`` Tarantool поддерживает четыре базовых операции: **insert**, **delete**, **update** и **select**. -.. Note:: НЕОБХОДИМО ОБЪЯСНИТЬ КАКИЕ ДАННЫЕ ИСПОЛЬЗУЮТСЯ ДЛЯ ПРИМЕРА - Добавление и замещение записей ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -151,10 +149,10 @@ Tarantool поддерживает четыре базовых операции: >>> user.insert((user_id, email, int(time.time()))) -Первый элемент кортежа всегда является его уникальным первичным ключом. +Первый элемент кортежа — это всегда его уникальный первичный ключ. Если запись с таким ключом уже существует, она будет замещена -без какого либо предупреждения или сообщения об ошибке. +без какого-либо предупреждения или сообщения об ошибке. .. note:: Для :meth:`Space.insert() ` ``Response.rowcount`` всегда равен ``1``. @@ -199,11 +197,11 @@ Tarantool поддерживает следующие операции обно .. note:: Нулевое (т.е. [0]) поле кортежа нельзя обновить, - поскольку оно является первичным ключом + поскольку оно является первичным ключом. -.. seealso:: Подробности в документации по методу :meth:`Space.update() ` +.. seealso:: Подробности можно найти в документации по методу :meth:`Space.update() `. -.. warning:: Операция ``'splice'`` пока не реализована +.. warning:: Операция ``'splice'`` пока не реализована. Выборка записей @@ -236,16 +234,16 @@ Tarantool поддерживает следующие операции обно Аргумент ``index=1`` указывает, что при запросе следует использовать индекс ``1``. -По умолчанию используется первыичный ключ (``index=0``). +По умолчанию используется первичный ключ (``index=0``). -.. note:: Вторичные индексы должны быть явно объявлены в конфигурации севера +.. note:: Вторичные индексы должны быть явно объявлены в конфигурации сервера. .. rubric:: Запрос записей по нескольким ключам -.. note:: Это аналог ``where key in (k1, k2, k3...)`` +.. note:: Это аналог ``where key in (k1, k2, k3...)``. -Извлечь записи со значениями первичного ключа ``3800``, ``3805`` and ``3796``:: +Извлечь записи со значениями первичного ключа ``3800``, ``3805`` и ``3796``:: >>>> world.select([3800, 3805, 3796]) [(3800, u'USA', u'Texas', u'Dallas', 1188580), @@ -263,14 +261,14 @@ Tarantool поддерживает следующие операции обно .. rubric:: Запрос с явным указанием типов полей -Tarantool не имеет строгой схемы и поля кортежей являются просто байтовыми массивами. -Можно указать типа полей непосредственно в параметре ``schema`` для ```Connection`` +Tarantool не имеет строгой схемы, так что поля кортежей являются просто байтовыми массивами. +Можно указывать типы полей непосредственно в параметре ``schema`` для ```Connection``. Вызов хранимых функций ---------------------- -Хранимые процедуры на Lua могут делать выборки и изменять данные, -имеют доcтуп к конфигурации и могут выполнять административные функции. +С помощью хранимых процедур на Lua можно делать выборки и изменять данные, +получать доcтуп к конфигурации и выполнять административные функции. Для вызова хранимых функций следует использовать метод :meth:`Connection.call() `. @@ -283,4 +281,4 @@ Tarantool не имеет строгой схемы и поля кортежей .. seealso:: - Tarantool/Box User Guide » `Writing stored procedures in Lua `_ \ No newline at end of file + Tarantool documentation » `Insert one million tuples with a Lua stored procedure `_ diff --git a/doc/index.rst b/doc/index.rst index 346c656c..6f4ff0ca 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -1,7 +1,7 @@ .. encoding: utf-8 -Python client library for Tarantool Database -============================================ +Python client library for Tarantool +=================================== :Version: |version| @@ -12,13 +12,13 @@ Python client library for Tarantool Database **Install** - .. code-block:: none + .. code-block:: bash $ pip install tarantool -`Tarantool`_ is a damn fast key/value data store originally designed by -`Mail.Ru`_ and released under the terms of `BSD license`_. +`Tarantool`_ is a damn fast in-memory computing platform originally designed by +`VK`_ and released under the terms of `BSD license`_. @@ -30,7 +30,7 @@ Documentation quick-start.en guide.en -.. seealso:: `Tarantool/Box User Guide`_ +.. seealso:: `Tarantool documentation`_ API Reference @@ -55,9 +55,9 @@ API Reference .. _`Tarantool`: -.. _`Tarantool homepage`: http://tarantool.org -.. _`Tarantool/Box User Guide`: http://tarantool.org/doc/book/index.html -.. _`Mail.Ru`: http://mail.ru +.. _`Tarantool homepage`: https://tarantool.io +.. _`Tarantool documentation`: https://www.tarantool.io/en/doc/latest/ +.. _`VK`: https://vk.company .. _`BSD`: .. _`BSD license`: http://www.gnu.org/licenses/license-list.html#ModifiedBSD .. _`PyPI`: http://pypi.python.org/pypi/tarantool diff --git a/doc/index.ru.rst b/doc/index.ru.rst index ddf1b528..562dd6c6 100644 --- a/doc/index.ru.rst +++ b/doc/index.ru.rst @@ -1,7 +1,7 @@ .. encoding: utf-8 -Клиентская библиотека для базы данных Tarantool -=============================================== +Клиентская библиотека для платформы Tarantool +============================================= :Версия: |version| @@ -17,8 +17,8 @@ $ pip install tarantool -`Tarantool`_ – это очень быстрая in-memory база данных "ключ-значение". -Изначально разработана в `Mail.Ru`_ и выпущена под лицензией `BSD`_. +`Tarantool`_ – это очень быстрая платформа in-memory-вычислений. +Изначально разработана в `VK`_ и выпущена под лицензией `BSD`_. @@ -30,7 +30,7 @@ quick-start.ru guide.ru -.. seealso:: `Tarantool/Box User Guide`_ +.. seealso:: `Документация Tarantool`_ Справочник по API @@ -56,9 +56,9 @@ .. _`Tarantool`: -.. _`Tarantool homepage`: http://tarantool.org -.. _`Tarantool/Box User Guide`: http://tarantool.org/tarantool_user_guide.html -.. _`Mail.Ru`: http://mail.ru +.. _`Tarantool homepage`: https://tarantool.io +.. _`Документация Tarantool`: https://www.tarantool.io/en/doc/latest/ +.. _`VK`: https://vk.company .. _`BSD`: .. _`BSD license`: http://www.gnu.org/licenses/license-list.html#ModifiedBSD .. _`PyPI`: http://pypi.python.org/pypi/tarantool diff --git a/doc/quick-start.en.rst b/doc/quick-start.en.rst index 659c428d..4f024ef3 100644 --- a/doc/quick-start.en.rst +++ b/doc/quick-start.en.rst @@ -4,7 +4,7 @@ Quick start Connecting to the server ------------------------ -Create connection to the server:: +Create a connection to the server:: >>> import tarantool >>> server = tarantool.connect("localhost", 33013) @@ -13,17 +13,17 @@ Create connection to the server:: Creating a space instance ------------------------- -Instance of :class:`~tarantool.space.Space` is a named object to access +An instance of :class:`~tarantool.space.Space` is a named object to access the key space. -Create `` demo `` object which will be used to access the space `` 0 `` :: +Create a ``demo`` object that will be used to access the space ``cool_space`` :: - >>> demo = server.space(0) + >>> demo = server.space(cool_space) -All subsequent operations with space ``0`` performed using methods of the ``demo``. +All subsequent operations with ``cool_space`` are performed using the methods of ``demo``. -Data Manipulation +Data manipulation ----------------- Select @@ -43,7 +43,7 @@ Select several records using primary index:: Insert ^^^^^^ -Insert tuple ``('DDDD', 'Delta')`` into the space ``demo``:: +Insert the tuple ``('DDDD', 'Delta')`` into the space ``demo``:: >>> demo.insert(('DDDD', 'Delta')) @@ -59,40 +59,39 @@ into the field ``1``:: >>> demo.update('DDDD', [(1, '=', 'Denver')]) [('DDDD', 'Denver')] -To find the record :meth:`~tarantool.space.Space.update` always uses +To find the record, :meth:`~tarantool.space.Space.update` always uses the primary index. -Fields numbers are starting from zero. -So field ``0`` is the first element in the tuple. +Field numeration starts from zero, so the field ``0`` is the first element in the tuple. Delete ^^^^^^ -Delete single record identified by id ``'DDDD'``:: +Delete a single record identified by id ``'DDDD'``:: >>> demo.delete('DDDD') [('DDDD', 'Denver')] -To find the record :meth:`~tarantool.space.Space.delete` always uses +To find the record, :meth:`~tarantool.space.Space.delete` always uses the primary index. Call server-side functions -------------------------- -To call stored function method -:meth:`Connection.call() ` can be used:: +One of the ways to call a stored function is using +:meth:`Connection.call() `:: >>> server.call("box.select_range", (0, 0, 2, 'AAAA')) [('AAAA', 'Alpha'), ('BBBB', 'Bravo')] -The same can be done using -:meth:`Space.call() ` method:: +Another way is using +:meth:`Space.call() `:: - >>> demo = server.space(0) + >>> demo = server.space(``cool_space``) >>> demo.call("box.select_range", (0, 0, 2, 'AAAA')) [('AAAA', 'Alpha'), ('BBBB', 'Bravo')] -Method :meth:`Space.call() ` is just +The method :meth:`Space.call() ` is just an alias for -:meth:`Connection.call() ` +:meth:`Connection.call() `. diff --git a/doc/quick-start.ru.rst b/doc/quick-start.ru.rst index 6aae452c..5c9c0170 100644 --- a/doc/quick-start.ru.rst +++ b/doc/quick-start.ru.rst @@ -10,17 +10,17 @@ >>> server = tarantool.connect("localhost", 33013) -Создаем объект доступа к пространству -------------------------------------- +Создаем объект доступа к спейсу +------------------------------- -Экземпляр :class:`~tarantool.space.Space` - это именованный объект для доступа -к пространству ключей. +Экземпляр :class:`~tarantool.space.Space` — это именованный объект для доступа +к спейсу ключей. -Создаем объект ``demo``, который будет использоваться для доступа к пространству ``0``:: +Создаем объект ``demo``, который будет использоваться для доступа к спейсу ``cool_space``:: - >>> demo = server.space(0) + >>> demo = server.space(cool_space) -Все последующие операции с пространством ``0`` выполняются при помощи методов объекта ``demo``. +Все последующие операции с ``cool_space`` выполняются при помощи методов объекта ``demo``. Работа с данными @@ -29,12 +29,12 @@ Select ^^^^^^ -Извлечь одну запись с id ``'AAAA'`` из пространства ``demo`` +Извлечь одну запись с id ``'AAAA'`` из спейса ``demo`` по первичному ключу (нулевой индекс):: >>> demo.select('AAAA') -Извлечь несколько записей используя первичный индекс:: +Извлечь несколько записей, используя первичный индекс:: >>> demo.select(['AAAA', 'BBBB', 'CCCC']) [('AAAA', 'Alpha'), ('BBBB', 'Bravo'), ('CCCC', 'Charlie')] @@ -43,11 +43,11 @@ Select Insert ^^^^^^ -Вставить кортеж ``('DDDD', 'Delta')`` в пространство ``demo``:: +Вставить кортеж ``('DDDD', 'Delta')`` в спейс ``demo``:: >>> demo.insert(('DDDD', 'Delta')) -Первый элемент является первичным ключом для данного кортежа. +Первый элемент является первичным ключом для этого кортежа. Update @@ -59,10 +59,10 @@ Update >>> demo.update('DDDD', [(1, '=', 'Denver')]) [('DDDD', 'Denver')] -Для поиска записи :meth:`~tarantool.space.Space.update` всгеда использует +Для поиска записи :meth:`~tarantool.space.Space.update` всегда использует первичный индекс. Номера полей начинаются с нуля. -Таким образом, поле ``0`` - это первый элемент кортежа. +Таким образом, поле ``0`` — это первый элемент кортежа. Delete @@ -73,7 +73,7 @@ Delete >>> demo.delete('DDDD') [('DDDD', 'Denver')] -Для поиска записи :meth:`~tarantool.space.Space.delete` всгеда использует +Для поиска записи :meth:`~tarantool.space.Space.delete` всегда использует первичный индекс. @@ -86,12 +86,12 @@ Delete >>> server.call("box.select_range", (0, 0, 2, 'AAAA')) [('AAAA', 'Alpha'), ('BBBB', 'Bravo')] -Тоже самое можно получить при помощи метода +То же самое можно получить при помощи метода :meth:`Space.call() `:: >>> demo.call("box.select_range", (0, 0, 2, 'AAAA')) [('AAAA', 'Alpha'), ('BBBB', 'Bravo')] -Метод :meth:`Space.call() ` - это просто +Метод :meth:`Space.call() ` — это просто псевдоним для :meth:`Connection.call() ` diff --git a/tarantool/__init__.py b/tarantool/__init__.py index 4a9e7345..3d4a19a8 100644 --- a/tarantool/__init__.py +++ b/tarantool/__init__.py @@ -70,9 +70,9 @@ def connect(host="localhost", port=33013, user=None, password=None, def connectmesh(addrs=({'host': 'localhost', 'port': 3301},), user=None, password=None, encoding=ENCODING_DEFAULT): ''' - Create a connection to the mesh of Tarantool servers. + Create a connection to a mesh of Tarantool servers. - :param list addrs: A list of maps: {'host':(HOSTNAME|IP_ADDR), 'port':PORT}. + :param list addrs: List of maps: {'host':(HOSTNAME|IP_ADDR), 'port':PORT}. :rtype: :class:`~tarantool.mesh_connection.MeshConnection` diff --git a/tarantool/connection.py b/tarantool/connection.py index b6c20a4f..702254a1 100644 --- a/tarantool/connection.py +++ b/tarantool/connection.py @@ -180,7 +180,7 @@ class Connection(ConnectionInterface): This class is responsible for connection and network exchange with the server. - Also this class provides low-level interface to data manipulation + It also provides a low-level interface for data manipulation (insert/delete/update/select). ''' # DBAPI Extension: supply exceptions as attributes on the connection @@ -217,24 +217,25 @@ def __init__(self, host, port, ''' Initialize a connection to the server. - :param str host: Server hostname or IP-address - :param int port: Server port - :param bool connect_now: if True (default) than __init__() actually - creates network connection. if False than you have to call - connect() manualy. - :param str transport: It enables SSL encryption for a connection if set - to ssl. At least Python 3.5 is required for SSL encryption. - :param str ssl_key_file: A path to a private SSL key file. - :param str ssl_cert_file: A path to an SSL certificate file. - :param str ssl_ca_file: A path to a trusted certificate authorities - (CA) file. - :param str ssl_ciphers: A colon-separated (:) list of SSL cipher suites - the connection can use. + :param str host: server hostname or IP address + :param int port: server port + :param bool connect_now: if True (default), __init__() actually + creates a network connection; if False, you have to call + connect() manually + :param str transport: set to `ssl` to enable + SSL encryption for a connection. + SSL encryption requires Python >= 3.5 + :param str ssl_key_file: path to the private SSL key file + :param str ssl_cert_file: path to the SSL certificate file + :param str ssl_ca_file: path to the trusted certificate authority + (CA) file + :param str ssl_ciphers: colon-separated (:) list of SSL cipher suites + the connection can use ''' if msgpack.version >= (1, 0, 0) and encoding not in (None, 'utf-8'): - raise ConfigurationError("Only None and 'utf-8' encoding option " + - "values are supported with msgpack>=1.0.0") + raise ConfigurationError("msgpack>=1.0.0 only supports None and " + + "'utf-8' encoding option values") if os.name == 'nt': libc = ctypes.WinDLL( @@ -272,14 +273,14 @@ def __init__(self, host, port, def close(self): ''' - Close connection to the server + Close a connection to the server. ''' self._socket.close() self._socket = None def is_closed(self): ''' - Returns the state of the Connection instance + Returns the state of a Connection instance. :rtype: Boolean ''' return self._socket is None @@ -292,7 +293,7 @@ def connect_basic(self): def connect_tcp(self): ''' - Create connection to the host and port specified in __init__(). + Create a connection to the host and port specified in __init__(). :raise: `NetworkError` ''' @@ -312,7 +313,7 @@ def connect_tcp(self): def connect_unix(self): ''' - Create connection to the host and port specified in __init__(). + Create a connection to the host and port specified in __init__(). :raise: `NetworkError` ''' @@ -332,13 +333,13 @@ def connect_unix(self): def wrap_socket_ssl(self): ''' - Wrap an existing socket with SSL socket. + Wrap an existing socket with an SSL socket. :raise: SslError :raise: `ssl.SSLError` ''' if not is_ssl_supported: - raise SslError("SSL is unsupported by the python.") + raise SslError("Your version of Python doesn't support SSL") ver = sys.version_info if ver[0] < 3 or (ver[0] == 3 and ver[1] < 5): @@ -347,8 +348,8 @@ def wrap_socket_ssl(self): if ((self.ssl_cert_file is None and self.ssl_key_file is not None) or (self.ssl_cert_file is not None and self.ssl_key_file is None)): - raise SslError("ssl_cert_file and ssl_key_file should be both " + - "configured or not") + raise SslError("Both ssl_cert_file and ssl_key_file should be " + + "configured or unconfigured") try: if hasattr(ssl, 'TLSVersion'): @@ -375,7 +376,7 @@ def wrap_socket_ssl(self): # interaction with a human + a Tarantool implementation does # not support this at least for now. def password_raise_error(): - raise SslError("a password for decrypting the private " + + raise SslError("Password for decrypting the private " + "key is unsupported") context.load_cert_chain(certfile=self.ssl_cert_file, keyfile=self.ssl_key_file, @@ -410,9 +411,9 @@ def handshake(self): def connect(self): ''' - Create connection to the host and port specified in __init__(). - Usually there is no need to call this method directly, - since it is called when you create an `Connection` instance. + Create a connection to the host and port specified in __init__(). + Usually, there is no need to call this method directly, + because it is called when you create a `Connection` instance. :raise: `NetworkError` :raise: `SslError` @@ -438,7 +439,7 @@ def _recv(self, to_read): self._socket.close() err = socket.error( errno.ECONNRESET, - "Too big packet. Closing connection to server" + "Packet too large. Closing connection to server" ) raise NetworkError(err) except socket.error: @@ -460,7 +461,7 @@ def _recv(self, to_read): def _read_response(self): ''' - Read response from the transport (socket) + Read response from the transport (socket). :return: tuple of the form (header, body) :rtype: tuple of two byte arrays @@ -492,8 +493,9 @@ def _send_request_wo_reconnect(self, request): def _opt_reconnect(self): ''' - Check that connection is alive using low-level recv from libc(ctypes) - **Due to bug in python - timeout is internal python construction. + Check that the connection is alive + using low-level recv from libc(ctypes). + **Bug in Python: timeout is an internal Python construction. ''' if not self._socket: return self.connect() @@ -545,7 +547,7 @@ def check(): # Check that connection is alive else: if self.connected: break - warn("Reconnect attempt %d of %d" % + warn("Reconnecting, attempt %d of %d" % (attempt, self.reconnect_max_attempts), NetworkWarning) if attempt == self.reconnect_max_attempts: raise NetworkError( @@ -557,8 +559,8 @@ def check(): # Check that connection is alive def _send_request(self, request): ''' - Send the request to the server through the socket. - Return an instance of `Response` class. + Send a request to the server through the socket. + Return an instance of the `Response` class. :param request: object representing a request :type request: `Request` instance @@ -585,7 +587,7 @@ def flush_schema(self): def call(self, func_name, *args): ''' - Execute CALL request. Call stored Lua function. + Execute a CALL request. Call a stored Lua function. :param func_name: stored Lua function name :type func_name: str @@ -606,7 +608,7 @@ def call(self, func_name, *args): def eval(self, expr, *args): ''' - Execute EVAL request. Eval Lua expression. + Execute an EVAL request. Eval a Lua expression. :param expr: Lua expression :type expr: str @@ -627,8 +629,8 @@ def eval(self, expr, *args): def replace(self, space_name, values): ''' - Execute REPLACE request. - It won't throw error if there's no tuple with this PK exists + Execute a REPLACE request. + Doesn't throw an error if there is no tuple with the specified PK. :param int space_name: space id to insert a record :type space_name: int or str @@ -645,9 +647,9 @@ def replace(self, space_name, values): def authenticate(self, user, password): ''' - Execute AUTHENTICATE request. + Execute an AUTHENTICATE request. - :param string user: user to authenticate with + :param string user: user to authenticate :param string password: password for the user :rtype: `Response` instance @@ -720,10 +722,10 @@ def subscribe(self, cluster_uuid, server_uuid, vclock=None): def insert(self, space_name, values): ''' - Execute INSERT request. - It will throw error if there's tuple with same PK exists. + Execute an INSERT request. + Throws an error if there is a tuple with the same PK. - :param int space_name: space id to insert a record + :param int space_name: space id to insert the record :type space_name: int or str :param values: record to be inserted. The tuple must contain only scalar (integer or strings) values @@ -739,7 +741,7 @@ def insert(self, space_name, values): def delete(self, space_name, key, **kwargs): ''' Execute DELETE request. - Delete single record identified by `key`. If you're using secondary + Delete a single record identified by `key`. If you're using a secondary index, it must be unique. :param space_name: space number or name to delete a record @@ -763,33 +765,33 @@ def upsert(self, space_name, tuple_value, op_list, **kwargs): ''' Execute UPSERT request. - If there is an existing tuple which matches the key fields of + If an existing tuple matches the key fields of `tuple_value`, then the request has the same effect as UPDATE and the [(field_1, symbol_1, arg_1), ...] parameter is used. - If there is no existing tuple which matches the key fields of + If there is no tuple matching the key fields of `tuple_value`, then the request has the same effect as INSERT and the `tuple_value` parameter is used. However, unlike insert - or update, upsert will not read a tuple and perform error checks + or update, upsert will neither read the tuple nor perform error checks before returning -- this is a design feature which enhances throughput but requires more caution on the part of the user. - If you're using secondary index, it must be unique. + If you're using a secondary index, it must be unique. - List of operations allows to update individual fields. + The list of operations allows updating individual fields. + + For every operation, you must provide the field number to apply this + operation to. *Allowed operations:* - (For every operation you must provide field number, to apply this - operation to) - * `+` for addition (values must be numeric) * `-` for subtraction (values must be numeric) * `&` for bitwise AND (values must be unsigned numeric) * `|` for bitwise OR (values must be unsigned numeric) * `^` for bitwise XOR (values must be unsigned numeric) - * `:` for string splice (you must provide `offset`, `count` and `value` - for this operation) + * `:` for string splice (you must provide `offset`, `count`, + and `value` for this operation) * `!` for insertion (provide any element to insert) * `=` for assignment (provide any element to assign) * `#` for deletion (provide count of fields to delete) @@ -798,11 +800,11 @@ def upsert(self, space_name, tuple_value, op_list, **kwargs): :type space_name: int or str :param index: index number or name to update a record :type index: int or str - :param tuple_value: tuple, that + :param tuple_value: tuple :type tuple_value: :param op_list: list of operations. Each operation - is tuple of three (or more) values - :type op_list: a list of the form [(symbol_1, field_1, arg_1), + is a tuple of three (or more) values + :type op_list: list of the form [(symbol_1, field_1, arg_1), (symbol_2, field_2, arg_2_1, arg_2_2, arg_2_3),...] :rtype: `Response` instance @@ -811,14 +813,15 @@ def upsert(self, space_name, tuple_value, op_list, **kwargs): .. code-block:: python - # 'ADD' 55 to second field - # Assign 'x' to third field + # 'ADD' 55 to the second field + # Assign 'x' to the third field [('+', 2, 55), ('=', 3, 'x')] - # 'OR' third field with '1' - # Cut three symbols starting from second and replace them with '!!' - # Insert 'hello, world' field before fifth element of tuple + # 'OR' the third field with '1' + # Cut three symbols, starting from the second, + # and replace them with '!!' + # Insert 'hello, world' field before the fifth element of the tuple [('|', 3, 1), (':', 2, 2, 3, '!!'), ('!', 5, 'hello, world')] - # Delete two fields starting with second field + # Delete two fields, starting with the second field [('#', 2, 2)] ''' index_name = kwargs.get("index", 0) @@ -834,29 +837,29 @@ def upsert(self, space_name, tuple_value, op_list, **kwargs): def update(self, space_name, key, op_list, **kwargs): ''' - Execute UPDATE request. + Execute an UPDATE request. The `update` function supports operations on fields — assignment, arithmetic (if the field is unsigned numeric), cutting and pasting - fragments of a field, deleting or inserting a field. Multiple + fragments of the field, deleting or inserting a field. Multiple operations can be combined in a single update request, and in this case they are performed atomically and sequentially. Each operation - requires specification of a field number. When multiple operations are - present, the field number for each operation is assumed to be relative + requires that you specify a field number. With multiple operations, + the field number for each operation is assumed to be relative to the most recent state of the tuple, that is, as if all previous - operations in a multi-operation update have already been applied. + operations in the multi-operation update have already been applied. In other words, it is always safe to merge multiple update invocations into a single invocation, with no change in semantics. - Update single record identified by `key`. + Update a single record identified by `key`. - List of operations allows to update individual fields. + The list of operations allows updating individual fields. + + For every operation, you must provide the field number to apply this + operation to. *Allowed operations:* - (For every operation you must provide field number, to apply this - operation to) - * `+` for addition (values must be numeric) * `-` for subtraction (values must be numeric) * `&` for bitwise AND (values must be unsigned numeric) @@ -868,15 +871,15 @@ def update(self, space_name, key, op_list, **kwargs): * `=` for assignment (provide any element to assign) * `#` for deletion (provide count of fields to delete) - :param space_name: space number or name to update a record + :param space_name: space number or name to update the record :type space_name: int or str - :param index: index number or name to update a record + :param index: index number or name to update the record :type index: int or str - :param key: key that identifies a record + :param key: key that identifies the record :type key: int or str :param op_list: list of operations. Each operation - is tuple of three (or more) values - :type op_list: a list of the form [(symbol_1, field_1, arg_1), + is a tuple of three (or more) values + :type op_list: list of the form [(symbol_1, field_1, arg_1), (symbol_2, field_2, arg_2_1, arg_2_2, arg_2_3), ...] :rtype: ``Response`` instance @@ -886,13 +889,14 @@ def update(self, space_name, key, op_list, **kwargs): .. code-block:: python # 'ADD' 55 to second field - # Assign 'x' to third field + # Assign 'x' to the third field [('+', 2, 55), ('=', 3, 'x')] - # 'OR' third field with '1' - # Cut three symbols starting from second and replace them with '!!' - # Insert 'hello, world' field before fifth element of tuple + # 'OR' the third field with '1' + # Cut three symbols, starting from second, + # and replace them with '!!' + # Insert 'hello, world' field before the fifth element of the tuple [('|', 3, 1), (':', 2, 2, 3, '!!'), ('!', 5, 'hello, world')] - # Delete two fields starting with second field + # Delete two fields, starting with the second field [('#', 2, 2)] ''' index_name = kwargs.get("index", 0) @@ -908,8 +912,8 @@ def update(self, space_name, key, op_list, **kwargs): def ping(self, notime=False): ''' - Execute PING request. - Send empty request and receive empty response from server. + Execute a PING request. + Send an empty request and receive an empty response from the server. :return: response time in seconds :rtype: float @@ -926,15 +930,15 @@ def ping(self, notime=False): def select(self, space_name, key=None, **kwargs): ''' - Execute SELECT request. + Execute a SELECT request. Select and retrieve data from the database. - :param space_name: specifies which space to query + :param space_name: space to query :type space_name: int or str - :param values: values to search over the index + :param values: values to search by index :type values: list, tuple, set, frozenset of tuples - :param index: specifies which index to use (default is **0** which - means that the **primary index** will be used) + :param index: index to search by (default is **0**, which + means that the **primary index** is used) :type index: int or str :param offset: offset in the resulting tuple set :type offset: int @@ -943,13 +947,13 @@ def select(self, space_name, key=None, **kwargs): :rtype: `Response` instance - You may use names for index/space. Matching id's -> names connector - will get from server. + You can use index/space names. The driver will get + the matching id's -> names from the server. - Select one single record (from space=0 and using index=0) + Select a single record (from space=0 and using index=0) >>> select(0, 1) - Select single record from space=0 (with name='space') using + Select a single record from space=0 (with name='space') using composite index=1 (with name '_name'). >>> select(0, [1,'2'], index=1) # OR @@ -992,10 +996,11 @@ def select(self, space_name, key=None, **kwargs): def space(self, space_name): ''' - Create `Space` instance for particular space + Create a `Space` instance for a particular space. - `Space` instance encapsulates the identifier of the space and provides - more convenient syntax for accessing the database space. + A `Space` instance encapsulates the identifier + of the space and provides a more convenient syntax + for accessing the database space. :param space_name: identifier of the space :type space_name: int or str @@ -1006,19 +1011,19 @@ def space(self, space_name): def generate_sync(self): ''' - Need override for async io connection + Need override for async io connection. ''' return 0 def execute(self, query, params=None): ''' - Execute SQL request. + Execute an SQL request. - Tarantool binary protocol for SQL requests + The Tarantool binary protocol for SQL requests supports "qmark" and "named" param styles. - Sequence of values can be used for "qmark" style. + A sequence of values can be used for "qmark" style. A mapping is used for "named" param style - without leading colon in the keys. + without the leading colon in the keys. Example for "qmark" arguments: >>> args = ['email@example.com'] @@ -1031,7 +1036,7 @@ def execute(self, query, params=None): :param query: SQL syntax query :type query: str - :param params: Bind values to use in the query. + :param params: bind values to use in the query :type params: list, dict :return: query result data diff --git a/tarantool/connection_pool.py b/tarantool/connection_pool.py index 73e2c3c8..6bf78a54 100644 --- a/tarantool/connection_pool.py +++ b/tarantool/connection_pool.py @@ -182,23 +182,23 @@ class PoolTask(): class ConnectionPool(ConnectionInterface): ''' - Represents pool of connections to the cluster of Tarantool servers. + Represents the pool of connections to a cluster of Tarantool servers. - ConnectionPool API is the same as a plain Connection API. - On each request, a connection is chosen to execute this request. - Connection is selected based on request mode: + ConnectionPool API is the same as Connection API. + On each request, a connection is chosen to execute the request. + The connection is selected based on request mode: * Mode.ANY chooses any instance. * Mode.RW chooses an RW instance. * Mode.RO chooses an RO instance. - * Mode.PREFER_RW chooses an RW instance, if possible, RO instance + * Mode.PREFER_RW chooses an RW instance, if possible, an RO instance otherwise. - * Mode.PREFER_RO chooses an RO instance, if possible, RW instance + * Mode.PREFER_RO chooses an RO instance, if possible, an RW instance otherwise. - All requests that are guaranteed to write (insert, replace, delete, - upsert, update) use RW mode by default. select uses ANY by default. You - can set the mode explicitly. call, eval, execute and ping requests + All requests that guarantee to write data (insert, replace, delete, + upsert, update) use the RW mode by default. select uses ANY by default. You + can set the mode explicitly. The call, eval, execute, and ping requests require to set the mode explicitly. ''' def __init__(self, @@ -215,7 +215,7 @@ def __init__(self, strategy_class=RoundRobinStrategy, refresh_delay=POOL_REFRESH_DELAY): ''' - Initialize connections to the cluster of servers. + Initialize connections to a cluster of servers. :param list addrs: List of @@ -231,11 +231,11 @@ def __init__(self, ssl_ciphers: "str" # optional } - dictionaries, describing server addresses. - See :func:`tarantool.Connection` parameters with same names. + dictionaries describing server addresses. + See similar :func:`tarantool.Connection` parameters. :param str user: Username used to authenticate. User must be able - to call box.info function. For example, to give grants to - 'guest' user, evaluate + to call the box.info function. For example, to grant permissions to + the 'guest' user, evaluate: box.schema.func.create('box.info') box.schema.user.grant('guest', 'execute', 'function', 'box.info') on Tarantool instances. @@ -249,7 +249,7 @@ def __init__(self, reconnect parameters in ConnectionPool since every status refresh is also a request with reconnection. Default is 0. :param StrategyInterface strategy_class: Class for choosing - instance based on request mode. By default, round-robin + instance based on request mode. By default, the round-robin strategy is used. :param int refresh_delay: Minimal time between RW/RO status refreshes. diff --git a/tarantool/dbapi.py b/tarantool/dbapi.py index 9f4e1e10..cda09948 100644 --- a/tarantool/dbapi.py +++ b/tarantool/dbapi.py @@ -21,9 +21,10 @@ def callproc(self, procname, *params): """ Call a stored database procedure with the given name. The sequence of parameters must contain one entry for each argument that the - procedure expects. The result of the call is returned as modified - copy of the input sequence. Input parameters are left untouched, - output and input/output parameters replaced with possibly new values. + procedure expects. The result of the call is returned as a modified + copy of the input sequence. The input parameters are left untouched, + the output and input/output parameters replaced with + possibly new values. """ raise NotSupportedError("callproc() method is not supported") diff --git a/tarantool/mesh_connection.py b/tarantool/mesh_connection.py index 97631b77..09596d94 100644 --- a/tarantool/mesh_connection.py +++ b/tarantool/mesh_connection.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- ''' -This module provides MeshConnection class with automatic switch -between tarantool instances and basic Round-Robin strategy. +This module provides the MeshConnection class with automatic switch +between Tarantool instances by the basic round-robin strategy. ''' import time @@ -204,15 +204,16 @@ class MeshConnection(Connection): Represents a connection to a cluster of Tarantool servers. This class uses Connection to connect to one of the nodes of the cluster. - The initial list of nodes is passed to the constructor in 'addrs' parameter. - The class set in 'strategy_class' parameter is used to select a node from - the list and switch nodes in case of unavailability of the current node. + The initial list of nodes is passed to the constructor in the + 'addrs' parameter. The class set in the 'strategy_class' parameter + is used to select a node from the list and switch nodes in case the + current node is unavailable. - 'cluster_discovery_function' param of the constructor sets the name of a - stored Lua function used to refresh the list of available nodes. The - function takes no parameters and returns a list of strings in format - 'host:port'. A generic function for getting the list of nodes looks like - this: + The 'cluster_discovery_function' param of the constructor sets the name + of the stored Lua function used to refresh the list of available nodes. + The function takes no parameters and returns a list of strings in the + format 'host:port'. A generic function for getting the list of nodes + looks like this: .. code-block:: lua @@ -224,9 +225,9 @@ class MeshConnection(Connection): } end - You may put in this list whatever you need depending on your cluster - topology. Chances are you'll want to make the list of nodes from nodes' - replication config. Here is an example for it: + You can put in this list whatever you need, depending on your + cluster topology. Chances are you'll want to derive the list of nodes + from the nodes' replication configuration. Here is an example: .. code-block:: lua @@ -245,7 +246,7 @@ class MeshConnection(Connection): end end - -- if your replication config doesn't contain the current node + -- if your replication config doesn't contain the current node, -- you have to add it manually like this: table.insert(nodes, '192.168.0.1:3301') @@ -354,8 +355,8 @@ def _opt_reconnect(self): def _opt_refresh_instances(self): ''' - Refresh list of tarantool instances in a cluster. - Reconnect if a current instance was gone from the list. + Refresh the list of tarantool instances in a cluster. + Reconnect if the current instance has disappeared from the list. ''' now = time.time() @@ -370,14 +371,14 @@ def _opt_refresh_instances(self): try: resp = self._send_request_wo_reconnect(request) except DatabaseError as e: - msg = 'got "%s" error, skipped addresses updating' % str(e) + msg = 'got "%s" error, skipped address updates' % str(e) warn(msg, ClusterDiscoveryWarning) return if not resp.data or not resp.data[0] or \ not isinstance(resp.data[0], list): msg = "got incorrect response instead of URI list, " + \ - "skipped addresses updating" + "skipped address updates" warn(msg, ClusterDiscoveryWarning) return @@ -397,7 +398,7 @@ def _opt_refresh_instances(self): new_addrs.append(new_addr) if not new_addrs: - msg = "got no correct URIs, skipped addresses updating" + msg = "got no correct URIs, skipped address updates" warn(msg, ClusterDiscoveryWarning) return @@ -421,11 +422,12 @@ def _opt_refresh_instances(self): def _send_request(self, request): ''' - Update instances list if "cluster_discovery_function" is provided and a - last update was more then "cluster_discovery_delay" seconds ago. + Update the instances list if `cluster_discovery_function` + is provided and the last update was more than + `cluster_discovery_delay` seconds ago. - After that perform a request as usual and return an instance of - `Response` class. + After that, perform a request as usual and return an instance of + the `Response` class. :param request: object representing a request :type request: `Request` instance diff --git a/tarantool/response.py b/tarantool/response.py index 24464fda..177fd146 100644 --- a/tarantool/response.py +++ b/tarantool/response.py @@ -35,15 +35,16 @@ class Response(Sequence): Represents a single response from the server in compliance with the Tarantool protocol. Responsible for data encapsulation (i.e. received list of tuples) - and parses binary packet received from the server. + and parsing of binary packets received from the server. ''' def __init__(self, conn, response): ''' - Create an instance of `Response` using data received from the server. + Create an instance of `Response` + using the data received from the server. - __init__() itself reads data from the socket, parses response body and - sets appropriate instance attributes. + __init__() reads data from the socket, parses the response body, and + sets the appropriate instance attributes. :param body: body of the response :type body: array of bytes @@ -125,37 +126,37 @@ def __init__(self, conn, response): def __getitem__(self, idx): if self._data is None: - raise InterfaceError("Trying to access data, when there's no data") + raise InterfaceError("Trying to access data when there's no data") return self._data.__getitem__(idx) def __len__(self): if self._data is None: - raise InterfaceError("Trying to access data, when there's no data") + raise InterfaceError("Trying to access data when there's no data") return len(self._data) def __contains__(self, item): if self._data is None: - raise InterfaceError("Trying to access data, when there's no data") + raise InterfaceError("Trying to access data when there's no data") return item in self._data def __iter__(self): if self._data is None: - raise InterfaceError("Trying to access data, when there's no data") + raise InterfaceError("Trying to access data when there's no data") return iter(self._data) def __reversed__(self): if self._data is None: - raise InterfaceError("Trying to access data, when there's no data") + raise InterfaceError("Trying to access data when there's no data") return reversed(self._data) def index(self, *args): if self._data is None: - raise InterfaceError("Trying to access data, when there's no data") + raise InterfaceError("Trying to access data when there's no data") return self._data.index(*args) def count(self, item): if self._data is None: - raise InterfaceError("Trying to access data, when there's no data") + raise InterfaceError("Trying to access data when there's no data") return self._data.count(item) @property @@ -173,7 +174,7 @@ def body(self): :type: dict Required field in the server response. - Contains raw response body. + Contains the raw response body. ''' return self._body @@ -183,7 +184,7 @@ def code(self): :type: int Required field in the server response. - Contains response type id. + Contains the response type id. ''' return self._code @@ -193,7 +194,7 @@ def sync(self): :type: int Required field in the server response. - Contains response header IPROTO_SYNC. + Contains the response header IPROTO_SYNC. ''' return self._sync @@ -203,9 +204,10 @@ def return_code(self): :type: int Required field in the server response. - Value of :attr:`return_code` can be ``0`` if request was sucessfull - or contains an error code. - If :attr:`return_code` is non-zero than :attr:`return_message` + If the request was successful, + the value of :attr:`return_code` is ``0``. + Otherwise, :attr:`return_code` contains an error code. + If :attr:`return_code` is non-zero, :attr:`return_message` contains an error message. ''' return self._return_code @@ -216,7 +218,7 @@ def data(self): :type: object Required field in the server response. - Contains list of tuples of SELECT, REPLACE and DELETE requests + Contains the list of tuples for SELECT, REPLACE and DELETE requests and arbitrary data for CALL. ''' return self._data @@ -226,8 +228,8 @@ def strerror(self): ''' :type: str - It may be ER_OK if request was successful, - or contain error code string. + Contains ER_OK if the request was successful, + or contains an error code string. ''' return tnt_strerror(self._return_code) @@ -237,7 +239,7 @@ def return_message(self): :type: str The error message returned by the server in case - of :attr:`return_code` is non-zero. + :attr:`return_code` is non-zero. ''' return self._return_message @@ -252,8 +254,8 @@ def schema_version(self): def __str__(self): ''' - Return user friendy string representation of the object. - Useful for the interactive sessions and debuging. + Return a user-friendy string representation of the object. + Useful for interactive sessions and debuging. :rtype: str or None ''' @@ -281,7 +283,7 @@ def autoincrement_ids(self): Returns a list with the new primary-key value (or values) for an INSERT in a table defined with PRIMARY KEY AUTOINCREMENT - (NOT result set size) + (NOT result set size). :rtype: list or None """ diff --git a/tarantool/schema.py b/tarantool/schema.py index 8d0ec790..ba34885a 100644 --- a/tarantool/schema.py +++ b/tarantool/schema.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # pylint: disable=R0903 ''' -This module provides :class:`~tarantool.schema.Schema` class. +This module provides the :class:`~tarantool.schema.Schema` class. It is a Tarantool schema description. ''' @@ -20,7 +20,7 @@ class RecursionError(Error): """Report the situation when max recursion depth is reached. - This is internal error for caller + This is an internal error of caller, and it should be re-raised properly be the caller. """ @@ -32,8 +32,8 @@ def to_unicode(s): def to_unicode_recursive(x, max_depth): - """Same as to_unicode(), but traverses over dictionaries, - lists and tuples recursivery. + """Same as to_unicode(), but traverses recursively over dictionaries, + lists and tuples. x: value to convert diff --git a/tarantool/space.py b/tarantool/space.py index 53f40dc7..9c3f9fdc 100644 --- a/tarantool/space.py +++ b/tarantool/space.py @@ -1,15 +1,15 @@ # -*- coding: utf-8 -*- # pylint: disable=C0301,W0105,W0401,W0614 ''' -This module provides :class:`~tarantool.space.Space` class. -It is an object-oriented wrapper for request over Tarantool space. +This module provides the :class:`~tarantool.space.Space` class. +It is an object-oriented wrapper for requests to a Tarantool space. ''' class Space(object): ''' Object-oriented wrapper for accessing a particular space. - Encapsulates the identifier of the space and provides more convenient + Encapsulates the identifier of the space and provides a more convenient syntax for database operations. ''' @@ -17,7 +17,7 @@ def __init__(self, connection, space_name): ''' Create Space instance. - :param connection: Object representing connection to the server + :param connection: object representing connection to the server :type connection: :class:`~tarantool.connection.Connection` instance :param int space_name: space no or name to insert a record :type space_name: int or str @@ -28,56 +28,56 @@ def __init__(self, connection, space_name): def insert(self, *args, **kwargs): ''' - Execute INSERT request. + Execute an INSERT request. - See `~tarantool.connection.insert` for more information + See `~tarantool.connection.insert` for more information. ''' return self.connection.insert(self.space_no, *args, **kwargs) def replace(self, *args, **kwargs): ''' - Execute REPLACE request. + Execute a REPLACE request. - See `~tarantool.connection.replace` for more information + See `~tarantool.connection.replace` for more information. ''' return self.connection.replace(self.space_no, *args, **kwargs) def delete(self, *args, **kwargs): ''' - Execute DELETE request. + Execute a DELETE request. - See `~tarantool.connection.delete` for more information + See `~tarantool.connection.delete` for more information. ''' return self.connection.delete(self.space_no, *args, **kwargs) def update(self, *args, **kwargs): ''' - Execute UPDATE request. + Execute an UPDATE request. - See `~tarantool.connection.update` for more information + See `~tarantool.connection.update` for more information. ''' return self.connection.update(self.space_no, *args, **kwargs) def upsert(self, *args, **kwargs): ''' - Execute UPDATE request. + Execute an UPDATE request. - See `~tarantool.connection.upsert` for more information + See `~tarantool.connection.upsert` for more information. ''' return self.connection.upsert(self.space_no, *args, **kwargs) def select(self, *args, **kwargs): ''' - Execute SELECT request. + Execute a SELECT request. - See `~tarantool.connection.select` for more information + See `~tarantool.connection.select` for more information. ''' return self.connection.select(self.space_no, *args, **kwargs) def call(self, func_name, *args, **kwargs): ''' - Execute CALL request. Call stored Lua function. + Execute a CALL request. Call a stored Lua function. - It's deprecated, use `~tarantool.connection.call` instead + Deprecated, use `~tarantool.connection.call` instead. ''' return self.connection.call(func_name, *args, **kwargs)