nlbone 0.1.33__tar.gz → 0.1.34__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.
Files changed (64) hide show
  1. {nlbone-0.1.33 → nlbone-0.1.34}/PKG-INFO +1 -1
  2. {nlbone-0.1.33 → nlbone-0.1.34}/pyproject.toml +1 -1
  3. {nlbone-0.1.33 → nlbone-0.1.34}/src/nlbone/adapters/http_clients/uploadchi.py +34 -12
  4. {nlbone-0.1.33 → nlbone-0.1.34}/.gitignore +0 -0
  5. {nlbone-0.1.33 → nlbone-0.1.34}/LICENSE +0 -0
  6. {nlbone-0.1.33 → nlbone-0.1.34}/README.md +0 -0
  7. {nlbone-0.1.33 → nlbone-0.1.34}/src/nlbone/__init__.py +0 -0
  8. {nlbone-0.1.33 → nlbone-0.1.34}/src/nlbone/adapters/__init__.py +0 -0
  9. {nlbone-0.1.33 → nlbone-0.1.34}/src/nlbone/adapters/auth/__init__.py +0 -0
  10. {nlbone-0.1.33 → nlbone-0.1.34}/src/nlbone/adapters/auth/keycloak.py +0 -0
  11. {nlbone-0.1.33 → nlbone-0.1.34}/src/nlbone/adapters/db/__init__.py +0 -0
  12. {nlbone-0.1.33 → nlbone-0.1.34}/src/nlbone/adapters/db/memory.py +0 -0
  13. {nlbone-0.1.33 → nlbone-0.1.34}/src/nlbone/adapters/db/postgres.py +0 -0
  14. {nlbone-0.1.33 → nlbone-0.1.34}/src/nlbone/adapters/db/query_builder.py +0 -0
  15. {nlbone-0.1.33 → nlbone-0.1.34}/src/nlbone/adapters/db/sqlalchemy/__init__.py +0 -0
  16. {nlbone-0.1.33 → nlbone-0.1.34}/src/nlbone/adapters/db/sqlalchemy/base.py +0 -0
  17. {nlbone-0.1.33 → nlbone-0.1.34}/src/nlbone/adapters/db/sqlalchemy/engine.py +0 -0
  18. {nlbone-0.1.33 → nlbone-0.1.34}/src/nlbone/adapters/db/sqlalchemy/query/__init__.py +0 -0
  19. {nlbone-0.1.33 → nlbone-0.1.34}/src/nlbone/adapters/db/sqlalchemy/query/builder.py +0 -0
  20. {nlbone-0.1.33 → nlbone-0.1.34}/src/nlbone/adapters/db/sqlalchemy/query/coercion.py +0 -0
  21. {nlbone-0.1.33 → nlbone-0.1.34}/src/nlbone/adapters/db/sqlalchemy/query/filters.py +0 -0
  22. {nlbone-0.1.33 → nlbone-0.1.34}/src/nlbone/adapters/db/sqlalchemy/query/ordering.py +0 -0
  23. {nlbone-0.1.33 → nlbone-0.1.34}/src/nlbone/adapters/db/sqlalchemy/query/types.py +0 -0
  24. {nlbone-0.1.33 → nlbone-0.1.34}/src/nlbone/adapters/db/sqlalchemy/schema.py +0 -0
  25. {nlbone-0.1.33 → nlbone-0.1.34}/src/nlbone/adapters/http_clients/__init__.py +0 -0
  26. {nlbone-0.1.33 → nlbone-0.1.34}/src/nlbone/adapters/http_clients/email_gateway.py +0 -0
  27. {nlbone-0.1.33 → nlbone-0.1.34}/src/nlbone/adapters/http_clients/uploadchi_async.py +0 -0
  28. {nlbone-0.1.33 → nlbone-0.1.34}/src/nlbone/adapters/messaging/__init__.py +0 -0
  29. {nlbone-0.1.33 → nlbone-0.1.34}/src/nlbone/adapters/messaging/redis.py +0 -0
  30. {nlbone-0.1.33 → nlbone-0.1.34}/src/nlbone/config/__init__.py +0 -0
  31. {nlbone-0.1.33 → nlbone-0.1.34}/src/nlbone/config/logging.py +0 -0
  32. {nlbone-0.1.33 → nlbone-0.1.34}/src/nlbone/config/settings.py +0 -0
  33. {nlbone-0.1.33 → nlbone-0.1.34}/src/nlbone/container.py +0 -0
  34. {nlbone-0.1.33 → nlbone-0.1.34}/src/nlbone/core/__init__.py +0 -0
  35. {nlbone-0.1.33 → nlbone-0.1.34}/src/nlbone/core/application/__init__.py +0 -0
  36. {nlbone-0.1.33 → nlbone-0.1.34}/src/nlbone/core/application/services/__init__.py +0 -0
  37. {nlbone-0.1.33 → nlbone-0.1.34}/src/nlbone/core/application/services.py +0 -0
  38. {nlbone-0.1.33 → nlbone-0.1.34}/src/nlbone/core/application/use_cases/__init__.py +0 -0
  39. {nlbone-0.1.33 → nlbone-0.1.34}/src/nlbone/core/application/use_cases/register_user.py +0 -0
  40. {nlbone-0.1.33 → nlbone-0.1.34}/src/nlbone/core/domain/__init__.py +0 -0
  41. {nlbone-0.1.33 → nlbone-0.1.34}/src/nlbone/core/domain/events.py +0 -0
  42. {nlbone-0.1.33 → nlbone-0.1.34}/src/nlbone/core/domain/models.py +0 -0
  43. {nlbone-0.1.33 → nlbone-0.1.34}/src/nlbone/core/ports/__init__.py +0 -0
  44. {nlbone-0.1.33 → nlbone-0.1.34}/src/nlbone/core/ports/auth.py +0 -0
  45. {nlbone-0.1.33 → nlbone-0.1.34}/src/nlbone/core/ports/files.py +0 -0
  46. {nlbone-0.1.33 → nlbone-0.1.34}/src/nlbone/core/ports/messaging.py +0 -0
  47. {nlbone-0.1.33 → nlbone-0.1.34}/src/nlbone/core/ports/repo.py +0 -0
  48. {nlbone-0.1.33 → nlbone-0.1.34}/src/nlbone/interfaces/__init__.py +0 -0
  49. {nlbone-0.1.33 → nlbone-0.1.34}/src/nlbone/interfaces/api/__init__.py +0 -0
  50. {nlbone-0.1.33 → nlbone-0.1.34}/src/nlbone/interfaces/api/dependencies/__init__.py +0 -0
  51. {nlbone-0.1.33 → nlbone-0.1.34}/src/nlbone/interfaces/api/dependencies/db.py +0 -0
  52. {nlbone-0.1.33 → nlbone-0.1.34}/src/nlbone/interfaces/api/exceptions.py +0 -0
  53. {nlbone-0.1.33 → nlbone-0.1.34}/src/nlbone/interfaces/api/pagination/__init__.py +0 -0
  54. {nlbone-0.1.33 → nlbone-0.1.34}/src/nlbone/interfaces/api/pagination/offset_base.py +0 -0
  55. {nlbone-0.1.33 → nlbone-0.1.34}/src/nlbone/interfaces/api/routers.py +0 -0
  56. {nlbone-0.1.33 → nlbone-0.1.34}/src/nlbone/interfaces/api/schemas.py +0 -0
  57. {nlbone-0.1.33 → nlbone-0.1.34}/src/nlbone/interfaces/cli/__init__.py +0 -0
  58. {nlbone-0.1.33 → nlbone-0.1.34}/src/nlbone/interfaces/cli/init_db.py +0 -0
  59. {nlbone-0.1.33 → nlbone-0.1.34}/src/nlbone/interfaces/cli/main.py +0 -0
  60. {nlbone-0.1.33 → nlbone-0.1.34}/src/nlbone/interfaces/jobs/__init__.py +0 -0
  61. {nlbone-0.1.33 → nlbone-0.1.34}/src/nlbone/interfaces/jobs/sync_tokens.py +0 -0
  62. {nlbone-0.1.33 → nlbone-0.1.34}/src/nlbone/types.py +0 -0
  63. {nlbone-0.1.33 → nlbone-0.1.34}/src/nlbone/utils/__init__.py +0 -0
  64. {nlbone-0.1.33 → nlbone-0.1.34}/src/nlbone/utils/time.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nlbone
3
- Version: 0.1.33
3
+ Version: 0.1.34
4
4
  Summary: Backbone package for interfaces and infrastructure in Python projects
5
5
  Author-email: Amir Hosein Kahkbazzadeh <a.khakbazzadeh@gmail.com>
6
6
  License: MIT
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "nlbone"
7
- version = "0.1.33"
7
+ version = "0.1.34"
8
8
  description = "Backbone package for interfaces and infrastructure in Python projects"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -1,27 +1,35 @@
1
1
  from __future__ import annotations
2
2
  import json
3
3
  from typing import Any, Optional
4
+ from urllib.parse import urlparse, urlunparse
5
+
4
6
  import httpx
7
+ import requests
5
8
 
6
9
  from nlbone.core.ports.files import FileServicePort
7
10
  from nlbone.config.settings import get_settings
8
11
 
12
+
9
13
  class UploadchiError(RuntimeError):
10
14
  def __init__(self, status: int, detail: Any | None = None):
11
15
  super().__init__(f"Uploadchi HTTP {status}: {detail}")
12
16
  self.status = status
13
17
  self.detail = detail
14
18
 
19
+
15
20
  def _resolve_token(explicit: str | None) -> str | None:
16
21
  if explicit is not None:
17
22
  return explicit
18
23
  s = get_settings()
19
24
  return s.UPLOADCHI_TOKEN.get_secret_value() if s.UPLOADCHI_TOKEN else None
20
25
 
26
+
21
27
  def _auth_headers(token: str | None) -> dict[str, str]:
22
28
  return {"Authorization": f"Bearer {token}"} if token else {}
23
29
 
24
- def _build_list_query(limit: int, offset: int, filters: dict[str, Any] | None, sort: list[tuple[str, str]] | None) -> dict[str, Any]:
30
+
31
+ def _build_list_query(limit: int, offset: int, filters: dict[str, Any] | None, sort: list[tuple[str, str]] | None) -> \
32
+ dict[str, Any]:
25
33
  q: dict[str, Any] = {"limit": limit, "offset": offset}
26
34
  if filters:
27
35
  q["filters"] = json.dumps(filters)
@@ -29,6 +37,7 @@ def _build_list_query(limit: int, offset: int, filters: dict[str, Any] | None, s
29
37
  q["sort"] = ",".join([f"{f}:{o}" for f, o in sort])
30
38
  return q
31
39
 
40
+
32
41
  def _filename_from_cd(cd: str | None, fallback: str) -> str:
33
42
  if not cd:
34
43
  return fallback
@@ -36,49 +45,62 @@ def _filename_from_cd(cd: str | None, fallback: str) -> str:
36
45
  return cd.split("filename=", 1)[1].strip("\"'")
37
46
  return fallback
38
47
 
48
+
49
+ def _normalize_https_base(url: str) -> str:
50
+ p = urlparse(url.strip())
51
+ p = p._replace(scheme="https") # enforce https
52
+ if p.path.endswith("/"):
53
+ p = p._replace(path=p.path.rstrip("/"))
54
+ return str(urlunparse(p))
55
+
56
+
39
57
  class UploadchiClient(FileServicePort):
40
- def __init__(self, base_url: Optional[str] = None, timeout_seconds: Optional[float] = None, client: httpx.Client | None = None) -> None:
58
+ def __init__(self, base_url: Optional[str] = None, timeout_seconds: Optional[float] = None,
59
+ client: httpx.Client | None = None) -> None:
41
60
  s = get_settings()
42
- self._base_url = base_url or str(s.UPLOADCHI_BASE_URL)
61
+ self._base_url = _normalize_https_base(base_url or str(s.UPLOADCHI_BASE_URL))
43
62
  self._timeout = timeout_seconds or float(s.HTTP_TIMEOUT_SECONDS)
44
- self._client = client or httpx.Client(base_url=self._base_url, timeout=self._timeout, follow_redirects=True)
63
+ self._client = client or requests.session()
45
64
 
46
65
  def close(self) -> None:
47
66
  self._client.close()
48
67
 
49
- def upload_file(self, file_bytes: bytes, filename: str, params: dict[str, Any] | None = None, token: str | None = None) -> dict:
68
+ def upload_file(self, file_bytes: bytes, filename: str, params: dict[str, Any] | None = None,
69
+ token: str | None = None) -> dict:
50
70
  tok = _resolve_token(token)
51
71
  files = {"file": (filename, file_bytes)}
52
72
  data = (params or {}).copy()
53
- r = self._client.post("", files=files, data=data, headers=_auth_headers(tok))
73
+ r = self._client.post(self._base_url, files=files, data=data, headers=_auth_headers(tok))
54
74
  if r.status_code >= 400:
55
75
  raise UploadchiError(r.status_code, r.text)
56
76
  return r.json()
57
77
 
58
78
  def commit_file(self, file_id: int, client_id: str, token: str | None = None) -> None:
59
79
  tok = _resolve_token(token)
60
- r = self._client.post(f"/{file_id}/commit", headers=_auth_headers(tok), params={"client_id": client_id} if client_id else None)
80
+ r = self._client.post(f"{self._base_url}/{file_id}/commit", headers=_auth_headers(tok),
81
+ params={"client_id": client_id} if client_id else None)
61
82
  if r.status_code not in (204, 200):
62
83
  raise UploadchiError(r.status_code, r.text)
63
84
 
64
- def list_files(self, limit: int = 10, offset: int = 0, filters: dict[str, Any] | None = None, sort: list[tuple[str, str]] | None = None, token: str | None = None) -> dict:
85
+ def list_files(self, limit: int = 10, offset: int = 0, filters: dict[str, Any] | None = None,
86
+ sort: list[tuple[str, str]] | None = None, token: str | None = None) -> dict:
65
87
  tok = _resolve_token(token)
66
88
  q = _build_list_query(limit, offset, filters, sort)
67
- r = self._client.get("", params=q, headers=_auth_headers(tok))
89
+ r = self._client.get(self._base_url, params=q, headers=_auth_headers(tok))
68
90
  if r.status_code >= 400:
69
91
  raise UploadchiError(r.status_code, r.text)
70
92
  return r.json()
71
93
 
72
94
  def get_file(self, file_id: int, token: str | None = None) -> dict:
73
95
  tok = _resolve_token(token)
74
- r = self._client.get(f"/{file_id}", headers=_auth_headers(tok))
96
+ r = self._client.get(f"{self._base_url}/{file_id}", headers=_auth_headers(tok))
75
97
  if r.status_code >= 400:
76
98
  raise UploadchiError(r.status_code, r.text)
77
99
  return r.json()
78
100
 
79
101
  def download_file(self, file_id: int, token: str | None = None) -> tuple[bytes, str, str]:
80
102
  tok = _resolve_token(token)
81
- r = self._client.get(f"/{file_id}/download", headers=_auth_headers(tok))
103
+ r = self._client.get(f"{self._base_url}/{file_id}/download", headers=_auth_headers(tok))
82
104
  if r.status_code >= 400:
83
105
  raise UploadchiError(r.status_code, r.text)
84
106
  filename = _filename_from_cd(r.headers.get("content-disposition"), fallback=f"file-{file_id}")
@@ -87,6 +109,6 @@ class UploadchiClient(FileServicePort):
87
109
 
88
110
  def delete_file(self, file_id: int, token: str | None = None) -> None:
89
111
  tok = _resolve_token(token)
90
- r = self._client.delete(f"/{file_id}", headers=_auth_headers(tok))
112
+ r = self._client.delete(f"{self._base_url}/{file_id}", headers=_auth_headers(tok))
91
113
  if r.status_code not in (204, 200):
92
114
  raise UploadchiError(r.status_code, r.text)
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes