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 #357

Merged
merged 56 commits into from
Jun 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
f4b80f0
Bump black from 22.6.0 to 24.3.0
dependabot[bot] Apr 12, 2024
2c3d535
Bump idna from 3.2 to 3.7
dependabot[bot] Apr 12, 2024
8979957
Format
juuso-j Apr 16, 2024
b0b58d6
Format
juuso-j Apr 16, 2024
cd63af0
Format
juuso-j Apr 16, 2024
4562cb2
Format
juuso-j Apr 16, 2024
da189e5
Format
juuso-j Apr 16, 2024
8acb2ea
Format
juuso-j Apr 16, 2024
ff96f71
Format
juuso-j Apr 16, 2024
7fc02c3
Format
juuso-j Apr 16, 2024
09afd7e
Merge pull request #346 from City-of-Turku/dependabot/pip/black-24.3.0
juuso-j Apr 16, 2024
33b308a
Merge pull request #347 from City-of-Turku/dependabot/pip/idna-3.7
juuso-j Apr 16, 2024
4784e4e
Add API documentation
juuso-j Apr 16, 2024
1f6cd79
Parametrize and validate input value in search query
juuso-j Apr 16, 2024
57f3873
Accept plus sign in search validation
juuso-j Apr 16, 2024
33af966
Catch potential tsquery errors more gracefully
juuso-j Apr 16, 2024
004675b
Filter by rank and hyphenate only compound words
juuso-j Apr 16, 2024
e23b7ba
Fix service search results order
juuso-j Apr 16, 2024
4146554
Accept dot and apostrophe in search validation
juuso-j Apr 17, 2024
1145aa7
Add option to disable provider_type ordering in search
juuso-j Apr 17, 2024
dc7fa11
Display search API documentation
juuso-j Apr 17, 2024
7df0e8c
Catch similarity errors more gracefully
juuso-j Apr 17, 2024
8b8b5bf
Assert response status code
juuso-j Apr 18, 2024
73c98fc
Run initial import only if data is found
juuso-j Apr 18, 2024
3b443db
Add force_initial_import_counter_data task
juuso-j Apr 18, 2024
923d2f2
Add --force option
juuso-j Apr 18, 2024
5207277
Handle telraam importing in import_data function
juuso-j Apr 18, 2024
6e0a5d1
Use django-filterset to filter parameters
juuso-j Apr 19, 2024
3337254
Add tests and fixtures
juuso-j Apr 19, 2024
0031550
Merge pull request #348 from City-of-Turku/feature/search-add-helsink…
juuso-j Apr 19, 2024
b5b68e3
Merge pull request #349 from City-of-Turku/feature/eco-counter-ensure…
juuso-j Apr 19, 2024
b0909a7
Handle multiple release_time formats
juuso-j Apr 23, 2024
a254ca0
Move get_csv_file_name to utils.py and rename to get_full_csv_file_name
juuso-j May 2, 2024
ebd1e06
Add parking garage importer
juuso-j May 2, 2024
f579b7e
Add ParkingGarage data type
juuso-j May 2, 2024
aec0a02
Add split_string_at_digit function
juuso-j May 2, 2024
c6b8309
Initial source parking garages source data
juuso-j May 3, 2024
37103a7
Add task that imports parking garages
juuso-j May 3, 2024
d912edb
Add parking garage importer tests
juuso-j May 3, 2024
f4334b8
Merge pull request #350 from City-of-Turku/feature/environment-data-r…
juuso-j May 3, 2024
41270cd
Merge pull request #351 from City-of-Turku/feature/import-traffic-sit…
juuso-j May 3, 2024
b5cc7d2
Mock get_full_csv_file_name
juuso-j May 3, 2024
e08853c
Rename split_string_at_digit to split_string_at_first_digit
juuso-j May 3, 2024
7924924
Bump sqlparse from 0.4.4 to 0.5.0
dependabot[bot] May 16, 2024
bb8975f
Merge pull request #352 from City-of-Turku/feature/import-parking-gar…
juuso-j May 21, 2024
ac68000
Update info about importing parking machines
juuso-j May 22, 2024
56bc7da
Import parking machines with the WFS importer
juuso-j May 22, 2024
bb47ff6
Fix faulty assertion
juuso-j May 22, 2024
c6e4429
Add configuration for parking machines
juuso-j May 22, 2024
35443cf
Add feature to store address with translations
juuso-j May 22, 2024
1fa7c66
Add translate_fi_address_field and translate_fi_address_municipality_id
juuso-j May 22, 2024
100336e
Add comment that the importer is deprecated
juuso-j May 22, 2024
9ecf9bb
Fix comment for translate_fi_address_field
juuso-j May 22, 2024
9d1ef09
Fix geometry assertion
juuso-j May 22, 2024
5058a82
Merge pull request #355 from City-of-Turku/feature/import-parking-mac…
juuso-j May 23, 2024
0e269f4
Merge pull request #353 from City-of-Turku/dependabot/pip/sqlparse-0.5.0
juuso-j May 24, 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
146 changes: 89 additions & 57 deletions eco_counter/management/commands/import_counter_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -387,72 +387,100 @@ def save_telraam_data(start_time):
)


def handle_initial_import(initial_import_counters):
delete_tables(csv_data_sources=initial_import_counters)
for counter in initial_import_counters:
ImportState.objects.filter(csv_data_source=counter).delete()
ImportState.objects.create(csv_data_source=counter)
logger.info(f"Retrieving stations for {counter}.")
# As Telraam counters are dynamic, create after CSV data is processed
if counter == TELRAAM_COUNTER:
Station.objects.filter(csv_data_source=counter).delete()
def handle_initial_import(counter):
logger.info(f"Deleting tables for: {counter}")
delete_tables(csv_data_sources=[counter])
ImportState.objects.filter(csv_data_source=counter).delete()
import_state = ImportState.objects.create(csv_data_source=counter)
logger.info(f"Retrieving stations for {counter}.")
# As Telraam counters are dynamic, create after CSV data is processed
if counter == TELRAAM_COUNTER:
Station.objects.filter(csv_data_source=counter).delete()
else:
save_stations(counter)
return import_state


def get_start_time(counter, import_state):
if import_state.current_year_number and import_state.current_month_number:
start_time = "{year}-{month}-1T00:00".format(
year=import_state.current_year_number,
month=import_state.current_month_number,
)
else:
start_month = (
TELRAAM_COUNTER_START_MONTH if counter == TELRAAM_COUNTER else "01"
)
start_time = f"{COUNTER_START_YEARS[counter]}-{start_month}-01"

start_time = dateutil.parser.parse(start_time)
start_time = TIMEZONE.localize(start_time)
# The timeformat for the input data is : 2020-03-01T00:00
# Convert starting time to input datas timeformat
return start_time


def get_csv_data(counter, import_state, start_time, verbose=True):
match counter:
# case COUNTERS.TELRAAM_COUNTER:
# Telraam counters are handled differently due to their dynamic nature
case COUNTERS.LAM_COUNTER:
csv_data = get_lam_counter_csv(start_time.date())
case COUNTERS.ECO_COUNTER:
csv_data = get_eco_counter_csv()
case COUNTERS.TRAFFIC_COUNTER:
if import_state.current_year_number:
start_year = import_state.current_year_number
else:
start_year = TRAFFIC_COUNTER_START_YEAR
csv_data = get_traffic_counter_csv(start_year=start_year)

start_time_string = start_time.strftime("%Y-%m-%dT%H:%M")
start_index = csv_data.index[
csv_data[INDEX_COLUMN_NAME] == start_time_string
].values[0]
if verbose:
# As LAM data is fetched with a timespan, no index data is available, instead display start_time.
if counter == LAM_COUNTER:
logger.info(f"Starting saving observations at time:{start_time}")
else:
save_stations(counter)
logger.info(f"Starting saving observations at index:{start_index}")

csv_data = csv_data[start_index:]
return csv_data


def import_data(counters):
def import_data(counters, initial_import=False, force=False):
for counter in counters:
logger.info(f"Importing/counting data for {counter}...")
import_state = ImportState.objects.filter(csv_data_source=counter).first()

# Before deleting state and data, check that data is available.
if not force and import_state and initial_import:
start_time = get_start_time(counter, import_state)
csv_data = get_csv_data(counter, import_state, start_time, verbose=False)
if len(csv_data) == 0:
logger.info(
"No data to retrieve, skipping initial import. Use --force to discard."
)
continue

if initial_import:
handle_initial_import(counter)
import_state = ImportState.objects.filter(csv_data_source=counter).first()

if not import_state:
logger.error(
"ImportState instance not found, try importing with the '--init' argument."
)
break
if import_state.current_year_number and import_state.current_month_number:
start_time = "{year}-{month}-1T00:00".format(
year=import_state.current_year_number,
month=import_state.current_month_number,
)
else:
start_month = (
TELRAAM_COUNTER_START_MONTH if counter == TELRAAM_COUNTER else "01"
)
start_time = f"{COUNTER_START_YEARS[counter]}-{start_month}-01"

start_time = dateutil.parser.parse(start_time)
start_time = TIMEZONE.localize(start_time)
# The timeformat for the input data is : 2020-03-01T00:00
# Convert starting time to input datas timeformat
start_time_string = start_time.strftime("%Y-%m-%dT%H:%M")
match counter:
# case COUNTERS.TELRAAM_COUNTER:
# Telraam counters are handled differently due to their dynamic nature
case COUNTERS.LAM_COUNTER:
csv_data = get_lam_counter_csv(start_time.date())
case COUNTERS.ECO_COUNTER:
csv_data = get_eco_counter_csv()
case COUNTERS.TRAFFIC_COUNTER:
if import_state.current_year_number:
start_year = import_state.current_year_number
else:
start_year = TRAFFIC_COUNTER_START_YEAR
csv_data = get_traffic_counter_csv(start_year=start_year)

start_time = get_start_time(counter, import_state)

if counter == TELRAAM_COUNTER:
save_telraam_data(start_time)
else:
start_index = csv_data.index[
csv_data[INDEX_COLUMN_NAME] == start_time_string
].values[0]
# As LAM data is fetched with a timespan, no index data is available, instead
# show time.
if counter == LAM_COUNTER:
logger.info(f"Starting saving observations at time:{start_time}")
else:
logger.info(f"Starting saving observations at index:{start_index}")

csv_data = csv_data[start_index:]
csv_data = get_csv_data(counter, import_state, start_time)
save_observations(
csv_data,
start_time,
Expand All @@ -464,7 +492,6 @@ def import_data(counters):


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)
Expand Down Expand Up @@ -500,20 +527,25 @@ def add_arguments(self, parser):
default=False,
help=f"Import specific counter(s) data, choices are: {COUNTER_CHOICES_STR}.",
)
parser.add_argument(
"--force",
action="store_true",
help="Force the initial import and discard data check",
)

def handle(self, *args, **options):
initial_import_counters = None
start_time = None
initial_import = False
force = options.get("force", False)
if options["initial_import"]:
if len(options["initial_import"]) == 0:
raise CommandError(
f"Specify the counter(s), choices are: {COUNTER_CHOICES_STR}."
)
else:
initial_import_counters = options["initial_import"]
check_counters_argument(initial_import_counters)
logger.info(f"Deleting tables for: {initial_import_counters}")
handle_initial_import(initial_import_counters)
initial_import = True

if options["test_counter"]:
logger.info("Testing eco_counter importer.")
Expand All @@ -536,7 +568,7 @@ def handle(self, *args, **options):
if not initial_import_counters:
# run with counters argument
counters = options["counters"]
check_counters_argument(counters)
else:
counters = initial_import_counters
import_data(counters)
check_counters_argument(counters)
import_data(counters, initial_import, force)
5 changes: 5 additions & 0 deletions eco_counter/management/commands/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,11 @@ def get_traffic_counter_csv(start_year=2015):

def get_lam_dataframe(csv_url):
response = requests.get(csv_url, headers=LAM_STATION_USER_HEADER)
assert (
response.status_code == 200
), "Fetching LAM data from {} , status code {}".format(
settings.ECO_COUNTER_STATIONS_URL, response.status_code
)
string_data = response.content
csv_data = pd.read_csv(io.StringIO(string_data.decode("utf-8")), delimiter=";")
return csv_data
Expand Down
5 changes: 5 additions & 0 deletions eco_counter/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ def initial_import_counter_data(args, name="initial_import_counter_data"):
management.call_command("import_counter_data", "--init", args)


@shared_task_email
def force_initial_import_counter_data(args, name="force_initial_import_counter_data"):
management.call_command("import_counter_data", "--force", "--init", args)


@shared_task_email
def delete_counter_data(args, name="delete_counter_data"):
management.call_command("delete_counter_data", "--counters", args)
Expand Down
1 change: 1 addition & 0 deletions eco_counter/tests/test_import_counter_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
The main purpose of these tests are to verify that the importer
imports and calculates the data correctly.
"""

import calendar
from datetime import datetime, timedelta
from io import StringIO
Expand Down
Loading
Loading