Skip to content

Commit

Permalink
Stored regex as dictionary and updated credential checks.
Browse files Browse the repository at this point in the history
  • Loading branch information
PiaSchroeder committed Dec 12, 2023
1 parent 76f60c5 commit 380e078
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 39 deletions.
22 changes: 12 additions & 10 deletions nb/00_Setup.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@
"cells": [
{
"cell_type": "markdown",
"id": "ab52102c",
"metadata": {},
"source": [
"# Setup `pystatis`\n",
"\n",
"You don't need to do much to use `pystatis`. Basically, the first time you import the package, it will create a `config.ini` file under `~/.pystatis`. This file is used for storing settings, for example your credentials for the supported databases.\n",
"You don't need to do much to use `pystatis`. Basically, the first time you import the package, it will create a `config.ini` file under `~/.pystatis`. This file is used for storing settings, for example your credentials fpr the supported databases.\n",
"\n",
"To set up your credentials, we need to ask you for your username and password. This is done by the `setup_credentials()` function. It will ask you interactively for the credentials, or you can set the following environment variables:\n",
"To set up your credentials, we need to ask you for your username and password. This is done by the `setup_credentials()` function. It will ask you interactivly for the credentials, or you can set the following environmental variables:\n",
"- `PYSTATIS_GENESIS_API_USERNAME`\n",
"- `PYSTATIS_GENESIS_API_PASSWORD`\n",
"- `PYSTATIS_ZENSUS_API_USERNAME`\n",
Expand All @@ -19,14 +20,15 @@
},
{
"cell_type": "markdown",
"id": "bd45ca01",
"metadata": {},
"source": [
"`dotenv` is used here to load a local `.env` file that contains the above mentioned environment variables so we don't have to input them."
"`dotenv` is uses here to load a local `.env` file that contains the above mentioned environmental variables so we don't have to input them."
]
},
{
"cell_type": "code",
"execution_count": 5,
"execution_count": 4,
"id": "888706f5-3a9e-4e0a-9ca6-fa430280bc03",
"metadata": {},
"outputs": [
Expand All @@ -43,7 +45,7 @@
"True"
]
},
"execution_count": 5,
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
Expand All @@ -61,13 +63,13 @@
},
{
"cell_type": "code",
"execution_count": 6,
"execution_count": 5,
"id": "ee7969b6",
"metadata": {},
"outputs": [],
"source": [
"# only execute if you want to delete your config file for test purposes\n",
"pystatis.config.delete_config()"
"# pystatis.config.delete_config()"
]
},
{
Expand All @@ -85,16 +87,16 @@
"source": [
"The only thing you have to do is to set up your user credentials.\n",
"\n",
"You can do so by following either of these steps:\n",
"1. specifying the 6 environment variables `PYSTATIS_GENESIS_API_USERNAME|PASSWORD`, `PYSTATIS_ZENSUS_API_USERNAME|PASSWORD`, `PYSTATIS_REGIO_API_USERNAME|PASSWORD`\n",
"You can do so either by:\n",
"1. specifying the 4 environment variables `PYSTATIS_GENESIS_API_USERNAME|PASSWORD`, and `PYSTATIS_ZENSUS_API_USERNAME|PASSWORD`\n",
"2. calling the function `setup_credentials()` which will guide you through the process\n",
"\n",
"Even if you do 1. please call `setup_credentials()` once as it will read out the environment variables and write the credentials to the `config.ini` in your config dir."
]
},
{
"cell_type": "code",
"execution_count": 7,
"execution_count": 6,
"id": "6c301da5",
"metadata": {},
"outputs": [],
Expand Down
11 changes: 7 additions & 4 deletions src/pystatis/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,18 @@
"""
import logging
import os
import re
from configparser import ConfigParser
from pathlib import Path

PKG_NAME = __name__.split(".", maxsplit=1)[0]
DEFAULT_CONFIG_DIR = str(Path().home() / f".{PKG_NAME}")
SUPPORTED_DB = ["genesis", "zensus", "regio"]
REGEX_DB = ["^((\d{5}-\d{4})|([0-9A-Z]{10}))$",
"^\d{4}[A-Z]-\d{4}$",
"^((\d{5}-.{1,2}($|-.*$))|(A.*$)|([0-9A-Z]{10}))"]

REGEX_DB = {
"genesis": re.compile("^((\d{5}-\d{4})|([0-9A-Z]{10}))$"),
"zensus": re.compile("^\d{4}[A-Z]-\d{4}$"),
"regio": re.compile("^((\d{5}-.{1,2}($|-.*$))|(A.*$)|([0-9A-Z]{10}$))")
}

logger = logging.getLogger(__name__)
config = ConfigParser(interpolation=None)
Expand Down Expand Up @@ -181,6 +183,7 @@ def get_supported_db() -> list[str]:
"""Get a list of supported database names."""
return SUPPORTED_DB


def get_db_identifiers() -> list[str]:
"""Get a list of regex patterns matching item codes in the supported databases."""
return REGEX_DB
Expand Down
40 changes: 18 additions & 22 deletions src/pystatis/db.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
"""Module provides functions to set the active database and get active database properties."""
import logging
import re

from pystatis import config
from pystatis.cache import normalize_name
from pystatis.exception import PystatisConfigError

logger = logging.getLogger(__name__)

Expand All @@ -17,32 +15,15 @@ def identify_db(name: str) -> str:
Returns:
db_name (str): Name of matching database.
"""
supported_dbs = config.get_supported_db()
regex_db = config.get_db_identifiers()

# Strip optional leading * and trailing job id
name = normalize_name(name).lstrip("*")

# Get list of matching dbs
db_match = [idb for idb, irx in zip(supported_dbs, regex_db) if re.match(irx, name)]

if db_match:
# If more than one db matches it must be a Cube (provided all regexing works as intended).
# --> Choose db based on available credentials.
if len(db_match) > 1:
for db_name in db_match:
if get_db_user(db_name) and get_db_pw(db_name):
return db_name
else:
raise PystatisConfigError(
"Missing credentials! " \
"To access this item you need access to either GENESIS-online or Regionalstatistik. " \
"Please run setup_credentials()."
)
else:
return db_match[0]
else:
return ""
db_match = [db_name for db_name, reg in regex_db.items() if reg.match(name)]

return db_match


def get_db_host(db_name: str) -> str:
Expand All @@ -65,3 +46,18 @@ def set_db_pw(db_name: str, new_pw: str) -> None:
def get_db_settings(db_name: str) -> tuple[str, str, str]:
"""Get database settings (host, user, password)."""
return get_db_host(db_name), get_db_user(db_name), get_db_pw(db_name)


def check_db_credentials(db_name: str) -> bool:
"""
Checks if a username and password is stored for the specified database.
Args:
db_name: Name of database to check credentials for.
Returns:
TRUE if credentials were found, FALSE otherwise.
"""
return get_db_user(db_name) and get_db_pw(db_name)


18 changes: 16 additions & 2 deletions src/pystatis/http_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
normalize_name,
read_from_cache,
)
from pystatis.exception import DestatisStatusError
from pystatis.exception import DestatisStatusError, PystatisConfigError

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -107,7 +107,21 @@ def get_data_from_endpoint(
name = params.get("name", params.get("selection", ""))

if name is not None:
db_name = db.identify_db(name)
db_match = db.identify_db(name)

# Check credentials (Note: we might want to do this also for explicitly specified db_names?)
# If more than one db matches it must be a Cube (provided all regexing works as intended).
# --> Choose db based on available credentials.
if db_match:
for db_name in db_match:
if db.check_db_credentials(db_name):
break
else:
raise PystatisConfigError(
"Missing credentials!\n" \
f"To access this item you need to be a registered user of: {db_match} \n" \
"Please run setup_credentials()."
)

if not db_name:
raise ValueError(
Expand Down
2 changes: 1 addition & 1 deletion src/pystatis/profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def change_password(db_name: str, new_password: str) -> str:

# change remote password
response_text = load_data(
endpoint="profile", method="password", params=params
endpoint="profile", method="password", params=params, db_name=db_name
)
# change local password
db.set_db_pw(db_name, new_password)
Expand Down

0 comments on commit 380e078

Please sign in to comment.