rftools-io 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 (35) hide show
  1. rftools_io-0.1.0/LICENSE +21 -0
  2. rftools_io-0.1.0/PKG-INFO +232 -0
  3. rftools_io-0.1.0/README.md +195 -0
  4. rftools_io-0.1.0/pyproject.toml +58 -0
  5. rftools_io-0.1.0/rftools/__init__.py +68 -0
  6. rftools_io-0.1.0/rftools/_catalog.py +3968 -0
  7. rftools_io-0.1.0/rftools/_cli.py +168 -0
  8. rftools_io-0.1.0/rftools/calculators/__init__.py +2 -0
  9. rftools_io-0.1.0/rftools/calculators/antenna.py +236 -0
  10. rftools_io-0.1.0/rftools/calculators/audio.py +487 -0
  11. rftools_io-0.1.0/rftools/calculators/emc.py +472 -0
  12. rftools_io-0.1.0/rftools/calculators/general.py +649 -0
  13. rftools_io-0.1.0/rftools/calculators/motor.py +546 -0
  14. rftools_io-0.1.0/rftools/calculators/pcb.py +417 -0
  15. rftools_io-0.1.0/rftools/calculators/power.py +632 -0
  16. rftools_io-0.1.0/rftools/calculators/protocol.py +333 -0
  17. rftools_io-0.1.0/rftools/calculators/rf.py +800 -0
  18. rftools_io-0.1.0/rftools/calculators/sensor.py +505 -0
  19. rftools_io-0.1.0/rftools/calculators/signal.py +391 -0
  20. rftools_io-0.1.0/rftools/calculators/thermal.py +204 -0
  21. rftools_io-0.1.0/rftools/calculators/unit_conversion.py +409 -0
  22. rftools_io-0.1.0/rftools/client.py +389 -0
  23. rftools_io-0.1.0/rftools/exceptions.py +38 -0
  24. rftools_io-0.1.0/rftools/types.py +69 -0
  25. rftools_io-0.1.0/rftools_io.egg-info/PKG-INFO +232 -0
  26. rftools_io-0.1.0/rftools_io.egg-info/SOURCES.txt +33 -0
  27. rftools_io-0.1.0/rftools_io.egg-info/dependency_links.txt +1 -0
  28. rftools_io-0.1.0/rftools_io.egg-info/entry_points.txt +2 -0
  29. rftools_io-0.1.0/rftools_io.egg-info/requires.txt +12 -0
  30. rftools_io-0.1.0/rftools_io.egg-info/top_level.txt +1 -0
  31. rftools_io-0.1.0/setup.cfg +4 -0
  32. rftools_io-0.1.0/tests/test_cli.py +69 -0
  33. rftools_io-0.1.0/tests/test_client.py +136 -0
  34. rftools_io-0.1.0/tests/test_stubs.py +53 -0
  35. rftools_io-0.1.0/tests/test_types.py +41 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 rftools.io
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.
@@ -0,0 +1,232 @@
1
+ Metadata-Version: 2.4
2
+ Name: rftools-io
3
+ Version: 0.1.0
4
+ Summary: Python client for rftools.io — 203 RF & electronics calculators
5
+ Author-email: "rftools.io" <hello@rftools.io>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://rftools.io
8
+ Project-URL: Documentation, https://rftools.io/docs/python
9
+ Project-URL: Repository, https://github.com/rftools/rftools-py
10
+ Project-URL: Bug Tracker, https://github.com/rftools/rftools-py/issues
11
+ Keywords: rf,electronics,calculator,antenna,pcb,signal
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Intended Audience :: Science/Research
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Topic :: Scientific/Engineering
21
+ Classifier: Topic :: Software Development :: Libraries
22
+ Requires-Python: >=3.9
23
+ Description-Content-Type: text/markdown
24
+ License-File: LICENSE
25
+ Requires-Dist: httpx>=0.27
26
+ Requires-Dist: pydantic>=2.0
27
+ Requires-Dist: click>=8.1
28
+ Provides-Extra: dev
29
+ Requires-Dist: pytest>=8.0; extra == "dev"
30
+ Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
31
+ Requires-Dist: respx>=0.21; extra == "dev"
32
+ Requires-Dist: ruff>=0.4; extra == "dev"
33
+ Requires-Dist: build; extra == "dev"
34
+ Requires-Dist: twine; extra == "dev"
35
+ Requires-Dist: pytest-cov>=4.0; extra == "dev"
36
+ Dynamic: license-file
37
+
38
+ # rftools
39
+
40
+ [![PyPI](https://img.shields.io/pypi/v/rftools)](https://pypi.org/project/rftools/)
41
+ [![Python](https://img.shields.io/pypi/pyversions/rftools)](https://pypi.org/project/rftools/)
42
+
43
+ Python client for **rftools.io** — 203 RF & electronics calculators accessible from Python and the command line.
44
+
45
+ ## Installation
46
+
47
+ ```bash
48
+ pip install rftools-io
49
+ ```
50
+
51
+ ## Quick Start (free tier)
52
+
53
+ No API key needed. Free tier: 5 calls/day per IP.
54
+
55
+ ```python
56
+ import rftools
57
+
58
+ result = rftools.calculate("vswr-return-loss", {"vswr": 2.5})
59
+ print(result["returnLoss"]) # 9.54 dB
60
+ print(result.values) # {"returnLoss": 9.54, "reflectionCoeff": 0.333, ...}
61
+ ```
62
+
63
+ ## Authenticated Usage (API tier)
64
+
65
+ Get an API key at [rftools.io/pricing](https://rftools.io/pricing) ($19/mo, 10,000 calls/month).
66
+
67
+ ```python
68
+ import rftools
69
+
70
+ client = rftools.Client(api_key="rfc_live_xxx")
71
+ # or set environment variable: export RFTOOLS_API_KEY=rfc_live_xxx
72
+
73
+ result = client.calculate("free-space-path-loss", {"frequency": 2400, "distance": 100})
74
+ print(result["pathLoss"]) # dB
75
+ ```
76
+
77
+ ## Batch Calculations
78
+
79
+ Run up to 50 calculations in a single HTTP request (API tier only):
80
+
81
+ ```python
82
+ results = client.batch([
83
+ ("vswr-return-loss", {"vswr": 1.5}),
84
+ ("vswr-return-loss", {"vswr": 2.0}),
85
+ ("free-space-path-loss", {"frequency": 2400, "distance": 50}),
86
+ ])
87
+ for r in results:
88
+ if r.ok:
89
+ print(r.values)
90
+ else:
91
+ print(f"Error: {r.error}")
92
+ ```
93
+
94
+ ## Typed Category Stubs
95
+
96
+ IDE-friendly typed functions with parameter defaults matching the web UI:
97
+
98
+ ```python
99
+ from rftools.calculators import rf, pcb, antenna, power
100
+
101
+ # RF
102
+ result = rf.vswr_return_loss(vswr=2.5)
103
+ result = rf.free_space_path_loss(frequency=2400.0, distance=100.0)
104
+
105
+ # Antenna
106
+ result = antenna.dipole_antenna(frequency=433.0)
107
+ result = antenna.parabolic_dish_antenna(frequency=10000.0, diameter=0.6)
108
+
109
+ # PCB
110
+ result = pcb.trace_width_current(current=2.0, tempRise=10.0, thickness=1.0)
111
+
112
+ # Power
113
+ result = power.voltage_divider(vin=12.0, r1=10000.0, r2=10000.0)
114
+ ```
115
+
116
+ All 13 categories available: `rf`, `pcb`, `power`, `signal`, `antenna`, `general`, `motor`, `protocol`, `emc`, `thermal`, `sensor`, `unit_conversion`, `audio`.
117
+
118
+ ## CLI
119
+
120
+ ```bash
121
+ # Run a calculation
122
+ rftools calc vswr-return-loss --vswr 2.5
123
+
124
+ # With API key
125
+ RFTOOLS_API_KEY=rfc_xxx rftools calc free-space-path-loss --frequency 2400 --distance 100
126
+
127
+ # JSON output (pipe to jq)
128
+ rftools calc vswr-return-loss --vswr 2.5 --json | jq '.values.returnLoss'
129
+
130
+ # List all calculators
131
+ rftools list
132
+
133
+ # Filter by category
134
+ rftools list --category rf
135
+
136
+ # Show calculator inputs/outputs
137
+ rftools info free-space-path-loss
138
+
139
+ # Library version
140
+ rftools version
141
+ ```
142
+
143
+ ## Error Handling
144
+
145
+ ```python
146
+ from rftools.exceptions import AuthError, RateLimitError, ValidationError, NotFoundError, APIError
147
+
148
+ try:
149
+ result = client.calculate("vswr-return-loss", {"vswr": 2.5})
150
+ except RateLimitError as e:
151
+ print(f"Quota exceeded. Retry after: {e.retry_after}s")
152
+ except AuthError:
153
+ print("Invalid API key")
154
+ except NotFoundError:
155
+ print("Unknown calculator slug")
156
+ except ValidationError as e:
157
+ print(f"Bad inputs: {e.detail}")
158
+ ```
159
+
160
+ | Exception | When |
161
+ |---|---|
162
+ | `AuthError` | Invalid or missing API key |
163
+ | `RateLimitError` | Monthly quota exceeded |
164
+ | `ValidationError` | Bad inputs (HTTP 422) |
165
+ | `NotFoundError` | Unknown calculator slug |
166
+ | `APIError` | Unexpected HTTP error |
167
+
168
+ ## Async Support
169
+
170
+ ```python
171
+ import asyncio
172
+ import rftools
173
+
174
+ async def main():
175
+ async with rftools.AsyncClient(api_key="rfc_live_xxx") as client:
176
+ result = await client.calculate("vswr-return-loss", {"vswr": 2.5})
177
+ print(result["returnLoss"])
178
+
179
+ asyncio.run(main())
180
+ ```
181
+
182
+ Ideal for running many calculations concurrently in FastAPI or async scripts.
183
+
184
+ ## Browse the Catalog
185
+
186
+ ```python
187
+ # List all calculators
188
+ calcs = rftools.list_calculators()
189
+ print(f"{len(calcs)} calculators available")
190
+
191
+ # Filter by category
192
+ rf_calcs = rftools.list_calculators(category="rf")
193
+ for c in rf_calcs:
194
+ print(f"{c.slug}: {c.title}")
195
+
196
+ # Get a single calculator's metadata
197
+ info = rftools.get_calculator("vswr-return-loss")
198
+ print(info.inputs) # tuple of InputField
199
+ print(info.outputs) # tuple of OutputField
200
+ ```
201
+
202
+ ## All Calculator Categories
203
+
204
+ | Category | Count | Example |
205
+ |---|---|---|
206
+ | `rf` | 26 | `vswr-return-loss`, `free-space-path-loss`, `rf-link-budget` |
207
+ | `pcb` | 13 | `trace-width-current`, `via-calculator`, `microstrip-impedance` |
208
+ | `power` | 20 | `voltage-divider`, `led-resistor`, `battery-life` |
209
+ | `signal` | 13 | `filter-designer`, `op-amp-gain`, `pwm-duty-cycle` |
210
+ | `antenna` | 8 | `dipole-antenna`, `eirp-calculator`, `parabolic-dish-antenna` |
211
+ | `general` | 21 | `lc-resonance`, `ohms-law`, `rc-time-constant` |
212
+ | `motor` | 18 | `brushless-dc-motor`, `stepper-motor`, `servo-motor` |
213
+ | `protocol` | 11 | `uart-baud-rate`, `i2c-pullup`, `can-bus-bit-timing` |
214
+ | `emc` | 16 | `emi-filter-lc`, `shielding-effectiveness`, `ground-loop` |
215
+ | `thermal` | 6 | `thermal-resistance`, `heat-sink`, `junction-temperature` |
216
+ | `sensor` | 17 | `thermistor-ntc`, `strain-gauge`, `hall-effect` |
217
+ | `unit-conversion` | 17 | `dbm-watts`, `frequency-wavelength`, `temperature` |
218
+ | `audio` | 17 | `speaker-crossover`, `amplifier-gain`, `room-acoustics` |
219
+
220
+ ## Contributing
221
+
222
+ Regenerate stubs after calculator changes:
223
+
224
+ ```bash
225
+ python scripts/generate_stubs.py --frontend-dir /path/to/rfhub/frontend
226
+ ```
227
+
228
+ Then bump the version in `pyproject.toml` and publish a new release.
229
+
230
+ ## License
231
+
232
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,195 @@
1
+ # rftools
2
+
3
+ [![PyPI](https://img.shields.io/pypi/v/rftools)](https://pypi.org/project/rftools/)
4
+ [![Python](https://img.shields.io/pypi/pyversions/rftools)](https://pypi.org/project/rftools/)
5
+
6
+ Python client for **rftools.io** — 203 RF & electronics calculators accessible from Python and the command line.
7
+
8
+ ## Installation
9
+
10
+ ```bash
11
+ pip install rftools-io
12
+ ```
13
+
14
+ ## Quick Start (free tier)
15
+
16
+ No API key needed. Free tier: 5 calls/day per IP.
17
+
18
+ ```python
19
+ import rftools
20
+
21
+ result = rftools.calculate("vswr-return-loss", {"vswr": 2.5})
22
+ print(result["returnLoss"]) # 9.54 dB
23
+ print(result.values) # {"returnLoss": 9.54, "reflectionCoeff": 0.333, ...}
24
+ ```
25
+
26
+ ## Authenticated Usage (API tier)
27
+
28
+ Get an API key at [rftools.io/pricing](https://rftools.io/pricing) ($19/mo, 10,000 calls/month).
29
+
30
+ ```python
31
+ import rftools
32
+
33
+ client = rftools.Client(api_key="rfc_live_xxx")
34
+ # or set environment variable: export RFTOOLS_API_KEY=rfc_live_xxx
35
+
36
+ result = client.calculate("free-space-path-loss", {"frequency": 2400, "distance": 100})
37
+ print(result["pathLoss"]) # dB
38
+ ```
39
+
40
+ ## Batch Calculations
41
+
42
+ Run up to 50 calculations in a single HTTP request (API tier only):
43
+
44
+ ```python
45
+ results = client.batch([
46
+ ("vswr-return-loss", {"vswr": 1.5}),
47
+ ("vswr-return-loss", {"vswr": 2.0}),
48
+ ("free-space-path-loss", {"frequency": 2400, "distance": 50}),
49
+ ])
50
+ for r in results:
51
+ if r.ok:
52
+ print(r.values)
53
+ else:
54
+ print(f"Error: {r.error}")
55
+ ```
56
+
57
+ ## Typed Category Stubs
58
+
59
+ IDE-friendly typed functions with parameter defaults matching the web UI:
60
+
61
+ ```python
62
+ from rftools.calculators import rf, pcb, antenna, power
63
+
64
+ # RF
65
+ result = rf.vswr_return_loss(vswr=2.5)
66
+ result = rf.free_space_path_loss(frequency=2400.0, distance=100.0)
67
+
68
+ # Antenna
69
+ result = antenna.dipole_antenna(frequency=433.0)
70
+ result = antenna.parabolic_dish_antenna(frequency=10000.0, diameter=0.6)
71
+
72
+ # PCB
73
+ result = pcb.trace_width_current(current=2.0, tempRise=10.0, thickness=1.0)
74
+
75
+ # Power
76
+ result = power.voltage_divider(vin=12.0, r1=10000.0, r2=10000.0)
77
+ ```
78
+
79
+ All 13 categories available: `rf`, `pcb`, `power`, `signal`, `antenna`, `general`, `motor`, `protocol`, `emc`, `thermal`, `sensor`, `unit_conversion`, `audio`.
80
+
81
+ ## CLI
82
+
83
+ ```bash
84
+ # Run a calculation
85
+ rftools calc vswr-return-loss --vswr 2.5
86
+
87
+ # With API key
88
+ RFTOOLS_API_KEY=rfc_xxx rftools calc free-space-path-loss --frequency 2400 --distance 100
89
+
90
+ # JSON output (pipe to jq)
91
+ rftools calc vswr-return-loss --vswr 2.5 --json | jq '.values.returnLoss'
92
+
93
+ # List all calculators
94
+ rftools list
95
+
96
+ # Filter by category
97
+ rftools list --category rf
98
+
99
+ # Show calculator inputs/outputs
100
+ rftools info free-space-path-loss
101
+
102
+ # Library version
103
+ rftools version
104
+ ```
105
+
106
+ ## Error Handling
107
+
108
+ ```python
109
+ from rftools.exceptions import AuthError, RateLimitError, ValidationError, NotFoundError, APIError
110
+
111
+ try:
112
+ result = client.calculate("vswr-return-loss", {"vswr": 2.5})
113
+ except RateLimitError as e:
114
+ print(f"Quota exceeded. Retry after: {e.retry_after}s")
115
+ except AuthError:
116
+ print("Invalid API key")
117
+ except NotFoundError:
118
+ print("Unknown calculator slug")
119
+ except ValidationError as e:
120
+ print(f"Bad inputs: {e.detail}")
121
+ ```
122
+
123
+ | Exception | When |
124
+ |---|---|
125
+ | `AuthError` | Invalid or missing API key |
126
+ | `RateLimitError` | Monthly quota exceeded |
127
+ | `ValidationError` | Bad inputs (HTTP 422) |
128
+ | `NotFoundError` | Unknown calculator slug |
129
+ | `APIError` | Unexpected HTTP error |
130
+
131
+ ## Async Support
132
+
133
+ ```python
134
+ import asyncio
135
+ import rftools
136
+
137
+ async def main():
138
+ async with rftools.AsyncClient(api_key="rfc_live_xxx") as client:
139
+ result = await client.calculate("vswr-return-loss", {"vswr": 2.5})
140
+ print(result["returnLoss"])
141
+
142
+ asyncio.run(main())
143
+ ```
144
+
145
+ Ideal for running many calculations concurrently in FastAPI or async scripts.
146
+
147
+ ## Browse the Catalog
148
+
149
+ ```python
150
+ # List all calculators
151
+ calcs = rftools.list_calculators()
152
+ print(f"{len(calcs)} calculators available")
153
+
154
+ # Filter by category
155
+ rf_calcs = rftools.list_calculators(category="rf")
156
+ for c in rf_calcs:
157
+ print(f"{c.slug}: {c.title}")
158
+
159
+ # Get a single calculator's metadata
160
+ info = rftools.get_calculator("vswr-return-loss")
161
+ print(info.inputs) # tuple of InputField
162
+ print(info.outputs) # tuple of OutputField
163
+ ```
164
+
165
+ ## All Calculator Categories
166
+
167
+ | Category | Count | Example |
168
+ |---|---|---|
169
+ | `rf` | 26 | `vswr-return-loss`, `free-space-path-loss`, `rf-link-budget` |
170
+ | `pcb` | 13 | `trace-width-current`, `via-calculator`, `microstrip-impedance` |
171
+ | `power` | 20 | `voltage-divider`, `led-resistor`, `battery-life` |
172
+ | `signal` | 13 | `filter-designer`, `op-amp-gain`, `pwm-duty-cycle` |
173
+ | `antenna` | 8 | `dipole-antenna`, `eirp-calculator`, `parabolic-dish-antenna` |
174
+ | `general` | 21 | `lc-resonance`, `ohms-law`, `rc-time-constant` |
175
+ | `motor` | 18 | `brushless-dc-motor`, `stepper-motor`, `servo-motor` |
176
+ | `protocol` | 11 | `uart-baud-rate`, `i2c-pullup`, `can-bus-bit-timing` |
177
+ | `emc` | 16 | `emi-filter-lc`, `shielding-effectiveness`, `ground-loop` |
178
+ | `thermal` | 6 | `thermal-resistance`, `heat-sink`, `junction-temperature` |
179
+ | `sensor` | 17 | `thermistor-ntc`, `strain-gauge`, `hall-effect` |
180
+ | `unit-conversion` | 17 | `dbm-watts`, `frequency-wavelength`, `temperature` |
181
+ | `audio` | 17 | `speaker-crossover`, `amplifier-gain`, `room-acoustics` |
182
+
183
+ ## Contributing
184
+
185
+ Regenerate stubs after calculator changes:
186
+
187
+ ```bash
188
+ python scripts/generate_stubs.py --frontend-dir /path/to/rfhub/frontend
189
+ ```
190
+
191
+ Then bump the version in `pyproject.toml` and publish a new release.
192
+
193
+ ## License
194
+
195
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,58 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "rftools-io"
7
+ version = "0.1.0"
8
+ description = "Python client for rftools.io — 203 RF & electronics calculators"
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ license-files = ["LICENSE"]
12
+ authors = [{ name = "rftools.io", email = "hello@rftools.io" }]
13
+ keywords = ["rf", "electronics", "calculator", "antenna", "pcb", "signal"]
14
+ classifiers = [
15
+ "Development Status :: 3 - Alpha",
16
+ "Intended Audience :: Developers",
17
+ "Intended Audience :: Science/Research",
18
+ "Programming Language :: Python :: 3",
19
+ "Programming Language :: Python :: 3.9",
20
+ "Programming Language :: Python :: 3.10",
21
+ "Programming Language :: Python :: 3.11",
22
+ "Programming Language :: Python :: 3.12",
23
+ "Topic :: Scientific/Engineering",
24
+ "Topic :: Software Development :: Libraries",
25
+ ]
26
+ requires-python = ">=3.9"
27
+ dependencies = [
28
+ "httpx>=0.27",
29
+ "pydantic>=2.0",
30
+ "click>=8.1",
31
+ ]
32
+
33
+ [project.optional-dependencies]
34
+ dev = [
35
+ "pytest>=8.0",
36
+ "pytest-asyncio>=0.23",
37
+ "respx>=0.21",
38
+ "ruff>=0.4",
39
+ "build",
40
+ "twine",
41
+ "pytest-cov>=4.0",
42
+ ]
43
+
44
+ [project.scripts]
45
+ rftools = "rftools._cli:cli"
46
+
47
+ [project.urls]
48
+ Homepage = "https://rftools.io"
49
+ Documentation = "https://rftools.io/docs/python"
50
+ Repository = "https://github.com/rftools/rftools-py"
51
+ "Bug Tracker" = "https://github.com/rftools/rftools-py/issues"
52
+
53
+ [tool.setuptools.packages.find]
54
+ where = ["."]
55
+ include = ["rftools*"]
56
+
57
+ [tool.pytest.ini_options]
58
+ asyncio_mode = "auto"
@@ -0,0 +1,68 @@
1
+ # rftools/__init__.py
2
+ """
3
+ rftools — Python client for rftools.io (203 RF & electronics calculators).
4
+
5
+ Quick start (free tier, 5 calls/day):
6
+ import rftools
7
+ result = rftools.calculate("vswr-return-loss", {"vswr": 2.5})
8
+ print(result["returnLoss"]) # 9.54
9
+
10
+ Authenticated (API tier, 10,000 calls/month):
11
+ client = rftools.Client(api_key="rfc_live_xxx")
12
+ result = client.calculate("free-space-path-loss", {"frequency": 2400, "distance": 100})
13
+ """
14
+ import os
15
+
16
+ __version__ = "0.1.0"
17
+ __all__ = [
18
+ "Client",
19
+ "AsyncClient",
20
+ "calculate",
21
+ "list_calculators",
22
+ "get_calculator",
23
+ "CalculatorResult",
24
+ "CalculatorInfo",
25
+ "InputField",
26
+ "OutputField",
27
+ "RFToolsError",
28
+ "AuthError",
29
+ "RateLimitError",
30
+ "ValidationError",
31
+ "NotFoundError",
32
+ "APIError",
33
+ ]
34
+
35
+ from rftools.client import Client, AsyncClient
36
+ from rftools.types import CalculatorResult, CalculatorInfo, InputField, OutputField
37
+ from rftools.exceptions import (
38
+ RFToolsError, AuthError, RateLimitError, ValidationError, NotFoundError, APIError,
39
+ )
40
+
41
+ _default_client: Client | None = None
42
+
43
+
44
+ def _get_default_client() -> Client:
45
+ global _default_client
46
+ env_key = os.environ.get("RFTOOLS_API_KEY")
47
+ if _default_client is None or (env_key and _default_client._api_key != env_key):
48
+ _default_client = Client(api_key=env_key)
49
+ return _default_client
50
+
51
+
52
+ def calculate(slug: str, inputs: dict) -> CalculatorResult:
53
+ """
54
+ Run a calculator using the free tier (no API key required).
55
+
56
+ 5 calls/day per IP. For higher limits, use ``rftools.Client(api_key=...)``.
57
+ """
58
+ return _get_default_client().calculate(slug, inputs)
59
+
60
+
61
+ def list_calculators(category: str | None = None) -> list[CalculatorInfo]:
62
+ """Return metadata for all 203 calculators, optionally filtered by category."""
63
+ return _get_default_client().list_calculators(category=category)
64
+
65
+
66
+ def get_calculator(slug: str) -> CalculatorInfo:
67
+ """Return metadata for a single calculator by slug."""
68
+ return _get_default_client().get_calculator(slug)