Skip to content

Commit

Permalink
Merge pull request #111 from statisticsnorway/110-application-of-time…
Browse files Browse the repository at this point in the history
…zone-moves-publishing-date-forward-one-day

110 application of timezone moves publishing date forward one day
  • Loading branch information
aecorn authored Mar 22, 2024
2 parents 3e3f653 + ac4e3a5 commit 296143a
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 23 deletions.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "dapla-statbank-client"
version = "1.1.0"
version = "1.1.1"
description = "Handles data transfer Statbank <-> Dapla for Statistics Norway"
authors = ["Statistics Norway", "Carl F. Corneil <[email protected]>"]
license = "MIT"
Expand Down
28 changes: 18 additions & 10 deletions src/statbank/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
from statbank.globals import STATBANK_TABLE_ID_LEN
from statbank.globals import TOMORROW
from statbank.globals import Approve
from statbank.globals import _approve_type_check
from statbank.statbank_logger import logger
from statbank.transfer import StatbankTransfer
from statbank.uttrekk import StatbankUttrekksBeskrivelse
Expand Down Expand Up @@ -57,8 +58,9 @@ class StatbankClient(StatbankAuth):
Defaults to the same as "cc"
overwrite (bool): False = no overwrite
True = overwrite
approve (Approve): 0 = manual approval
1 = automatic approval at transfer-time (immediately)
approve (Approve | str | int):
0 = MANUAL approval
1 = AUTOMATIC approval at transfer-time (immediately)
2 = JIT (Just In Time), approval right before publishing time
log (list[str]): Each "action" (method used) on the client is appended to the log.
Nice to use for appending to your own logging after you are done,
Expand All @@ -74,7 +76,9 @@ def __init__( # noqa: PLR0913
cc: str = "",
bcc: str = "",
overwrite: bool = True,
approve: Approve = APPROVE_DEFAULT_JIT, # Changing back to 2, after wish from Rakel Gading
approve: (
int | str | Approve
) = APPROVE_DEFAULT_JIT, # Changing back to 2, after wish from Rakel Gading
check_username_password: bool = True,
) -> None:
"""Initialize the client, storing password etc. on the client."""
Expand All @@ -83,15 +87,17 @@ def __init__( # noqa: PLR0913
self.cc = cc
self.bcc = bcc
self.overwrite = overwrite
self.approve = approve
self.approve = _approve_type_check(approve)
self.check_username_password = check_username_password
self._validate_params_init()
self.__headers = self._build_headers()
self.log: list[str] = []
if isinstance(date, str):
self.date: dt.datetime = dt.datetime.strptime(date, "%Y-%m-%d").astimezone(
OSLO_TIMEZONE,
)
) + dt.timedelta(
hours=1,
) # Compensate for setting the timezone, stop publishing date from moving
else:
self.date = date
self._validate_date()
Expand Down Expand Up @@ -178,7 +184,9 @@ def set_publish_date(self, date: dt.datetime | str | widgets.DatePicker) -> None
dt.datetime.min.time(),
)
elif isinstance(date, str):
date_date = dt.datetime.strptime(date, "%Y-%m-%d").astimezone(OSLO_TIMEZONE)
date_date = dt.datetime.strptime(date, "%Y-%m-%d").astimezone(
OSLO_TIMEZONE,
) + dt.timedelta(hours=1)
elif isinstance(date, dt.datetime):
date_date = date
else:
Expand All @@ -190,7 +198,7 @@ def set_publish_date(self, date: dt.datetime | str | widgets.DatePicker) -> None
self._validate_date()
logger.info("Publishing date set to: %s", self.date)
self.log.append(
f"Date set to {self.date.isoformat('T', 'seconds')} at {dt.datetime.now().astimezone(OSLO_TIMEZONE).isoformat('T', 'seconds')}",
f"Date set to {self.date.isoformat('T', 'seconds')} at {(dt.datetime.now().astimezone(OSLO_TIMEZONE) + dt.timedelta(hours=1)).isoformat('T', 'seconds')}",
)

# Descriptions
Expand All @@ -211,7 +219,7 @@ def get_description(
"""
self._validate_params_action(tableid)
self.log.append(
f"Getting description for tableid {tableid} at {dt.datetime.now().astimezone(OSLO_TIMEZONE,).isoformat('T', 'seconds')}",
f"Getting description for tableid {tableid} at {(dt.datetime.now().astimezone(OSLO_TIMEZONE,) + dt.timedelta(hours=1)).isoformat('T', 'seconds')}",
)
return StatbankUttrekksBeskrivelse(
tableid=tableid,
Expand Down Expand Up @@ -278,7 +286,7 @@ def validate(
)
validation_errors = validator.validate(dfs)
self.log.append(
f"Validated data for tableid {tableid} at {dt.datetime.now().astimezone(OSLO_TIMEZONE).isoformat('T', 'seconds')}",
f"Validated data for tableid {tableid} at {(dt.datetime.now().astimezone(OSLO_TIMEZONE) + dt.timedelta(hours=1)).isoformat('T', 'seconds')}",
)
return validation_errors

Expand All @@ -300,7 +308,7 @@ def transfer(
"""
self._validate_params_action(tableid)
self.log.append(
f"Transferring tableid {tableid} at {dt.datetime.now().astimezone(OSLO_TIMEZONE).isoformat('T', 'seconds')}",
f"Transferring tableid {tableid} at {(dt.datetime.now().astimezone(OSLO_TIMEZONE) + dt.timedelta(hours=1)).isoformat('T', 'seconds')}",
)
return StatbankTransfer(
dfs,
Expand Down
17 changes: 17 additions & 0 deletions src/statbank/globals.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import annotations

import datetime as dt
import enum

Expand All @@ -13,6 +15,21 @@ class Approve(enum.IntEnum):
"""Just in time approval right before publishing time."""


def _approve_type_check(approve: Approve | int | str) -> Approve:
if isinstance(approve, int) and not isinstance(approve, Approve):
result: Approve = Approve(approve)
elif isinstance(approve, str) and approve.isdigit():
result = Approve(int(approve))
elif isinstance(approve, str):
result = getattr(Approve, approve)
elif isinstance(approve, Approve):
result = approve
else:
error_msg = f"Dont know how to handle approve of type {type(approve)}" # type: ignore[unreachable]
raise TypeError(error_msg)
return result


OSLO_TIMEZONE = dt.timezone(dt.timedelta(hours=1))
TOMORROW = dt.datetime.now(tz=OSLO_TIMEZONE) + dt.timedelta(days=1)
APPROVE_DEFAULT_JIT = Approve.JIT
Expand Down
16 changes: 9 additions & 7 deletions src/statbank/transfer.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@
import requests as r

from statbank.auth import StatbankAuth
from statbank.globals import APPROVE_DEFAULT_JIT
from statbank.globals import OSLO_TIMEZONE
from statbank.globals import SSB_TBF_LEN
from statbank.globals import Approve
from statbank.globals import _approve_type_check
from statbank.statbank_logger import logger

if TYPE_CHECKING:
Expand Down Expand Up @@ -44,9 +46,9 @@ class StatbankTransfer(StatbankAuth):
overwrite (bool):
- False = no overwrite
- True = overwrite
approve (Approve):
- 0 = manual approval
- 1 = automatic approval at transfer-time (immediately)
approve (Approve | str | int):
- 0 = MANUAL approval
- 1 = AUTOMATIC approval at transfer-time (immediately)
- 2 = JIT (Just In Time), approval right before publishing time
validation (bool):
- True, if you want the python-validation code to run user-side.
Expand All @@ -73,7 +75,7 @@ def __init__( # noqa: PLR0913
cc: str = "",
bcc: str = "",
overwrite: bool = True,
approve: Approve = Approve.MANUAL,
approve: int | str | Approve = APPROVE_DEFAULT_JIT,
validation: bool = True,
delay: bool = False,
headers: dict[str, str] | None = None,
Expand All @@ -87,7 +89,7 @@ def __init__( # noqa: PLR0913
self.data = data
self.tableid = tableid
self.overwrite = overwrite
self.approve = approve
self.approve = _approve_type_check(approve)
self.validation = validation
self.__delay = delay
self.oppdragsnummer: str = ""
Expand Down Expand Up @@ -183,7 +185,7 @@ def _set_user_attrs(
def _set_date(self, date: dt | str | None = None) -> None:
# At this point we want date to be a string?
if date is None:
date = dt.now().astimezone(OSLO_TIMEZONE) + td(days=1)
date = dt.now().astimezone(OSLO_TIMEZONE) + td(days=1, hours=1)
if isinstance(date, str):
self.date: str = date
else:
Expand Down Expand Up @@ -325,7 +327,7 @@ def _handle_response(self) -> None:
publish_date = dt.strptime(
response_msg.split("Publiseringsdato '")[1].split("',")[0],
"%d.%m.%Y %H:%M:%S",
).astimezone(OSLO_TIMEZONE)
).astimezone(OSLO_TIMEZONE) + td(hours=1)
publish_hour = int(response_msg.split("Publiseringstid '")[1].split(":")[0])
publish_minute = int(
response_msg.split("Publiseringstid '")[1].split(":")[1].split("'")[0],
Expand Down
43 changes: 38 additions & 5 deletions tests/test_statbank.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import json
from datetime import datetime
from datetime import timedelta as td
from pathlib import Path
from typing import TYPE_CHECKING
from typing import Any
Expand Down Expand Up @@ -229,8 +230,40 @@ def test_transfer_approve_wrong_format(
test_transfer_make_request.return_value = fake_post_response_transfer_successful()
test_transfer_encrypt.return_value = fake_post_response_key_service()
test_build_user_agent.return_value = fake_build_user_agent()
with pytest.raises(ValueError, match="approve") as _:
StatbankTransfer(fake_data(), "10000", fake_user(), approve="1")
with pytest.raises(TypeError, match="approve") as _:
StatbankTransfer(fake_data(), "10000", fake_user(), approve={"1"})


@suppress_type_checks
@mock.patch.object(StatbankTransfer, "_make_transfer_request")
@mock.patch.object(StatbankTransfer, "_encrypt_request")
@mock.patch.object(StatbankTransfer, "_build_user_agent")
def test_transfer_approve_int_intstr_str(
test_build_user_agent: Callable,
test_transfer_encrypt: Callable,
test_transfer_make_request: Callable,
):
test_transfer_make_request.return_value = fake_post_response_transfer_successful()
test_transfer_encrypt.return_value = fake_post_response_key_service()
test_build_user_agent.return_value = fake_build_user_agent()
assert StatbankTransfer(
fake_data(),
"10000",
fake_user(),
approve=1,
).oppdragsnummer.isdigit()
assert StatbankTransfer(
fake_data(),
"10000",
fake_user(),
approve="1",
).oppdragsnummer.isdigit()
assert StatbankTransfer(
fake_data(),
"10000",
fake_user(),
approve="MANUAL",
).oppdragsnummer.isdigit()


def test_repr_transfer(transfer_success: StatbankTransfer):
Expand Down Expand Up @@ -317,8 +350,8 @@ def test_client_approve_wrong_datatype(
):
encrypt_fake.return_value = fake_post_response_key_service()
test_build_user_agent.return_value = fake_build_user_agent()
with pytest.raises(ValueError, match="approve") as _:
StatbankClient(fake_user(), approve="1", check_username_password=False)
with pytest.raises(TypeError, match="handle approve") as _:
StatbankClient(fake_user(), approve=[1], check_username_password=False)


@suppress_type_checks
Expand Down Expand Up @@ -390,7 +423,7 @@ def test_client_set_date_int_raises(client_fake: StatbankClient):

def test_client_set_date_datetime(client_fake: StatbankClient):
client_fake.set_publish_date(
datetime.now().astimezone(OSLO_TIMEZONE),
datetime.now().astimezone(OSLO_TIMEZONE) + td(hours=1),
)
assert "Date set to " in client_fake.log[-1]

Expand Down

0 comments on commit 296143a

Please sign in to comment.