av-cli 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.
@@ -0,0 +1,34 @@
1
+ # GitHub Actions config secrets
2
+ .github/config-*.json
3
+
4
+ # Editor / IDE
5
+ .gemini
6
+ .vscode
7
+
8
+ # OS
9
+ *.DS_Store
10
+
11
+ # Environment
12
+ .venv
13
+ .env
14
+ .env.bak
15
+ .env*
16
+
17
+ # Python-generated files
18
+ __pycache__/
19
+ *.py[oc]
20
+ build/
21
+ dist/
22
+ wheels/
23
+ *.egg-info
24
+
25
+ # AWS SAM build artifacts
26
+ .aws-sam/
27
+
28
+ # Dev docs
29
+ dev_docs
30
+
31
+ # Generated / local files
32
+ requirements.txt
33
+ sessions.db
34
+ mcp.json
av_cli-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,9 @@
1
+ Metadata-Version: 2.4
2
+ Name: av-cli
3
+ Version: 0.1.0
4
+ Summary: CLI wrapper for Alpha Vantage APIs
5
+ Requires-Python: >=3.10
6
+ Requires-Dist: av-api
7
+ Requires-Dist: click
8
+ Requires-Dist: httpx
9
+ Requires-Dist: loguru
av_cli-0.1.0/README.md ADDED
@@ -0,0 +1,15 @@
1
+ # av-cli
2
+
3
+ CLI wrapper for Alpha Vantage APIs.
4
+
5
+ ## Install
6
+
7
+ ```
8
+ pip install av-cli
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```
14
+ av-cli --version
15
+ ```
@@ -0,0 +1,24 @@
1
+ [project]
2
+ name = "av-cli"
3
+ version = "0.1.0"
4
+ description = "CLI wrapper for Alpha Vantage APIs"
5
+ requires-python = ">=3.10"
6
+ dependencies = [
7
+ "av-api",
8
+ "click",
9
+ "httpx",
10
+ "loguru",
11
+ ]
12
+
13
+ [project.scripts]
14
+ av-cli = "av_cli.main:cli"
15
+
16
+ [build-system]
17
+ requires = ["hatchling"]
18
+ build-backend = "hatchling.build"
19
+
20
+ [tool.hatch.build.targets.wheel]
21
+ packages = ["src/av_cli"]
22
+
23
+ [tool.uv.sources]
24
+ av-api = { workspace = true }
@@ -0,0 +1 @@
1
+ __version__ = "0.1.0"
@@ -0,0 +1,147 @@
1
+ import inspect
2
+ import json
3
+ import os
4
+ import sys
5
+ from typing import Union, get_type_hints
6
+
7
+ import click
8
+
9
+ from av_cli import __version__
10
+
11
+
12
+ def _python_type_to_click(param_type):
13
+ """Map a Python type hint to a Click type."""
14
+ if param_type == bool or param_type == 'bool':
15
+ return bool
16
+ if param_type == int or param_type == 'int':
17
+ return click.INT
18
+ if param_type == float or param_type == 'float':
19
+ return click.FLOAT
20
+ # Handle Optional[X]
21
+ if hasattr(param_type, '__origin__') and param_type.__origin__ is Union:
22
+ args = param_type.__args__
23
+ if len(args) == 2 and type(None) in args:
24
+ inner = args[0] if args[1] is type(None) else args[1]
25
+ return _python_type_to_click(inner)
26
+ return click.STRING
27
+
28
+
29
+ def _make_tool_command(func, tool_name):
30
+ """Build a Click command for a single tool function."""
31
+ from av_api.registry import extract_description
32
+
33
+ sig = inspect.signature(func)
34
+ try:
35
+ hints = get_type_hints(func)
36
+ except Exception:
37
+ hints = {}
38
+
39
+ # Build short option flags, skipping conflicts with -h (help)
40
+ used_shorts = {'h'}
41
+ short_map = {}
42
+ for pname in sig.parameters:
43
+ for ch in pname.lower():
44
+ if ch.isalpha() and ch not in used_shorts:
45
+ used_shorts.add(ch)
46
+ short_map[pname] = f'-{ch}'
47
+ break
48
+
49
+ params = []
50
+ for pname, param in sig.parameters.items():
51
+ ptype = hints.get(pname, str)
52
+ click_type = _python_type_to_click(ptype)
53
+ short = short_map.get(pname)
54
+
55
+ if click_type is bool:
56
+ params.append(
57
+ click.Option(
58
+ [f'--{pname}/--no-{pname}'],
59
+ default=param.default if param.default is not inspect.Parameter.empty else False,
60
+ help=f'{pname} flag',
61
+ )
62
+ )
63
+ else:
64
+ required = param.default is inspect.Parameter.empty
65
+ decls = [f'--{pname}']
66
+ if short:
67
+ decls.append(short)
68
+ params.append(
69
+ click.Option(
70
+ decls,
71
+ type=click_type,
72
+ required=required,
73
+ default=None if required else param.default,
74
+ help=pname,
75
+ )
76
+ )
77
+
78
+ def callback(**kwargs):
79
+ from av_api.context import set_api_key
80
+
81
+ ctx = click.get_current_context()
82
+ api_key = ctx.obj.get('api_key') or os.getenv('ALPHA_VANTAGE_API_KEY')
83
+ if not api_key:
84
+ click.echo('Error: API key required. Use --api-key or set ALPHA_VANTAGE_API_KEY.', err=True)
85
+ sys.exit(1)
86
+
87
+ set_api_key(api_key)
88
+ result = func(**kwargs)
89
+
90
+ if isinstance(result, str):
91
+ click.echo(result)
92
+ else:
93
+ click.echo(json.dumps(result, indent=2, default=str))
94
+
95
+ cmd = click.Command(
96
+ name=tool_name,
97
+ callback=callback,
98
+ params=params,
99
+ help=extract_description(func),
100
+ )
101
+ return cmd
102
+
103
+
104
+ class ToolGroup(click.Group):
105
+ """Click group that lazily loads tool commands from the registry."""
106
+
107
+ def __init__(self, *args, **kwargs):
108
+ super().__init__(*args, **kwargs)
109
+ self._tools_loaded = False
110
+
111
+ def _load_tools(self):
112
+ if self._tools_loaded:
113
+ return
114
+ self._tools_loaded = True
115
+
116
+ from av_api.registry import _all_tools_registry, ensure_tools_loaded
117
+
118
+ ensure_tools_loaded()
119
+
120
+ for func in _all_tools_registry:
121
+ name = func.__name__
122
+ cmd = _make_tool_command(func, name)
123
+ self.add_command(cmd)
124
+
125
+ def list_commands(self, ctx):
126
+ self._load_tools()
127
+ return super().list_commands(ctx)
128
+
129
+ def get_command(self, ctx, cmd_name):
130
+ self._load_tools()
131
+ return super().get_command(ctx, cmd_name.lower())
132
+
133
+
134
+ @click.group(cls=ToolGroup, context_settings=dict(help_option_names=['-h', '--help']))
135
+ @click.version_option(version=__version__, prog_name="av-cli")
136
+ @click.option('--api-key', '-k', envvar='ALPHA_VANTAGE_API_KEY', help='Alpha Vantage API key')
137
+ @click.option('--verbose', '-v', is_flag=True, help='Enable verbose logging')
138
+ @click.pass_context
139
+ def cli(ctx, api_key, verbose):
140
+ """Alpha Vantage CLI - direct access to all Alpha Vantage API tools."""
141
+ ctx.ensure_object(dict)
142
+ ctx.obj['api_key'] = api_key
143
+ ctx.obj['verbose'] = verbose
144
+
145
+
146
+ if __name__ == "__main__":
147
+ cli()