Compare commits

...
10 Commits
27 changed files with 114 additions and 246 deletions
+1 -4
View File
@@ -1,9 +1,6 @@
DOCKER_REPO=git.shmyga.ru DOCKER_REPO=git.shmyga.ru
DOCKER_GROUP=infernalgames DOCKER_GROUP=infernalgames
DOCKER_ROOT="$DOCKER_REPO/$DOCKER_GROUP" DOCKER_ROOT="${DOCKER_REPO}/${DOCKER_GROUP}"
VERSION=$(grep -m 1 'version' ./pyproject.toml | grep -oP 'version\s*=\s*"\K[^"]+')
PYTHON_VERSION=$(grep -m 1 'python' ./pyproject.toml | grep -oP 'python\s*=\s*"\^?\K[^"]+')
DOCKER_PROJECTS=("gallery")
DOCKER_TAG="${DOCKER_TAG:-latest}" DOCKER_TAG="${DOCKER_TAG:-latest}"
OPENWEATHER_KEY="" OPENWEATHER_KEY=""
+1 -3
View File
@@ -1,6 +1,4 @@
[presets.python.tasks.setup.playwright] modules = [".", "static"]
conditions = ["{{ '.venv/bin/playwright' | file }}"]
commands = [".venv/bin/playwright install chromium --with-deps --only-shell"]
[presets.locales.tasks.build.locales] [presets.locales.tasks.build.locales]
priority = 1 priority = 1
+9 -4
View File
@@ -23,14 +23,19 @@ COPY static ./
RUN npm run build RUN npm run build
FROM python:3.14-slim FROM python:3.14-slim
ENV PATH="/app/.venv/bin:$PATH"
WORKDIR /app
ENV PLAYWRIGHT_BROWSERS_PATH="/opt/playwright-browsers"
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
--mount=type=cache,target=/var/lib/apt,sharing=locked \
pip install playwright && \
playwright install --with-deps chromium
ENV PATH="/app/.venv/bin:$PATH"
ENV TZ="Europe/Moscow" ENV TZ="Europe/Moscow"
COPY --from=builder /app ./ WORKDIR /app
RUN .venv/bin/playwright install chromium --with-deps --only-shell
COPY --from=builder /app ./
COPY --from=node-builder /app/dist ./static/dist COPY --from=node-builder /app/dist ./static/dist
COPY gallery gallery/ COPY gallery gallery/
+2 -1
View File
@@ -16,6 +16,7 @@ def build_app(api_bundle: ApiBundle) -> FastAPI:
app.state.api = api_bundle app.state.api = api_bundle
app.mount("/static", StaticFiles(directory=root_path / "static/dist")) app.mount("/static", StaticFiles(directory=root_path / "static/dist"))
doc.mount(app) doc.mount(app)
app.include_router(api.router) api.app.state.api = api_bundle
app.mount("/api", api.app)
app.include_router(view.router) app.include_router(view.router)
return app return app
+12 -4
View File
@@ -1,7 +1,15 @@
from fastapi import APIRouter from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from . import schedule, weather from . import schedule, weather
router = APIRouter(prefix="/api") app = FastAPI(openapi_prefix="/api")
router.include_router(weather.router) app.add_middleware(
router.include_router(schedule.router) CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
app.include_router(weather.router)
app.include_router(schedule.router)
+3 -5
View File
@@ -7,17 +7,15 @@ from gallery.sketch.weather.model import (
Precipitation, Precipitation,
Sky, Sky,
WindDirection, WindDirection,
WindDirectionDeg,
) )
from gallery.util import root_path from gallery.util import root_path
def wind_direction_icon(wind_direction_deg: float) -> str: def wind_direction_icon(wind_direction: WindDirection | None) -> str:
wind_direction = WindDirectionDeg(wind_direction_deg).direction if wind_direction is None:
if wind_direction == WindDirection.CALM:
return "wind-calm" return "wind-calm"
else: else:
return f"wind-from-{wind_direction.name.lower()}" return f"wind-from-{wind_direction.lower()}"
def cloudness_icon(sky: Sky, date: datetime.datetime, period: str) -> list[str]: def cloudness_icon(sky: Sky, date: datetime.datetime, period: str) -> list[str]:
@@ -107,8 +107,8 @@ locale=request.state.language)}}{% endblock %}
{% for value in response.values %} {% for value in response.values %}
<td class="wind" <td class="wind"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
data-bs-title="{{ value.wind_direction }}"> data-bs-title="{{ value.wind.direction }}">
<div class="wi-svg wi-s wi-{{value.wind_direction | wind_direction_icon}}" <div class="wi-svg wi-s wi-{{value.wind.direction | wind_direction_icon}}"
style="margin: 0 auto;">{{ 'wind-deg' | weather_icon_svg }}</div> style="margin: 0 auto;">{{ 'wind-deg' | weather_icon_svg }}</div>
</td> </td>
{% endfor %} {% endfor %}
@@ -123,11 +123,11 @@ locale=request.state.language)}}{% endblock %}
<tr> <tr>
{% for value in response.values %} {% for value in response.values %}
<td class="wind" <td class="wind"
style="background-color: rgba(128, 128, 128, {{value.wind_speed * 0.05}});"> style="background-color: rgba(128, 128, 128, {{value.wind.speed * 0.05}});">
<span class="speed">{{value.wind_speed}}</span> <span class="speed">{{value.wind.speed}}</span>
{% if value.wind_gust != value.wind_speed and value.wind_gust > 0 %} {% if value.wind.gust != value.wind.speed and value.wind.gust > 0 %}
<span class="gust"> <span class="gust">
({{value.wind_gust}}) ({{value.wind.gust}})
</span> </span>
{% endif %} {% endif %}
</td> </td>
+11 -2
View File
@@ -28,6 +28,15 @@ def format_date(date: datetime.date) -> str:
return f"{days + 1}-day" return f"{days + 1}-day"
def set_dict_nested_value(target: dict, key: str, value: Any):
parts = key.split(".")
for part in parts[:-1]:
if part not in target:
target[part] = {}
target = target[part]
target[parts[-1]] = value
class GismeteoApi(WeatherApi): class GismeteoApi(WeatherApi):
PROVIDER = "gismeteo" PROVIDER = "gismeteo"
@@ -46,7 +55,7 @@ class GismeteoApi(WeatherApi):
for index, value in enumerate(parser.parse_row(widget)): for index, value in enumerate(parser.parse_row(widget)):
while len(result) < index + 1: while len(result) < index + 1:
result.append({}) result.append({})
result[index][parser.KEY] = value set_dict_nested_value(result[index], parser.KEY, value)
values = [WeatherValue(**item) for item in result] values = [WeatherValue(**item) for item in result]
# group values by 3 hours # group values by 3 hours
if len(values) > 8: if len(values) > 8:
@@ -70,7 +79,7 @@ class GismeteoApi(WeatherApi):
for index, value in enumerate(parser.parse_row(widget)): for index, value in enumerate(parser.parse_row(widget)):
while len(result) < index + 1: while len(result) < index + 1:
result.append({}) result.append({})
result[index][parser.KEY] = value set_dict_nested_value(result[index], parser.KEY, value)
values = [WeatherValue(**item) for item in result] values = [WeatherValue(**item) for item in result]
return WeatherResponse( return WeatherResponse(
location=location or "n/a", location=location or "n/a",
+3 -3
View File
@@ -161,7 +161,7 @@ class TemperatureParser(RowParser[list[int]]):
class WindSpeedParser(RowParser[int]): class WindSpeedParser(RowParser[int]):
KEY = "wind_speed" KEY = "wind.speed"
def parse_row(self, tag: Tag) -> Iterable[int]: def parse_row(self, tag: Tag) -> Iterable[int]:
for item in tag.select(".widget-row-wind > .row-item > .wind-speed > speed-value"): for item in tag.select(".widget-row-wind > .row-item > .wind-speed > speed-value"):
@@ -169,7 +169,7 @@ class WindSpeedParser(RowParser[int]):
class WindGustParser(RowParser[int]): class WindGustParser(RowParser[int]):
KEY = "wind_gust" KEY = "wind.gust"
def parse_row(self, tag: Tag) -> Iterable[int]: def parse_row(self, tag: Tag) -> Iterable[int]:
for item in tag.select(".widget-row-wind > .row-item > .wind-gust"): for item in tag.select(".widget-row-wind > .row-item > .wind-gust"):
@@ -178,7 +178,7 @@ class WindGustParser(RowParser[int]):
class WindDirectionParser(RowParser[WindDirection]): class WindDirectionParser(RowParser[WindDirection]):
KEY = "wind_direction" KEY = "wind.direction"
def parse_row(self, tag: Tag) -> Iterable[float]: def parse_row(self, tag: Tag) -> Iterable[float]:
for item in tag.select(".widget-row-wind > .row-item > .wind-speed > .wind-direction"): for item in tag.select(".widget-row-wind > .row-item > .wind-speed > .wind-direction"):
+4 -3
View File
@@ -3,6 +3,7 @@ import datetime
from gallery.sketch.weather.model import Cloudness, Precipitation, WeatherValue from gallery.sketch.weather.model import Cloudness, Precipitation, WeatherValue
from gallery.sketch.weather.util import build_weather_value from gallery.sketch.weather.util import build_weather_value
from ...sketch.weather.parser import parse_wind_direction
from .openweather import ForecastItem from .openweather import ForecastItem
@@ -31,9 +32,9 @@ class ForecastItemParser:
# value.temperature = [round(item.main.temp_max), round(item.main.temp_min)] # value.temperature = [round(item.main.temp_max), round(item.main.temp_min)]
value.pressure = [round(item.main.pressure * 0.75006)] value.pressure = [round(item.main.pressure * 0.75006)]
value.humidity = item.main.humidity value.humidity = item.main.humidity
value.wind_speed = round(item.wind.speed) value.wind.speed = round(item.wind.speed)
value.wind_gust = round(item.wind.gust) value.wind.gust = round(item.wind.gust)
value.wind_direction = item.wind.deg value.wind.direction = parse_wind_direction(item.wind.deg)
value.sky.cloudness = self.CLOUDNESS_MAP.get(item.weather[0].description, Cloudness.CLEAR) value.sky.cloudness = self.CLOUDNESS_MAP.get(item.weather[0].description, Cloudness.CLEAR)
value.sky.precipitation = self.PRECIPITATION_MAP.get(item.weather[0].description, Precipitation.NO) value.sky.precipitation = self.PRECIPITATION_MAP.get(item.weather[0].description, Precipitation.NO)
if item.rain: if item.rain:
+4 -4
View File
@@ -54,7 +54,7 @@ class RowType(Enum):
def _iter_table_rows(table: Tag) -> Iterable[tuple[RowType, Tag]]: def _iter_table_rows(table: Tag) -> Iterable[tuple[RowType, Tag]]:
for row in table.select("tr"): for row in table.select("tr"):
title = row.select_one("td").text.strip().lower() title = row.select_one("td").text.strip().lower()
if "сегодня" in title: if "сегодня" in title or "завтра" in title:
yield RowType.DATE, row yield RowType.DATE, row
elif "местное время" in title: elif "местное время" in title:
yield RowType.TIME, row yield RowType.TIME, row
@@ -133,13 +133,13 @@ def parse_page(page: BeautifulSoup) -> list[WeatherResponse]:
values[index].pressure = [int(cell.select_one(".p_0").text.strip())] values[index].pressure = [int(cell.select_one(".p_0").text.strip())]
case RowType.WIND_SPEED: case RowType.WIND_SPEED:
for index, cell in enumerate(row.select("td")[1:]): for index, cell in enumerate(row.select("td")[1:]):
values[index].wind_speed = _parse_wind_speed(cell) values[index].wind.speed = _parse_wind_speed(cell)
case RowType.WIND_GUST: case RowType.WIND_GUST:
for index, cell in enumerate(row.select("td")[1:]): for index, cell in enumerate(row.select("td")[1:]):
values[index].wind_gust = _parse_wind_speed(cell) values[index].wind.gust = _parse_wind_speed(cell)
case RowType.WIND_DIRECTION: case RowType.WIND_DIRECTION:
for index, cell in enumerate(row.select("td")[1:]): for index, cell in enumerate(row.select("td")[1:]):
values[index].wind_direction = parse_wind_direction(cell.text.strip()) values[index].wind.direction = parse_wind_direction(cell.text.strip())
case RowType.HUMIDITY: case RowType.HUMIDITY:
for index, cell in enumerate(row.select("td")[1:]): for index, cell in enumerate(row.select("td")[1:]):
values[index].humidity = int(cell.text.strip()) values[index].humidity = int(cell.text.strip())
+2 -2
View File
@@ -72,10 +72,10 @@ def parse_article(article: Tag, location: str) -> WeatherResponse:
value.temperature.append(temperature) value.temperature.append(temperature)
wind_speed_tag = temperature_tag.next_element.next_element wind_speed_tag = temperature_tag.next_element.next_element
wind_speed = int(wind_speed_tag.text.strip()) wind_speed = int(wind_speed_tag.text.strip())
value.wind_speed = wind_speed value.wind.speed = wind_speed
wind_direction_tag = wind_speed_tag.next_element.next_element.next_element.next_element wind_direction_tag = wind_speed_tag.next_element.next_element.next_element.next_element
wind_direction_str = wind_direction_tag.text.strip() wind_direction_str = wind_direction_tag.text.strip()
value.wind_direction = parse_wind_direction(wind_direction_str) value.wind.direction = parse_wind_direction(wind_direction_str)
humidity_tag = wind_direction_tag.next_element.next_element.next_element.next_element humidity_tag = wind_direction_tag.next_element.next_element.next_element.next_element
humidity = int(humidity_tag.text.strip().rstrip("%")) humidity = int(humidity_tag.text.strip().rstrip("%"))
value.humidity = humidity value.humidity = humidity
+5 -51
View File
@@ -58,7 +58,6 @@ class Sky(Model):
class WindDirection(StrEnum): class WindDirection(StrEnum):
CALM = auto()
N = auto() N = auto()
NE = auto() NE = auto()
E = auto() E = auto()
@@ -69,62 +68,17 @@ class WindDirection(StrEnum):
NW = auto() NW = auto()
class WindDirectionDeg(float): class Wind(Model):
@property speed: int
def direction(self) -> WindDirection: gust: int
return self.to_direction() direction: WindDirection | None = None
@property
def value(self) -> float:
return self
# pylint:disable=too-many-return-statements
def to_direction(self) -> WindDirection:
if self == -1:
return WindDirection.CALM
elif self > 337.5 or self <= 22.25:
return WindDirection.N
elif self <= 67.5:
return WindDirection.NE
elif self <= 112.5:
return WindDirection.E
elif self <= 157.5:
return WindDirection.SE
elif self <= 202.5:
return WindDirection.S
elif self <= 247.5:
return WindDirection.SW
elif self <= 292.5:
return WindDirection.W
elif self <= 337.5:
return WindDirection.NW
else:
raise ValueError(self)
@classmethod
def from_direction(cls, direction: WindDirection) -> Self:
return cls(
{
WindDirection.CALM: -1,
WindDirection.N: 0,
WindDirection.NE: 45,
WindDirection.E: 90,
WindDirection.SE: 135,
WindDirection.S: 180,
WindDirection.SW: 225,
WindDirection.W: 270,
WindDirection.NW: 315,
}[direction]
)
class WeatherValue(Model): class WeatherValue(Model):
date: datetime.datetime date: datetime.datetime
sky: Sky sky: Sky
wind: Wind
temperature: list[int] temperature: list[int]
wind_speed: int
wind_gust: int
wind_direction: float
precipitation: float precipitation: float
pressure: list[int] = Field(default=[]) pressure: list[int] = Field(default=[])
humidity: int = Field(default=-1) humidity: int = Field(default=-1)
+33 -8
View File
@@ -1,6 +1,6 @@
from typing import Self from typing import Self
from gallery.sketch.weather.model import WindDirection, WindDirectionDeg from gallery.sketch.weather.model import WindDirection
class ParseError(Exception): class ParseError(Exception):
@@ -9,11 +9,7 @@ class ParseError(Exception):
return cls("Invalid date string", date_str) return cls("Invalid date string", date_str)
WIND_DIRECTION_MAP: dict[str, WindDirection] = { WIND_DIRECTION_MAP: dict[str, WindDirection | None] = {
"—": WindDirection.CALM,
"": WindDirection.CALM,
"штиль": WindDirection.CALM,
"штл": WindDirection.CALM,
"с": WindDirection.N, "с": WindDirection.N,
"св": WindDirection.NE, "св": WindDirection.NE,
"в": WindDirection.E, "в": WindDirection.E,
@@ -25,5 +21,34 @@ WIND_DIRECTION_MAP: dict[str, WindDirection] = {
} }
def parse_wind_direction(value: str) -> WindDirectionDeg: # pylint:disable=too-many-return-statements
return WindDirectionDeg.from_direction(WIND_DIRECTION_MAP[value.replace("-", "").lower()]) def _parse_wind_direction_number(value: int | float) -> WindDirection | None:
if value > 337.5 or value <= 22.25:
return WindDirection.N
elif value <= 67.5:
return WindDirection.NE
elif value <= 112.5:
return WindDirection.E
elif value <= 157.5:
return WindDirection.SE
elif value <= 202.5:
return WindDirection.S
elif value <= 247.5:
return WindDirection.SW
elif value <= 292.5:
return WindDirection.W
elif value <= 337.5:
return WindDirection.NW
else:
return None
def _parse_wind_direction_str(value: str) -> WindDirection | None:
return WIND_DIRECTION_MAP.get(value.replace("-", "").lower())
def parse_wind_direction(value: str | int | float) -> WindDirection | None:
if isinstance(value, str):
return _parse_wind_direction_str(value)
else:
return _parse_wind_direction_number(value)
+13 -11
View File
@@ -1,8 +1,8 @@
import datetime import datetime
import statistics import statistics
from typing import Literal from typing import Counter, Literal
from .model import Cloudness, Precipitation, Sky, WeatherValue, WindDirectionDeg from .model import Cloudness, Precipitation, Sky, WeatherValue, Wind
MergeMode = Literal["interval", "average"] MergeMode = Literal["interval", "average"]
@@ -16,10 +16,12 @@ def build_weather_value(date: datetime.datetime) -> WeatherValue:
thunder=False, thunder=False,
fog=False, fog=False,
), ),
wind=Wind(
speed=0,
gust=0,
direction=None,
),
temperature=[], temperature=[],
wind_speed=0,
wind_gust=0,
wind_direction=WindDirectionDeg(-1),
precipitation=0, precipitation=0,
pressure=[], pressure=[],
humidity=-1, humidity=-1,
@@ -55,18 +57,18 @@ def merge_weather_values(
temperatures += value.temperature temperatures += value.temperature
pressures += value.pressure pressures += value.pressure
humidities.append(value.humidity) humidities.append(value.humidity)
wind_speeds.append(value.wind_speed) wind_speeds.append(value.wind.speed)
wind_gusts.append(value.wind_gust) wind_gusts.append(value.wind.gust)
wind_directions.append(value.wind_direction) wind_directions.append(value.wind.direction)
cloudnesses.append(value.sky.cloudness) cloudnesses.append(value.sky.cloudness)
precipitations.append(value.sky.precipitation) precipitations.append(value.sky.precipitation)
precipitation += value.precipitation precipitation += value.precipitation
result.temperature = _merge_values(temperatures, mode) result.temperature = _merge_values(temperatures, mode)
result.pressure = _merge_values(pressures, mode) result.pressure = _merge_values(pressures, mode)
result.humidity = round(statistics.mean(humidities)) result.humidity = round(statistics.mean(humidities))
result.wind_speed = round(statistics.mean(wind_speeds)) result.wind.speed = round(statistics.mean(wind_speeds))
result.wind_gust = round(statistics.mean(wind_gusts)) result.wind.gust = round(statistics.mean(wind_gusts))
result.wind_direction = statistics.mean(wind_directions) result.wind.direction = Counter(wind_directions).most_common(1)[0][0]
for item in cloudnesses: for item in cloudnesses:
if Cloudness.values.index(item) > Cloudness.values.index(result.sky.cloudness): if Cloudness.values.index(item) > Cloudness.values.index(result.sky.cloudness):
result.sky.cloudness = item result.sky.cloudness = item
+1 -1
View File
@@ -1,7 +1,7 @@
[project] [project]
name = "gallery" name = "gallery"
description = "" description = ""
version = "0.8.2" version = "0.8.4"
readme = "README.md" readme = "README.md"
authors = [{ name = "shmyga", email = "shmyga.z@gmail.com" }] authors = [{ name = "shmyga", email = "shmyga.z@gmail.com" }]
requires-python = '>=3.14,<4.0' requires-python = '>=3.14,<4.0'
-5
View File
@@ -1,5 +0,0 @@
#!/usr/bin/env bash
set -e
cd "$(dirname $(dirname "$0"))" || exit
docker compose -f docker-compose-develop.yaml up --build --watch
-55
View File
@@ -1,55 +0,0 @@
#!/usr/bin/env bash
set -e
cd "$(dirname $(dirname "$0"))" || exit
. .env
build () {
echo "build: $1"
. "$1/.env"
for PROJECT in "${DOCKER_PROJECTS[@]}"; do
IFS=: read -r PROJECT_NAME PROJECT_TARGET <<< "$PROJECT"
ARGS=("build")
for ARG in ${DOCKER_ARGS[@]}; do
ARGS+=("--build-arg" "$ARG")
done
if [ -n "$PROJECT_TARGET" ]; then
ARGS+=("--target" "$PROJECT_TARGET")
fi
ARGS+=("-t" "$DOCKER_GROUP/$PROJECT_NAME" ".")
ARGS+=("-f" "$1/Dockerfile")
echo "${ARGS[@]}"
docker "${ARGS[@]}"
done
}
publish () {
echo "publish: $1"
. "$1/.env"
for PROJECT in "${DOCKER_PROJECTS[@]}"; do
IFS=: read -r PROJECT_NAME PROJECT_TARGET <<< "$PROJECT"
docker tag $DOCKER_GROUP/$PROJECT_NAME $DOCKER_ROOT/$PROJECT_NAME:$VERSION
docker tag $DOCKER_GROUP/$PROJECT_NAME $DOCKER_ROOT/$PROJECT_NAME:$DOCKER_TAG
docker push $DOCKER_ROOT/$PROJECT_NAME:$VERSION
docker push $DOCKER_ROOT/$PROJECT_NAME:$DOCKER_TAG
done
}
save () {
echo "save: $1"
. "$1/.env"
mkdir -p "$1/dist"
for PROJECT in "${DOCKER_PROJECTS[@]}"; do
IFS=: read -r PROJECT_NAME PROJECT_TARGET <<< "$PROJECT"
docker save --output "$1/dist/$PROJECT_NAME-$VERSION.tar" "$DOCKER_GROUP/$PROJECT_NAME"
done
}
DEFAULT_TARGETS="."
TARGETS="${@-$DEFAULT_TARGETS}"
DOCKER_ACTION="${DOCKER_ACTION-build}"
for TARGET in $TARGETS; do
$DOCKER_ACTION "$TARGET"
done
-8
View File
@@ -1,8 +0,0 @@
#!/usr/bin/env bash
set -e
cd "$(dirname $(dirname "$0"))" || exit
TARGET="gallery"
poetry run isort $TARGET
poetry run black $TARGET -q
-9
View File
@@ -1,9 +0,0 @@
#!/usr/bin/env bash
set -e
cd "$(dirname $(dirname "$0"))" || exit
TARGET="gallery"
poetry run pylint $TARGET -sn
poetry run isort $TARGET --check-only
poetry run black $TARGET -q --check --diff
-6
View File
@@ -1,6 +0,0 @@
#!/usr/bin/env bash
set -e
cd "$(dirname $(dirname "$0"))" || exit
cd locales/ru/LC_MESSAGES || exit
msgfmt messages.po
-23
View File
@@ -1,23 +0,0 @@
#!/usr/bin/env bash
set -e
cd "$(dirname $(dirname "$0"))" || exit
# env
if [[ ! -f .env ]]; then
cp .env-base .env
fi
source .env
# python
poetry env use ${PYTHON_VERSION}
poetry install
.venv/bin/playwright install chromium --with-deps --only-shell
# static
cd static || exit
if [[ -f $HOME/.nvm/nvm.sh ]]; then
source "$HOME/.nvm/nvm.sh"
nvm use
fi
npm ci
-5
View File
@@ -1,5 +0,0 @@
#!/usr/bin/env bash
set -e
cd "$(dirname $(dirname "$0"))" || exit
OPENWEATHER_KEY="" poetry run pytest tests
-19
View File
@@ -1,19 +0,0 @@
#!/usr/bin/env bash
set -e
cd "$(dirname $(dirname "$0"))" || exit
if [ -z "$1" ]; then
echo "Usage: $0 [version]"
exit 1
fi
if [[ ! -z "$(git status -s)" ]]; then
echo "Uncomitted changes"
exit 1
fi
poetry version $1
(cd static && npm version $1 --allow-same-version)
git add .
git commit -m "ci(version): $1"
git tag $1
+2 -2
View File
@@ -1,12 +1,12 @@
{ {
"name": "gallery", "name": "gallery",
"version": "0.8.2", "version": "0.8.4",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "gallery", "name": "gallery",
"version": "0.8.2", "version": "0.8.4",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"@popperjs/core": "^2.11.8", "@popperjs/core": "^2.11.8",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "gallery", "name": "gallery",
"version": "0.8.2", "version": "0.8.4",
"type": "module", "type": "module",
"scripts": { "scripts": {
"build": "webpack --mode production", "build": "webpack --mode production",
+1 -1
View File
@@ -18,7 +18,7 @@ async def test_search(yandexweather_api: YandexWeatherApi):
async def test_day(yandexweather_api: YandexWeatherApi): async def test_day(yandexweather_api: YandexWeatherApi):
result = await yandexweather_api.get_day("test", datetime.date.today()) result = await yandexweather_api.get_day("test", datetime.date(2026, 9, 1))
assert len(result.values) == 4 assert len(result.values) == 4