4 Commits

7 changed files with 62 additions and 134 deletions

View File

@@ -1,33 +0,0 @@
when:
- event: pull_request
branch:
exclude: [master, release/*]
steps:
- name: prepare
image: python:3.12-alpine
commands: |
cd ./backend
python3 -m venv local
wget -O - -q https://raw.githubusercontent.com/reviewdog/reviewdog/master/install.sh | sh -s latest -b ./local/bin/
source ./local/bin/activate
pip install poetry
poetry install --only=linters --no-root
- name: ruff
image: python:3.12-alpine
failure: ignore
secrets: ["reviewdog_gitea_api_token", "gitea_address"]
commands: |
cd ./backend
source ./local/bin/activate
poetry run ruff --output-format sarif . | ./local/bin/reviewdog -f sarif -reporter gitea-pr-review -filter-mode nofilter
- name: mypy
image: python:3.12-alpine
failure: ignore
secrets: ["reviewdog_gitea_api_token", "gitea_address"]
commands: |
cd ./backend
source ./local/bin/activate
poetry run mypy --no-incremental . | ./local/bin/reviewdog -f mypy -reporter gitea-pr-review -filter-mode nofilter

View File

@@ -1,10 +1,7 @@
from asyncio import sleep from asyncio import sleep
from logging import getLogger from logging import getLogger
from typing import Annotated, AsyncIterator
from fastapi import Depends
from opentelemetry.instrumentation.sqlalchemy import SQLAlchemyInstrumentor from opentelemetry.instrumentation.sqlalchemy import SQLAlchemyInstrumentor
from sqlalchemy import text
from sqlalchemy.exc import OperationalError, SQLAlchemyError from sqlalchemy.exc import OperationalError, SQLAlchemyError
from sqlalchemy.ext.asyncio import ( from sqlalchemy.ext.asyncio import (
async_sessionmaker, async_sessionmaker,
@@ -16,6 +13,7 @@ from sqlalchemy.ext.asyncio import (
from .base_class import Base from .base_class import Base
from ..settings import DatabaseSettings from ..settings import DatabaseSettings
logger = getLogger(__name__) logger = getLogger(__name__)
@@ -30,8 +28,7 @@ class Database:
except (SQLAlchemyError, AttributeError) as e: except (SQLAlchemyError, AttributeError) as e:
logger.exception(e) logger.exception(e)
raise
return None
# TODO: Preserve UserLastStopSearchResults table from drop. # TODO: Preserve UserLastStopSearchResults table from drop.
async def connect( async def connect(

View File

@@ -35,26 +35,6 @@ if TYPE_CHECKING:
logger = getLogger(__name__) logger = getLogger(__name__)
# import cProfile
# import io
# import pstats
# import contextlib
# @contextlib.contextmanager
# def profiled():
# pr = cProfile.Profile()
# pr.enable()
# yield
# pr.disable()
# s = io.StringIO()
# ps = pstats.Stats(pr, stream=s).sort_stats("cumulative")
# ps.print_stats()
# # uncomment this to see who's calling what
# # ps.print_callers()
# print(s.getvalue())
class StopAreaStopAssociations(Base): class StopAreaStopAssociations(Base):
id = mapped_column(BigInteger, primary_key=True) id = mapped_column(BigInteger, primary_key=True)

View File

@@ -18,14 +18,13 @@ from api.routers import line, stop
@asynccontextmanager @asynccontextmanager
async def lifespan(app: FastAPI) -> None: async def lifespan(app: FastAPI):
FastAPICache.init(redis_backend, prefix="api", enable=settings.cache.enable) FastAPICache.init(redis_backend, prefix="api", enable=settings.cache.enable)
await db.connect(settings.db, settings.clear_static_data) await db.connect(settings.db, settings.clear_static_data)
if settings.clear_static_data: if settings.clear_static_data:
await idfm_interface.startup() await idfm_interface.startup()
print("OK")
yield yield
await db.disconnect() await db.disconnect()

View File

@@ -24,7 +24,6 @@ psycopg = "^3.1.9"
pyyaml = "^6.0" pyyaml = "^6.0"
fastapi-cache2 = {extras = ["redis"], version = "^0.2.1"} fastapi-cache2 = {extras = ["redis"], version = "^0.2.1"}
pydantic-settings = "^2.0.3" pydantic-settings = "^2.0.3"
ruff = "^0.2.1"
[tool.poetry.group.db_updater.dependencies] [tool.poetry.group.db_updater.dependencies]
aiofiles = "^22.1.0" aiofiles = "^22.1.0"
@@ -53,36 +52,28 @@ build-backend = "poetry.core.masonry.api"
[tool.poetry.group.dev.dependencies] [tool.poetry.group.dev.dependencies]
pylsp-mypy = "^0.6.2" pylsp-mypy = "^0.6.2"
python-lsp-black = "^1.2.1"
wrapt = "^1.14.1"
dill = "^0.3.6"
python-lsp-ruff = "^1.0.5"
python-lsp-server = "^1.7.1"
icecream = "^2.1.3"
[tool.poetry.group.linters.dependencies]
autopep8 = "^2.0.1"
black = "^22.10.0"
mccabe = "^0.7.0" mccabe = "^0.7.0"
mypy = "^1.0.0"
pydocstyle = "^6.2.2"
pyflakes = "^3.0.1"
rope = "^1.3.0" rope = "^1.3.0"
ruff = "^0.2.1" python-lsp-black = "^1.2.1"
black = "^22.10.0"
types-aiofiles = "^22.1.0.2" types-aiofiles = "^22.1.0.2"
wrapt = "^1.14.1"
pydocstyle = "^6.2.2"
dill = "^0.3.6"
python-lsp-ruff = "^2.1.0"
python-lsp-server = "^1.7.1"
autopep8 = "^2.0.1"
pyflakes = "^3.0.1"
yapf = "^0.32.0"
whatthepatch = "^1.0.4"
mypy = "^1.0.0"
icecream = "^2.1.3"
types-sqlalchemy-utils = "^1.0.1" types-sqlalchemy-utils = "^1.0.1"
types-pyyaml = "^6.0.12.9" types-pyyaml = "^6.0.12.9"
types-tqdm = "^4.65.0.1" types-tqdm = "^4.65.0.1"
whatthepatch = "^1.0.4"
yapf = "^0.32.0"
sqlalchemy = "^2.0.26"
[tool.mypy] [tool.mypy]
plugins = "sqlalchemy.ext.mypy.plugin" plugins = "sqlalchemy.ext.mypy.plugin"
exclude = ['docker', 'docs']
strict = true
[tool.black] [tool.black]
target-version = ['py311'] target-version = ['py311']

View File

@@ -30,7 +30,7 @@
"@stitches/core": "^1.2.8", "@stitches/core": "^1.2.8",
"date-fns": "^2.29.3", "date-fns": "^2.29.3",
"matrix-widget-api": "^1.1.1", "matrix-widget-api": "^1.1.1",
"ol": "^7.3.0", "ol": "^8.2.0",
"solid-js": "^1.6.6", "solid-js": "^1.6.6",
"solid-transition-group": "^0.0.10", "solid-transition-group": "^0.0.10",
"solidjs-lazily": "^0.1.2" "solidjs-lazily": "^0.1.2"

View File

@@ -41,57 +41,13 @@ export const Map: ParentComponent<{}> = () => {
// TODO: Set padding according to the marker design. // TODO: Set padding according to the marker design.
const fitPointsPadding = [50, 50, 50, 50]; const fitPointsPadding = [50, 50, 50, 50];
let mapDiv: HTMLDivElement | undefined;
let popup: StopPopup | undefined = undefined; let popup: StopPopup | undefined = undefined;
const [mapRef, setMapRef] = createSignal<HTMLDivElement>();
const stopVectorSource = new OlVectorSource({ features: [] }); const stopVectorSource = new OlVectorSource({ features: [] });
const stopVectorLayer = new OlVectorLayer({ source: stopVectorSource }); const stopVectorLayer = new OlVectorLayer({ source: stopVectorSource });
let overlay: OlOverlay | undefined = undefined;
let map: OlMap | undefined = undefined;
const displayedFeatures: Record<number, OlFeature> = {};
const buildMap = (div: HTMLDivElement): void => {
overlay = new OlOverlay({
element: popup,
autoPan: {
animation: {
duration: 250,
},
},
});
map = new OlMap({
target: div,
controls: [], // remove controls
view: new OlView({
center: mapCenter,
zoom: 10,
}),
layers: [
new OlTileLayer({
source: new OlOSM(),
}),
stopVectorLayer,
],
overlays: [overlay],
});
console.log("map=", map);
map.on('singleclick', onClickedMap);
}
const onClickedMap = async (event): Promise<void> => {
const features = await stopVectorLayer.getFeatures(event.pixel);
// Handle only the first feature
if (features.length > 0) {
await onClickedFeature(features[0]);
}
else {
setPopupDisplayed(false);
setSelectedMapStop(undefined);
}
}
const onClickedFeature = async (feature: OlFeatureLike): Promise<void> => { const onClickedFeature = async (feature: OlFeatureLike): Promise<void> => {
const stopId: number = feature.getId(); const stopId: number = feature.getId();
const stop = getStop(stopId); const stop = getStop(stopId);
@@ -109,10 +65,48 @@ export const Map: ParentComponent<{}> = () => {
} }
} }
onMount(() => { const onClickedMap = async (event): Promise<void> => {
buildMap(mapDiv); const features = await stopVectorLayer.getFeatures(event.pixel);
}) // Handle only the first feature
; if (features.length > 0) {
await onClickedFeature(features[0]);
}
else {
setPopupDisplayed(false);
setSelectedMapStop(undefined);
}
}
const displayedFeatures: Record<number, OlFeature> = {};
const overlay = new OlOverlay({
element: popup,
autoPan: {
animation: {
duration: 250,
},
},
});
const map = new OlMap({
target: "map",
controls: [], // remove controls
view: new OlView({
center: mapCenter,
zoom: 10,
}),
layers: [
new OlTileLayer({
source: new OlOSM(),
}),
stopVectorLayer,
],
overlays: [overlay],
});
map.on('singleclick', onClickedMap);
createEffect(() => {
map.setTarget(mapRef());
});
// Filling the map with stops shape // Filling the map with stops shape
createEffect(() => { createEffect(() => {
@@ -211,7 +205,7 @@ export const Map: ParentComponent<{}> = () => {
} }
return <> return <>
<div ref={mapDiv!} class="map"> <div ref={setMapRef!} class="map">
<StopPopup ref={popup!} stop={selectedMapStop()} show={isPopupDisplayed()} /> <StopPopup ref={popup!} stop={selectedMapStop()} show={isPopupDisplayed()} />
</div> </div>
<For each={getFoundStops()}>{(stop) => <MapStop stop={stop} selected={selectedMapStop()} />}</For> <For each={getFoundStops()}>{(stop) => <MapStop stop={stop} selected={selectedMapStop()} />}</For>