from dataclasses import dataclass, field
from functools import partialmethod
from logging import getLogger
from typing import ClassVar

import requests
from tenacity import TryAgain, retry, stop_after_attempt, wait_incrementing

log = getLogger(__name__)

class TooManyIterations(Exception):

class LocatorAPIv1:
    key: str
    session: requests.Session = field(default_factory=requests.Session)
    adapter: requests.adapters.HTTPAdapter = requests.adapters.HTTPAdapter(

    API_URL: ClassVar[str] = ''
    TIMEOUT: ClassVar[int] = 10

    def __post_init__(self):
        self.session.mount('http://', self.adapter)

        wait=wait_incrementing(start=1, increment=2),
    def request(self, method: str, path: str, **kwargs) -> requests.Response:
        if path.startswith('/'):
            path = self.API_URL + path

        kwargs.setdefault('timeout', self.TIMEOUT)
        response = self.session.request(method, path, **kwargs)

        if response.status_code ==
            raise TryAgain()

        return response

    get = partialmethod(request, 'get')
    post = partialmethod(request, 'post')

    def get_devices(self) -> list[dict]:
        response = self.get('/devices/')
        return response.json()['devices']

Share a link to this review

1.89% issue ratio

L20 Hardcoded value

If some value is hidden somewhere in the middle of code, it will be very hard to find it later. Better solutions: 1) use environment variables 2) use constants in module's top section 3) use class variables.

Create new review request