nlbone 0.1.31__py3-none-any.whl → 0.1.33__py3-none-any.whl

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,177 +1,92 @@
1
1
  from __future__ import annotations
2
-
3
2
  import json
4
- from typing import Any, AsyncIterator, Optional
5
-
3
+ from typing import Any, Optional
6
4
  import httpx
7
5
 
8
6
  from nlbone.core.ports.files import FileServicePort
9
7
  from nlbone.config.settings import get_settings
10
8
 
11
-
12
- class FileServiceException(RuntimeError):
9
+ class UploadchiError(RuntimeError):
13
10
  def __init__(self, status: int, detail: Any | None = None):
14
11
  super().__init__(f"Uploadchi HTTP {status}: {detail}")
15
12
  self.status = status
16
13
  self.detail = detail
17
14
 
15
+ def _resolve_token(explicit: str | None) -> str | None:
16
+ if explicit is not None:
17
+ return explicit
18
+ s = get_settings()
19
+ return s.UPLOADCHI_TOKEN.get_secret_value() if s.UPLOADCHI_TOKEN else None
18
20
 
19
21
  def _auth_headers(token: str | None) -> dict[str, str]:
20
22
  return {"Authorization": f"Bearer {token}"} if token else {}
21
23
 
22
-
23
- def _build_list_query(
24
- limit: int,
25
- offset: int,
26
- filters: dict[str, Any] | None,
27
- sort: list[tuple[str, str]] | None,
28
- ) -> dict[str, Any]:
24
+ def _build_list_query(limit: int, offset: int, filters: dict[str, Any] | None, sort: list[tuple[str, str]] | None) -> dict[str, Any]:
29
25
  q: dict[str, Any] = {"limit": limit, "offset": offset}
30
26
  if filters:
31
- # سرور شما `filters` را به صورت string می‌گیرد؛
32
- # اگر سمت سرور JSON هم قبول می‌کند، این بهتر است:
33
27
  q["filters"] = json.dumps(filters)
34
28
  if sort:
35
- # "created_at:desc,id:asc"
36
29
  q["sort"] = ",".join([f"{f}:{o}" for f, o in sort])
37
30
  return q
38
31
 
32
+ def _filename_from_cd(cd: str | None, fallback: str) -> str:
33
+ if not cd:
34
+ return fallback
35
+ if "filename=" in cd:
36
+ return cd.split("filename=", 1)[1].strip("\"'")
37
+ return fallback
39
38
 
40
39
  class UploadchiClient(FileServicePort):
41
- """
42
- httpx-based client for the Uploadchi microservice.
43
-
44
- Base URL نمونه: http://uploadchi.internal/api/v1/files
45
- """
46
-
47
- def __init__(
48
- self,
49
- base_url: Optional[str] = None,
50
- timeout_seconds: Optional[float] = None,
51
- client: httpx.AsyncClient | None = None,
52
- ) -> None:
40
+ def __init__(self, base_url: Optional[str] = None, timeout_seconds: Optional[float] = None, client: httpx.Client | None = None) -> None:
53
41
  s = get_settings()
54
42
  self._base_url = base_url or str(s.UPLOADCHI_BASE_URL)
55
43
  self._timeout = timeout_seconds or float(s.HTTP_TIMEOUT_SECONDS)
56
- # اگر کلاینت تزریق نشد، خودمان می‌سازیم
57
- self._client = client or httpx.AsyncClient(
58
- base_url=self._base_url,
59
- timeout=self._timeout,
60
- follow_redirects=True,
61
- )
62
-
63
- async def aclose(self) -> None:
64
- await self._client.aclose()
44
+ self._client = client or httpx.Client(base_url=self._base_url, timeout=self._timeout, follow_redirects=True)
65
45
 
66
- # ---------- Endpoints ----------
46
+ def close(self) -> None:
47
+ self._client.close()
67
48
 
68
- async def upload_file(
69
- self,
70
- file_bytes: bytes,
71
- filename: str,
72
- params: dict[str, Any] | None = None,
73
- token: str | None = None,
74
- ) -> dict:
75
- """
76
- POST "" → returns FileOut (dict)
77
- fields:
78
- - file: Upload (multipart)
79
- - other params (e.g., bucket, folder, content_type, ...)
80
- """
49
+ def upload_file(self, file_bytes: bytes, filename: str, params: dict[str, Any] | None = None, token: str | None = None) -> dict:
50
+ tok = _resolve_token(token)
81
51
  files = {"file": (filename, file_bytes)}
82
52
  data = (params or {}).copy()
83
- r = await self._client.post(
84
- url="",
85
- files=files,
86
- data=data,
87
- headers=_auth_headers(token),
88
- )
53
+ r = self._client.post("", files=files, data=data, headers=_auth_headers(tok))
89
54
  if r.status_code >= 400:
90
- raise FileServiceException(r.status_code, r.text)
55
+ raise UploadchiError(r.status_code, r.text)
91
56
  return r.json()
92
57
 
93
- async def commit_file(
94
- self,
95
- file_id: int,
96
- client_id: str,
97
- token: str | None = None,
98
- ) -> None:
99
- """
100
- POST "/{file_id}/commit" 204
101
- """
102
- r = await self._client.post(
103
- f"/{file_id}/commit",
104
- headers=_auth_headers(token),
105
- params={"client_id": client_id} if client_id else None,
106
- )
58
+ def commit_file(self, file_id: int, client_id: str, token: str | None = None) -> None:
59
+ 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)
107
61
  if r.status_code not in (204, 200):
108
- raise FileServiceException(r.status_code, r.text)
62
+ raise UploadchiError(r.status_code, r.text)
109
63
 
110
- async def list_files(
111
- self,
112
- limit: int = 10,
113
- offset: int = 0,
114
- filters: dict[str, Any] | None = None,
115
- sort: list[tuple[str, str]] | None = None,
116
- token: str | None = None,
117
- ) -> dict:
118
- """
119
- GET "" → returns PaginateResponse-like dict
120
- { "data": [...], "total_count": int | null, "total_page": int | null }
121
- """
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:
65
+ tok = _resolve_token(token)
122
66
  q = _build_list_query(limit, offset, filters, sort)
123
- r = await self._client.get("", params=q, headers=_auth_headers(token))
67
+ r = self._client.get("", params=q, headers=_auth_headers(tok))
124
68
  if r.status_code >= 400:
125
- raise FileServiceException(r.status_code, r.text)
69
+ raise UploadchiError(r.status_code, r.text)
126
70
  return r.json()
127
71
 
128
- async def get_file(
129
- self,
130
- file_id: int,
131
- token: str | None = None,
132
- ) -> dict:
133
- """
134
- GET "/{file_id}" → FileOut dict
135
- """
136
- r = await self._client.get(f"/{file_id}", headers=_auth_headers(token))
72
+ def get_file(self, file_id: int, token: str | None = None) -> dict:
73
+ tok = _resolve_token(token)
74
+ r = self._client.get(f"/{file_id}", headers=_auth_headers(tok))
137
75
  if r.status_code >= 400:
138
- raise FileServiceException(r.status_code, r.text)
76
+ raise UploadchiError(r.status_code, r.text)
139
77
  return r.json()
140
78
 
141
- async def download_file(
142
- self,
143
- file_id: int,
144
- token: str | None = None,
145
- ) -> tuple[AsyncIterator[bytes], str, str]:
146
- """
147
- GET "/{file_id}/download" → stream + headers (filename, content-type)
148
- """
149
- r = await self._client.get(f"/{file_id}/download", headers=_auth_headers(token))
79
+ def download_file(self, file_id: int, token: str | None = None) -> tuple[bytes, str, str]:
80
+ tok = _resolve_token(token)
81
+ r = self._client.get(f"/{file_id}/download", headers=_auth_headers(tok))
150
82
  if r.status_code >= 400:
151
- text = await r.aread()
152
- raise FileServiceException(r.status_code, text.decode(errors="ignore"))
153
-
154
- disp = r.headers.get("content-disposition", "")
155
- filename = (
156
- disp.split("filename=", 1)[1].strip("\"'") if "filename=" in disp else f"file-{file_id}"
157
- )
83
+ raise UploadchiError(r.status_code, r.text)
84
+ filename = _filename_from_cd(r.headers.get("content-disposition"), fallback=f"file-{file_id}")
158
85
  media_type = r.headers.get("content-type", "application/octet-stream")
86
+ return r.content, filename, media_type
159
87
 
160
- async def _aiter() -> AsyncIterator[bytes]:
161
- async for chunk in r.aiter_bytes():
162
- yield chunk
163
- await r.aclose()
164
-
165
- return _aiter(), filename, media_type
166
-
167
- async def delete_file(
168
- self,
169
- file_id: int,
170
- token: str | None = None,
171
- ) -> None:
172
- """
173
- DELETE "/{file_id}" → 204
174
- """
175
- r = await self._client.delete(f"/{file_id}", headers=_auth_headers(token))
88
+ def delete_file(self, file_id: int, token: str | None = None) -> None:
89
+ tok = _resolve_token(token)
90
+ r = self._client.delete(f"/{file_id}", headers=_auth_headers(tok))
176
91
  if r.status_code not in (204, 200):
177
- raise FileServiceException(r.status_code, r.text)
92
+ raise UploadchiError(r.status_code, r.text)
@@ -0,0 +1,72 @@
1
+ from __future__ import annotations
2
+ from typing import Any, Optional, AsyncIterator
3
+ import httpx
4
+
5
+ from nlbone.core.ports.files import AsyncFileServicePort
6
+ from nlbone.config.settings import get_settings
7
+ from .uploadchi import UploadchiError, _auth_headers, _build_list_query, _filename_from_cd, _resolve_token
8
+
9
+ class UploadchiAsyncClient(AsyncFileServicePort):
10
+ def __init__(self, base_url: Optional[str] = None, timeout_seconds: Optional[float] = None, client: httpx.AsyncClient | None = None) -> None:
11
+ s = get_settings()
12
+ self._base_url = base_url or str(s.UPLOADCHI_BASE_URL)
13
+ self._timeout = timeout_seconds or float(s.HTTP_TIMEOUT_SECONDS)
14
+ self._client = client or httpx.AsyncClient(base_url=self._base_url, timeout=self._timeout, follow_redirects=True)
15
+
16
+ async def aclose(self) -> None:
17
+ await self._client.aclose()
18
+
19
+ async def upload_file(self, file_bytes: bytes, filename: str, params: dict[str, Any] | None = None, token: str | None = None) -> dict:
20
+ tok = _resolve_token(token)
21
+ files = {"file": (filename, file_bytes)}
22
+ data = (params or {}).copy()
23
+ r = await self._client.post("", files=files, data=data, headers=_auth_headers(tok))
24
+ if r.status_code >= 400:
25
+ raise UploadchiError(r.status_code, await r.aread())
26
+ return r.json()
27
+
28
+ async def commit_file(self, file_id: int, client_id: str, token: str | None = None) -> None:
29
+ tok = _resolve_token(token)
30
+ r = await self._client.post(f"/{file_id}/commit", headers=_auth_headers(tok), params={"client_id": client_id} if client_id else None)
31
+ if r.status_code not in (204, 200):
32
+ raise UploadchiError(r.status_code, await r.aread())
33
+
34
+ async 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:
35
+ tok = _resolve_token(token)
36
+ q = _build_list_query(limit, offset, filters, sort)
37
+ r = await self._client.get("", params=q, headers=_auth_headers(tok))
38
+ if r.status_code >= 400:
39
+ raise UploadchiError(r.status_code, await r.aread())
40
+ return r.json()
41
+
42
+ async def get_file(self, file_id: int, token: str | None = None) -> dict:
43
+ tok = _resolve_token(token)
44
+ r = await self._client.get(f"/{file_id}", headers=_auth_headers(tok))
45
+ if r.status_code >= 400:
46
+ raise UploadchiError(r.status_code, await r.aread())
47
+ return r.json()
48
+
49
+ async def download_file(self, file_id: int, token: str | None = None) -> tuple[AsyncIterator[bytes], str, str]:
50
+ tok = _resolve_token(token)
51
+ r = await self._client.get(f"/{file_id}/download", headers=_auth_headers(tok), stream=True)
52
+ if r.status_code >= 400:
53
+ body = await r.aread()
54
+ raise UploadchiError(r.status_code, body.decode(errors="ignore"))
55
+ filename = _filename_from_cd(r.headers.get("content-disposition"), fallback=f"file-{file_id}")
56
+ media_type = r.headers.get("content-type", "application/octet-stream")
57
+
58
+ async def _aiter() -> AsyncIterator[bytes]:
59
+ try:
60
+ async for chunk in r.aiter_bytes():
61
+ yield chunk
62
+ finally:
63
+ await r.aclose()
64
+
65
+ return _aiter(), filename, media_type
66
+
67
+ async def delete_file(self, file_id: int, token: str | None = None) -> None:
68
+ tok = _resolve_token(token)
69
+ r = await self._client.delete(f"/{file_id}", headers=_auth_headers(tok))
70
+ if r.status_code not in (204, 200):
71
+ body = await r.aread()
72
+ raise UploadchiError(r.status_code, body.decode(errors="ignore"))
nlbone/config/settings.py CHANGED
@@ -2,7 +2,7 @@ import os
2
2
  from functools import lru_cache
3
3
  from pathlib import Path
4
4
  from typing import Literal
5
- from pydantic import AnyHttpUrl, Field, SecretStr
5
+ from pydantic import AnyHttpUrl, Field, SecretStr, AliasChoices
6
6
  from pydantic_settings import BaseSettings, SettingsConfigDict
7
7
 
8
8
 
@@ -54,7 +54,14 @@ class Settings(BaseSettings):
54
54
  # ---------------------------
55
55
  REDIS_URL: str = Field(default="redis://localhost:6379/0")
56
56
 
57
+ # ---------------------------
58
+ # UPLOADCHI
59
+ # ---------------------------
57
60
  UPLOADCHI_BASE_URL: AnyHttpUrl = Field(default="https://uploadchi.numberland.ir/v1/files")
61
+ UPLOADCHI_TOKEN: SecretStr | None = Field(
62
+ default=None,
63
+ validation_alias=AliasChoices("NLBONE_UPLOADCHI_TOKEN", "UPLOADCHI_TOKEN"),
64
+ )
58
65
 
59
66
  model_config = SettingsConfigDict(
60
67
  env_prefix="NLBONE_",
@@ -1,7 +1,8 @@
1
1
  from nlbone.adapters.http_clients.uploadchi import UploadchiClient
2
+ from nlbone.adapters.http_clients.uploadchi_async import UploadchiAsyncClient
2
3
  from nlbone.config.settings import Settings
3
4
  from nlbone.adapters.auth.keycloak import KeycloakAuthService
4
- from nlbone.core.ports.files import FileServicePort
5
+ from nlbone.core.ports.files import FileServicePort, AsyncFileServicePort
5
6
 
6
7
 
7
8
  class Container:
@@ -9,3 +10,4 @@ class Container:
9
10
  self.settings = settings or Settings()
10
11
  self.auth: KeycloakAuthService = KeycloakAuthService(self.settings)
11
12
  self.file_service: FileServicePort = UploadchiClient()
13
+ self.afiles_service: AsyncFileServicePort = UploadchiAsyncClient()
@@ -3,45 +3,18 @@ from typing import Protocol, runtime_checkable, AsyncIterator, Any
3
3
 
4
4
  @runtime_checkable
5
5
  class FileServicePort(Protocol):
6
- async def upload_file(
7
- self,
8
- file_bytes: bytes,
9
- filename: str,
10
- params: dict[str, Any] | None = None,
11
- token: str | None = None,
12
- ) -> dict: ...
6
+ def upload_file(self, file_bytes: bytes, filename: str, params: dict[str, Any] | None = None, token: str | None = None) -> dict: ...
7
+ def commit_file(self, file_id: int, client_id: str, token: str | None = None) -> None: ...
8
+ 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: ...
9
+ def get_file(self, file_id: int, token: str | None = None) -> dict: ...
10
+ def download_file(self, file_id: int, token: str | None = None) -> tuple[bytes, str, str]: ...
11
+ def delete_file(self, file_id: int, token: str | None = None) -> None: ...
13
12
 
14
- async def commit_file(
15
- self,
16
- file_id: int,
17
- client_id: str,
18
- token: str | None = None,
19
- ) -> None: ...
20
-
21
- async def list_files(
22
- self,
23
- limit: int = 10,
24
- offset: int = 0,
25
- filters: dict[str, Any] | None = None,
26
- sort: list[tuple[str, str]] | None = None,
27
- token: str | None = None,
28
- ) -> dict: ...
29
-
30
- async def get_file(
31
- self,
32
- file_id: int,
33
- token: str | None = None,
34
- ) -> dict: ...
35
-
36
- async def download_file(
37
- self,
38
- file_id: int,
39
- token: str | None = None,
40
- ) -> tuple[AsyncIterator[bytes], str, str]:
41
- ...
42
-
43
- async def delete_file(
44
- self,
45
- file_id: int,
46
- token: str | None = None,
47
- ) -> None: ...
13
+ @runtime_checkable
14
+ class AsyncFileServicePort(Protocol):
15
+ async def upload_file(self, file_bytes: bytes, filename: str, params: dict[str, Any] | None = None, token: str | None = None) -> dict: ...
16
+ async def commit_file(self, file_id: int, client_id: str, token: str | None = None) -> None: ...
17
+ async 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: ...
18
+ async def get_file(self, file_id: int, token: str | None = None) -> dict: ...
19
+ async def download_file(self, file_id: int, token: str | None = None) -> tuple[AsyncIterator[bytes], str, str]: ...
20
+ async def delete_file(self, file_id: int, token: str | None = None) -> None: ...
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nlbone
3
- Version: 0.1.31
3
+ Version: 0.1.33
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
@@ -1,4 +1,5 @@
1
1
  nlbone/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ nlbone/container.py,sha256=JLEiJSh7vZAl7kBY6bwqtL3IzHFOxhrfreaZDU6K9n0,663
2
3
  nlbone/types.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
4
  nlbone/adapters/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
5
  nlbone/adapters/auth/__init__.py,sha256=Eh9kWjY1I8vi17gK0oOzBLJwJX_GFuUcJIN7cLU6lJg,41
@@ -19,12 +20,13 @@ nlbone/adapters/db/sqlalchemy/query/ordering.py,sha256=THbuxZmoFZzJIa28KfDQ6ioS8
19
20
  nlbone/adapters/db/sqlalchemy/query/types.py,sha256=M2j6SOSyFkLuyXq4kvPYgZQYz5TKCBe3osoIIN1yfBI,287
20
21
  nlbone/adapters/http_clients/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
22
  nlbone/adapters/http_clients/email_gateway.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
- nlbone/adapters/http_clients/uploadchi.py,sha256=tr-huESnVDg08FQh3QTFST7_JQz7dPShr2CAX9CQYLU,5737
23
+ nlbone/adapters/http_clients/uploadchi.py,sha256=k6d1JW9BLvY1aEjCMp8AJF6a-VVKOIVR0OsaYHxVnhc,4201
24
+ nlbone/adapters/http_clients/uploadchi_async.py,sha256=u-CHisQoTjuhyXb5h-TLDnfeUnN47e-VEbKamUnkaYI,3710
23
25
  nlbone/adapters/messaging/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
26
  nlbone/adapters/messaging/redis.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
25
27
  nlbone/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
26
28
  nlbone/config/logging.py,sha256=68WRQejEpL6eHEY_cOgdlOjndKc-RWth0n4YmXnceC8,5041
27
- nlbone/config/settings.py,sha256=ElE--1waYQ2o_5u7HzHi800zsK9n_oJBz1VnewYm-Y0,2368
29
+ nlbone/config/settings.py,sha256=IbjhevN_0TuO_on1-VxXH_aOaVwj3K7YBhU8X9tIWE4,2626
28
30
  nlbone/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
29
31
  nlbone/core/application/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
30
32
  nlbone/core/application/services.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -36,11 +38,9 @@ nlbone/core/domain/events.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,
36
38
  nlbone/core/domain/models.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
37
39
  nlbone/core/ports/__init__.py,sha256=J24ldeLIQ_AWqKpdNbtaEWq4-G4cyWx8XEG0Dt6keao,29
38
40
  nlbone/core/ports/auth.py,sha256=v2NiH8FzKXZ1MabzQxaK7AQvnt-GQindYIki90swTE4,492
39
- nlbone/core/ports/files.py,sha256=dYBMFsaesyIVaWxzTShGFMFzRZWbWcQtPdzhELY6t4A,1119
41
+ nlbone/core/ports/files.py,sha256=yJwW0kFWxkrT4ntfXDdJYyKSEWB6daEuaI6zgmeg0Gg,1596
40
42
  nlbone/core/ports/messaging.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
41
43
  nlbone/core/ports/repo.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
42
- nlbone/di/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
43
- nlbone/di/container.py,sha256=nzWx8nctyBMAERoqjolt0vWS38H2JH2QhqVaLvAvF8U,488
44
44
  nlbone/interfaces/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
45
45
  nlbone/interfaces/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
46
46
  nlbone/interfaces/api/exceptions.py,sha256=OczR1FND2nbCngwbfgaPrgDbDaz4Pc47mFSHgtL7tW8,313
@@ -57,7 +57,7 @@ nlbone/interfaces/jobs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3
57
57
  nlbone/interfaces/jobs/sync_tokens.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
58
58
  nlbone/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
59
59
  nlbone/utils/time.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
60
- nlbone-0.1.31.dist-info/METADATA,sha256=AQxSX36K4Z747tRRCrLWQ0qpuZyI586sVHKK00WAooo,2256
61
- nlbone-0.1.31.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
62
- nlbone-0.1.31.dist-info/licenses/LICENSE,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
63
- nlbone-0.1.31.dist-info/RECORD,,
60
+ nlbone-0.1.33.dist-info/METADATA,sha256=Ug8O3AcnsrkA6y8ZBRZDGymAXaqjjIBW1Js-hQqvLHw,2256
61
+ nlbone-0.1.33.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
62
+ nlbone-0.1.33.dist-info/licenses/LICENSE,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
63
+ nlbone-0.1.33.dist-info/RECORD,,
nlbone/di/__init__.py DELETED
File without changes