diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 00000000..07b7645f --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,18 @@ +name: Deploy Sphinx documentation to Github Pages + +on: + push: + branches: [main] # branch to trigger deployment + +jobs: + pages: + runs-on: ubuntu-20.04 + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + permissions: + pages: write + id-token: write + steps: + - id: deployment + uses: sphinx-notes/pages@v3 \ No newline at end of file diff --git a/README.md b/README.md index cfc57eb2..db7c3de2 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,12 @@ YDB Python SDK Officially supported Python client for YDB. +--- + +**Documentation**: https://ydb-platform.github.io/ydb-python-sdk + +--- + ## Quickstart ### Prerequisites diff --git a/docs/_static/logo.svg b/docs/_static/logo.svg new file mode 100644 index 00000000..0a813215 --- /dev/null +++ b/docs/_static/logo.svg @@ -0,0 +1,4 @@ + + + + diff --git a/docs/apireference.rst b/docs/apireference.rst new file mode 100644 index 00000000..1d6a2821 --- /dev/null +++ b/docs/apireference.rst @@ -0,0 +1,244 @@ +YDB API Reference +================= + +.. toctree:: + :caption: Contents: + + +.. module:: ydb + +Driver +------ + +DriverConfig +^^^^^^^^^^^^ + +.. autoclass:: ydb.DriverConfig + :members: + :inherited-members: + :undoc-members: + :exclude-members: database, ca_cert, channel_options, secure_channel, endpoint, endpoints, credentials, use_all_nodes, root_certificates, certificate_chain, private_key, grpc_keep_alive_timeout, table_client_settings, primary_user_agent + + +Driver +^^^^^^ + +.. autoclass:: ydb.Driver + :members: + :inherited-members: + :undoc-members: + + +Driver (AsyncIO) +^^^^^^^^^^^^^^^ + +.. autoclass:: ydb.aio.Driver + :members: + :inherited-members: + :undoc-members: + +------------------------ + +Common +------------- + +BaseRequestSettings +^^^^^^^^^^^^^^^^^^^ + +.. autoclass:: ydb.BaseRequestSettings + :members: + :inherited-members: + :undoc-members: + :exclude-members: trace_id, request_type, timeout, cancel_after, operation_timeout, compression, need_rpc_auth, headers, make_copy, tracer + + +RetrySettings +^^^^^^^^^^^^^ + +.. autoclass:: ydb.RetrySettings + :members: + :inherited-members: + :undoc-members: + + +Result Sets +^^^^^^^^^^^ + +.. autoclass:: ydb.convert._ResultSet + :members: + :inherited-members: + :undoc-members: + + +------------------------ + +Query Service +------------- + +QueryClientSettings +^^^^^^^^^^^^^^^^^^^ + +.. autoclass:: ydb.QueryClientSettings + :members: + :inherited-members: + :undoc-members: + + +QuerySessionPool +^^^^^^^^^^^^^^^^ + +.. autoclass:: ydb.QuerySessionPool + :members: + :inherited-members: + :undoc-members: + +QuerySession +^^^^^^^^^^^^ + +.. autoclass:: ydb.QuerySession + :members: + :inherited-members: + :undoc-members: + + +QueryTxContext +^^^^^^^^^^^^^^ + +.. autoclass:: ydb.QueryTxContext + :members: + :inherited-members: + :undoc-members: + + +QuerySessionPool (AsyncIO) +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. autoclass:: ydb.aio.QuerySessionPool + :members: + :inherited-members: + :undoc-members: + + +QuerySession (AsyncIO) +^^^^^^^^^^^^^^^^^^^^^^ + +.. autoclass:: ydb.aio.QuerySession + :members: + :inherited-members: + :undoc-members: + + +QueryTxContext (AsyncIO) +^^^^^^^^^^^^^^^^^^^^^^^^ + +.. autoclass:: ydb.aio.QueryTxContext + :members: + :inherited-members: + :undoc-members: + + +Query Tx Mode +^^^^^^^^^^^^^ + +.. autoclass:: ydb.BaseQueryTxMode + :members: + :inherited-members: + :undoc-members: + :exclude-members: name, to_proto + + +.. autoclass:: ydb.QueryOnlineReadOnly + :members: + :inherited-members: + :undoc-members: + :exclude-members: name, to_proto + + +.. autoclass:: ydb.QuerySerializableReadWrite + :members: + :inherited-members: + :undoc-members: + :exclude-members: name, to_proto + + +.. autoclass:: ydb.QuerySnapshotReadOnly + :members: + :inherited-members: + :undoc-members: + :exclude-members: name, to_proto + + +.. autoclass:: ydb.QueryStaleReadOnly + :members: + :inherited-members: + :undoc-members: + :exclude-members: name, to_proto + + +------------------------ + +Table Service +------------- + +TableClient +^^^^^^^^^^^ +.. autoclass:: ydb.TableClient + :members: + :inherited-members: + :undoc-members: + +TableClientSettings +^^^^^^^^^^^^^^^^^^^ + +.. autoclass:: ydb.TableClientSettings + :members: + :inherited-members: + :undoc-members: + +Session Pool +^^^^^^^^^^^^ + +.. autoclass:: ydb.SessionPool + :members: + :inherited-members: + :undoc-members: + +Session +^^^^^^^ + +.. autoclass:: ydb.Session + :members: + :inherited-members: + :undoc-members: + +Transaction Context +^^^^^^^^^^^^^^^^^^^ + +.. autoclass:: ydb.TxContext + :members: + :inherited-members: + :undoc-members: + +DataQuery +^^^^^^^^^ + +.. autoclass:: ydb.DataQuery + :members: + :inherited-members: + :undoc-members: + +-------------------------- + +Scheme +------ + +SchemeClient +^^^^^^^^^^^^ + +.. autoclass:: ydb.SchemeClient + :members: + :inherited-members: + :undoc-members: + +------------------ + diff --git a/docs/conf.py b/docs/conf.py index f8cc5f6d..13d7e22d 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -20,7 +20,7 @@ # -- Project information ----------------------------------------------------- project = 'ydb' -copyright = '2021, yandex' +copyright = '2024, yandex' author = 'yandex' # The short X.Y version @@ -39,11 +39,12 @@ # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ - 'sphinx.ext.autodoc', - 'sphinx.ext.viewcode', - 'sphinx.ext.todo', - 'sphinx.ext.napoleon', - 'sphinx.ext.coverage', + 'sphinx.ext.autodoc', + 'sphinx.ext.viewcode', + 'sphinx.ext.todo', + 'sphinx.ext.napoleon', + 'sphinx.ext.coverage', + 'sphinx_copybutton', ] # Add any paths that contain templates here, relative to this directory. @@ -79,15 +80,20 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # -html_theme = 'alabaster' +html_theme = 'sphinx_rtd_theme' html_theme_options = { - 'fixed_sidebar': True, - 'page_width': '1140px', - 'show_related': True, - 'show_powered_by': False + 'fixed_sidebar': True, + 'page_width': '1140px', + 'show_related': True, + 'show_powered_by': False } +html_logo = '_static/logo.svg' +html_favicon = '_static/logo.svg' + +html_show_sourcelink = False + # 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. @@ -97,7 +103,7 @@ # 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'] +html_static_path = ['_static'] # Custom sidebar templates, must be a dictionary that maps document names # to template names. diff --git a/docs/examples.rst b/docs/examples.rst index 920d1292..4f8dee84 100644 --- a/docs/examples.rst +++ b/docs/examples.rst @@ -1,67 +1,155 @@ Examples =============== -ydb -^^^ +Basic example +^^^^^^^^^^^^^ + +All examples in this section are parts of `basic example `_. + +For deeper upderstanding it is better to read the whole example. Create table ------------ -:: - - ... create an instance of Driver ... - - description = ( - ydb.TableDescription() - .with_primary_keys('key1', 'key2') - .with_columns( - ydb.Column('key1', ydb.OptionalType(ydb.PrimitiveType.Uint64)), - ydb.Column('key2', ydb.OptionalType(ydb.PrimitiveType.Uint64)), - ydb.Column('value', ydb.OptionalType(ydb.PrimitiveType.Utf8)) - ) - .with_profile( - ydb.TableProfile() - .with_partitioning_policy( - ydb.PartitioningPolicy() - .with_explicit_partitions( - ydb.ExplicitPartitions( - ( - ydb.KeyBound((100, )), - ydb.KeyBound((300, 100)), - ydb.KeyBound((400, )), - ) - ) - ) - ) - ) - ) - - session = driver.table_client.session().create() - session.create_table('/my/table/', description) - - -Read table +.. code-block:: python + + def create_tables(pool: ydb.QuerySessionPool): + print("\nCreating table series...") + pool.execute_with_retries( + """ + CREATE table `series` ( + `series_id` Int64, + `title` Utf8, + `series_info` Utf8, + `release_date` Date, + PRIMARY KEY (`series_id`) + ) + """ + ) + + print("\nCreating table seasons...") + pool.execute_with_retries( + """ + CREATE table `seasons` ( + `series_id` Int64, + `season_id` Int64, + `title` Utf8, + `first_aired` Date, + `last_aired` Date, + PRIMARY KEY (`series_id`, `season_id`) + ) + """ + ) + + print("\nCreating table episodes...") + pool.execute_with_retries( + """ + CREATE table `episodes` ( + `series_id` Int64, + `season_id` Int64, + `episode_id` Int64, + `title` Utf8, + `air_date` Date, + PRIMARY KEY (`series_id`, `season_id`, `episode_id`) + ) + """ + ) + + +Upsert Simple +------------- + +.. code-block:: python + + def upsert_simple(pool: ydb.QuerySessionPool): + print("\nPerforming UPSERT into episodes...") + + pool.execute_with_retries( + """ + UPSERT INTO episodes (series_id, season_id, episode_id, title) VALUES (2, 6, 1, "TBD"); + """ + ) + + +Simple Select ---------- -:: - - .... initialize driver and session .... - - key_prefix_type = ydb.TupleType().add_element( - ydb.OptionalType(ydb.PrimitiveType.Uint64).add_element( - ydb.OptionalType(ydb.PrimitiveType.Utf8)) - async_table_iterator = session.read_table( - '/my/table', - columns=('KeyColumn0', 'KeyColumn1', 'ValueColumn'), - ydb.KeyRange( - ydb.KeyBound((100, 'hundred'), key_prefix_type) - ydb.KeyBound((200, 'two-hundreds'), key_prefix_type) - ) + +.. code-block:: python + + def select_simple(pool: ydb.QuerySessionPool): + print("\nCheck series table...") + result_sets = pool.execute_with_retries( + """ + SELECT + series_id, + title, + release_date + FROM series + WHERE series_id = 1; + """, + ) + first_set = result_sets[0] + for row in first_set.rows: + print( + "series, id: ", + row.series_id, + ", title: ", + row.title, + ", release date: ", + row.release_date, ) - while True: - try: - chunk_future = next(table_iterator) - chunk = chunk_future.result() # or any other way to await - ... additional data processing ... - except StopIteration: - break + return first_set + +Select With Parameters +---------------------- + +.. code-block:: python + + def select_with_parameters(pool: ydb.QuerySessionPool, series_id, season_id, episode_id): + result_sets = pool.execute_with_retries( + """ + DECLARE $seriesId AS Int64; + DECLARE $seasonId AS Int64; + DECLARE $episodeId AS Int64; + + SELECT + title, + air_date + FROM episodes + WHERE series_id = $seriesId AND season_id = $seasonId AND episode_id = $episodeId; + """, + { + "$seriesId": series_id, # could be defined implicit + "$seasonId": (season_id, ydb.PrimitiveType.Int64), # could be defined via tuple + "$episodeId": ydb.TypedValue(episode_id, ydb.PrimitiveType.Int64), # could be defined via special class + }, + ) + + print("\n> select_with_parameters:") + first_set = result_sets[0] + for row in first_set.rows: + print("episode title:", row.title, ", air date:", row.air_date) + + return first_set + +Huge Select +----------- + +.. code-block:: python + + def huge_select(pool: ydb.QuerySessionPool): + def callee(session: ydb.QuerySessionSync): + query = """SELECT * from episodes;""" + + with session.transaction().execute( + query, + commit_tx=True, + ) as result_sets: + print("\n> Huge SELECT call") + for result_set in result_sets: + for row in result_set.rows: + print("episode title:", row.title, ", air date:", row.air_date) + + return pool.retry_operation_sync(callee) + diff --git a/docs/index.rst b/docs/index.rst index 9a69b2bc..184a35ab 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -3,16 +3,16 @@ You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. -Welcome to ydb's documentation! +YDB Python SDK =============================== .. toctree:: - :maxdepth: 10 - - ydb.rst - examples.rst - + :maxdepth: 3 + overview + quickstart + examples + apireference Indices and tables diff --git a/docs/overview.rst b/docs/overview.rst new file mode 100644 index 00000000..81abf94d --- /dev/null +++ b/docs/overview.rst @@ -0,0 +1,21 @@ +Overview +======== + +Project Homepage +---------------- + +YDB Python SDK is hosted on GitHub at https://github.com/ydb-platform/ydb-python-sdk under the ydb-platform organization. + +Releases and project status are available on Pypi at https://pypi.org/project/ydb. + +The most recent published version of this documentation should be at https://ydb-platform.github.io/ydb-python-sdk. + + +Community +--------- + +You can ask your questions in official Telegram chats: `EN `_ | `RU `_. + +Bugs and feature enhancements to YDB Python SDK should be reported on the `GitHub +issue tracker +`_. \ No newline at end of file diff --git a/docs/quickstart.rst b/docs/quickstart.rst new file mode 100644 index 00000000..cb1d1062 --- /dev/null +++ b/docs/quickstart.rst @@ -0,0 +1,119 @@ +Quick Start +=========== + +Installation +------------ + +Prerequisites +^^^^^^^^^^^^^ + +* Python 3.8 or higher; +* ``pip`` version 9.0.1 or higher; + +If necessary, upgrade your version of ``pip``:: + + python -m pip install --upgrade pip + +If you cannot upgrade `pip` due to a system-owned installation, you can run the example in a virtualenv:: + + python -m pip install virtualenv + virtualenv venv + source venv/bin/activate + python -m pip install --upgrade pip + +Installation via Pypi +^^^^^^^^^^^^^^^^^^^^^ + +To install YDB Python SDK through Pypi execute the following command:: + + pip install ydb + +Usage +----- + +Import Package +^^^^^^^^^^^^^^ + +.. code-block:: python + + import ydb + +Driver Initialization +^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: python + + endpoint = "grpc://localhost:2136" # your ydb endpoint + database = "/local" # your ydb database + + with ydb.Driver( + endpoint=endpoint, + database=database, + credentials=ydb.credentials_from_env_variables(), + ) as driver: + driver.wait(timeout=5, fail_fast=True) + +SessionPool Initialization +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: python + + with ydb.QuerySessionPool(driver) as pool: + pass + +Query Execution +^^^^^^^^^^^^^^^ + +Python SDK supports queries described by YQL syntax. +There are two primary methods for executing queries, each with different properties and use cases: + +* ``pool.execute_with_retries``: + + * Buffers the entire result set in client memory. + * Automatically retries execution in case of retriable issues. + * Does not allow specifying a transaction execution mode. + * Recommended for one-off queries that are expected to produce small result sets. + +* ``tx.execute``: + + * Returns an iterator over the query results, allowing processing of results that may not fit into client memory. + * Retries must be handled manually via `pool.retry_operation_sync`. + * Allows specifying a transaction execution mode. + * Recommended for scenarios where `pool.execute_with_retries` is insufficient. + + +Usage of ``pool.execute_with_retries()``: + +.. code-block:: python + + pool.execute_with_retries("DROP TABLE IF EXISTS example") + pool.execute_with_retries("CREATE TABLE example(key UInt64, value String, PRIMARY KEY (key))") + + pool.execute_with_retries("INSERT INTO example (key, value) VALUES (1, 'luffy')") + + res = pool.execute_with_retries("SELECT COUNT(*) AS rows_count FROM example") + +>>> res[0].rows_count +1 + +Example of ``tx.execute()``: + +.. code-block:: python + + def callee(session: ydb.QuerySessionSync): + with session.transaction() as tx: + with tx.execute( + "INSERT INTO example (key, value) VALUES (2, 'zoro')" + ): + pass + + with tx.execute( + "INSERT INTO example (key, value) VALUES (3, 'sanji')", + commit_tx=True, + ): + pass + + pool.retry_operation_sync(callee) + + + diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 00000000..f8306480 --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,2 @@ +sphinx_rtd_theme==2.0.0 +sphinx-copybutton==0.5.2 diff --git a/docs/ydb.rst b/docs/ydb.rst deleted file mode 100644 index 53297005..00000000 --- a/docs/ydb.rst +++ /dev/null @@ -1,111 +0,0 @@ -ydb -=== - -.. toctree:: - :caption: Contents: - - -.. module:: ydb - -Module contents ---------------- - -Driver -^^^^^^ - -Driver object -~~~~~~~~~~~~~ - -.. autoclass:: Driver - :members: - :inherited-members: - :undoc-members: - - -DriverConfig -~~~~~~~~~~~~ - -.. autoclass:: DriverConfig - :members: - :inherited-members: - :undoc-members: - :exclude-members: database, ca_cert, channel_options, secure_channel, endpoint, endpoints, credentials, use_all_nodes, root_certificates, certificate_chain, private_key, grpc_keep_alive_timeout, table_client_settings, primary_user_agent - ------------------------- - -Table -^^^^^ -TableClient -~~~~~~~~~~~ -.. autoclass:: TableClient - :members: - :inherited-members: - :undoc-members: - -TableClientSettings -~~~~~~~~~~~~~~~~~~~ - -.. autoclass:: TableClientSettings - :members: - :inherited-members: - :undoc-members: - -Session -~~~~~~~ - -.. autoclass:: Session - :members: - :inherited-members: - :undoc-members: - -Transaction Context -~~~~~~~~~~~~~~~~~~~ - -.. autoclass:: TxContext - :members: - :inherited-members: - :undoc-members: - --------------------------- - -Scheme -^^^^^^ - -SchemeClient -~~~~~~~~~~~~ - -.. autoclass:: SchemeClient - :members: - :inherited-members: - :undoc-members: - ------------------- - -Session Pool -^^^^^^^^^^^^ - -.. autoclass:: SessionPool - :members: - :inherited-members: - :undoc-members: - ------------------------------ - - -Result Sets -^^^^^^^^^^^ - -.. autoclass:: ydb.convert._ResultSet - :members: - :inherited-members: - :undoc-members: - ------------------------------ - -DataQuery -^^^^^^^^^ - -.. autoclass:: DataQuery - :members: - :inherited-members: - :undoc-members: diff --git a/ydb/_grpc/grpcwrapper/ydb_query_public_types.py b/ydb/_grpc/grpcwrapper/ydb_query_public_types.py index d79a2967..9888a677 100644 --- a/ydb/_grpc/grpcwrapper/ydb_query_public_types.py +++ b/ydb/_grpc/grpcwrapper/ydb_query_public_types.py @@ -11,6 +11,8 @@ class BaseQueryTxMode(IToProto): + """Abstract class for Query Transaction Modes.""" + @property @abc.abstractmethod def name(self) -> str: @@ -18,6 +20,11 @@ def name(self) -> str: class QuerySnapshotReadOnly(BaseQueryTxMode): + """All the read operations within a transaction access the database snapshot. + All the data reads are consistent. The snapshot is taken when the transaction begins, + meaning the transaction sees all changes committed before it began. + """ + def __init__(self): self._name = "snapshot_read_only" @@ -30,6 +37,10 @@ def to_proto(self) -> ydb_query_pb2.SnapshotModeSettings: class QuerySerializableReadWrite(BaseQueryTxMode): + """This mode guarantees that the result of successful parallel transactions is equivalent + to their serial execution, and there are no read anomalies for successful transactions. + """ + def __init__(self): self._name = "serializable_read_write" @@ -42,6 +53,15 @@ def to_proto(self) -> ydb_query_pb2.SerializableModeSettings: class QueryOnlineReadOnly(BaseQueryTxMode): + """Each read operation in the transaction is reading the data that is most recent at execution time. + The consistency of retrieved data depends on the allow_inconsistent_reads setting: + * false (consistent reads): Each individual read operation returns consistent data, + but no consistency is guaranteed between reads. + Reading the same table range twice may return different results. + * true (inconsistent reads): Even the data fetched by a particular + read operation may contain inconsistent results. + """ + def __init__(self, allow_inconsistent_reads: bool = False): self.allow_inconsistent_reads = allow_inconsistent_reads self._name = "online_read_only" @@ -55,6 +75,11 @@ def to_proto(self) -> ydb_query_pb2.OnlineModeSettings: class QueryStaleReadOnly(BaseQueryTxMode): + """Read operations within a transaction may return results that are slightly out-of-date + (lagging by fractions of a second). Each individual read returns consistent data, + but no consistency between different reads is guaranteed. + """ + def __init__(self): self._name = "stale_read_only" diff --git a/ydb/aio/__init__.py b/ydb/aio/__init__.py index a755713d..1c9c887c 100644 --- a/ydb/aio/__init__.py +++ b/ydb/aio/__init__.py @@ -1,3 +1,3 @@ from .driver import Driver # noqa from .table import SessionPool, retry_operation # noqa -from .query import QuerySessionPool, QuerySession # noqa +from .query import QuerySessionPool, QuerySession, QueryTxContext # noqa diff --git a/ydb/aio/query/__init__.py b/ydb/aio/query/__init__.py index ea5273d7..8e7dd4fd 100644 --- a/ydb/aio/query/__init__.py +++ b/ydb/aio/query/__init__.py @@ -1,7 +1,9 @@ __all__ = [ "QuerySessionPool", "QuerySession", + "QueryTxContext", ] from .pool import QuerySessionPool from .session import QuerySession +from .transaction import QueryTxContext diff --git a/ydb/aio/query/pool.py b/ydb/aio/query/pool.py index f0b962c3..e8d53438 100644 --- a/ydb/aio/query/pool.py +++ b/ydb/aio/query/pool.py @@ -44,6 +44,13 @@ async def _create_new_session(self): return session async def acquire(self) -> QuerySession: + """WARNING: This API is experimental and could be changed. + + Acquire a session from Session Pool. + + :return A QuerySession object. + """ + if self._should_stop.is_set(): logger.error("An attempt to take session from closed session pool.") raise RuntimeError("An attempt to take session from closed session pool.") @@ -79,12 +86,18 @@ async def acquire(self) -> QuerySession: return session async def release(self, session: QuerySession) -> None: + """WARNING: This API is experimental and could be changed. + + Release a session back to Session Pool. + """ + self._queue.put_nowait(session) logger.debug("Session returned to queue: %s", session._state.session_id) def checkout(self) -> "SimpleQuerySessionCheckoutAsync": """WARNING: This API is experimental and could be changed. - Return a Session context manager, that opens session on enter and closes session on exit. + + Return a Session context manager, that acquires session on enter and releases session on exit. """ return SimpleQuerySessionCheckoutAsync(self) @@ -93,6 +106,7 @@ async def retry_operation_async( self, callee: Callable, retry_settings: Optional[RetrySettings] = None, *args, **kwargs ): """WARNING: This API is experimental and could be changed. + Special interface to execute a bunch of commands with session in a safe, retriable way. :param callee: A function, that works with session. @@ -118,6 +132,7 @@ async def execute_with_retries( **kwargs, ) -> List[convert.ResultSet]: """WARNING: This API is experimental and could be changed. + Special interface to execute a one-shot queries in a safe, retriable way. Note: this method loads all data from stream before return, do not use this method with huge read queries. diff --git a/ydb/aio/query/session.py b/ydb/aio/query/session.py index 5f51b671..4c1c1a10 100644 --- a/ydb/aio/query/session.py +++ b/ydb/aio/query/session.py @@ -116,6 +116,7 @@ async def execute( """WARNING: This API is experimental and could be changed. Sends a query to Query Service + :param query: (YQL or SQL text) to be executed. :param syntax: Syntax of the query, which is a one from the following choises: 1) QuerySyntax.YQL_V1, which is default; diff --git a/ydb/aio/query/transaction.py b/ydb/aio/query/transaction.py index 0e3ab602..b115a4b4 100644 --- a/ydb/aio/query/transaction.py +++ b/ydb/aio/query/transaction.py @@ -114,6 +114,7 @@ async def execute( """WARNING: This API is experimental and could be changed. Sends a query to Query Service + :param query: (YQL or SQL text) to be executed. :param parameters: dict with parameters and YDB types; :param commit_tx: A special flag that allows transaction commit. diff --git a/ydb/query/__init__.py b/ydb/query/__init__.py index 1e950bb7..0f818789 100644 --- a/ydb/query/__init__.py +++ b/ydb/query/__init__.py @@ -1,11 +1,13 @@ __all__ = [ + "BaseQueryTxMode", "QueryOnlineReadOnly", "QuerySerializableReadWrite", "QuerySnapshotReadOnly", "QueryStaleReadOnly", "QuerySessionPool", - "QueryClientSync", + "QueryClientSettings", "QuerySession", + "QueryTxContext", ] import logging @@ -15,9 +17,11 @@ ) from .session import QuerySession +from .transaction import QueryTxContext from .._grpc.grpcwrapper import common_utils from .._grpc.grpcwrapper.ydb_query_public_types import ( + BaseQueryTxMode, QueryOnlineReadOnly, QuerySerializableReadWrite, QuerySnapshotReadOnly, diff --git a/ydb/query/pool.py b/ydb/query/pool.py index 1ee9ea83..839d8688 100644 --- a/ydb/query/pool.py +++ b/ydb/query/pool.py @@ -29,7 +29,8 @@ class QuerySessionPool: def __init__(self, driver: common_utils.SupportedDriverType, size: int = 100): """ - :param driver: A driver instance + :param driver: A driver instance. + :param size: Max size of Session Pool. """ logger.warning("QuerySessionPool is an experimental API, which could be changed.") @@ -47,6 +48,15 @@ def _create_new_session(self, timeout: Optional[float]): return session def acquire(self, timeout: Optional[float] = None) -> QuerySession: + """WARNING: This API is experimental and could be changed. + + Acquire a session from Session Pool. + + :param timeout: A timeout to wait in seconds. + + :return A QuerySession object. + """ + start = time.monotonic() lock_acquire_timeout = timeout if timeout is not None else -1 @@ -92,18 +102,27 @@ def acquire(self, timeout: Optional[float] = None) -> QuerySession: self._lock.release() def release(self, session: QuerySession) -> None: + """WARNING: This API is experimental and could be changed. + + Release a session back to Session Pool. + """ + self._queue.put_nowait(session) logger.debug("Session returned to queue: %s", session._state.session_id) def checkout(self, timeout: Optional[float] = None) -> "SimpleQuerySessionCheckout": """WARNING: This API is experimental and could be changed. - Return a Session context manager, that opens session on enter and closes session on exit. + + Return a Session context manager, that acquires session on enter and releases session on exit. + + :param timeout: A timeout to wait in seconds. """ return SimpleQuerySessionCheckout(self, timeout) def retry_operation_sync(self, callee: Callable, retry_settings: Optional[RetrySettings] = None, *args, **kwargs): """WARNING: This API is experimental and could be changed. + Special interface to execute a bunch of commands with session in a safe, retriable way. :param callee: A function, that works with session. @@ -129,6 +148,7 @@ def execute_with_retries( **kwargs, ) -> List[convert.ResultSet]: """WARNING: This API is experimental and could be changed. + Special interface to execute a one-shot queries in a safe, retriable way. Note: this method loads all data from stream before return, do not use this method with huge read queries. diff --git a/ydb/query/session.py b/ydb/query/session.py index 66e86501..5b4db26c 100644 --- a/ydb/query/session.py +++ b/ydb/query/session.py @@ -269,6 +269,7 @@ def transaction(self, tx_mode: Optional[base.BaseQueryTxMode] = None) -> QueryTx """WARNING: This API is experimental and could be changed. Creates a transaction context manager with specified transaction mode. + :param tx_mode: Transaction mode, which is a one from the following choises: 1) QuerySerializableReadWrite() which is default mode; 2) QueryOnlineReadOnly(allow_inconsistent_reads=False); @@ -301,6 +302,7 @@ def execute( """WARNING: This API is experimental and could be changed. Sends a query to Query Service + :param query: (YQL or SQL text) to be executed. :param syntax: Syntax of the query, which is a one from the following choises: 1) QuerySyntax.YQL_V1, which is default; diff --git a/ydb/query/transaction.py b/ydb/query/transaction.py index 9ad3552f..21ba0279 100644 --- a/ydb/query/transaction.py +++ b/ydb/query/transaction.py @@ -394,6 +394,7 @@ def execute( """WARNING: This API is experimental and could be changed. Sends a query to Query Service + :param query: (YQL or SQL text) to be executed. :param parameters: dict with parameters and YDB types; :param commit_tx: A special flag that allows transaction commit. diff --git a/ydb/settings.py b/ydb/settings.py index 6739a46f..019b75a8 100644 --- a/ydb/settings.py +++ b/ydb/settings.py @@ -39,7 +39,7 @@ def make_copy(self): .with_need_rpc_auth(self.need_rpc_auth) ) - def with_compression(self, compression): + def with_compression(self, compression) -> "BaseRequestSettings": """ Enables compression for the specific RPC :param compression: An RPCCompression enum value. @@ -48,11 +48,11 @@ def with_compression(self, compression): self.compression = compression return self - def with_need_rpc_auth(self, need_rpc_auth): + def with_need_rpc_auth(self, need_rpc_auth) -> "BaseRequestSettings": self.need_rpc_auth = need_rpc_auth return self - def with_header(self, key, value): + def with_header(self, key, value) -> "BaseRequestSettings": """ Adds a key-value pair to the request headers. :param key: A string with a header key. @@ -62,7 +62,7 @@ def with_header(self, key, value): self.headers.append((key, value)) return self - def with_trace_id(self, trace_id): + def with_trace_id(self, trace_id) -> "BaseRequestSettings": """ Includes trace id for RPC headers :param trace_id: A trace id string @@ -71,7 +71,7 @@ def with_trace_id(self, trace_id): self.trace_id = trace_id return self - def with_request_type(self, request_type): + def with_request_type(self, request_type) -> "BaseRequestSettings": """ Includes request type for RPC headers :param request_type: A request type string @@ -80,7 +80,7 @@ def with_request_type(self, request_type): self.request_type = request_type return self - def with_operation_timeout(self, timeout): + def with_operation_timeout(self, timeout) -> "BaseRequestSettings": """ Indicates that client is no longer interested in the result of operation after the specified duration starting from the time operation arrives at the server. @@ -89,12 +89,12 @@ def with_operation_timeout(self, timeout): Timeout of operation does not tell anything about its result, it might be completed successfully or cancelled on server. :param timeout: - :return: + :return: The self instance """ self.operation_timeout = timeout return self - def with_cancel_after(self, timeout): + def with_cancel_after(self, timeout) -> "BaseRequestSettings": """ Server will try to cancel the operation after the specified duration starting from the time the operation arrives at server. @@ -102,12 +102,12 @@ def with_cancel_after(self, timeout): sent back to client if it was waiting for the operation result. In case when cancellation isn't possible, no action will be performed. :param timeout: - :return: + :return: The self instance """ self.cancel_after = timeout return self - def with_timeout(self, timeout): + def with_timeout(self, timeout) -> "BaseRequestSettings": """ Client-side timeout to complete request. Since YDB doesn't support request cancellation at this moment, this feature should be