Skip to content

Commit

Permalink
Merge pull request #116 from statisticsnorway/lastebruker-as-input
Browse files Browse the repository at this point in the history
Lastebruker as input
  • Loading branch information
aecorn authored Apr 2, 2024
2 parents 0ea89af + 1c2fc49 commit db3521f
Show file tree
Hide file tree
Showing 12 changed files with 176 additions and 99 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,13 @@ ssb-project build
Make a notebook with the project's kernel, try this code to verify that you can "log in":
```python
from statbank import StatbankClient
stat_client = StatbankClient(loaduser = "LASTEBRUKER")
stat_client = StatbankClient()
# Change LASTEBRUKER to your load-statbank-username
# Fill out password
# Default publishing-date is TOMORROW
print(stat_client)
# Printing will show you all the default settings on the client.
# You can change for example date by specifying it: StatbankClient(loaduser = "LASTEBRUKER", date="2023-02-16")
# You can change for example date by specifying it: StatbankClient(date="2023-02-16")
```

Be aware that from the **dapla-staging environment** you will be sending to statbank-TEST-database, your changes will not be published. For this you need the "test-password", which is for the same user (lastebruker), but different from the ordinary password (lastepassord). If you are missing the test-password, have the statbank-team send it to you for your loaduser. If you are in the main dapla-jupyterlab (prod), you **WILL** publish to statbanken, in the PROD database. So pay extra attention to the **publishing-date** when in dapla-main-prod-jupyterlab. And be aware of which password you are entering, based on your environment. [To see data actually published to the test-database, you can use this link if you work at SSB.](https://i.test.ssb.no/pxwebi/pxweb/no/test_24v_intern/)
Expand Down
2 changes: 1 addition & 1 deletion demo/01_enkleste_bruk.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@
},
"outputs": [],
"source": [
"client = StatbankClient(loaduser=\"LAST360\")"
"client = StatbankClient()"
]
},
{
Expand Down
2 changes: 1 addition & 1 deletion demo/02_bruke_filbeskrivelse.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
},
"outputs": [],
"source": [
"client = StatbankClient(loaduser=\"LAST360\")"
"client = StatbankClient()"
]
},
{
Expand Down
3 changes: 1 addition & 2 deletions demo/03_alleparametre_datewidget.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,7 @@
"metadata": {},
"outputs": [],
"source": [
"client = StatbankClient(loaduser=\"LAST360\",\n",
" #date=\"2023-02-21\",\n",
"client = StatbankClient(#date=\"2023-02-21\",\n",
" shortuser=\"cfc\",\n",
" cc=\"thu\",\n",
" bcc=\"tir\",\n",
Expand Down
2 changes: 1 addition & 1 deletion demo/fillna_dict_dev.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
},
"outputs": [],
"source": [
"client = StatbankClient(loaduser=\"LAST360\")"
"client = StatbankClient()"
]
},
{
Expand Down
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.2"
version = "1.2.0"
description = "Handles data transfer Statbank <-> Dapla for Statistics Norway"
authors = ["Statistics Norway", "Carl F. Corneil <[email protected]>"]
license = "MIT"
Expand Down
20 changes: 11 additions & 9 deletions src/statbank/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ def __init__(self) -> None:
This is for typing with Mypy.
"""
self.loaduser: str

def _build_headers(self) -> dict[str, str]:
return {
Expand Down Expand Up @@ -70,17 +69,20 @@ def _build_user_agent(self) -> str:
return user_agent + r.utils.default_headers()["User-agent"]

def _build_auth(self) -> str:
response = self._encrypt_request()
try:
username_encryptedpassword = (
bytes(self.loaduser, "UTF-8")
+ bytes(":", "UTF-8")
+ bytes(json.loads(response.text)["message"], "UTF-8")
username_encryptedpassword = (
bytes(
self._get_user(),
"UTF-8",
)
finally:
del response
+ bytes(":", "UTF-8")
+ bytes(json.loads(self._encrypt_request().text)["message"], "UTF-8")
)
return "Basic " + base64.b64encode(username_encryptedpassword).decode("utf8")

@staticmethod
def _get_user() -> str:
return getpass.getpass("Lastebruker:")

def _encrypt_request(self) -> r.Response:
db = self.check_database()
if AuthClient.is_ready():
Expand Down
31 changes: 14 additions & 17 deletions src/statbank/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,6 @@ class StatbankClient(StatbankAuth):
- get published data from the external or internal API of statbanken: apidata_all() / apidata()
Attributes:
loaduser (str): Username for Statbanken, not the same as "tbf"
or "common personal username" in other SSB-systems
date (str): Date for publishing the transfer. Shape should be "yyyy-mm-dd",
like "2022-01-01".
Statbanken only allows publishing four months into the future?
Expand All @@ -70,7 +68,6 @@ class StatbankClient(StatbankAuth):

def __init__( # noqa: PLR0913
self,
loaduser: str = "",
date: str | dt.datetime = TOMORROW,
shortuser: str = "",
cc: str = "",
Expand All @@ -82,7 +79,6 @@ def __init__( # noqa: PLR0913
check_username_password: bool = True,
) -> None:
"""Initialize the client, storing password etc. on the client."""
self.loaduser = loaduser
self.shortuser = shortuser
self.cc = cc
self.bcc = bcc
Expand All @@ -93,11 +89,18 @@ def __init__( # noqa: PLR0913
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
try:
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
except ValueError as e:
error_msg = f"Loaduser parameter removed, please do not use it in your code. OR: {e}"
raise ValueError(error_msg) from e
else:
self.date = date
self._validate_date()
Expand All @@ -114,7 +117,7 @@ def __init__( # noqa: PLR0913
# Representation
def __str__(self) -> str:
"""Print a human readable text of the clients attributes."""
return f"""StatbankClient for user {self.loaduser}
return f"""StatbankClient
Publishing at {self.date}
Shortuser {self.shortuser}
Sending mail to {self.cc}
Expand All @@ -129,7 +132,7 @@ def __str__(self) -> str:

def __repr__(self) -> str:
"""Represent the class with the necessary argument to replicate."""
result = f'StatbankClient(loaduser = "{self.loaduser}"'
result = "StatbankClient("
if self.date != TOMORROW:
result += f', date = "{self.date.isoformat("T", "seconds")}")'
if self.shortuser:
Expand Down Expand Up @@ -226,7 +229,6 @@ def get_description(
)
return StatbankUttrekksBeskrivelse(
tableid=tableid,
loaduser=self.loaduser,
headers=self.__headers,
)

Expand Down Expand Up @@ -283,7 +285,6 @@ def validate(
self._validate_params_action(tableid)
validator = StatbankUttrekksBeskrivelse(
tableid=tableid,
loaduser=self.loaduser,
raise_errors=raise_errors,
headers=self.__headers,
)
Expand Down Expand Up @@ -316,7 +317,6 @@ def transfer(
return StatbankTransfer(
dfs,
tableid=tableid,
loaduser=self.loaduser,
headers=self.__headers,
shortuser=self.shortuser,
date=self.date,
Expand Down Expand Up @@ -435,9 +435,6 @@ def _validate_params_action(self, tableid: str) -> None:

def _validate_params_init(self) -> None:
"""Validates many of the parameters sent in on client-initialization."""
if not self.loaduser or not isinstance(self.loaduser, str):
error_msg = "Please pass in a string for loaduser."
raise TypeError(error_msg)
if not self.shortuser:
self.shortuser = self._get_user_tbf()
if not self.cc:
Expand Down
19 changes: 6 additions & 13 deletions src/statbank/transfer.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,6 @@ class StatbankTransfer(StatbankAuth):
the uttakksbeskrivelse.
Dict-shape can be retrieved and validated before transfer with the
Uttakksbeskrivelses-class.
loaduser (str): Username for Statbanken, not the same as "shortuser" or
"common personal username" in other SSB-systems
tableid (str): The numeric id of the table, matching the one found on the website.
Should be a 5-length numeric-string. Alternatively it should be possible to send in the "hovedtabellnavn" instead of the tableid.
shortuser (str): The abbrivation of username at ssb. Three letters, like "cfc"
Expand Down Expand Up @@ -69,7 +67,6 @@ def __init__( # noqa: PLR0913
self,
data: dict[str, pd.DataFrame],
tableid: str = "",
loaduser: str = "",
shortuser: str = "",
date: dt | str | None = None,
cc: str = "",
Expand All @@ -84,9 +81,12 @@ def __init__( # noqa: PLR0913
May run the validations from the StatbankValidation class before the transfer.
"""
self._set_user_attrs(loaduser=loaduser, shortuser=shortuser, cc=cc, bcc=bcc)
self._set_user_attrs(shortuser=shortuser, cc=cc, bcc=bcc)
self._set_date(date=date)
self.data = data
if not isinstance(tableid, str) or not tableid.isdigit():
error_msg = "Loaduser is no longer a parameter, make sure the tableid parameter is a string of digits."
raise ValueError(error_msg)
self.tableid = tableid
self.overwrite = overwrite
self.approve = _approve_type_check(approve)
Expand Down Expand Up @@ -141,7 +141,7 @@ def transfer(self, headers: dict[str, str] | None = None) -> None:

def __str__(self) -> str:
"""Print a string with the status of the transfer."""
first_line = f"Overføring for statbanktabell {self.tableid}.\nloaduser: {self.loaduser}.\n"
first_line = f"Overføring for statbanktabell {self.tableid}.\n"
if self.delay:
result = f"""{first_line}Ikke overført enda."""
else:
Expand All @@ -150,7 +150,7 @@ def __str__(self) -> str:

def __repr__(self) -> str:
"""Get a representation of how to recreate the object using parameters."""
return f'StatbankTransfer([data], tableid="{self.tableid}", loaduser="{self.loaduser}")'
return f'StatbankTransfer([data], tableid="{self.tableid}")'

@property
def delay(self) -> bool:
Expand All @@ -159,17 +159,10 @@ def delay(self) -> bool:

def _set_user_attrs(
self,
loaduser: str = "",
shortuser: str = "",
cc: str = "",
bcc: str = "",
) -> None:
if isinstance(loaduser, str) and loaduser != "":
self.loaduser = loaduser
else:
error_msg = "You must set loaduser as a parameter"
raise ValueError(error_msg)

if shortuser:
self.shortuser = shortuser
else:
Expand Down
13 changes: 7 additions & 6 deletions src/statbank/uttrekk.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ class StatbankUttrekksBeskrivelse(StatbankAuth, StatbankUttrekkValidators):
Attributes:
loaduser (str): Username for Statbanken, not the same as "tbf" or "common personal username" in other SSB-systems
url (str): Main url for transfer
time_retrieved (str): Time of getting the Uttrekksbeskrivelse
tableid (str): Originally the ID of the main table, which to get the
Expand All @@ -56,15 +55,18 @@ class StatbankUttrekksBeskrivelse(StatbankAuth, StatbankUttrekkValidators):
def __init__(
self,
tableid: str,
loaduser: str,
raise_errors: bool = False,
headers: dict[str, str] | None = None,
) -> None:
"""Makes a request to the Statbank-API, populates the objects attributes with parts of the return values."""
self.loaduser = loaduser
self.url = self._build_urls()["uttak"]
self.time_retrieved = ""
self.tableid = tableid
if not isinstance(raise_errors, bool):
error_msg = ( # type: ignore[unreachable]
"raise_errors must be a bool, the loaduser parameter has been removed."
)
raise TypeError(error_msg)
self.raise_errors = raise_errors
self.tablename = ""
self.subtables: dict[str, str] = {}
Expand Down Expand Up @@ -114,7 +116,6 @@ def __str__(self) -> str:
variabel_text += f'\n"Ekspandert matrise/antall koder i kodelistene ganget med hverandre er: {mult_codelists}'

return f"""Uttrekksbeskrivelse for statbanktabell {self.tableid}.
loaduser: {self.loaduser}.
Hele filbeskrivelsen "rå" ligger under .filbeskrivelse
Andre attributter:
Expand All @@ -124,7 +125,7 @@ def __str__(self) -> str:

def __repr__(self) -> str:
"""Return a string representation of how to instantiate this object again."""
return f'StatbankUttrekksBeskrivelse(tableid="{self.tableid}", loaduser="{self.loaduser}")'
return f'StatbankUttrekksBeskrivelse(tableid="{self.tableid}",)'

def transferdata_template(
self,
Expand Down Expand Up @@ -251,7 +252,7 @@ def validate(
if raise_errors and validation_errors:
raise StatbankValidateError(list(validation_errors.values()))
logger.info(
"validation finished (if nothing is logged over debug level, everything should be fine.)",
"validation finished (if nothing is logged over info level, everything should be fine.)",
)
return validation_errors

Expand Down
5 changes: 4 additions & 1 deletion tests/test_apidata.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,14 +64,17 @@ def fake_post_apidata() -> requests.Response:

@pytest.fixture()
@mock.patch.object(StatbankClient, "_encrypt_request")
@mock.patch.object(StatbankClient, "_get_user")
@mock.patch.object(StatbankClient, "_build_user_agent")
def client_fake(
test_build_user_agent: Callable,
test_get_user: Callable,
encrypt_fake: Callable,
) -> StatbankClient:
encrypt_fake.return_value = fake_post_response_key_service()
test_get_user.return_value = fake_user()
test_build_user_agent.return_value = fake_build_user_agent()
return StatbankClient(fake_user(), check_username_password=False)
return StatbankClient(check_username_password=False)


@pytest.fixture()
Expand Down
Loading

0 comments on commit db3521f

Please sign in to comment.