Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Production update #332

Merged
merged 51 commits into from
Feb 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
d997a3b
Add updated data, based on a mapping done December 2023
juuso-j Dec 21, 2023
b9615b9
Cache result of list view for 15 minues
juuso-j Jan 25, 2024
8c77d77
Refactor into atomic tests
juuso-j Jan 25, 2024
c0187a6
Add apt-get update
juuso-j Jan 25, 2024
09fc14c
Change v1 to v1
juuso-j Jan 25, 2024
4e882de
Add Redis
juuso-j Jan 25, 2024
6f61c97
Merge pull request #320 from City-of-Turku/feature/update-chargin-sta…
juuso-j Jan 25, 2024
7f00c30
Merge pull request #321 from City-of-Turku/feature/street-maintenance…
juuso-j Jan 25, 2024
375c2b0
Update to changed source data location and format
juuso-j Jan 25, 2024
91c6688
Update fixture data to reflect changed source data
juuso-j Jan 25, 2024
37b4b30
Add data_until_date and data_from_date fields
juuso-j Jan 26, 2024
7c18bfc
Add sensor_types field
juuso-j Jan 26, 2024
6fbee97
Add is_active field
juuso-j Jan 26, 2024
43bca6f
Add helper functions that precalcs station fields
juuso-j Jan 26, 2024
0673ca9
Remove obsolete code
juuso-j Jan 26, 2024
7e98ee1
Add data_until_date, data_from_date, sensor_types and is_active
juuso-j Jan 26, 2024
9b1a3a0
Cache station list view for 60 minutes
juuso-j Jan 26, 2024
cc669ad
Precalc data_from_date, data_until_date, is_active and sensor_types f…
juuso-j Jan 26, 2024
8352faf
Add precalced fields to station fixtures
juuso-j Jan 26, 2024
df01454
Test that fields are precalced for stations
juuso-j Jan 26, 2024
e4b996e
Bump django from 4.1.10 to 4.1.13
dependabot[bot] Jan 26, 2024
f8d2c8c
Merge pull request #325 from City-of-Turku/dependabot/pip/django-4.1.13
juuso-j Jan 26, 2024
84e33f2
Add new event mappings
juuso-j Jan 29, 2024
f9aec32
Test week data measurements
juuso-j Jan 30, 2024
57156cd
Fix bug, duplicate measurements created for week data
juuso-j Jan 30, 2024
f088363
Add wfs_version example
juuso-j Jan 30, 2024
4bcf2dc
Add wfs_version parameter functionality
juuso-j Jan 30, 2024
27d9785
Refactor test_import_week_data_measurements
juuso-j Jan 30, 2024
c1e7b5d
Cache mobility data list view
juuso-j Feb 1, 2024
350df10
Merge pull request #323 from City-of-Turku/feature/update-over-and-un…
juuso-j Feb 1, 2024
16d4916
Merge pull request #324 from City-of-Turku/feature/eco-counter-statio…
juuso-j Feb 1, 2024
a3e47cd
Merge pull request #326 from City-of-Turku/feature/street-maintenance…
juuso-j Feb 1, 2024
f291142
Merge pull request #327 from City-of-Turku/bugfix/environment-data-in…
juuso-j Feb 1, 2024
ccc131d
Merge pull request #328 from City-of-Turku/feature/wfs-importer-add-v…
juuso-j Feb 1, 2024
51c1048
Merge pull request #329 from City-of-Turku/feature/mobility-data-cach…
juuso-j Feb 1, 2024
970369f
Add info about school and kindergarten accessibility areas
juuso-j Feb 2, 2024
dd6e752
Add task to import school and kindergarten accessibility areas
juuso-j Feb 2, 2024
af776c3
Add content type name for school and kindergarten accessibility areas
juuso-j Feb 2, 2024
27fb6db
Add config for school and kindergarten accessibility areas
juuso-j Feb 2, 2024
efdba29
Merge pull request #330 from City-of-Turku/feature/import-school-and-…
juuso-j Feb 8, 2024
bc11aea
Serialize parameters in use from db
juuso-j Feb 22, 2024
1d33421
Add parameters in use to stations
juuso-j Feb 22, 2024
b90aab3
Format
juuso-j Feb 22, 2024
c1e6327
Add parameter
juuso-j Feb 22, 2024
907b1fb
Improve parameters in use test
juuso-j Feb 22, 2024
cb66b8a
Format
juuso-j Feb 22, 2024
2fe56d5
Test parameters that are in user are added
juuso-j Feb 22, 2024
c337321
Cache stations list view
juuso-j Feb 22, 2024
921e870
Merge pull request #331 from City-of-Turku/feature/environment-data-s…
juuso-j Feb 22, 2024
a399520
Remove breakpoint
juuso-j Feb 26, 2024
c63fd90
Merge pull request #333 from City-of-Turku/fix/eco-counter-fetch-telr…
juuso-j Feb 26, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ jobs:

# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
Expand All @@ -53,7 +53,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
uses: github/codeql-action/autobuild@v2

# ℹ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
Expand All @@ -67,4 +67,4 @@ jobs:
# make release

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
uses: github/codeql-action/analyze@v2
6 changes: 3 additions & 3 deletions .github/workflows/run-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ jobs:
ECO_COUNTER_STATIONS_URL: https://dev.turku.fi/datasets/ecocounter/liikennelaskimet.geojson
ECO_COUNTER_OBSERVATIONS_URL: https://data.turku.fi/cjtv3brqr7gectdv7rfttc/counters-15min.csv
TRAFFIC_COUNTER_OBSERVATIONS_BASE_URL: https://data.turku.fi/2yxpk2imqi2mzxpa6e6knq/
CACHE_LOCATION: redis://localhost:6379/0

steps:
- uses: actions/checkout@v3
Expand All @@ -29,9 +30,8 @@ jobs:
python-version: 3.10.0
- name: Install required Ubuntu packages
run: |
sudo apt-get install gdal-bin
sudo apt-get install voikko-fi
sudo apt-get install libvoikko-dev
sudo apt-get update && sudo apt-get -y --no-install-recommends install gdal-bin voikko-fi libvoikko-dev
sudo apt-get install redis-server
- name: Create needed postgis extensions
run: |
psql -h localhost -U postgres template1 -c 'create extension hstore;'
Expand Down
48 changes: 0 additions & 48 deletions eco_counter/api/serializers.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from datetime import date, timedelta

from django.db.models import Q
from rest_framework import serializers

Expand Down Expand Up @@ -38,10 +36,6 @@ class StationSerializer(serializers.ModelSerializer):
y = serializers.SerializerMethodField()
lon = serializers.SerializerMethodField()
lat = serializers.SerializerMethodField()
sensor_types = serializers.SerializerMethodField()
data_until_date = serializers.SerializerMethodField()
data_from_date = serializers.SerializerMethodField()
is_active = serializers.SerializerMethodField()

class Meta:
model = Station
Expand Down Expand Up @@ -78,48 +72,6 @@ def get_lon(self, obj):
obj.location.transform(4326)
return obj.location.x

def get_sensor_types(self, obj):
# Return the sensor types(car, bike etc) that has a total year value >0.
# i.e., there are sensors for counting the type of data.
types = ["at", "pt", "jt", "bt"]
result = []
for type in types:
filter = {"station": obj, f"value_{type}__gt": 0}
if YearData.objects.filter(**filter).count() > 0:
result.append(type)
return result

def get_is_active(self, obj):
num_days = [1, 7, 30, 365]
res = {}
for days in num_days:
from_date = date.today() - timedelta(days=days - 1)
day_qs = Day.objects.filter(station=obj, date__gte=from_date)
day_data_qs = DayData.objects.filter(day__in=day_qs)
if day_data_qs.filter(Q_EXP).count() > 0:
res[days] = True
else:
res[days] = False
return res

def get_data_until_date(self, obj):
try:
return (
DayData.objects.filter(Q_EXP, station=obj).latest("day__date").day.date
)
except DayData.DoesNotExist:
return None

def get_data_from_date(self, obj):
try:
return (
DayData.objects.filter(Q_EXP, station=obj)
.earliest("day__date")
.day.date
)
except DayData.DoesNotExist:
return None


class YearSerializer(serializers.ModelSerializer):
station_name = serializers.PrimaryKeyRelatedField(
Expand Down
3 changes: 3 additions & 0 deletions eco_counter/api/views.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import sys

from django.utils.decorators import method_decorator
from django.views.decorators.cache import cache_page
from rest_framework import status, viewsets
from rest_framework.decorators import action
from rest_framework.exceptions import ParseError
Expand Down Expand Up @@ -54,6 +56,7 @@ class StationViewSet(viewsets.ReadOnlyModelViewSet):
queryset = Station.objects.all()
serializer_class = StationSerializer

@method_decorator(cache_page(60 * 60))
def list(self, request):
queryset = Station.objects.all()
filters = self.request.query_params
Expand Down
16 changes: 16 additions & 0 deletions eco_counter/management/commands/import_counter_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,13 @@
from .utils import (
check_counters_argument,
gen_eco_counter_test_csv,
get_data_from_date,
get_data_until_date,
get_eco_counter_csv,
get_is_active,
get_lam_counter_csv,
get_or_create_telraam_station,
get_sensor_types,
get_telraam_data_frames,
get_test_dataframe,
get_traffic_counter_csv,
Expand Down Expand Up @@ -360,6 +364,7 @@ def save_observations(csv_data, start_time, csv_data_source=ECO_COUNTER, station
import_state.current_month_number = end_date.month
import_state.current_day_number = end_date.day
import_state.save()
add_additional_data_to_stations(csv_data_source)
logger.info(f"Imported observations until:{str(end_date)}")


Expand Down Expand Up @@ -458,6 +463,17 @@ def import_data(counters):
gc.collect()


def add_additional_data_to_stations(csv_data_source):

logger.info(f"Updating {csv_data_source} stations informations...")
for station in Station.objects.filter(csv_data_source=csv_data_source):
station.data_from_date = get_data_from_date(station)
station.data_until_date = get_data_until_date(station)
station.sensor_types = get_sensor_types(station)
station.is_active = get_is_active(station)
station.save()


class Command(BaseCommand):
help = "Imports traffic counter data in the Turku region."

Expand Down
51 changes: 50 additions & 1 deletion eco_counter/management/commands/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from django.contrib.gis.gdal import DataSource
from django.contrib.gis.geos import GEOSGeometry, LineString, MultiLineString, Point
from django.core.management.base import CommandError
from django.db.models import Q

from eco_counter.constants import (
COUNTER_CHOICES_STR,
Expand All @@ -33,11 +34,12 @@
TRAFFIC_COUNTER_CSV_URLS,
TRAFFIC_COUNTER_METADATA_GEOJSON,
)
from eco_counter.models import Station
from eco_counter.models import Day, DayData, Station, YearData
from eco_counter.tests.constants import TEST_COLUMN_NAMES
from mobility_data.importers.utils import get_root_dir

logger = logging.getLogger("eco_counter")
Q_EXP = Q(value_at__gt=0) | Q(value_pt__gt=0) | Q(value_jt__gt=0) | Q(value_bt__gt=0)


class LAMStation:
Expand Down Expand Up @@ -112,6 +114,53 @@
self.geometry = geometry


def get_is_active(station):
# Returns if the station has been active during time period defined in num_days
num_days = [1, 7, 30, 365]
res = {}
for days in num_days:
from_date = date.today() - timedelta(days=days - 1)
day_qs = Day.objects.filter(station=station, date__gte=from_date)
day_data_qs = DayData.objects.filter(day__in=day_qs)
if day_data_qs.filter(Q_EXP).count() > 0:
res[days] = True
else:
res[days] = False
return res


def get_sensor_types(station):
# Return the sensor types(car, bike etc) that has a total year value >0.
# i.e., there are sensors for counting the type of data.
types = ["at", "pt", "jt", "bt"]
result = []
for type in types:
filter = {"station": station, f"value_{type}__gt": 0}
if YearData.objects.filter(**filter).count() > 0:
result.append(type)
return result


def get_data_until_date(station):
try:
return (
DayData.objects.filter(Q_EXP, station=station).latest("day__date").day.date
)
except DayData.DoesNotExist:
return None

Check warning on line 150 in eco_counter/management/commands/utils.py

View check run for this annotation

Codecov / codecov/patch

eco_counter/management/commands/utils.py#L149-L150

Added lines #L149 - L150 were not covered by tests


def get_data_from_date(station):
try:
return (
DayData.objects.filter(Q_EXP, station=station)
.earliest("day__date")
.day.date
)
except DayData.DoesNotExist:
return None

Check warning on line 161 in eco_counter/management/commands/utils.py

View check run for this annotation

Codecov / codecov/patch

eco_counter/management/commands/utils.py#L160-L161

Added lines #L160 - L161 were not covered by tests


def check_counters_argument(counters):
for counter in counters:
if counter not in COUNTERS_LIST:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Generated by Django 4.1.10 on 2024-01-25 11:04

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("eco_counter", "0018_add_geometry_to_station"),
]

operations = [
migrations.AddField(
model_name="station",
name="data_from_date",
field=models.DateField(blank=True, null=True),
),
migrations.AddField(
model_name="station",
name="data_until_date",
field=models.DateField(blank=True, null=True),
),
]
21 changes: 21 additions & 0 deletions eco_counter/migrations/0020_station_sensor_types.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Generated by Django 4.1.10 on 2024-01-25 11:58

import django.contrib.postgres.fields
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("eco_counter", "0019_station_data_from_date_station_data_until_date"),
]

operations = [
migrations.AddField(
model_name="station",
name="sensor_types",
field=django.contrib.postgres.fields.ArrayField(
base_field=models.CharField(max_length=2), default=list, size=None
),
),
]
18 changes: 18 additions & 0 deletions eco_counter/migrations/0021_station_is_active.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 4.1.10 on 2024-01-25 12:24

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("eco_counter", "0020_station_sensor_types"),
]

operations = [
migrations.AddField(
model_name="station",
name="is_active",
field=models.JSONField(blank=True, null=True),
),
]
4 changes: 4 additions & 0 deletions eco_counter/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ class Station(models.Model):
# Optioal id of the station, used when fetching LAM
# and TELRAAM station data
station_id = models.CharField(max_length=16, null=True)
data_until_date = models.DateField(null=True, blank=True)
data_from_date = models.DateField(null=True, blank=True)
sensor_types = ArrayField(models.CharField(max_length=2), default=list)
is_active = models.JSONField(null=True, blank=True)

def __str__(self):
return "%s %s" % (self.name, self.location)
Expand Down
7 changes: 7 additions & 0 deletions eco_counter/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ def stations():
name=TEST_EC_STATION_NAME,
location="POINT(60.4487578455581 22.269454227550053)",
csv_data_source=ECO_COUNTER,
sensor_types=["at"],
data_until_date="2020-01-07",
data_from_date="2020-01-01",
)
)
stations.append(
Expand Down Expand Up @@ -201,24 +204,28 @@ def is_active_fixtures():
name="Station with 0 day of data",
location="POINT(0 0)",
csv_data_source=LAM_COUNTER,
is_active={"1": False, "7": False, "30": False, "365": False},
)
station1 = Station.objects.create(
id=1,
name="Station with 1 day of data",
location="POINT(0 0)",
csv_data_source=LAM_COUNTER,
is_active={"1": True, "7": True, "30": True, "365": True},
)
station7 = Station.objects.create(
id=7,
name="Station with 7 days of data",
location="POINT(0 0)",
csv_data_source=LAM_COUNTER,
is_active={"1": False, "7": True, "30": True, "365": True},
)
station30 = Station.objects.create(
id=30,
name="Station with 30 days of data",
location="POINT(0 0)",
csv_data_source=LAM_COUNTER,
is_active={"1": False, "7": False, "30": True, "365": True},
)
start_date = date.today()
current_date = start_date
Expand Down
13 changes: 11 additions & 2 deletions eco_counter/tests/test_import_counter_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
imports and calculates the data correctly.
"""
import calendar
from datetime import timedelta
from datetime import datetime, timedelta
from io import StringIO
from unittest.mock import patch

Expand Down Expand Up @@ -402,7 +402,16 @@
start_time = dateutil.parser.parse("2020-01-01T00:00")
end_time = dateutil.parser.parse("2020-02-29T23:45")
import_command(test_counter=(TRAFFIC_COUNTER, start_time, end_time))
num_tc_stations = Station.objects.filter(csv_data_source=TRAFFIC_COUNTER).count()
stations_qs = Station.objects.filter(csv_data_source=TRAFFIC_COUNTER)
num_tc_stations = stations_qs.count()
station1 = stations_qs.first()
assert station1.sensor_types == ["at", "pt", "jt", "bt"]
assert station1.data_from_date == datetime.strptime("2020-01-01", "%Y-%m-%d").date()
assert (

Check warning on line 410 in eco_counter/tests/test_import_counter_data.py

View check run for this annotation

Codecov / codecov/patch

eco_counter/tests/test_import_counter_data.py#L405-L410

Added lines #L405 - L410 were not covered by tests
station1.data_until_date == datetime.strptime("2020-02-29", "%Y-%m-%d").date()
)
assert station1.is_active == {"1": False, "7": False, "30": False, "365": False}

Check warning on line 413 in eco_counter/tests/test_import_counter_data.py

View check run for this annotation

Codecov / codecov/patch

eco_counter/tests/test_import_counter_data.py#L413

Added line #L413 was not covered by tests

state = ImportState.objects.get(csv_data_source=TRAFFIC_COUNTER)
assert state.current_year_number == 2020
assert state.current_month_number == 2
Expand Down
Loading
Loading