luminus-py 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.
@@ -0,0 +1,196 @@
1
+ Metadata-Version: 2.4
2
+ Name: luminus-py
3
+ Version: 0.2.1
4
+ Summary: Notebook-friendly Python client for luminus-mcp
5
+ Author: Keith So
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/kitfunso/luminus
8
+ Project-URL: Repository, https://github.com/kitfunso/luminus
9
+ Project-URL: Issues, https://github.com/kitfunso/luminus/issues
10
+ Project-URL: Changelog, https://github.com/kitfunso/luminus/blob/master/CHANGELOG.md
11
+ Keywords: mcp,jupyter,notebook,energy,electricity,gis
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Intended Audience :: Financial and Insurance Industry
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Topic :: Scientific/Engineering
21
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
22
+ Requires-Python: >=3.10
23
+ Description-Content-Type: text/markdown
24
+ Provides-Extra: notebook
25
+ Requires-Dist: pandas>=2.0; extra == "notebook"
26
+ Provides-Extra: gis
27
+ Requires-Dist: geopandas>=0.14; extra == "gis"
28
+ Provides-Extra: all
29
+ Requires-Dist: pandas>=2.0; extra == "all"
30
+ Requires-Dist: geopandas>=0.14; extra == "all"
31
+
32
+ # luminus-py
33
+
34
+ A notebook-friendly Python client for `luminus-mcp`.
35
+
36
+ This package starts the existing Node MCP server under the hood, calls tools over stdio, and returns Python-native result objects with optional pandas helpers.
37
+
38
+ Any MCP tool exposed by `luminus-mcp` is callable directly as a Python method, so the SDK does not need a hand-written wrapper for every tool.
39
+
40
+ The SDK also includes geospatial helpers for notebook workflows: `to_geojson()` for lightweight mapping and `to_geodataframe()` for GeoPandas users.
41
+
42
+ Roadmap: see [`../docs/python-sdk-roadmap.md`](../docs/python-sdk-roadmap.md).
43
+
44
+ ## Install
45
+
46
+ ```bash
47
+ pip install luminus-py[notebook]
48
+ ```
49
+
50
+ For GIS notebook work:
51
+
52
+ ```bash
53
+ pip install luminus-py[all]
54
+ ```
55
+
56
+ You also need `luminus-mcp` itself available on your machine, because the Python SDK starts the existing Node MCP server under the hood.
57
+
58
+ ```bash
59
+ npm install -g luminus-mcp@0.2.0
60
+ ```
61
+
62
+ ## API keys
63
+
64
+ Keyed tools use the same auth model as the Node server. Resolution order is:
65
+ 1. environment variables like `ENTSOE_API_KEY`
66
+ 2. `~/.luminus/keys.json`
67
+
68
+ Example `~/.luminus/keys.json`:
69
+
70
+ ```json
71
+ {
72
+ "ENTSOE_API_KEY": "...",
73
+ "GIE_API_KEY": "...",
74
+ "FINGRID_API_KEY": "..."
75
+ }
76
+ ```
77
+
78
+ Per-notebook overrides are also supported:
79
+
80
+ ```python
81
+ lum = Luminus(profile="trader", env={"ENTSOE_API_KEY": "..."})
82
+ ```
83
+
84
+ ## Quick start
85
+
86
+ ```python
87
+ from luminus import Luminus
88
+
89
+ with Luminus(profile="trader") as lum:
90
+ prices = lum.get_day_ahead_prices(zone="DE")
91
+ df = prices.to_pandas()
92
+
93
+ # Any MCP tool can be called directly
94
+ flows = lum.get_cross_border_flows(from_zone="DE", to_zone="NL")
95
+ site = lum.compare_sites(sites=[
96
+ {"name": "A", "lat": 52.1, "lon": 0.1},
97
+ {"name": "B", "lat": 52.2, "lon": 0.2},
98
+ ], country="GB")
99
+
100
+ # GIS-friendly exports
101
+ geojson = site.to_geojson(data_key="rankings")
102
+
103
+ # Batch several calls into one DataFrame
104
+ multi_zone = lum.call_many_to_pandas(
105
+ "get_day_ahead_prices",
106
+ [{"zone": "DE"}, {"zone": "FR"}, {"zone": "NL"}],
107
+ parallel=True,
108
+ )
109
+
110
+ # One-shot export helpers
111
+ prices_df = lum.call_tool_to_pandas("get_day_ahead_prices", {"zone": "DE"})
112
+ rankings_geojson = lum.call_tool_to_geojson("compare_sites", {
113
+ "country": "GB",
114
+ "sites": [
115
+ {"label": "A", "lat": 52.1, "lon": 0.1},
116
+ {"label": "B", "lat": 52.2, "lon": 0.2},
117
+ ],
118
+ }, data_key="rankings")
119
+ ```
120
+
121
+ ## Notebook demos
122
+
123
+ Polished notebook demos live in [`examples/`](examples/):
124
+
125
+ - [Trader workflow](examples/trader_workflow.ipynb)
126
+ - [GIS siting workflow](examples/gis_siting_workflow.ipynb)
127
+ - [BESS shortlist workflow](examples/bess_shortlist_workflow.ipynb)
128
+
129
+ ## Notebook-first helpers
130
+
131
+ The Python SDK now ships a few opinionated helpers for high-usage analyst flows:
132
+
133
+ - `lum.get_outages_frame(...)`
134
+ - `lum.get_cross_border_flows_many([...])`
135
+ - `lum.get_grid_proximity_substations(...)`
136
+ - `lum.get_grid_proximity_lines(...)`
137
+ - `lum.get_grid_proximity_snapshot(...)`
138
+ - `lum.get_grid_connection_queue_projects(...)`
139
+ - `lum.get_grid_connection_queue_sites(...)`
140
+ - `lum.get_grid_connection_queue_snapshot(...)`
141
+ - `lum.estimate_site_revenue_frame(...)`
142
+ - `lum.estimate_site_revenue_estimate(...)`
143
+
144
+ Example:
145
+
146
+ ```python
147
+ from luminus import GridProximitySnapshot, Luminus, SiteRevenueEstimate
148
+
149
+ with Luminus(profile="gis") as lum:
150
+ outages = lum.get_outages_frame(zone="DE", type="generation")
151
+ flows = lum.get_cross_border_flows_many([("DE", "NL"), ("FR", "DE")])
152
+ substations = lum.get_grid_proximity_substations(lat=52.0, lon=0.1)
153
+ queue = lum.get_grid_connection_queue_projects(connection_site_query="Berkswell")
154
+ revenue = lum.estimate_site_revenue_frame(
155
+ lat=52.0,
156
+ lon=0.1,
157
+ zone="GB",
158
+ technology="bess",
159
+ capacity_mw=20,
160
+ )
161
+
162
+ proximity: GridProximitySnapshot = lum.get_grid_proximity_snapshot(lat=52.0, lon=0.1)
163
+ estimate: SiteRevenueEstimate = lum.estimate_site_revenue_estimate(
164
+ lat=52.0,
165
+ lon=0.1,
166
+ zone="GB",
167
+ technology="bess",
168
+ )
169
+ ```
170
+
171
+ ## Errors and typed models
172
+
173
+ - Startup failures now raise `LuminusStartupError`.
174
+ - Tool-side configuration failures raise `LuminusConfigurationError`.
175
+ - Tool-side upstream/data-source failures raise `LuminusUpstreamError`.
176
+ - Dynamic whole-surface access still works through `LuminusResult`, and common GIS/revenue flows also expose opt-in typed models.
177
+
178
+ ## Notes
179
+
180
+ - Use `lum.list_tools()` to see the live tool surface for the active profile.
181
+ - Use `lum.describe_tool("tool_name")` to inspect the MCP description/schema metadata.
182
+ - Use `lum.call_many()` / `lum.call_many_to_pandas()` for generic multi-zone or multi-site notebook pulls.
183
+ - Use `parallel=True` on batch helpers when you want the SDK to fan out across multiple MCP subprocesses.
184
+ - Use `lum.get_day_ahead_prices_many()` and `lum.get_generation_mix_many()` for common analyst workflows.
185
+ - Use `lum.compare_sites_rankings()` together with `lum.compare_sites_rankings_geojson()` and `lum.compare_sites_rankings_geodataframe()` for ranked siting output.
186
+ - Use the typed snapshots only when they help notebook readability; the raw dynamic MCP surface is still available.
187
+ - Notebook demos live in [`examples/`](examples/).
188
+ - Use `to_geojson()` for lightweight mapping and `to_geodataframe()` when GeoPandas is installed.
189
+
190
+ - Requires `luminus-mcp` to be available on `PATH`, unless you pass an explicit command.
191
+ - By default the client starts `luminus-mcp --profile <profile>`.
192
+ - For local repo development you can point it at the built server directly:
193
+
194
+ ```python
195
+ lum = Luminus(command=["node", r"C:\Users\skf_s\luminus\dist\index.js"], profile="gis")
196
+ ```
@@ -0,0 +1,165 @@
1
+ # luminus-py
2
+
3
+ A notebook-friendly Python client for `luminus-mcp`.
4
+
5
+ This package starts the existing Node MCP server under the hood, calls tools over stdio, and returns Python-native result objects with optional pandas helpers.
6
+
7
+ Any MCP tool exposed by `luminus-mcp` is callable directly as a Python method, so the SDK does not need a hand-written wrapper for every tool.
8
+
9
+ The SDK also includes geospatial helpers for notebook workflows: `to_geojson()` for lightweight mapping and `to_geodataframe()` for GeoPandas users.
10
+
11
+ Roadmap: see [`../docs/python-sdk-roadmap.md`](../docs/python-sdk-roadmap.md).
12
+
13
+ ## Install
14
+
15
+ ```bash
16
+ pip install luminus-py[notebook]
17
+ ```
18
+
19
+ For GIS notebook work:
20
+
21
+ ```bash
22
+ pip install luminus-py[all]
23
+ ```
24
+
25
+ You also need `luminus-mcp` itself available on your machine, because the Python SDK starts the existing Node MCP server under the hood.
26
+
27
+ ```bash
28
+ npm install -g luminus-mcp@0.2.0
29
+ ```
30
+
31
+ ## API keys
32
+
33
+ Keyed tools use the same auth model as the Node server. Resolution order is:
34
+ 1. environment variables like `ENTSOE_API_KEY`
35
+ 2. `~/.luminus/keys.json`
36
+
37
+ Example `~/.luminus/keys.json`:
38
+
39
+ ```json
40
+ {
41
+ "ENTSOE_API_KEY": "...",
42
+ "GIE_API_KEY": "...",
43
+ "FINGRID_API_KEY": "..."
44
+ }
45
+ ```
46
+
47
+ Per-notebook overrides are also supported:
48
+
49
+ ```python
50
+ lum = Luminus(profile="trader", env={"ENTSOE_API_KEY": "..."})
51
+ ```
52
+
53
+ ## Quick start
54
+
55
+ ```python
56
+ from luminus import Luminus
57
+
58
+ with Luminus(profile="trader") as lum:
59
+ prices = lum.get_day_ahead_prices(zone="DE")
60
+ df = prices.to_pandas()
61
+
62
+ # Any MCP tool can be called directly
63
+ flows = lum.get_cross_border_flows(from_zone="DE", to_zone="NL")
64
+ site = lum.compare_sites(sites=[
65
+ {"name": "A", "lat": 52.1, "lon": 0.1},
66
+ {"name": "B", "lat": 52.2, "lon": 0.2},
67
+ ], country="GB")
68
+
69
+ # GIS-friendly exports
70
+ geojson = site.to_geojson(data_key="rankings")
71
+
72
+ # Batch several calls into one DataFrame
73
+ multi_zone = lum.call_many_to_pandas(
74
+ "get_day_ahead_prices",
75
+ [{"zone": "DE"}, {"zone": "FR"}, {"zone": "NL"}],
76
+ parallel=True,
77
+ )
78
+
79
+ # One-shot export helpers
80
+ prices_df = lum.call_tool_to_pandas("get_day_ahead_prices", {"zone": "DE"})
81
+ rankings_geojson = lum.call_tool_to_geojson("compare_sites", {
82
+ "country": "GB",
83
+ "sites": [
84
+ {"label": "A", "lat": 52.1, "lon": 0.1},
85
+ {"label": "B", "lat": 52.2, "lon": 0.2},
86
+ ],
87
+ }, data_key="rankings")
88
+ ```
89
+
90
+ ## Notebook demos
91
+
92
+ Polished notebook demos live in [`examples/`](examples/):
93
+
94
+ - [Trader workflow](examples/trader_workflow.ipynb)
95
+ - [GIS siting workflow](examples/gis_siting_workflow.ipynb)
96
+ - [BESS shortlist workflow](examples/bess_shortlist_workflow.ipynb)
97
+
98
+ ## Notebook-first helpers
99
+
100
+ The Python SDK now ships a few opinionated helpers for high-usage analyst flows:
101
+
102
+ - `lum.get_outages_frame(...)`
103
+ - `lum.get_cross_border_flows_many([...])`
104
+ - `lum.get_grid_proximity_substations(...)`
105
+ - `lum.get_grid_proximity_lines(...)`
106
+ - `lum.get_grid_proximity_snapshot(...)`
107
+ - `lum.get_grid_connection_queue_projects(...)`
108
+ - `lum.get_grid_connection_queue_sites(...)`
109
+ - `lum.get_grid_connection_queue_snapshot(...)`
110
+ - `lum.estimate_site_revenue_frame(...)`
111
+ - `lum.estimate_site_revenue_estimate(...)`
112
+
113
+ Example:
114
+
115
+ ```python
116
+ from luminus import GridProximitySnapshot, Luminus, SiteRevenueEstimate
117
+
118
+ with Luminus(profile="gis") as lum:
119
+ outages = lum.get_outages_frame(zone="DE", type="generation")
120
+ flows = lum.get_cross_border_flows_many([("DE", "NL"), ("FR", "DE")])
121
+ substations = lum.get_grid_proximity_substations(lat=52.0, lon=0.1)
122
+ queue = lum.get_grid_connection_queue_projects(connection_site_query="Berkswell")
123
+ revenue = lum.estimate_site_revenue_frame(
124
+ lat=52.0,
125
+ lon=0.1,
126
+ zone="GB",
127
+ technology="bess",
128
+ capacity_mw=20,
129
+ )
130
+
131
+ proximity: GridProximitySnapshot = lum.get_grid_proximity_snapshot(lat=52.0, lon=0.1)
132
+ estimate: SiteRevenueEstimate = lum.estimate_site_revenue_estimate(
133
+ lat=52.0,
134
+ lon=0.1,
135
+ zone="GB",
136
+ technology="bess",
137
+ )
138
+ ```
139
+
140
+ ## Errors and typed models
141
+
142
+ - Startup failures now raise `LuminusStartupError`.
143
+ - Tool-side configuration failures raise `LuminusConfigurationError`.
144
+ - Tool-side upstream/data-source failures raise `LuminusUpstreamError`.
145
+ - Dynamic whole-surface access still works through `LuminusResult`, and common GIS/revenue flows also expose opt-in typed models.
146
+
147
+ ## Notes
148
+
149
+ - Use `lum.list_tools()` to see the live tool surface for the active profile.
150
+ - Use `lum.describe_tool("tool_name")` to inspect the MCP description/schema metadata.
151
+ - Use `lum.call_many()` / `lum.call_many_to_pandas()` for generic multi-zone or multi-site notebook pulls.
152
+ - Use `parallel=True` on batch helpers when you want the SDK to fan out across multiple MCP subprocesses.
153
+ - Use `lum.get_day_ahead_prices_many()` and `lum.get_generation_mix_many()` for common analyst workflows.
154
+ - Use `lum.compare_sites_rankings()` together with `lum.compare_sites_rankings_geojson()` and `lum.compare_sites_rankings_geodataframe()` for ranked siting output.
155
+ - Use the typed snapshots only when they help notebook readability; the raw dynamic MCP surface is still available.
156
+ - Notebook demos live in [`examples/`](examples/).
157
+ - Use `to_geojson()` for lightweight mapping and `to_geodataframe()` when GeoPandas is installed.
158
+
159
+ - Requires `luminus-mcp` to be available on `PATH`, unless you pass an explicit command.
160
+ - By default the client starts `luminus-mcp --profile <profile>`.
161
+ - For local repo development you can point it at the built server directly:
162
+
163
+ ```python
164
+ lum = Luminus(command=["node", r"C:\Users\skf_s\luminus\dist\index.js"], profile="gis")
165
+ ```
@@ -0,0 +1,29 @@
1
+ from .client import Luminus
2
+ from .exceptions import (
3
+ LuminusConfigurationError,
4
+ LuminusError,
5
+ LuminusProtocolError,
6
+ LuminusStartupError,
7
+ LuminusToolError,
8
+ LuminusTransportError,
9
+ LuminusUpstreamError,
10
+ )
11
+ from .models import GridConnectionQueueSnapshot, GridProximitySnapshot, SiteRevenueEstimate
12
+ from .result import LuminusResult
13
+
14
+ __all__ = [
15
+ "Luminus",
16
+ "GridConnectionQueueSnapshot",
17
+ "GridProximitySnapshot",
18
+ "LuminusError",
19
+ "LuminusConfigurationError",
20
+ "LuminusProtocolError",
21
+ "LuminusStartupError",
22
+ "LuminusToolError",
23
+ "LuminusTransportError",
24
+ "LuminusUpstreamError",
25
+ "LuminusResult",
26
+ "SiteRevenueEstimate",
27
+ ]
28
+
29
+ __version__ = "0.2.1"