opa-python-client 2.0.1__tar.gz → 2.0.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +1,7 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.3
2
2
  Name: opa-python-client
3
- Version: 2.0.1
3
+ Version: 2.0.3
4
4
  Summary: Client for connection to the OPA service
5
- Home-page: https://github.com/Turall/OPA-python-client
6
5
  License: MIT
7
6
  Author: Tural Muradov
8
7
  Author-email: tural.muradoov@gmail.com
@@ -21,6 +20,8 @@ Classifier: Programming Language :: Python :: 3 :: Only
21
20
  Requires-Dist: aiofiles (>=24.1.0,<25.0.0)
22
21
  Requires-Dist: aiohttp[speedups] (>=3.10.9,<4.0.0)
23
22
  Requires-Dist: requests (>=2.32.3,<3.0.0)
23
+ Requires-Dist: urllib3 (>=2.5.0,<3.0.0)
24
+ Project-URL: Homepage, https://github.com/Turall/OPA-python-client
24
25
  Project-URL: Repository, https://github.com/Turall/OPA-python-client
25
26
  Description-Content-Type: text/markdown
26
27
 
@@ -380,31 +381,7 @@ await client.delete_data('users')
380
381
 
381
382
  #### Check Permission (Policy Evaluation)
382
383
 
383
- You can evaluate policies with input data using `check_permission`.
384
-
385
- - **Synchronous**:
386
-
387
- ```python
388
- input_data = {"user": "admin"}
389
- policy_name = 'example_policy'
390
- rule_name = 'allow'
391
-
392
- result = client.check_permission(input_data, policy_name, rule_name)
393
- print(result)
394
- ```
395
-
396
- - **Asynchronous**:
397
-
398
- ```python
399
- input_data = {"user": "admin"}
400
- policy_name = 'example_policy'
401
- rule_name = 'allow'
402
-
403
- result = await client.check_permission(input_data, policy_name, rule_name)
404
- print(result)
405
- ```
406
-
407
- Queries a package rule with the given input data
384
+ Evaluate a rule from a known package path. This is the **recommended method** for evaluating OPA decisions.
408
385
 
409
386
  ```python
410
387
 
@@ -448,6 +425,39 @@ print(await client.query_rule(input_data=check_data, package_path="play", rule_n
448
425
 
449
426
  ```
450
427
 
428
+ You can evaluate policies with input data using `check_permission`.
429
+ ### ⚠️ Deprecated: `check_permission()`
430
+
431
+ This method introspects the policy AST to construct a query path dynamically. It introduces unnecessary overhead and is **not recommended** for production use.
432
+
433
+ - **Synchronous**:
434
+
435
+ ```python
436
+ input_data = {"user": "admin"}
437
+ policy_name = 'example_policy'
438
+ rule_name = 'allow'
439
+
440
+ result = client.check_permission(input_data, policy_name, rule_name)
441
+ print(result)
442
+ ```
443
+ > 🔥 Prefer `query_rule()` instead for better performance and maintainability.
444
+
445
+ ### ⚠️ Deprecated: `check_permission()`
446
+
447
+ - **Asynchronous**:
448
+
449
+ ```python
450
+ input_data = {"user": "admin"}
451
+ policy_name = 'example_policy'
452
+ rule_name = 'allow'
453
+
454
+ result = await client.check_permission(input_data, policy_name, rule_name)
455
+ print(result)
456
+ ```
457
+ > 🔥 Prefer `query_rule()` instead for better performance and maintainability.
458
+
459
+
460
+
451
461
  ### Ad-hoc Queries
452
462
 
453
463
  Execute ad-hoc queries directly:
@@ -354,31 +354,7 @@ await client.delete_data('users')
354
354
 
355
355
  #### Check Permission (Policy Evaluation)
356
356
 
357
- You can evaluate policies with input data using `check_permission`.
358
-
359
- - **Synchronous**:
360
-
361
- ```python
362
- input_data = {"user": "admin"}
363
- policy_name = 'example_policy'
364
- rule_name = 'allow'
365
-
366
- result = client.check_permission(input_data, policy_name, rule_name)
367
- print(result)
368
- ```
369
-
370
- - **Asynchronous**:
371
-
372
- ```python
373
- input_data = {"user": "admin"}
374
- policy_name = 'example_policy'
375
- rule_name = 'allow'
376
-
377
- result = await client.check_permission(input_data, policy_name, rule_name)
378
- print(result)
379
- ```
380
-
381
- Queries a package rule with the given input data
357
+ Evaluate a rule from a known package path. This is the **recommended method** for evaluating OPA decisions.
382
358
 
383
359
  ```python
384
360
 
@@ -422,6 +398,39 @@ print(await client.query_rule(input_data=check_data, package_path="play", rule_n
422
398
 
423
399
  ```
424
400
 
401
+ You can evaluate policies with input data using `check_permission`.
402
+ ### ⚠️ Deprecated: `check_permission()`
403
+
404
+ This method introspects the policy AST to construct a query path dynamically. It introduces unnecessary overhead and is **not recommended** for production use.
405
+
406
+ - **Synchronous**:
407
+
408
+ ```python
409
+ input_data = {"user": "admin"}
410
+ policy_name = 'example_policy'
411
+ rule_name = 'allow'
412
+
413
+ result = client.check_permission(input_data, policy_name, rule_name)
414
+ print(result)
415
+ ```
416
+ > 🔥 Prefer `query_rule()` instead for better performance and maintainability.
417
+
418
+ ### ⚠️ Deprecated: `check_permission()`
419
+
420
+ - **Asynchronous**:
421
+
422
+ ```python
423
+ input_data = {"user": "admin"}
424
+ policy_name = 'example_policy'
425
+ rule_name = 'allow'
426
+
427
+ result = await client.check_permission(input_data, policy_name, rule_name)
428
+ print(result)
429
+ ```
430
+ > 🔥 Prefer `query_rule()` instead for better performance and maintainability.
431
+
432
+
433
+
425
434
  ### Ad-hoc Queries
426
435
 
427
436
  Execute ad-hoc queries directly:
@@ -11,7 +11,7 @@ def create_opa_client(async_mode=False, *args, **kwargs):
11
11
  return OpaClient(*args, **kwargs)
12
12
 
13
13
 
14
- __version__ = "2.0.1"
14
+ __version__ = "2.0.3"
15
15
  __author__ = "Tural Muradov"
16
16
  __license__ = "MIT"
17
17
 
@@ -23,6 +23,7 @@ class BaseClient:
23
23
  ssl: bool = False,
24
24
  cert: Optional[Union[str, tuple]] = None,
25
25
  headers: Optional[dict] = None,
26
+ retries: int = 2,
26
27
  timeout: float = 1.5,
27
28
  ):
28
29
  if not isinstance(port, int):
@@ -34,6 +35,7 @@ class BaseClient:
34
35
  self.ssl = ssl
35
36
  self.cert = cert
36
37
  self.timeout = timeout
38
+ self.retries = retries
37
39
 
38
40
  self.schema = "https://" if ssl else "http://"
39
41
  self.root_url = f"{self.schema}{self.host}:{self.port}/{self.version}"
@@ -41,8 +43,6 @@ class BaseClient:
41
43
  self.headers = headers
42
44
 
43
45
  self._session = None # Will be initialized in the subclass
44
- self.retries = 2
45
- self.timeout = 1.5
46
46
 
47
47
  def _build_url(
48
48
  self, path: str, query_params: Dict[str, str] = None
@@ -1,6 +1,6 @@
1
- import json
2
1
  import os
3
2
  import threading
3
+ import warnings
4
4
  from typing import Dict, Optional
5
5
  from urllib.parse import urlencode
6
6
 
@@ -62,7 +62,9 @@ class OpaClient(BaseClient):
62
62
  session.mount("https://", adapter)
63
63
 
64
64
  if self.ssl:
65
- session.verify = self.cert
65
+ session.verify = self.ssl
66
+ if self.cert:
67
+ session.cert = self.cert
66
68
 
67
69
  return session
68
70
 
@@ -202,7 +204,9 @@ class OpaClient(BaseClient):
202
204
  bool: True if the policy was successfully updated.
203
205
  """
204
206
  if not os.path.isfile(filepath):
205
- raise FileError(f"'{filepath}' is not a valid file")
207
+ raise FileError(
208
+ "file_not_found", f"'{filepath}' is not a valid file"
209
+ )
206
210
 
207
211
  with open(filepath, "r", encoding="utf-8") as file:
208
212
  policy_str = file.read()
@@ -300,7 +304,9 @@ class OpaClient(BaseClient):
300
304
  policy_raw = policy.get("result", {}).get("raw", "")
301
305
 
302
306
  if not policy_raw:
303
- raise PolicyNotFoundError("Policy content is empty")
307
+ raise PolicyNotFoundError(
308
+ "resource_not_found", "Policy content is empty"
309
+ )
304
310
 
305
311
  full_path = os.path.join(path or "", filename)
306
312
 
@@ -309,7 +315,9 @@ class OpaClient(BaseClient):
309
315
  file.write(policy_raw)
310
316
  return True
311
317
  except OSError as e:
312
- raise PathNotFoundError(f"Failed to write to '{full_path}'") from e
318
+ raise PathNotFoundError(
319
+ "path_not_found", f"Failed to write to '{full_path}'"
320
+ ) from e
313
321
 
314
322
  def get_policy(self, policy_name: str) -> dict:
315
323
  """
@@ -384,6 +392,11 @@ class OpaClient(BaseClient):
384
392
  Returns:
385
393
  dict: The result of the permission check.
386
394
  """
395
+ warnings.warn(
396
+ "check_permission is deprecated and will be removed in a future release. Use `query_rule` instead.",
397
+ DeprecationWarning,
398
+ stacklevel=2
399
+ )
387
400
  policy = self.get_policy(policy_name)
388
401
  ast = policy.get("result", {}).get("ast", {})
389
402
  package_path = "/".join(
@@ -395,7 +408,8 @@ class OpaClient(BaseClient):
395
408
 
396
409
  if rule_name not in rules:
397
410
  raise CheckPermissionError(
398
- f"Rule '{rule_name}' not found in policy '{policy_name}'"
411
+ "resource_not_found",
412
+ f"Rule '{rule_name}' not found in policy '{policy_name}'",
399
413
  )
400
414
 
401
415
  url = f"{self.root_url}/{package_path}/{rule_name}"
@@ -1,5 +1,5 @@
1
1
  import asyncio
2
- import json
2
+ import warnings
3
3
  import os
4
4
  import ssl
5
5
  from typing import Dict, Optional, Union
@@ -50,9 +50,6 @@ class AsyncOpaClient:
50
50
  headers: Optional[dict] = None,
51
51
  timeout: float = 1.5,
52
52
  ):
53
- if not isinstance(port, int):
54
- raise TypeError("The port must be an integer")
55
-
56
53
  self.host = host.strip()
57
54
  self.port = port
58
55
  self.version = version
@@ -221,9 +218,8 @@ class AsyncOpaClient:
221
218
  ) as response:
222
219
  if response.status == 200:
223
220
  return True
224
- else:
225
- error = await response.json()
226
- raise RegoParseError(error.get("code"), error.get("message"))
221
+ error = await response.json()
222
+ raise RegoParseError(error.get("code"), error.get("message"))
227
223
 
228
224
  async def update_policy_from_file(
229
225
  self, filepath: str, endpoint: str
@@ -426,6 +422,11 @@ class AsyncOpaClient:
426
422
  Returns:
427
423
  dict: The result of the permission check.
428
424
  """
425
+ warnings.warn(
426
+ "check_permission is deprecated and will be removed in a future release. Use `query_rule` instead.",
427
+ DeprecationWarning,
428
+ stacklevel=2
429
+ )
429
430
  policy = await self.get_policy(policy_name)
430
431
  ast = policy.get("result", {}).get("ast", {})
431
432
  package_path = "/".join(
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "opa-python-client"
3
- version = "2.0.1"
3
+ version = "2.0.3"
4
4
  description = "Client for connection to the OPA service"
5
5
  authors = ["Tural Muradov <tural.muradoov@gmail.com>"]
6
6
  license = "MIT"
@@ -25,6 +25,7 @@ python = "^3.9"
25
25
  requests = "^2.32.3"
26
26
  aiohttp = {extras = ["speedups"], version = "^3.10.9"}
27
27
  aiofiles = "^24.1.0"
28
+ urllib3 = "^2.5.0"
28
29
 
29
30
  [tool.poetry.group.dev.dependencies]
30
31
  pytest = "^8.3.3"