Skip to content

Commit 40d7309

Browse files
authored
Merge pull request #228 from burningmantech/reflex
Add Reflex app
2 parents f241fa2 + e1fbb95 commit 40d7309

35 files changed

+1413
-406
lines changed

.github/workflows/cicd.yml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -141,12 +141,12 @@ jobs:
141141
python-version: ["3.12"] # Versions to test with coverage
142142
tox-prefix: ["coverage"]
143143
optional: [false]
144-
include:
145-
# Test next Python version but allow it to fail
146-
- os: "ubuntu-latest"
147-
python-version: "3.13"
148-
optional: true
149-
tox-prefix: "test"
144+
# include:
145+
# # Test next Python version but allow it to fail
146+
# - os: "ubuntu-latest"
147+
# python-version: "3.13"
148+
# optional: true
149+
# tox-prefix: "test"
150150

151151
steps:
152152

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,7 @@ __pycache__/
1010
/dist/
1111
/htmlcov/
1212
/htmldocs/
13+
/reflex_app/.web/
14+
/rtx.sqlite
1315
/src/*.egg-info/
1416
/wheels/

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ repos:
2323
- id: check-json
2424
- id: check-merge-conflict
2525
- id: check-shebang-scripts-are-executable
26-
- id: check-symlinks
26+
# - id: check-symlinks
2727
- id: check-toml
2828
- id: check-vcs-permalinks
2929
- id: check-xml

MANIFEST.in

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
exclude reflex_app/data
12
include .coveragerc
23
include .pre-commit-config.yaml
34
include codecov.yml
@@ -6,6 +7,9 @@ include COPYRIGHT.txt
67
include LICENSE.txt
78
include mypy.ini
89
include pyproject.toml
10+
include reflex_app/assets/favicon.ico
11+
include src/transmissions/py.typed
912
include src/transmissions/store/sqlite/schema/*.sqlite
1013
include tox.ini
1114
include uv.lock
15+
recursive-include reflex_app *.py

mypy.ini

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@ ignore_missing_imports = True
3939
[mypy-hypothesis.*]
4040
ignore_missing_imports = True
4141

42+
[mypy-reflex]
43+
ignore_missing_imports = True
44+
45+
[mypy-reflex_ag_grid]
46+
ignore_missing_imports = True
47+
4248
[mypy-setuptools]
4349
ignore_missing_imports = True
4450

pyproject.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ readme = "README.rst"
1111
license = {file = "LICENSE.txt"}
1212

1313
# Requirements
14-
requires-python = ">=3.12"
14+
requires-python = ">=3.12,<3.13"
1515
dependencies = [
1616
"arrow==1.3.0",
1717
"attrs==25.1.0",
@@ -22,6 +22,8 @@ dependencies = [
2222
"openai-whisper==20240930; sys_platform!='darwin' or platform_machine!='x86_64'",
2323
"pydub==0.25.1",
2424
"pyobjc==11.0; sys_platform=='darwin'",
25+
"reflex==0.6.8",
26+
"reflex-ag-grid==0.0.10",
2527
"rich==13.9.4",
2628
"simpleaudio==1.0.4; sys_platform=='darwin'",
2729
"textual==1.0.0",

reflex_app/app/__init__.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
"""
2+
Transmissions Reflex Application
3+
"""
4+
5+
from .app import searchIndexFactory, storeFactory
6+
from .pages import transmissionsListPage
7+
8+
9+
__all__ = [
10+
"searchIndexFactory",
11+
"storeFactory",
12+
"transmissionsListPage",
13+
]

reflex_app/app/app.py

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
"""
2+
Application
3+
"""
4+
5+
from os import environ
6+
from pathlib import Path
7+
8+
from reflex import App
9+
from twisted.logger import Logger
10+
11+
from transmissions.ext.click import readConfig
12+
from transmissions.ext.logger import startLogging
13+
from transmissions.run._search import searchIndexFactoryFromConfig # FIXME: private
14+
from transmissions.run._store import storeFactoryFromConfig # FIXME: private
15+
from transmissions.search import TransmissionsIndex
16+
from transmissions.store import TXDataStore
17+
18+
19+
log = Logger()
20+
21+
22+
class StoreFactory:
23+
"""
24+
Factory for data store.
25+
"""
26+
27+
_store: TXDataStore | None = None
28+
29+
async def store(self) -> TXDataStore:
30+
"""
31+
Get and cache the data store.
32+
"""
33+
if self._store is None:
34+
log.info("Initializing data store...")
35+
storeFactory = storeFactoryFromConfig(configuration, create=False)
36+
self._store = await storeFactory()
37+
38+
return self._store
39+
40+
41+
class SearchIndexFactory:
42+
"""
43+
Factory for search index.
44+
"""
45+
46+
_index: TransmissionsIndex | None = None
47+
48+
async def index(self, store: TXDataStore) -> TransmissionsIndex:
49+
"""
50+
Get and cache the search index.
51+
"""
52+
if self._index is None:
53+
log.info("Initializing search index...")
54+
searchIndexFactory = searchIndexFactoryFromConfig(configuration)
55+
self._index = await searchIndexFactory(store)
56+
57+
return self._index
58+
59+
60+
startLogging()
61+
62+
defaultConfigPath = Path("~/.rtx.toml") # FIXME: Not DRY; see _command.py
63+
fileName = environ.get("CONFIG", defaultConfigPath)
64+
65+
log.info("Reading configuration file: {file}", file=fileName)
66+
configuration = readConfig(Path(fileName))
67+
68+
storeFactory = StoreFactory()
69+
searchIndexFactory = SearchIndexFactory()
70+
71+
app = App()

reflex_app/app/model/__init__.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
"""
2+
Reflex-compatible data models
3+
"""
4+
5+
from ._transmission import RXTransmission
6+
7+
8+
__all__ = [
9+
"RXTransmission",
10+
]
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
from typing import ClassVar, Self, overload
2+
3+
from reflex import Base
4+
5+
from transmissions.model import Transmission, TZInfo
6+
7+
8+
class RXTransmission(Base):
9+
"""
10+
Reflex model for Transmission
11+
"""
12+
13+
dateTimeFormat: ClassVar[str] = "%y-%m-%d %H:%M:%S%z"
14+
15+
@overload
16+
@classmethod
17+
def fromTransmission(cls, transmission: Transmission) -> Self: ...
18+
19+
@overload
20+
@classmethod
21+
def fromTransmission(cls, transmission: None) -> None: ...
22+
23+
@classmethod
24+
def fromTransmission(cls, transmission: Transmission | None) -> Self | None:
25+
if transmission is None:
26+
return None
27+
return cls(
28+
startTime=transmission.startTime.astimezone(TZInfo.PDT.value).strftime(
29+
cls.dateTimeFormat
30+
),
31+
eventID=transmission.eventID,
32+
station=transmission.station,
33+
system=transmission.system,
34+
channel=transmission.channel,
35+
duration=(
36+
transmission.duration.total_seconds() if transmission.duration else None
37+
),
38+
transcription=transmission.transcription,
39+
)
40+
41+
startTime: str
42+
eventID: str
43+
station: str
44+
system: str
45+
channel: str
46+
duration: float | None
47+
transcription: str | None

0 commit comments

Comments
 (0)