espark-core 0.5.3__tar.gz → 0.5.4__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.

Potentially problematic release.


This version of espark-core might be problematic. Click here for more details.

Files changed (49) hide show
  1. {espark_core-0.5.3/espark_core.egg-info → espark_core-0.5.4}/PKG-INFO +4 -4
  2. {espark_core-0.5.3 → espark_core-0.5.4/espark_core.egg-info}/PKG-INFO +4 -4
  3. {espark_core-0.5.3 → espark_core-0.5.4}/espark_core.egg-info/requires.txt +2 -2
  4. {espark_core-0.5.3 → espark_core-0.5.4}/esparkcore/data/repositories/base_repository.py +3 -3
  5. {espark_core-0.5.3 → espark_core-0.5.4}/esparkcore/data/repositories/telemetry_repository.py +1 -1
  6. {espark_core-0.5.3 → espark_core-0.5.4}/esparkcore/routers/base_router.py +6 -6
  7. {espark_core-0.5.3 → espark_core-0.5.4}/esparkcore/routers/device_router.py +2 -2
  8. {espark_core-0.5.3 → espark_core-0.5.4}/esparkcore/routers/telemetry_router.py +2 -2
  9. {espark_core-0.5.3 → espark_core-0.5.4}/requirements.txt +2 -2
  10. {espark_core-0.5.3 → espark_core-0.5.4}/setup.py +2 -2
  11. {espark_core-0.5.3 → espark_core-0.5.4}/LICENSE +0 -0
  12. {espark_core-0.5.3 → espark_core-0.5.4}/MANIFEST.in +0 -0
  13. {espark_core-0.5.3 → espark_core-0.5.4}/README.md +0 -0
  14. {espark_core-0.5.3 → espark_core-0.5.4}/espark_core.egg-info/SOURCES.txt +0 -0
  15. {espark_core-0.5.3 → espark_core-0.5.4}/espark_core.egg-info/dependency_links.txt +0 -0
  16. {espark_core-0.5.3 → espark_core-0.5.4}/espark_core.egg-info/top_level.txt +0 -0
  17. {espark_core-0.5.3 → espark_core-0.5.4}/esparkcore/__init__.py +0 -0
  18. {espark_core-0.5.3 → espark_core-0.5.4}/esparkcore/constants.py +0 -0
  19. {espark_core-0.5.3 → espark_core-0.5.4}/esparkcore/data/__init__.py +0 -0
  20. {espark_core-0.5.3 → espark_core-0.5.4}/esparkcore/data/database.py +0 -0
  21. {espark_core-0.5.3 → espark_core-0.5.4}/esparkcore/data/models/__init__.py +0 -0
  22. {espark_core-0.5.3 → espark_core-0.5.4}/esparkcore/data/models/device.py +0 -0
  23. {espark_core-0.5.3 → espark_core-0.5.4}/esparkcore/data/models/notification.py +0 -0
  24. {espark_core-0.5.3 → espark_core-0.5.4}/esparkcore/data/models/outbox.py +0 -0
  25. {espark_core-0.5.3 → espark_core-0.5.4}/esparkcore/data/models/telemetry.py +0 -0
  26. {espark_core-0.5.3 → espark_core-0.5.4}/esparkcore/data/models/trigger.py +0 -0
  27. {espark_core-0.5.3 → espark_core-0.5.4}/esparkcore/data/models/version.py +0 -0
  28. {espark_core-0.5.3 → espark_core-0.5.4}/esparkcore/data/repositories/__init__.py +0 -0
  29. {espark_core-0.5.3 → espark_core-0.5.4}/esparkcore/data/repositories/device_repository.py +0 -0
  30. {espark_core-0.5.3 → espark_core-0.5.4}/esparkcore/data/repositories/notification_repository.py +0 -0
  31. {espark_core-0.5.3 → espark_core-0.5.4}/esparkcore/data/repositories/outbox_repository.py +0 -0
  32. {espark_core-0.5.3 → espark_core-0.5.4}/esparkcore/data/repositories/trigger_repository.py +0 -0
  33. {espark_core-0.5.3 → espark_core-0.5.4}/esparkcore/data/repositories/version_repository.py +0 -0
  34. {espark_core-0.5.3 → espark_core-0.5.4}/esparkcore/notifications/__init__.py +0 -0
  35. {espark_core-0.5.3 → espark_core-0.5.4}/esparkcore/notifications/notifier.py +0 -0
  36. {espark_core-0.5.3 → espark_core-0.5.4}/esparkcore/notifications/slack_notifier.py +0 -0
  37. {espark_core-0.5.3 → espark_core-0.5.4}/esparkcore/routers/__init__.py +0 -0
  38. {espark_core-0.5.3 → espark_core-0.5.4}/esparkcore/routers/notification_router.py +0 -0
  39. {espark_core-0.5.3 → espark_core-0.5.4}/esparkcore/routers/trigger_router.py +0 -0
  40. {espark_core-0.5.3 → espark_core-0.5.4}/esparkcore/routers/version_router.py +0 -0
  41. {espark_core-0.5.3 → espark_core-0.5.4}/esparkcore/schedules/__init__.py +0 -0
  42. {espark_core-0.5.3 → espark_core-0.5.4}/esparkcore/schedules/outbox.py +0 -0
  43. {espark_core-0.5.3 → espark_core-0.5.4}/esparkcore/schedules/scheduler.py +0 -0
  44. {espark_core-0.5.3 → espark_core-0.5.4}/esparkcore/services/__init__.py +0 -0
  45. {espark_core-0.5.3 → espark_core-0.5.4}/esparkcore/services/mqtt.py +0 -0
  46. {espark_core-0.5.3 → espark_core-0.5.4}/esparkcore/utils/__init__.py +0 -0
  47. {espark_core-0.5.3 → espark_core-0.5.4}/esparkcore/utils/logging.py +0 -0
  48. {espark_core-0.5.3 → espark_core-0.5.4}/requirements.dev.txt +0 -0
  49. {espark_core-0.5.3 → espark_core-0.5.4}/setup.cfg +0 -0
@@ -1,18 +1,18 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: espark-core
3
- Version: 0.5.3
3
+ Version: 0.5.4
4
4
  Summary: The core module of the Espark ESP32-based IoT device management framework.
5
5
  License: MIT
6
- Requires-Python: >=3.8
6
+ Requires-Python: >=3.10
7
7
  Description-Content-Type: text/markdown
8
8
  License-File: LICENSE
9
9
  Requires-Dist: aiomqtt>=2.4.0
10
10
  Requires-Dist: apscheduler>=3.11.2
11
- Requires-Dist: fastapi>=0.127.0
11
+ Requires-Dist: fastapi>=0.128.0
12
12
  Requires-Dist: packaging>=25.0
13
13
  Requires-Dist: slack-sdk==3.39.0
14
14
  Requires-Dist: sqlalchemy>=2.0.45
15
- Requires-Dist: sqlmodel>=0.0.29
15
+ Requires-Dist: sqlmodel>=0.0.31
16
16
  Requires-Dist: uvicorn[standard]>=0.40.0
17
17
  Provides-Extra: dev
18
18
  Requires-Dist: aiosqlite==0.22.1; extra == "dev"
@@ -1,18 +1,18 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: espark-core
3
- Version: 0.5.3
3
+ Version: 0.5.4
4
4
  Summary: The core module of the Espark ESP32-based IoT device management framework.
5
5
  License: MIT
6
- Requires-Python: >=3.8
6
+ Requires-Python: >=3.10
7
7
  Description-Content-Type: text/markdown
8
8
  License-File: LICENSE
9
9
  Requires-Dist: aiomqtt>=2.4.0
10
10
  Requires-Dist: apscheduler>=3.11.2
11
- Requires-Dist: fastapi>=0.127.0
11
+ Requires-Dist: fastapi>=0.128.0
12
12
  Requires-Dist: packaging>=25.0
13
13
  Requires-Dist: slack-sdk==3.39.0
14
14
  Requires-Dist: sqlalchemy>=2.0.45
15
- Requires-Dist: sqlmodel>=0.0.29
15
+ Requires-Dist: sqlmodel>=0.0.31
16
16
  Requires-Dist: uvicorn[standard]>=0.40.0
17
17
  Provides-Extra: dev
18
18
  Requires-Dist: aiosqlite==0.22.1; extra == "dev"
@@ -1,10 +1,10 @@
1
1
  aiomqtt>=2.4.0
2
2
  apscheduler>=3.11.2
3
- fastapi>=0.127.0
3
+ fastapi>=0.128.0
4
4
  packaging>=25.0
5
5
  slack-sdk==3.39.0
6
6
  sqlalchemy>=2.0.45
7
- sqlmodel>=0.0.29
7
+ sqlmodel>=0.0.31
8
8
  uvicorn[standard]>=0.40.0
9
9
 
10
10
  [dev]
@@ -1,6 +1,6 @@
1
1
  from typing import Generic, Optional, Sequence, Type, TypeVar
2
2
 
3
- from sqlalchemy import func, ColumnElement
3
+ from sqlalchemy import ColumnElement, func, text
4
4
  from sqlalchemy.ext.asyncio import AsyncSession
5
5
  from sqlmodel import select, SQLModel
6
6
 
@@ -41,14 +41,14 @@ class AsyncRepository(Generic[T]):
41
41
 
42
42
  return (await session.execute(query)).scalars().first()
43
43
 
44
- async def list(self, session: AsyncSession, *conditions: ColumnElement[bool], offset: Optional[int] = None, order_by=None, limit: Optional[int] = None) -> Sequence[T]:
44
+ async def list(self, session: AsyncSession, *conditions: ColumnElement[bool], offset: Optional[int] = None, order_by: ColumnElement | str = None, limit: Optional[int] = None) -> Sequence[T]:
45
45
  query = select(self.model)
46
46
 
47
47
  if conditions:
48
48
  query = query.where(*conditions)
49
49
 
50
50
  if order_by is not None:
51
- query = query.order_by(order_by)
51
+ query = query.order_by(text(order_by) if isinstance(order_by, str) else order_by)
52
52
 
53
53
  if offset is not None:
54
54
  query = query.offset(offset)
@@ -17,7 +17,7 @@ class TelemetryRepository(AsyncRepository[Telemetry]):
17
17
  results = await self.list(session, and_(Telemetry.device_id == device_id, Telemetry.data_type == data_type), order_by=Telemetry.timestamp.desc(), limit=1)
18
18
  return results[0] if results else None
19
19
 
20
- async def list(self, session: AsyncSession, *conditions: ColumnElement[bool], offset: Optional[int] = None, order_by=None, limit: Optional[int] = None) -> Sequence[Telemetry]:
20
+ async def list(self, session: AsyncSession, *conditions: ColumnElement[bool], offset: Optional[int] = None, order_by: ColumnElement | str = None, limit: Optional[int] = None) -> Sequence[Telemetry]:
21
21
  if order_by is None:
22
22
  # pylint: disable=no-member
23
23
  order_by = Telemetry.timestamp.desc()
@@ -1,6 +1,6 @@
1
1
  from typing import Generic, List, Sequence, Type, TypeVar
2
2
 
3
- from fastapi import APIRouter, Body, Depends, HTTPException, Query, status, Response
3
+ from fastapi import APIRouter, Body, Depends, HTTPException, Query, status, Response, Path
4
4
  from sqlalchemy.ext.asyncio import AsyncSession
5
5
  from sqlmodel import SQLModel
6
6
 
@@ -57,7 +57,7 @@ class BaseRouter(Generic[T]):
57
57
  return result
58
58
 
59
59
  @self.router.delete('/{id}', status_code=status.HTTP_204_NO_CONTENT)
60
- async def delete(id: str, session: AsyncSession = Depends(BaseRouter._get_session)) -> None:
60
+ async def delete(id: str = Path(..., min_length=1), session: AsyncSession = Depends(BaseRouter._get_session)) -> None:
61
61
  entity = await self.repo.get(session, self.model.id == id)
62
62
  if not entity:
63
63
  raise HTTPException(status_code=status.HTTP_404_NOT_FOUND)
@@ -67,7 +67,7 @@ class BaseRouter(Generic[T]):
67
67
  await self._after_delete(entity, session)
68
68
 
69
69
  @self.router.get('/{id}', response_model=self.model)
70
- async def get(id: str, session: AsyncSession = Depends(BaseRouter._get_session)) -> T:
70
+ async def get(id: str = Path(..., min_length=1), session: AsyncSession = Depends(BaseRouter._get_session)) -> T:
71
71
  entity = await self.repo.get(session, self.model.id == id)
72
72
  if not entity:
73
73
  raise HTTPException(status_code=status.HTTP_404_NOT_FOUND)
@@ -75,13 +75,13 @@ class BaseRouter(Generic[T]):
75
75
  return entity
76
76
 
77
77
  @self.router.get('/', response_model=List[self.model])
78
- async def list(response: Response, session: AsyncSession = Depends(BaseRouter._get_session), offset: int = Query(None, ge=0), limit: int = Query(None, ge=1, le=100)) -> Sequence[T]:
78
+ async def list(response: Response, session: AsyncSession = Depends(BaseRouter._get_session), order_by: str = Query(None), offset: int = Query(0, ge=0), limit: int = Query(10, ge=1, le=100)) -> Sequence[T]:
79
79
  response.headers['X-Total-Count'] = str(await self.repo.count(session))
80
80
 
81
- return await self.repo.list(session, offset=offset, limit=limit)
81
+ return await self.repo.list(session, order_by=order_by, offset=offset, limit=limit)
82
82
 
83
83
  @self.router.put('/{id}', response_model=self.model)
84
- async def update(id: str, data: dict = Body(...), session: AsyncSession = Depends(BaseRouter._get_session)) -> T:
84
+ async def update(id: str = Path(..., min_length=1), data: dict = Body(...), session: AsyncSession = Depends(BaseRouter._get_session)) -> T:
85
85
  entity = await self.repo.get(session, self.model.id == id)
86
86
  if not entity:
87
87
  raise HTTPException(status_code=status.HTTP_404_NOT_FOUND)
@@ -31,10 +31,10 @@ class DeviceRouter(BaseRouter):
31
31
 
32
32
  def _setup_routes(self) -> None:
33
33
  @self.router.get('/all')
34
- async def list_all(response: Response, session: AsyncSession = Depends(BaseRouter._get_session), offset: int = Query(None, ge=0), limit: int = Query(None, ge=1, le=100)):
34
+ async def list_all(response: Response, session: AsyncSession = Depends(BaseRouter._get_session), order_by: str = Query(None), offset: int = Query(0, ge=0), limit: int = Query(10, ge=1, le=100)):
35
35
  response.headers['X-Total-Count'] = str(await self.repo.count(session))
36
36
 
37
- devices = await self.repo.list(session, offset=offset, limit=limit)
37
+ devices = await self.repo.list(session, order_by=order_by, offset=offset, limit=limit)
38
38
  devices_with_telemetry = []
39
39
  telemetry_repo = TelemetryRepository()
40
40
 
@@ -18,7 +18,7 @@ class TelemetryRouter(BaseRouter):
18
18
 
19
19
  def _setup_routes(self) -> None:
20
20
  @self.router.get('/history', response_model=Sequence[Telemetry])
21
- async def list_history(response: Response, session: AsyncSession = Depends(BaseRouter._get_session), device_id: int = Query(..., ge=1), offset: int = Query(..., min=0)) -> Sequence[Telemetry]:
21
+ async def list_history(response: Response, session: AsyncSession = Depends(BaseRouter._get_session), device_id: str = Query(..., min_length=1), offset: int = Query(0, min=0)) -> Sequence[Telemetry]:
22
22
  from_date = datetime.now(timezone.utc) - timedelta(seconds=offset)
23
23
  results = await self.repo.list(session, and_(Telemetry.device_id == device_id, Telemetry.timestamp >= from_date))
24
24
 
@@ -27,7 +27,7 @@ class TelemetryRouter(BaseRouter):
27
27
  return results
28
28
 
29
29
  @self.router.get('/recent', response_model=Sequence[Telemetry])
30
- async def list_recent(response: Response, session: AsyncSession = Depends(BaseRouter._get_session), offset: int = Query(..., min=0)) -> Sequence[Telemetry]:
30
+ async def list_recent(response: Response, session: AsyncSession = Depends(BaseRouter._get_session), offset: int = Query(0, min=0)) -> Sequence[Telemetry]:
31
31
  from_date = datetime.now(timezone.utc) - timedelta(seconds=offset)
32
32
  device_repo = DeviceRepository()
33
33
  # pylint: disable=no-member
@@ -1,8 +1,8 @@
1
1
  aiomqtt>=2.4.0
2
2
  apscheduler>=3.11.2
3
- fastapi>=0.127.0
3
+ fastapi>=0.128.0
4
4
  packaging>=25.0
5
5
  slack-sdk==3.39.0
6
6
  sqlalchemy>=2.0.45
7
- sqlmodel>=0.0.29
7
+ sqlmodel>=0.0.31
8
8
  uvicorn[standard]>=0.40.0
@@ -10,7 +10,7 @@ extra_requirements = (root / 'requirements.dev.txt').read_text().splitlines
10
10
 
11
11
  setup(
12
12
  name='espark-core',
13
- version='0.5.3',
13
+ version='0.5.4',
14
14
  description='The core module of the Espark ESP32-based IoT device management framework.',
15
15
  long_description=(root / 'README.md').read_text(),
16
16
  long_description_content_type='text/markdown',
@@ -18,7 +18,7 @@ setup(
18
18
  license_files=[
19
19
  'LICENSE',
20
20
  ],
21
- python_requires='>=3.8',
21
+ python_requires='>=3.10',
22
22
  packages=find_packages(where='.'),
23
23
  package_dir={
24
24
  '' : '.',
File without changes
File without changes
File without changes
File without changes