fredq 0.1.0__py3-none-any.whl
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.
- fredq/__init__.py +7 -0
- fredq/__main__.py +8 -0
- fredq/auth.py +114 -0
- fredq/cli.py +702 -0
- fredq/client.py +263 -0
- fredq/commands.py +1470 -0
- fredq/exceptions.py +54 -0
- fredq/params.py +247 -0
- fredq/parquet_writer.py +269 -0
- fredq/types.py +8 -0
- fredq-0.1.0.dist-info/METADATA +413 -0
- fredq-0.1.0.dist-info/RECORD +15 -0
- fredq-0.1.0.dist-info/WHEEL +4 -0
- fredq-0.1.0.dist-info/entry_points.txt +2 -0
- fredq-0.1.0.dist-info/licenses/LICENSE +21 -0
fredq/__init__.py
ADDED
fredq/__main__.py
ADDED
fredq/auth.py
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"""FRED API key resolution."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
import sys
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Final, TextIO
|
|
9
|
+
|
|
10
|
+
from fredq.exceptions import FredApiKeyMissingError
|
|
11
|
+
|
|
12
|
+
_ENV_VAR: Final[str] = "FRED_API_KEY"
|
|
13
|
+
# On POSIX, warn when the key file is readable by group or world.
|
|
14
|
+
_WIDE_MODE_MASK: Final[int] = 0o077
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def default_key_path() -> Path:
|
|
18
|
+
"""Return fredq's default API key file path.
|
|
19
|
+
|
|
20
|
+
Returns:
|
|
21
|
+
Path: Default location for the FRED API key file.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
return Path.home() / ".fredq" / "api_key"
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _check_key_file_permissions(path: Path, stderr: TextIO) -> None:
|
|
28
|
+
"""Emit a one-line warning to ``stderr`` when ``path`` is world- or group-readable.
|
|
29
|
+
|
|
30
|
+
Only runs on POSIX (``os.name != 'nt'``). Windows ACL checks are
|
|
31
|
+
too platform-specific and are skipped.
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
path: Path to the API key file.
|
|
35
|
+
stderr: Stream for the permission warning.
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
if os.name == "nt":
|
|
39
|
+
return
|
|
40
|
+
try:
|
|
41
|
+
mode = path.stat().st_mode
|
|
42
|
+
except OSError:
|
|
43
|
+
return
|
|
44
|
+
if mode & _WIDE_MODE_MASK:
|
|
45
|
+
stderr.write(
|
|
46
|
+
f"warning: {path} is readable by group or world; "
|
|
47
|
+
"run `chmod 600` to restrict access.\n"
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _read_key_file(path: Path, stderr: TextIO) -> str | None:
|
|
52
|
+
if not path.exists():
|
|
53
|
+
return None
|
|
54
|
+
_check_key_file_permissions(path, stderr)
|
|
55
|
+
try:
|
|
56
|
+
contents = path.read_text(encoding="utf-8").strip()
|
|
57
|
+
except OSError:
|
|
58
|
+
return None
|
|
59
|
+
if not contents:
|
|
60
|
+
return None
|
|
61
|
+
# Take only the first non-empty line so trailing whitespace or a
|
|
62
|
+
# comment-style second line cannot leak into the request.
|
|
63
|
+
return contents.splitlines()[0].strip() or None
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def resolve_api_key(
|
|
67
|
+
*,
|
|
68
|
+
explicit: str | None = None,
|
|
69
|
+
key_path: Path | None = None,
|
|
70
|
+
use_key_file: bool = True,
|
|
71
|
+
stderr: TextIO | None = None,
|
|
72
|
+
) -> str:
|
|
73
|
+
"""Resolve the FRED API key.
|
|
74
|
+
|
|
75
|
+
Lookup order:
|
|
76
|
+
1. ``explicit`` argument (e.g. from a CLI override).
|
|
77
|
+
2. ``FRED_API_KEY`` environment variable.
|
|
78
|
+
3. Single-line file at ``key_path`` (defaults to ``~/.fredq/api_key``),
|
|
79
|
+
unless ``use_key_file=False``.
|
|
80
|
+
|
|
81
|
+
Args:
|
|
82
|
+
explicit: Explicit API key from a CLI override; ignored when ``None``.
|
|
83
|
+
key_path: Override the fallback file path. Defaults to
|
|
84
|
+
:func:`default_key_path`.
|
|
85
|
+
use_key_file: When ``False``, skip the file fallback entirely. Set
|
|
86
|
+
by ``--no-key-file`` or ``FREDQ_DISABLE_KEY_FILE=1``.
|
|
87
|
+
stderr: Stream for the permission warning. Defaults to
|
|
88
|
+
``sys.stderr`` when ``None``.
|
|
89
|
+
|
|
90
|
+
Returns:
|
|
91
|
+
str: A non-empty FRED API key.
|
|
92
|
+
|
|
93
|
+
Raises:
|
|
94
|
+
FredApiKeyMissingError: If no key can be located by any mechanism.
|
|
95
|
+
"""
|
|
96
|
+
|
|
97
|
+
err = stderr if stderr is not None else sys.stderr
|
|
98
|
+
|
|
99
|
+
if explicit:
|
|
100
|
+
stripped = explicit.strip()
|
|
101
|
+
if stripped:
|
|
102
|
+
return stripped
|
|
103
|
+
|
|
104
|
+
env_value = os.environ.get(_ENV_VAR, "").strip()
|
|
105
|
+
if env_value:
|
|
106
|
+
return env_value
|
|
107
|
+
|
|
108
|
+
if use_key_file:
|
|
109
|
+
path = key_path or default_key_path()
|
|
110
|
+
from_file = _read_key_file(path, err)
|
|
111
|
+
if from_file:
|
|
112
|
+
return from_file
|
|
113
|
+
|
|
114
|
+
raise FredApiKeyMissingError
|