Compare commits
39 Commits
Author | SHA1 | Date | |
---|---|---|---|
ce671f4b10
|
|||
94d87c1c0e
|
|||
71f7519b2f
|
|||
99aeaae9f2
|
|||
06d446c3f9
|
|||
001c7330c6
|
|||
d4d24d13d2
|
|||
f1cafc7484
|
|||
30020d17cc
|
|||
85bdf2656c
|
|||
fe67cd0d98
|
|||
221125198d
|
|||
fe05e2a2c5
|
|||
f964ba9027
|
|||
117d549ea7
|
|||
529315bf50
|
|||
35882bda31
|
|||
688ffeb7f8
|
|||
0993c42557
|
|||
2b0eb40ab1
|
|||
8082f7f012
|
|||
2d9d7c51b5
|
|||
63cdbcb46e
|
|||
825a852c67
|
|||
812d7c0a61
|
|||
63abb677cb
|
|||
a089bbbf78
|
|||
55401dcd0c
|
|||
58c18a0479
|
|||
2eb8d59a0e
|
|||
137c28387c
|
|||
0cddf9dc7e
|
|||
bccbfe0ff3
|
|||
10ecd40ef5
|
|||
6687c2de15
|
|||
c8732a0375
|
|||
ff808e7c8f
|
|||
7ac719db24
|
|||
a8277fd018
|
33
backend/.woodpecker/.lint.yaml
Normal file
33
backend/.woodpecker/.lint.yaml
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
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
|
@@ -1,7 +1,10 @@
|
|||||||
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,
|
||||||
@@ -13,7 +16,6 @@ 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__)
|
||||||
|
|
||||||
|
|
||||||
@@ -28,7 +30,8 @@ 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(
|
||||||
|
@@ -35,6 +35,26 @@ 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)
|
||||||
|
@@ -18,13 +18,14 @@ from api.routers import line, stop
|
|||||||
|
|
||||||
|
|
||||||
@asynccontextmanager
|
@asynccontextmanager
|
||||||
async def lifespan(app: FastAPI):
|
async def lifespan(app: FastAPI) -> None:
|
||||||
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()
|
||||||
|
@@ -24,6 +24,7 @@ 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"
|
||||||
@@ -52,28 +53,36 @@ 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"
|
||||||
mccabe = "^0.7.0"
|
|
||||||
rope = "^1.3.0"
|
|
||||||
python-lsp-black = "^1.2.1"
|
python-lsp-black = "^1.2.1"
|
||||||
black = "^22.10.0"
|
|
||||||
types-aiofiles = "^22.1.0.2"
|
|
||||||
wrapt = "^1.14.1"
|
wrapt = "^1.14.1"
|
||||||
pydocstyle = "^6.2.2"
|
|
||||||
dill = "^0.3.6"
|
dill = "^0.3.6"
|
||||||
python-lsp-ruff = "^2.1.0"
|
python-lsp-ruff = "^1.0.5"
|
||||||
python-lsp-server = "^1.7.1"
|
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"
|
icecream = "^2.1.3"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[tool.poetry.group.linters.dependencies]
|
||||||
|
autopep8 = "^2.0.1"
|
||||||
|
black = "^22.10.0"
|
||||||
|
mccabe = "^0.7.0"
|
||||||
|
mypy = "^1.0.0"
|
||||||
|
pydocstyle = "^6.2.2"
|
||||||
|
pyflakes = "^3.0.1"
|
||||||
|
rope = "^1.3.0"
|
||||||
|
ruff = "^0.2.1"
|
||||||
|
types-aiofiles = "^22.1.0.2"
|
||||||
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']
|
||||||
|
@@ -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": "^8.2.0",
|
"ol": "^7.3.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"
|
||||||
|
@@ -41,13 +41,57 @@ 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);
|
||||||
@@ -65,48 +109,10 @@ export const Map: ParentComponent<{}> = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const onClickedMap = async (event): Promise<void> => {
|
onMount(() => {
|
||||||
const features = await stopVectorLayer.getFeatures(event.pixel);
|
buildMap(mapDiv);
|
||||||
// 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(() => {
|
||||||
@@ -205,7 +211,7 @@ export const Map: ParentComponent<{}> = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return <>
|
return <>
|
||||||
<div ref={setMapRef!} class="map">
|
<div ref={mapDiv!} 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>
|
||||||
|
Reference in New Issue
Block a user