arccos-api 0.2.0__tar.gz → 0.2.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. {arccos_api-0.2.0 → arccos_api-0.2.1}/PKG-INFO +1 -1
  2. {arccos_api-0.2.0 → arccos_api-0.2.1}/arccos/__init__.py +21 -0
  3. {arccos_api-0.2.0 → arccos_api-0.2.1}/arccos/_http.py +16 -3
  4. {arccos_api-0.2.0 → arccos_api-0.2.1}/arccos/auth.py +1 -1
  5. {arccos_api-0.2.0 → arccos_api-0.2.1}/arccos/client.py +1 -1
  6. {arccos_api-0.2.0 → arccos_api-0.2.1}/arccos/exceptions.py +4 -2
  7. {arccos_api-0.2.0 → arccos_api-0.2.1}/arccos_api.egg-info/PKG-INFO +1 -1
  8. {arccos_api-0.2.0 → arccos_api-0.2.1}/pyproject.toml +1 -1
  9. {arccos_api-0.2.0 → arccos_api-0.2.1}/tests/test_exceptions.py +2 -1
  10. {arccos_api-0.2.0 → arccos_api-0.2.1}/MANIFEST.in +0 -0
  11. {arccos_api-0.2.0 → arccos_api-0.2.1}/README.md +0 -0
  12. {arccos_api-0.2.0 → arccos_api-0.2.1}/arccos/__main__.py +0 -0
  13. {arccos_api-0.2.0 → arccos_api-0.2.1}/arccos/cli/__init__.py +0 -0
  14. {arccos_api-0.2.0 → arccos_api-0.2.1}/arccos/cli/_helpers.py +0 -0
  15. {arccos_api-0.2.0 → arccos_api-0.2.1}/arccos/cli/auth.py +0 -0
  16. {arccos_api-0.2.0 → arccos_api-0.2.1}/arccos/cli/rounds.py +0 -0
  17. {arccos_api-0.2.0 → arccos_api-0.2.1}/arccos/cli/stats.py +0 -0
  18. {arccos_api-0.2.0 → arccos_api-0.2.1}/arccos/resources/__init__.py +0 -0
  19. {arccos_api-0.2.0 → arccos_api-0.2.1}/arccos/resources/clubs.py +0 -0
  20. {arccos_api-0.2.0 → arccos_api-0.2.1}/arccos/resources/courses.py +0 -0
  21. {arccos_api-0.2.0 → arccos_api-0.2.1}/arccos/resources/handicap.py +0 -0
  22. {arccos_api-0.2.0 → arccos_api-0.2.1}/arccos/resources/rounds.py +0 -0
  23. {arccos_api-0.2.0 → arccos_api-0.2.1}/arccos/resources/stats.py +0 -0
  24. {arccos_api-0.2.0 → arccos_api-0.2.1}/arccos/types.py +0 -0
  25. {arccos_api-0.2.0 → arccos_api-0.2.1}/arccos_api.egg-info/SOURCES.txt +0 -0
  26. {arccos_api-0.2.0 → arccos_api-0.2.1}/arccos_api.egg-info/dependency_links.txt +0 -0
  27. {arccos_api-0.2.0 → arccos_api-0.2.1}/arccos_api.egg-info/entry_points.txt +0 -0
  28. {arccos_api-0.2.0 → arccos_api-0.2.1}/arccos_api.egg-info/requires.txt +0 -0
  29. {arccos_api-0.2.0 → arccos_api-0.2.1}/arccos_api.egg-info/top_level.txt +0 -0
  30. {arccos_api-0.2.0 → arccos_api-0.2.1}/setup.cfg +0 -0
  31. {arccos_api-0.2.0 → arccos_api-0.2.1}/tests/test_auth.py +0 -0
  32. {arccos_api-0.2.0 → arccos_api-0.2.1}/tests/test_cli.py +0 -0
  33. {arccos_api-0.2.0 → arccos_api-0.2.1}/tests/test_client.py +0 -0
  34. {arccos_api-0.2.0 → arccos_api-0.2.1}/tests/test_http.py +0 -0
  35. {arccos_api-0.2.0 → arccos_api-0.2.1}/tests/test_resources.py +0 -0
  36. {arccos_api-0.2.0 → arccos_api-0.2.1}/tests/test_rounds.py +0 -0
  37. {arccos_api-0.2.0 → arccos_api-0.2.1}/tests/test_security.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: arccos-api
3
- Version: 0.2.0
3
+ Version: 0.2.1
4
4
  Summary: Unofficial Python CLI and client library for the Arccos Golf API
5
5
  Author: Paul Frederiksen
6
6
  License: MIT
@@ -9,6 +9,8 @@ Quick start:
9
9
  print(client.handicap.current())
10
10
  """
11
11
 
12
+ import logging as _logging
13
+ import re as _re
12
14
  from importlib.metadata import version as _pkg_version
13
15
 
14
16
  from .auth import ArccosAuth
@@ -21,6 +23,25 @@ from .exceptions import (
21
23
  ArccosRateLimitError,
22
24
  )
23
25
 
26
+
27
+ class _SensitiveFilter(_logging.Filter):
28
+ """Redact tokens, access keys, and passwords from log messages."""
29
+
30
+ _PATTERNS = _re.compile(
31
+ r"(Bearer\s+)\S+|"
32
+ r"(eyJ[A-Za-z0-9_-]+\.eyJ[A-Za-z0-9_-]+\.)[A-Za-z0-9_-]+|"
33
+ r"(accessKey[\"']?\s*[:=]\s*[\"']?)\S+",
34
+ _re.IGNORECASE,
35
+ )
36
+
37
+ def filter(self, record: _logging.LogRecord) -> bool:
38
+ if isinstance(record.msg, str):
39
+ record.msg = self._PATTERNS.sub(r"\1\2\3[REDACTED]", record.msg)
40
+ return True
41
+
42
+
43
+ _logging.getLogger("arccos").addFilter(_SensitiveFilter())
44
+
24
45
  __version__ = _pkg_version("arccos-api")
25
46
  __all__ = [
26
47
  "ArccosClient",
@@ -7,6 +7,7 @@ Retries transient failures (429, 5xx, timeouts) with exponential backoff.
7
7
 
8
8
  from __future__ import annotations
9
9
 
10
+ import contextlib
10
11
  import logging
11
12
  import os
12
13
  import time
@@ -44,7 +45,13 @@ class HttpClient:
44
45
  "Content-Type": "application/json",
45
46
  "Accept": "application/json",
46
47
  })
47
- self._timeout = int(os.environ.get("ARCCOS_TIMEOUT", DEFAULT_TIMEOUT))
48
+ try:
49
+ self._timeout = int(os.environ.get("ARCCOS_TIMEOUT", DEFAULT_TIMEOUT))
50
+ if self._timeout <= 0:
51
+ raise ValueError
52
+ except (ValueError, TypeError):
53
+ logger.warning("Invalid ARCCOS_TIMEOUT, using default %ds", DEFAULT_TIMEOUT)
54
+ self._timeout = DEFAULT_TIMEOUT
48
55
 
49
56
  # ------------------------------------------------------------------
50
57
  # Public interface
@@ -125,7 +132,7 @@ class HttpClient:
125
132
  raise_for_status(resp)
126
133
  except Exception as exc:
127
134
  last_exc = exc
128
- self._backoff(attempt)
135
+ self._backoff(attempt, resp)
129
136
  continue
130
137
 
131
138
  # Non-retryable error (4xx other than 429)
@@ -135,7 +142,13 @@ class HttpClient:
135
142
  raise last_exc # type: ignore[misc]
136
143
 
137
144
  @staticmethod
138
- def _backoff(attempt: int) -> None:
145
+ def _backoff(attempt: int, resp: requests.Response | None = None) -> None:
139
146
  delay = RETRY_BACKOFF * (2 ** attempt)
147
+ # Respect Retry-After header if present (429 responses)
148
+ if resp is not None:
149
+ retry_after = resp.headers.get("Retry-After")
150
+ if retry_after:
151
+ with contextlib.suppress(ValueError, TypeError):
152
+ delay = max(float(retry_after), delay)
140
153
  logger.warning("Retrying in %.1fs (attempt %d/%d)", delay, attempt + 1, MAX_RETRIES)
141
154
  time.sleep(delay)
@@ -87,7 +87,7 @@ class Credentials:
87
87
  os.fchmod(fd, 0o600)
88
88
  with os.fdopen(fd, "w") as f:
89
89
  json.dump(self.to_dict(), f, indent=2)
90
- except BaseException:
90
+ except Exception:
91
91
  with contextlib.suppress(OSError):
92
92
  os.close(fd)
93
93
  raise
@@ -95,7 +95,7 @@ class ArccosClient:
95
95
  else:
96
96
  raise ValueError(
97
97
  "Provide email and password, or ensure cached credentials exist "
98
- f"at {creds_path}."
98
+ "at ~/.arccos_creds.json."
99
99
  )
100
100
 
101
101
  self._http = HttpClient(auth=self._auth, creds=self._creds)
@@ -58,10 +58,12 @@ def raise_for_status(response) -> None:
58
58
  body = response.json()
59
59
  error = body.get("error", {})
60
60
  code = error.get("code", status)
61
- message = error.get("description", response.text[:200])
61
+ raw = response.text
62
+ message = error.get("description", raw[:200] + ("\u2026" if len(raw) > 200 else ""))
62
63
  except Exception:
63
64
  code = status
64
- message = response.text[:200]
65
+ raw = response.text
66
+ message = raw[:200] + ("\u2026" if len(raw) > 200 else "")
65
67
 
66
68
  if status == 401 or (isinstance(code, int) and 40100 <= code <= 40199):
67
69
  raise ArccosAuthError(message, status_code=status, error_code=code)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: arccos-api
3
- Version: 0.2.0
3
+ Version: 0.2.1
4
4
  Summary: Unofficial Python CLI and client library for the Arccos Golf API
5
5
  Author: Paul Frederiksen
6
6
  License: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "arccos-api"
7
- version = "0.2.0"
7
+ version = "0.2.1"
8
8
  description = "Unofficial Python CLI and client library for the Arccos Golf API"
9
9
  readme = "README.md"
10
10
  license = {text = "MIT"}
@@ -83,7 +83,8 @@ class TestRaiseForStatus:
83
83
  resp = _mock_response(500, text="x" * 500)
84
84
  with pytest.raises(ArccosError) as exc_info:
85
85
  raise_for_status(resp)
86
- assert len(str(exc_info.value)) <= 200
86
+ # 200 chars + ellipsis indicator
87
+ assert len(str(exc_info.value)) <= 201
87
88
 
88
89
 
89
90
  class TestArccosError:
File without changes
File without changes
File without changes
File without changes
File without changes