Skip to content

Commit

Permalink
Merge pull request #376 from SevanSSP/feat/pass-credentials
Browse files Browse the repository at this point in the history
feat: pass credentials to client
  • Loading branch information
snorrefjellvang authored Oct 3, 2024
2 parents 79a978e + 4f6d339 commit aab5ccf
Show file tree
Hide file tree
Showing 7 changed files with 78 additions and 35 deletions.
3 changes: 3 additions & 0 deletions .env-template
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
INQUIRE_MODELTEST_API_HOST=http://127.0.0.1:8000
INQUIRE_MODELTEST_API_USER=
INQUIRE_MODELTEST_API_PASSWORD=
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,6 @@ venv.bak/
.nox

# Jupyter Notebook
.ipynb_checkpoints/
.ipynb_checkpoints/

.env
36 changes: 15 additions & 21 deletions modeltestsdk/client.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import os
import sys
from typing import Optional

import requests
import requests_cache
import logging
Expand All @@ -17,9 +19,6 @@
from requests.adapters import HTTPAdapter, Retry

log_levels = dict(debug=logging.DEBUG, info=logging.INFO, error=logging.ERROR)
retries = Retry(total=Config.requests_max_retries,
backoff_factor=Config.requests_backoff_factor,
status_forcelist=[500, 502, 503, 504])


class Client:
Expand All @@ -41,9 +40,9 @@ class Client:
"""

def __init__(self, config=Config):
def __init__(self, config: Optional[Config] = None):
"""Initialize objects for interacting with the API"""
self.config = config
self.config: Config = config if config is not None else Config(_env_file="../.env")
self.filter = Query(method_spec='filter')
self.sort = Query(method_spec='sort')
self.campaign = CampaignAPI(client=self)
Expand All @@ -56,13 +55,9 @@ def __init__(self, config=Config):
self.tag = TagsAPI(client=self)
self.floater_config = FloaterConfigAPI(client=self)

# check environmental variables
if os.getenv("INQUIRE_MODELTEST_API_USER") is None:
raise EnvironmentError("You have to set the INQUIRE_MODELTEST_API_USER environment variable to login.")
if os.getenv("INQUIRE_MODELTEST_API_PASSWORD") is None:
raise EnvironmentError("You have to set the INQUIRE_MODELTEST_API_PASSWORD environment variable to login.")
if os.getenv("INQUIRE_MODELTEST_API_HOST") is None:
raise EnvironmentError("You have to set the INQUIRE_MODELTEST_API_HOST environment variable to login.")
self.retries = Retry(total=self.config.requests_max_retries,
backoff_factor=self.config.requests_backoff_factor,
status_forcelist=[500, 502, 503, 504])

# configure logging
log_levels = dict(debug=logging.DEBUG, info=logging.INFO, error=logging.ERROR)
Expand All @@ -75,7 +70,7 @@ def __init__(self, config=Config):
logging.basicConfig(stream=sys.stdout, level=level, format=fmt)

def __str__(self):
return f"<Client host:'{self.config.host}'>"
return f"<Client host:'{self.config.api_host}'>"

def _request_token(self) -> str:
"""str: Authenticate and return access token."""
Expand All @@ -94,7 +89,7 @@ def _request_token(self) -> str:
passwd = os.getenv("INQUIRE_MODELTEST_API_PASSWORD")

s = requests.session()
s.mount('http://', HTTPAdapter(max_retries=retries))
s.mount('http://', HTTPAdapter(max_retries=self.retries))

r = s.post(
self._create_url(resource="auth", endpoint="token"),
Expand Down Expand Up @@ -150,7 +145,7 @@ def _create_url(self, resource: str = None, endpoint: str = None) -> str:
'{host}/{base_url}/{version}/{resource}/{endpoint}'
"""
url = f"{self.config.host}/{self.config.base_url}/{self.config.version}/"
url = f"{self.config.api_host}/{self.config.base_url}/{self.config.version}/"
url += "/".join([p for p in [resource, endpoint] if p is not None])
return url

Expand Down Expand Up @@ -188,7 +183,7 @@ def _do_request(self, method: str, resource: str = None, endpoint: str = None, p
headers = {
"Authorization": f"Bearer {token}",
"Connection": "keep-alive",
"Host": self.config.host.split("://")[-1], # remove leading http/https
"Host": self.config.api_host.split("://")[-1], # remove leading http/https
"Content-Type": "application/json",
"Accept": "application/json"
}
Expand All @@ -200,11 +195,11 @@ def _do_request(self, method: str, resource: str = None, endpoint: str = None, p
# do request (also encodes parameters)

s = requests.session()
s.mount('http://', HTTPAdapter(max_retries=retries))
s.mount('http://', HTTPAdapter(max_retries=self.retries))

try:
if cache:
with requests_cache.enabled(**Config.cache_settings):
with requests_cache.enabled(**self.config.cache_settings.model_dump()):
r = s.request(method, url, params=parameters, json=body, headers=headers)
r.raise_for_status()
else:
Expand Down Expand Up @@ -342,10 +337,9 @@ def delete(self, resource: str = None, endpoint: str = None, parameters: dict =
"""
return self._do_request("DELETE", resource=resource, endpoint=endpoint, parameters=parameters)

@staticmethod
def clear_cache():
def clear_cache(self):
"""
Removes cached datapoints (from mtdb.sqlite at local cache folder)
"""
with requests_cache.enabled(**Config.cache_settings): # pragma: no cover
with requests_cache.enabled(**self.config.cache_settings): # pragma: no cover
requests_cache.clear()
28 changes: 19 additions & 9 deletions modeltestsdk/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,30 @@
Configurations
"""
import os
from datetime import timedelta
from datetime import timedelta, datetime
from typing import Literal

from pydantic import BaseModel
from pydantic_settings import BaseSettings

class Config:

class CacheConfig(BaseModel):
cache_name: str = "mtdb"
backend: Literal["sqlite"] = "sqlite"
use_cache_dir: bool = True
expire_after: datetime = timedelta(days=7)


class Config(BaseSettings, env_prefix="INQUIRE_MODELTEST_"):
"""
Client configuration
"""
host: str = os.environ.get("INQUIRE_MODELTEST_API_HOST")
api_host: str
api_user: str
api_password: str
base_url: str = "api"
version: str = "v1"
log_level: str = "info"
cache_settings = {'cache_name': 'mtdb',
'backend': 'sqlite',
'use_cache_dir': True,
'expire_after': timedelta(days=7)}
requests_max_retries = 5
requests_backoff_factor = 1.0
cache_settings: CacheConfig = CacheConfig()
requests_max_retries: int = 5
requests_backoff_factor: float = 1.0
36 changes: 35 additions & 1 deletion poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "modeltestsdk"
version = "3.1.1"
version = "3.1.2"
description = "SDK for use with modeltest API"
authors = ["Jørgen Engelsen","Per Voie", "Snorre Fjellvang <[email protected]>", "Einar Glomnes <[email protected]>"]
license = "MIT"
Expand All @@ -19,6 +19,7 @@ pydantic = "^2.8.2"
requests-cache = "^1.2.1"
qats = "^5"
pandas = "<2.3"
pydantic-settings = "^2.5.2"

[tool.poetry.group.dev.dependencies]
bandit = "^1.7.9"
Expand Down
3 changes: 1 addition & 2 deletions tests/functional/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,7 @@ def client(http_service, admin_key):
os.environ['INQUIRE_MODELTEST_API_PASSWORD'] = 'password'
os.environ["INQUIRE_MODELTEST_API_HOST"] = api_url

config = Config
config.host = api_url
config = Config()

client = Client(config)
assert client.__str__()
Expand Down

0 comments on commit aab5ccf

Please sign in to comment.