fred-client 0.1.0__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. fred_client-0.1.0/.agents/plugins/marketplace.json +20 -0
  2. fred_client-0.1.0/.claude-plugin/marketplace.json +27 -0
  3. fred_client-0.1.0/.github/workflows/check.yml +24 -0
  4. fred_client-0.1.0/.github/workflows/publish.yml +77 -0
  5. fred_client-0.1.0/.github/workflows/reusable-check.yml +96 -0
  6. fred_client-0.1.0/.gitignore +33 -0
  7. fred_client-0.1.0/LICENSE +21 -0
  8. fred_client-0.1.0/PKG-INFO +385 -0
  9. fred_client-0.1.0/README.ko.md +354 -0
  10. fred_client-0.1.0/README.md +357 -0
  11. fred_client-0.1.0/plugins/fred/.claude-plugin/plugin.json +19 -0
  12. fred_client-0.1.0/plugins/fred/.codex-plugin/plugin.json +33 -0
  13. fred_client-0.1.0/plugins/fred/skills/fetch/SKILL.md +29 -0
  14. fred_client-0.1.0/plugins/fred/skills/fetch/agents/openai.yaml +4 -0
  15. fred_client-0.1.0/plugins/fred/skills/list/SKILL.md +18 -0
  16. fred_client-0.1.0/plugins/fred/skills/list/agents/openai.yaml +4 -0
  17. fred_client-0.1.0/plugins/fred/skills/metadata/SKILL.md +22 -0
  18. fred_client-0.1.0/plugins/fred/skills/metadata/agents/openai.yaml +4 -0
  19. fred_client-0.1.0/plugins/fred/skills/search/SKILL.md +34 -0
  20. fred_client-0.1.0/plugins/fred/skills/search/agents/openai.yaml +4 -0
  21. fred_client-0.1.0/pyproject.toml +73 -0
  22. fred_client-0.1.0/src/fred_client/__init__.py +89 -0
  23. fred_client-0.1.0/src/fred_client/_config.py +92 -0
  24. fred_client-0.1.0/src/fred_client/_endpoint.py +105 -0
  25. fred_client-0.1.0/src/fred_client/catalog.py +34 -0
  26. fred_client-0.1.0/src/fred_client/cli.py +221 -0
  27. fred_client-0.1.0/src/fred_client/client.py +1447 -0
  28. fred_client-0.1.0/src/fred_client/errors.py +75 -0
  29. fred_client-0.1.0/src/fred_client/py.typed +0 -0
  30. fred_client-0.1.0/src/fred_client/session.py +310 -0
  31. fred_client-0.1.0/src/fred_client/types.py +148 -0
  32. fred_client-0.1.0/tests/__init__.py +0 -0
  33. fred_client-0.1.0/tests/test_catalog.py +44 -0
  34. fred_client-0.1.0/tests/test_cli.py +332 -0
  35. fred_client-0.1.0/tests/test_client.py +486 -0
  36. fred_client-0.1.0/tests/test_config.py +145 -0
  37. fred_client-0.1.0/tests/test_session.py +499 -0
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "fred-client",
3
+ "interface": {
4
+ "displayName": "fred"
5
+ },
6
+ "plugins": [
7
+ {
8
+ "name": "fred",
9
+ "source": {
10
+ "source": "local",
11
+ "path": "./plugins/fred"
12
+ },
13
+ "policy": {
14
+ "installation": "AVAILABLE",
15
+ "authentication": "ON_INSTALL"
16
+ },
17
+ "category": "Productivity"
18
+ }
19
+ ]
20
+ }
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "fred-client",
3
+ "owner": {
4
+ "name": "seokhoonj"
5
+ },
6
+ "description": "Search and read FRED economic data",
7
+ "plugins": [
8
+ {
9
+ "name": "fred",
10
+ "displayName": "fred",
11
+ "source": "./plugins/fred",
12
+ "description": "Search and read FRED economic data",
13
+ "author": {
14
+ "name": "seokhoonj"
15
+ },
16
+ "homepage": "https://github.com/seokhoonj/fred-client",
17
+ "category": "Productivity",
18
+ "keywords": [
19
+ "fred",
20
+ "alfred",
21
+ "federal reserve",
22
+ "economic data",
23
+ "macroeconomics"
24
+ ]
25
+ }
26
+ ]
27
+ }
@@ -0,0 +1,24 @@
1
+ name: check
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ push:
6
+ branches: [main]
7
+ pull_request:
8
+
9
+ # A newer push to the same branch or PR makes the older run's result obsolete,
10
+ # so cancel it rather than let both run to completion.
11
+ concurrency:
12
+ group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.event.pull_request.number || github.ref }}
13
+ cancel-in-progress: true
14
+
15
+ # The check only reads the code to lint, type, and test it -- it never writes to the
16
+ # repo -- so it runs with the least privilege that still allows a checkout.
17
+ permissions:
18
+ contents: read
19
+
20
+ jobs:
21
+ check:
22
+ # The full check lives in reusable-check.yml so the release gate in
23
+ # publish.yml runs the identical job on the release commit.
24
+ uses: ./.github/workflows/reusable-check.yml
@@ -0,0 +1,77 @@
1
+ name: publish
2
+
3
+ # Publish to PyPI on a GitHub Release, via PyPI Trusted Publishing (OIDC): no API
4
+ # token or password is stored anywhere -- GitHub mints a short-lived identity token
5
+ # that PyPI verifies against the publisher registered for this repo (owner seokhoonj
6
+ # / repo fred-client / this workflow / environment "pypi").
7
+ #
8
+ # Three jobs. `gate` runs the same reusable check that check.yml runs, on the
9
+ # release commit, so a red build (a lint/type error, a broken test, a lost py.typed
10
+ # or console script, an accidental runtime dependency) cannot reach an upload.
11
+ # `build` builds the sdist and wheel and hands them to `publish` as an artifact.
12
+ # `publish` -- the only job holding the OIDC token -- downloads that artifact and
13
+ # uploads it, and checks out no source, so the privileged step runs the least code.
14
+
15
+ on:
16
+ release:
17
+ types: [published]
18
+
19
+ # Workflow-level floor: any job without its own `permissions:` block still gets a
20
+ # read-only token, so a job added later cannot silently inherit a write-capable
21
+ # default. The build and publish jobs narrow it further below.
22
+ permissions:
23
+ contents: read
24
+
25
+ jobs:
26
+ gate:
27
+ uses: ./.github/workflows/reusable-check.yml
28
+
29
+ build:
30
+ needs: gate
31
+ runs-on: ubuntu-latest
32
+ timeout-minutes: 15
33
+ permissions:
34
+ contents: read
35
+ steps:
36
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
37
+ with:
38
+ persist-credentials: false
39
+ - uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
40
+ - name: Confirm the release tag matches the package version
41
+ # The build takes the version from pyproject, not from the tag that fired the
42
+ # release. Assert they agree so a tag/version mismatch fails here instead of
43
+ # publishing a surprising or duplicate version.
44
+ run: |
45
+ tag='${{ github.event.release.tag_name }}'
46
+ version=$(python3 -c "import tomllib, pathlib; print(tomllib.loads(pathlib.Path('pyproject.toml').read_text())['project']['version'])")
47
+ test "$tag" = "v$version" || { echo "release tag $tag != package version v$version" >&2; exit 1; }
48
+ - name: Build sdist and wheel, then check the metadata
49
+ run: |
50
+ uv build
51
+ uvx twine check --strict dist/*
52
+ - name: Confirm the built wheel installs and runs in a clean environment
53
+ # The gate installs a fresh build from source; this exercises the *exact* wheel
54
+ # that gets uploaded, so a wheel that builds but is unusable never reaches PyPI.
55
+ run: |
56
+ uv venv /tmp/dist-check
57
+ uv pip install --python /tmp/dist-check/bin/python dist/*.whl
58
+ /tmp/dist-check/bin/python -c "import fred_client; print('installed', fred_client.__version__)"
59
+ /tmp/dist-check/bin/fred --version
60
+ - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
61
+ with:
62
+ name: dist
63
+ path: dist/
64
+
65
+ publish:
66
+ needs: build
67
+ runs-on: ubuntu-latest
68
+ timeout-minutes: 15
69
+ environment: pypi
70
+ permissions:
71
+ id-token: write # OIDC; this is what replaces a stored token
72
+ steps:
73
+ - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
74
+ with:
75
+ name: dist
76
+ path: dist/
77
+ - uses: pypa/gh-action-pypi-publish@ba38be9e461d3875417946c167d0b5f3d385a247 # v1.14.1
@@ -0,0 +1,96 @@
1
+ name: reusable check
2
+
3
+ # The full check -- tests, lint, types, and the packaging assertions -- factored
4
+ # into one reusable job so both `check.yml` (on push / PR) and the release gate in
5
+ # `publish.yml` run the *identical* thing. One definition is what makes "publish
6
+ # gates on the full check" true; a second hand-maintained copy would drift, and a
7
+ # check added here silently would not gate releases.
8
+
9
+ on:
10
+ workflow_call:
11
+
12
+ # The floor lives on the shared body, not only on `check.yml`: `publish.yml`'s gate
13
+ # calls this same workflow, and if the floor were only on `check.yml` the gate would
14
+ # run this check with the repo-default (possibly write) token. Declared here, the
15
+ # check is read-only from every caller. A reusable workflow can only downscope from
16
+ # the caller, so this never widens anyone's token.
17
+ permissions:
18
+ contents: read
19
+
20
+ jobs:
21
+ check:
22
+ runs-on: ubuntu-latest
23
+ timeout-minutes: 15
24
+ strategy:
25
+ fail-fast: false
26
+ matrix:
27
+ # requires-python says >=3.11; test every version the classifiers claim,
28
+ # 3.11 being the floor that claim has to hold on.
29
+ python-version: ["3.11", "3.12", "3.13", "3.14"]
30
+
31
+ steps:
32
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
33
+ with:
34
+ persist-credentials: false
35
+ - uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
36
+
37
+ - name: Install
38
+ # A venv per matrix version, not `uv pip --system`: the runner's system
39
+ # Python is externally managed and is one fixed version whatever the matrix
40
+ # says. This is also what the README tells a person to run.
41
+ run: |
42
+ uv venv --python ${{ matrix.python-version }}
43
+ uv pip install -e ".[dev]"
44
+ .venv/bin/python -c "import sys; print('testing on', sys.version)"
45
+
46
+ - name: Test
47
+ run: .venv/bin/pytest -q
48
+
49
+ - name: Lint
50
+ run: .venv/bin/ruff check src tests
51
+
52
+ - name: Types
53
+ run: .venv/bin/mypy
54
+
55
+ - name: Confirm there are no runtime dependencies
56
+ # The zero-dependency claim is documented in the pyproject comment; a claim
57
+ # nothing checks quietly stops being true. Installed into a bare environment,
58
+ # fred-client must import and run with nothing beyond the standard library.
59
+ run: |
60
+ uv venv /tmp/bare --python ${{ matrix.python-version }}
61
+ uv pip install --python /tmp/bare/bin/python .
62
+ /tmp/bare/bin/python -c "
63
+ import importlib.metadata as md
64
+ requires = md.requires('fred-client') or []
65
+ # A requirement guarded by 'extra ==' is an optional (dev) dependency, not a
66
+ # runtime one; the runtime set must be empty for the zero-dependency claim.
67
+ runtime = [r for r in requires if 'extra ==' not in r]
68
+ assert runtime == [], f'unexpected runtime dependencies: {runtime}'
69
+ import fred_client
70
+ print('fred_client imports with no third-party dependency present')
71
+ "
72
+ # The console script runs, and its top-level --version prints (not shoved
73
+ # into a required subcommand).
74
+ /tmp/bare/bin/fred --version
75
+
76
+ - name: Confirm a user's type checker can see the hints
77
+ # Every hint in this package is invisible to a user unless py.typed ships
78
+ # alongside it (PEP 561), and the source cannot answer whether it did:
79
+ # src/fred_client/py.typed can sit in git while the built wheel omits it. So
80
+ # ask it the way a user does -- install the built package into a clean
81
+ # environment and run their checker over their code.
82
+ run: |
83
+ uv venv /tmp/typed --python ${{ matrix.python-version }}
84
+ uv pip install --python /tmp/typed/bin/python . mypy
85
+ cat > /tmp/user_code.py <<'PY'
86
+ from fred_client import FRED
87
+
88
+ # series_id is str; an int is not, so a checker that can see the shipped
89
+ # hints must reject it and name the expected type.
90
+ FRED("x" * 32).series.get(123)
91
+ PY
92
+ /tmp/typed/bin/mypy /tmp/user_code.py > /tmp/mypy_out 2>&1 || true
93
+ cat /tmp/mypy_out
94
+ # Match the specific int-vs-str diagnostic, not just any line containing "str",
95
+ # so the check proves the shipped hint was seen rather than passing vacuously.
96
+ grep -q 'incompatible type "int"; expected "str"' /tmp/mypy_out
@@ -0,0 +1,33 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ .eggs/
6
+ build/
7
+ dist/
8
+ .venv/
9
+ venv/
10
+ .env
11
+
12
+ # uv
13
+ uv.lock
14
+
15
+ # Tooling caches
16
+ .pytest_cache/
17
+ .ruff_cache/
18
+ .mypy_cache/
19
+ .coverage
20
+ htmlcov/
21
+
22
+ # Local scratch (never tracked)
23
+ dev/
24
+ refs/
25
+
26
+ # AI coding agents
27
+ CLAUDE.md
28
+ .claude/
29
+ AGENTS.md
30
+ AGENT.md
31
+ .codex/
32
+ GEMINI.md
33
+ .gemini/
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Seokhoon Joo
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.