Skip to content

Commit

Permalink
Feature/#48 hello world and profile endpoint (#69)
Browse files Browse the repository at this point in the history
* added clean_cache function

function that removes all files from cache directory or only one, specified by name. Likely to be moved to cache.py, once this is on dev

* Added ToDos, Unified query param comparison

* Updated destatis status check #45

Incorporated further response codes and response type checks.
Output for Code 0 tbd

* Merged updates from personal branch

* Added http 5xx error check, added destatis status tests

* Updated urls, unified Destatis type-style

* Added generic response creation for generic http_helper test

* Updated type hints, made contents rely on functionality from http_helpers

* merged current dev into feature branch.

* Merged changes from draft branch, including pylint fixes, Exception and Error clarification. Also moved clean_cache function. Some ToDos still left, #45.

* fixed linting issues, including inconsistent returns.

* hotfix of overlooked error #45.

* narrowed the catched exception

* Updated clean_cache, updated http_helper

* Fix lint issue with assert

* mypy fixes for ci/cd pipeline #45

* Updated clean_cache function, added a first version of a test

* Fixed linting issues, #45

* updated with remarks from pull request #45, #46

* updated logging due to linting errors W1203

* Added most of the methods from helloworld and profile endpoint, without tests so far, #48

* Modified pre-commit hook (set black profile for isort) to avoid isort and black conflicting changes

* Added most of the methods from helloworld and profile endpoint - this time for real, without tests so far, #48

* Merged current dev into feature branch, #48

* Updated line-length argument for isort, added tests for helloworld and profile, #48

* merged dev again and fixed merge conflicts for automatic merge, #48

* Implemented removeresult + test, #48.

* updated profile password test, #48, still isort issues seem ominous.

* fixed isort in run tests to same line-length as used in pre-commit-config to avoid reoccuring conflicts in profile, #48, see also #60.

* Fix W0707 raise ... from, #48.

* Fix mypy type-hinting error, #48.

* Minor requested updates, #48.

* fixed mypy type, #48.

* isort toml configuration commit (check line-length specification at only one point)

* fixed line-length -> line_length

* Added notebooks for helloworld and profile endpoint functions, updated get_data_from_endpoint to load_data as requested, #48.

* fixed profile function text outputs, fixed tests, #48.

* Added casting for mypy/ ci/cd, #48
  • Loading branch information
MarcoHuebner authored Sep 27, 2022
1 parent 9188588 commit 3a73672
Show file tree
Hide file tree
Showing 8 changed files with 363 additions and 0 deletions.
77 changes: 77 additions & 0 deletions nb/helloworld.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"%load_ext autoreload\n",
"\n",
"%autoreload 2"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from pygenesis.helloworld import logincheck, whoami"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The `helloworld` module allows you to run basic functions checking your login credentials (`logincheck`) and test calling the Destatis API (`whoami`)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# test calling Destatis API (e.g. whether it is currently online)\n",
"whoami()\n",
"# test your login credentials (set via config functions)\n",
"logincheck()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3.9.12 ('pygenesis')",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.12"
},
"orig_nbformat": 4,
"vscode": {
"interpreter": {
"hash": "c50015765afe066708d859da3faaa0505e12b679b95f6727e524b172064c6917"
}
}
},
"nbformat": 4,
"nbformat_minor": 2
}
63 changes: 63 additions & 0 deletions nb/profile.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"%load_ext autoreload\n",
"\n",
"%autoreload 2"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from pygenesis.profile import change_password, remove_result"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The `profile` module allows you to change your password (`change_password`) and use the (unavailable) `remove_result` functionality, listed in the [documentation under 2.7.2](https://www-genesis.destatis.de/genesis/misc/GENESIS-Webservices_Einfuehrung.pdf)."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# change your password\n",
"change_password(new_password=DoNotUseThisAccidentally)\n",
"# use remove_result functionality\n",
"destatis_name_code = \"42131-0001\"\n",
"remove_result(name=destatis_name_code)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3.9.12 ('pygenesis')",
"language": "python",
"name": "python3"
},
"language_info": {
"name": "python",
"version": "3.9.12"
},
"orig_nbformat": 4,
"vscode": {
"interpreter": {
"hash": "c50015765afe066708d859da3faaa0505e12b679b95f6727e524b172064c6917"
}
}
},
"nbformat": 4,
"nbformat_minor": 2
}
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,4 @@ log_cli = false

[tool.isort]
profile = "black"
line_length = 80
49 changes: 49 additions & 0 deletions src/pygenesis/helloworld.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
"""Module provides wrapper for HelloWorld GENESIS REST-API functions."""

import requests

from pygenesis.config import load_config
from pygenesis.http_helper import _check_invalid_status_code


def whoami() -> str:
"""
Wrapper method which constructs an URL for testing the Destatis API
whoami method, which returns host name and IP address.
Returns:
str: text test response from Destatis
"""
config = load_config()
url = f"{config['GENESIS API']['base_url']}" + "helloworld/whoami"

response = requests.get(url, timeout=(1, 15))

_check_invalid_status_code(response.status_code)

return str(response.text)


def logincheck() -> str:
"""
Wrapper method which constructs an URL for testing the Destatis API
logincheck method, which tests the login credentials (from the config.ini).
Returns:
str: text logincheck response from Destatis
"""
config = load_config()
url = f"{config['GENESIS API']['base_url']}" + "helloworld/logincheck"

params = {
"username": config["GENESIS API"]["username"],
"password": config["GENESIS API"]["password"],
}

response = requests.get(url, params=params, timeout=(1, 15))

# NOTE: Cannot use get_data_from_endpoint due to colliding
# and misleading usage of "Status" key in API response
_check_invalid_status_code(response.status_code)

return str(response.text)
73 changes: 73 additions & 0 deletions src/pygenesis/profile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
"""Module provides wrapper for Profile GENESIS REST-API functions."""

import logging
from typing import cast

from pygenesis.config import (
_write_config,
get_config_path_from_settings,
load_config,
)
from pygenesis.http_helper import load_data

logger = logging.getLogger(__name__)


def change_password(new_password: str) -> str:
"""
Changes Genesis REST-API password and updates local config.
Args:
new_password (str): New password for the Genesis REST-API
Returns:
str: text response from Destatis
"""
params = {
"new": new_password,
"repeat": new_password,
}

# load config.ini beforehand, to ensure passwords are changed at the same time
config = load_config()
try:
config["GENESIS API"]["password"]
except KeyError as e:
raise KeyError(
"Password not found in config! Please make sure \
init_config() was run properly & your user data is set correctly!",
) from e

# change remote password
response_text = load_data(
endpoint="profile", method="password", params=params
)
# change local password
config["GENESIS API"]["password"] = new_password
_write_config(config, get_config_path_from_settings())

logger.info("Password changed successfully!")

return cast(str, response_text)


def remove_result(name: str, area: str = "all") -> str:
"""
Remove 'Ergebnistabellen' from the the permission space 'area'.
Should only apply for manually saved data, visible in 'Meine Tabellen' in the Web Interface.
Args:
name (str): 'Ergebnistabelle' to be removed
area (str): permission area in which the 'Ergebnistabelle' resides
Returns:
str: text response from Destatis
"""
params = {"name": name, "area": area, "language": "de"}

# remove 'Ergebnistabelle' with previously defined parameters
response_text = load_data(
endpoint="profile", method="removeresult", params=params
)

return cast(str, response_text)
1 change: 1 addition & 0 deletions tests/test_cache.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import re
from pathlib import Path
from typing import Optional

import pytest

Expand Down
34 changes: 34 additions & 0 deletions tests/test_helloworld.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
from mock import patch

from pygenesis.helloworld import logincheck, whoami
from tests.test_http_helper import _generic_request_status


@patch("requests.get")
@patch("pygenesis.helloworld.load_config")
def test_whoami(mock_config, mock_requests):
mock_config.return_value = {
"GENESIS API": {
"base_url": "mocked_url",
"username": "JaneDoe",
"password": "password",
}
}
mock_requests.return_value = _generic_request_status()

whoami()


@patch("requests.get")
@patch("pygenesis.helloworld.load_config")
def test_logincheck(mock_config, mock_requests):
mock_config.return_value = {
"GENESIS API": {
"base_url": "mocked_url",
"username": "JaneDoe",
"password": "password",
}
}
mock_requests.return_value = _generic_request_status()

logincheck()
65 changes: 65 additions & 0 deletions tests/test_profile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import re
from configparser import ConfigParser
from pathlib import Path

import pytest
from mock import patch

from pygenesis.profile import change_password, remove_result
from tests.test_http_helper import _generic_request_status


@pytest.fixture()
def cache_dir(tmp_path_factory):
# remove white-space and non-latin characters (issue fo some user names)
temp_dir = str(tmp_path_factory.mktemp(".pygenesis"))
temp_dir = re.sub(r"[^\x00-\x7f]", r"", temp_dir.replace(" ", ""))

return Path(temp_dir)


@patch("pygenesis.profile.get_config_path_from_settings")
@patch("pygenesis.profile.load_data")
@patch("pygenesis.profile.load_config")
def test_change_password(
mock_config, mock_requests, mock_config_dir, cache_dir
):
# mock configparser to be able to test writing of new password
config = ConfigParser()
config["GENESIS API"] = {
"base_url": "mocked_url",
"username": "JaneDoe",
"password": "password",
}
mock_config.return_value = config
mock_requests.return_value = str(_generic_request_status().text)
mock_config_dir.return_value = cache_dir / "config.ini"

change_password("new_password")


@patch("pygenesis.profile.get_config_path_from_settings")
@patch("pygenesis.profile.load_data")
@patch("pygenesis.profile.load_config")
def test_change_password_keyerror(
mock_config, mock_requests, mock_config_dir, cache_dir
):
# define empty config (no password)
mock_config.return_value = {"GENESIS API": {}}
mock_requests.return_value = str(_generic_request_status().text)
mock_config_dir.return_value = cache_dir

with pytest.raises(KeyError) as e:
change_password("new_password")
assert (
"Password not found in config! Please make sure \
init_config() was run properly & your user data is set correctly!"
in str(e.value)
)


@patch("pygenesis.profile.load_data")
def test_remove_result(mock_requests):
mock_requests.return_value = str(_generic_request_status().text)

remove_result("11111-0001")

0 comments on commit 3a73672

Please sign in to comment.