Skip to content

Commit b890983

Browse files
authored
feat: async client implementation (#3)
* feat: async client implementation * docs: updated documentation
1 parent daf20fc commit b890983

30 files changed

Lines changed: 2820 additions & 89 deletions

‎README.md‎

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
This library is a simple client for working with **[Yandex Lockbox](https://cloud.yandex.ru/en/docs/lockbox/)** over [REST API](https://cloud.yandex.ru/en/docs/lockbox/api-ref/), simplifying work with secrets and allowing you to work with them in the OOP paradigm.
99

10+
Supports two modes: synchronous and asynchronous.
11+
1012
**[Full library documentation link](https://akimrx.github.io/python-yc-lockbox/)**
1113

1214
**Supported Python versions**:
@@ -23,6 +25,11 @@ This library is a simple client for working with **[Yandex Lockbox](https://clou
2325
* [Requests](https://github.com/psf/requests)
2426

2527

28+
**Extra dependencies:**
29+
30+
* [aiohttp](https://github.com/aio-libs/aiohttp)
31+
32+
2633
**Currently, the following operations are not supported by the library:**
2734

2835
* List secret access bindings
@@ -34,7 +41,7 @@ This library is a simple client for working with **[Yandex Lockbox](https://clou
3441
**In the near future release:**
3542

3643
- [x] Tests
37-
- [ ] Async client implementation
44+
- [x] Async client implementation
3845
- [ ] Implement access bindings methods and view operations
3946
- [ ] Ansible action and lookup plugins
4047

@@ -189,4 +196,51 @@ for secret in lockbox.list_secrets(folder_id="b1xxxxxxxxxx", iterator=True):
189196
version.schedule_version_destruction()
190197
version.cancel_version_destruction()
191198

192-
```
199+
```
200+
201+
## Async mode
202+
203+
The client supports asynchronous mode using the aiohttp library. The signature of the methods does not differ from the synchronous implementation.
204+
205+
206+
Just import async client:
207+
208+
```python
209+
210+
from yc_lockbox import AsyncYandexLockboxClient
211+
212+
lockbox = AsyncYandexLockboxClient("oauth_or_iam_token")
213+
```
214+
215+
Alternative:
216+
217+
```python
218+
219+
from yc_lockbox import YandexLockboxFacade
220+
221+
lockbox = YandexLockboxFacade("oauth_or_iam_token", enable_async=True).client
222+
```
223+
224+
Example usage:
225+
226+
```python
227+
secret: Secret = await lockbox.get_secret("e6qxxxxxxxxxx")
228+
payload = await secret.payload()
229+
print(payload.entries) # list of SecretPayloadEntry objects
230+
231+
# Direct access
232+
233+
entry = payload["secret_entry_1"] # or payload.get("secret_entry_1")
234+
235+
print(entry.text_value) # return MASKED value like ***********
236+
print(entry.reveal_text_value()) # similar to entry.text_value.get_secret_value()
237+
238+
# Async iterators
239+
240+
secret_versions = await secret.list_versions(iterator=True)
241+
242+
async for version in secret_versions:
243+
if version.id != secret.current_version.id:
244+
await version.schedule_version_destruction()
245+
await version.cancel_version_destruction()
246+
```

‎docs/_modules/index.html‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ <h1>All modules for which code is available</h1>
231231

232232
</aside>
233233
</div>
234-
</div><script src="../_static/documentation_options.js?v=360bc84d"></script>
234+
</div><script src="../_static/documentation_options.js?v=938c9ccc"></script>
235235
<script src="../_static/doctools.js?v=888ff710"></script>
236236
<script src="../_static/sphinx_highlight.js?v=dc90522c"></script>
237237
<script src="../_static/scripts/furo.js?v=32e29ea5"></script>

‎docs/_modules/yc_lockbox/_auth.html‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ <h1>Source code for yc_lockbox._auth</h1><div class="highlight"><pre>
309309

310310
</aside>
311311
</div>
312-
</div><script src="../../_static/documentation_options.js?v=360bc84d"></script>
312+
</div><script src="../../_static/documentation_options.js?v=938c9ccc"></script>
313313
<script src="../../_static/doctools.js?v=888ff710"></script>
314314
<script src="../../_static/sphinx_highlight.js?v=dc90522c"></script>
315315
<script src="../../_static/scripts/furo.js?v=32e29ea5"></script>

‎docs/_modules/yc_lockbox/_lockbox.html‎

Lines changed: 573 additions & 12 deletions
Large diffs are not rendered by default.

‎docs/_modules/yc_lockbox/_models.html‎

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -197,13 +197,13 @@
197197
<article role="main">
198198
<h1>Source code for yc_lockbox._models</h1><div class="highlight"><pre>
199199
<span></span><span class="kn">import</span> <span class="nn">logging</span>
200-
<span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">Any</span><span class="p">,</span> <span class="n">Iterator</span><span class="p">,</span> <span class="n">Union</span>
200+
<span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">Any</span><span class="p">,</span> <span class="n">AsyncGenerator</span><span class="p">,</span> <span class="n">Iterator</span><span class="p">,</span> <span class="n">Union</span>
201201
<span class="kn">from</span> <span class="nn">datetime</span> <span class="kn">import</span> <span class="n">datetime</span>
202202
<span class="kn">from</span> <span class="nn">pydantic</span> <span class="kn">import</span> <span class="n">BaseModel</span><span class="p">,</span> <span class="n">ConfigDict</span><span class="p">,</span> <span class="n">Field</span><span class="p">,</span> <span class="n">SecretStr</span><span class="p">,</span> <span class="n">SecretBytes</span><span class="p">,</span> <span class="n">computed_field</span>
203203

204204
<span class="kn">from</span> <span class="nn">yc_lockbox._constants</span> <span class="kn">import</span> <span class="n">RpcError</span>
205205
<span class="kn">from</span> <span class="nn">yc_lockbox._abc</span> <span class="kn">import</span> <span class="n">AbstractYandexLockboxClient</span>
206-
<span class="kn">from</span> <span class="nn">yc_lockbox._types</span> <span class="kn">import</span> <span class="n">T</span>
206+
<span class="kn">from</span> <span class="nn">yc_lockbox._types</span> <span class="kn">import</span> <span class="n">T</span><span class="p">,</span> <span class="n">SecretVersionsResponse</span>
207207
<span class="kn">from</span> <span class="nn">yc_lockbox._exceptions</span> <span class="kn">import</span> <span class="n">LockboxError</span>
208208

209209

@@ -500,18 +500,32 @@ <h1>Source code for yc_lockbox._models</h1><div class="highlight"><pre>
500500
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">client</span><span class="o">.</span><span class="n">delete_secret</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">id</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span></div>
501501

502502

503+
<span class="k">async</span> <span class="k">def</span> <span class="nf">_async_refresh</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="s2">&quot;Secret&quot;</span><span class="p">:</span>
504+
<span class="n">data</span> <span class="o">=</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">client</span><span class="o">.</span><span class="n">get_secret</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">id</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
505+
<span class="bp">self</span><span class="o">.</span><span class="n">_update_attributes</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
506+
<span class="k">return</span> <span class="bp">self</span>
507+
508+
<span class="k">def</span> <span class="nf">_sync_refresh</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="s2">&quot;Secret&quot;</span><span class="p">:</span>
509+
<span class="n">data</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">client</span><span class="o">.</span><span class="n">get_secret</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">id</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
510+
<span class="bp">self</span><span class="o">.</span><span class="n">_update_attributes</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
511+
<span class="k">return</span> <span class="bp">self</span>
512+
513+
<span class="k">def</span> <span class="nf">_update_attributes</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">data</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
514+
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Method for update model attributes after refresh.&quot;&quot;&quot;</span>
515+
<span class="k">for</span> <span class="n">attr</span><span class="p">,</span> <span class="n">value</span> <span class="ow">in</span> <span class="n">data</span><span class="o">.</span><span class="n">model_dump</span><span class="p">()</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
516+
<span class="k">if</span> <span class="n">value</span> <span class="o">!=</span> <span class="nb">getattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">attr</span><span class="p">,</span> <span class="kc">None</span><span class="p">):</span>
517+
<span class="nb">setattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">attr</span><span class="p">,</span> <span class="n">value</span><span class="p">)</span>
518+
503519
<div class="viewcode-block" id="Secret.refresh">
504520
<a class="viewcode-back" href="../../pages/models.html#yc_lockbox._models.Secret.refresh">[docs]</a>
505521
<span class="k">def</span> <span class="nf">refresh</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="s2">&quot;Secret&quot;</span><span class="p">:</span>
506522
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Shortcut for refresh attributes for this secret.&quot;&quot;&quot;</span>
507523
<span class="bp">self</span><span class="o">.</span><span class="n">_raise_when_empty_client</span><span class="p">()</span>
508-
<span class="n">data</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">client</span><span class="o">.</span><span class="n">get_secret</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">id</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
509524

510-
<span class="k">for</span> <span class="n">attr</span><span class="p">,</span> <span class="n">value</span> <span class="ow">in</span> <span class="n">data</span><span class="o">.</span><span class="n">model_dump</span><span class="p">()</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
511-
<span class="k">if</span> <span class="n">value</span> <span class="o">!=</span> <span class="nb">getattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">attr</span><span class="p">):</span>
512-
<span class="nb">setattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">attr</span><span class="p">,</span> <span class="n">value</span><span class="p">)</span>
525+
<span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">client</span><span class="p">,</span> <span class="s2">&quot;enable_async&quot;</span><span class="p">)</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">client</span><span class="o">.</span><span class="n">enable_async</span><span class="p">:</span>
526+
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_async_refresh</span><span class="p">(</span><span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
513527

514-
<span class="k">return</span> <span class="n">data</span></div>
528+
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_sync_refresh</span><span class="p">(</span><span class="o">**</span><span class="n">kwargs</span><span class="p">)</span></div>
515529

516530

517531
<div class="viewcode-block" id="Secret.payload">
@@ -525,7 +539,7 @@ <h1>Source code for yc_lockbox._models</h1><div class="highlight"><pre>
525539
<a class="viewcode-back" href="../../pages/models.html#yc_lockbox._models.Secret.list_versions">[docs]</a>
526540
<span class="k">def</span> <span class="nf">list_versions</span><span class="p">(</span>
527541
<span class="bp">self</span><span class="p">,</span> <span class="n">page_size</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="mi">100</span><span class="p">,</span> <span class="n">page_token</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span> <span class="n">iterator</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span>
528-
<span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Union</span><span class="p">[</span><span class="s2">&quot;SecretVersionsList&quot;</span><span class="p">,</span> <span class="n">Iterator</span><span class="p">[</span><span class="s2">&quot;SecretVersion&quot;</span><span class="p">],</span> <span class="s2">&quot;YandexCloudError&quot;</span><span class="p">]:</span>
542+
<span class="p">)</span> <span class="o">-&gt;</span> <span class="n">SecretVersionsResponse</span><span class="p">:</span>
529543
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Shortcut for list all available versions of the current secret.&quot;&quot;&quot;</span>
530544
<span class="bp">self</span><span class="o">.</span><span class="n">_raise_when_empty_client</span><span class="p">()</span>
531545
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">client</span><span class="o">.</span><span class="n">list_secret_versions</span><span class="p">(</span>
@@ -664,7 +678,7 @@ <h1>Source code for yc_lockbox._models</h1><div class="highlight"><pre>
664678

665679
</aside>
666680
</div>
667-
</div><script src="../../_static/documentation_options.js?v=360bc84d"></script>
681+
</div><script src="../../_static/documentation_options.js?v=938c9ccc"></script>
668682
<script src="../../_static/doctools.js?v=888ff710"></script>
669683
<script src="../../_static/sphinx_highlight.js?v=dc90522c"></script>
670684
<script src="../../_static/scripts/furo.js?v=32e29ea5"></script>

‎docs/_sources/index.rst.txt‎

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,56 @@ Other operations with secret
225225
226226
227227
228+
Async mode
229+
----------
230+
231+
The client supports asynchronous mode using the aiohttp library. The signature of the methods does not differ from the synchronous implementation.
232+
233+
234+
Just import async client:
235+
236+
.. code-block:: python
237+
238+
from yc_lockbox import AsyncYandexLockboxClient
239+
240+
lockbox = AsyncYandexLockboxClient("oauth_or_iam_token")
241+
242+
243+
244+
Alternative:
245+
246+
.. code-block:: python
247+
248+
from yc_lockbox import YandexLockboxFacade
249+
250+
lockbox = YandexLockboxFacade("oauth_or_iam_token", enable_async=True).client
251+
252+
253+
Example usage:
254+
255+
.. code-block:: python
256+
257+
secret: Secret = await lockbox.get_secret("e6qxxxxxxxxxx")
258+
payload = await secret.payload()
259+
print(payload.entries) # list of SecretPayloadEntry objects
260+
261+
# Direct access
262+
263+
entry = payload["secret_entry_1"] # or payload.get("secret_entry_1")
264+
265+
print(entry.text_value) # return MASKED value like ***********
266+
print(entry.reveal_text_value()) # similar to entry.text_value.get_secret_value()
267+
268+
# Async iterators
269+
270+
secret_versions = await secret.list_versions(iterator=True)
271+
272+
async for version in secret_versions:
273+
if version.id != secret.current_version.id:
274+
await version.schedule_version_destruction()
275+
await version.cancel_version_destruction()
276+
277+
228278
229279
Modules
230280
-------
Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,22 @@
11
Client
22
======
33

4+
.. autoclass:: yc_lockbox.YandexLockboxFacade
5+
:members:
6+
:undoc-members:
7+
:show-inheritance:
8+
49
.. autoclass:: yc_lockbox.YandexLockboxClient
510
:members:
611
:undoc-members:
712
:show-inheritance:
813

14+
.. autoclass:: yc_lockbox.AsyncYandexLockboxClient
15+
:members:
16+
:undoc-members:
17+
:show-inheritance:
18+
919
.. autoclass:: yc_lockbox._auth.YandexAuthClient
1020
:members:
1121
:undoc-members:
12-
:show-inheritance:
22+
:show-inheritance:

‎docs/_static/documentation_options.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
const DOCUMENTATION_OPTIONS = {
2-
VERSION: '0.1.3',
2+
VERSION: '0.2.0',
33
LANGUAGE: 'en',
44
COLLAPSE_INDEX: false,
55
BUILDER: 'html',

0 commit comments

Comments
 (0)