helius-python 0.0.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,4 @@
1
+ [*.py]
2
+ indent_style = space
3
+ indent_size = 4
4
+ python_indent_open_paren = 4
@@ -0,0 +1,70 @@
1
+ # This workflow will upload a Python Package to PyPI when a release is created
2
+ # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries
3
+
4
+ # This workflow uses actions that are not certified by GitHub.
5
+ # They are provided by a third-party and are governed by
6
+ # separate terms of service, privacy policy, and support
7
+ # documentation.
8
+
9
+ name: Upload Python Package
10
+
11
+ on:
12
+ release:
13
+ types: [published]
14
+
15
+ permissions:
16
+ contents: read
17
+
18
+ jobs:
19
+ release-build:
20
+ runs-on: ubuntu-latest
21
+
22
+ steps:
23
+ - uses: actions/checkout@v4
24
+
25
+ - uses: actions/setup-python@v5
26
+ with:
27
+ python-version: "3.x"
28
+
29
+ - name: Build release distributions
30
+ run: |
31
+ # NOTE: put your own distribution build steps here.
32
+ python -m pip install build
33
+ python -m build
34
+
35
+ - name: Upload distributions
36
+ uses: actions/upload-artifact@v4
37
+ with:
38
+ name: release-dists
39
+ path: dist/
40
+
41
+ pypi-publish:
42
+ runs-on: ubuntu-latest
43
+ needs:
44
+ - release-build
45
+ permissions:
46
+ # IMPORTANT: this permission is mandatory for trusted publishing
47
+ id-token: write
48
+
49
+ # Dedicated environments with protections for publishing are strongly recommended.
50
+ # For more information, see: https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment#deployment-protection-rules
51
+ environment:
52
+ name: pypi
53
+ # OPTIONAL: uncomment and update to include your PyPI project URL in the deployment status:
54
+ # url: https://pypi.org/p/YOURPROJECT
55
+ #
56
+ # ALTERNATIVE: if your GitHub Release name is the PyPI project version string
57
+ # ALTERNATIVE: exactly, uncomment the following line instead:
58
+ # url: https://pypi.org/project/YOURPROJECT/${{ github.event.release.name }}
59
+
60
+ steps:
61
+ - name: Retrieve release distributions
62
+ uses: actions/download-artifact@v4
63
+ with:
64
+ name: release-dists
65
+ path: dist/
66
+
67
+ - name: Publish release distributions to PyPI
68
+ uses: pypa/gh-action-pypi-publish@release/v1
69
+ with:
70
+ packages-dir: dist/
@@ -0,0 +1,220 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[codz]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ # Usually these files are written by a python script from a template
31
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py.cover
50
+ *.lcov
51
+ .hypothesis/
52
+ .pytest_cache/
53
+ cover/
54
+
55
+ # Translations
56
+ *.mo
57
+ *.pot
58
+
59
+ # Django stuff:
60
+ *.log
61
+ local_settings.py
62
+ db.sqlite3
63
+ db.sqlite3-journal
64
+
65
+ # Flask stuff:
66
+ instance/
67
+ .webassets-cache
68
+
69
+ # Scrapy stuff:
70
+ .scrapy
71
+
72
+ # Sphinx documentation
73
+ docs/_build/
74
+
75
+ # PyBuilder
76
+ .pybuilder/
77
+ target/
78
+
79
+ # Jupyter Notebook
80
+ .ipynb_checkpoints
81
+
82
+ # IPython
83
+ profile_default/
84
+ ipython_config.py
85
+
86
+ # pyenv
87
+ # For a library or package, you might want to ignore these files since the code is
88
+ # intended to run in multiple environments; otherwise, check them in:
89
+ # .python-version
90
+
91
+ # pipenv
92
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
93
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
94
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
95
+ # install all needed dependencies.
96
+ # Pipfile.lock
97
+
98
+ # UV
99
+ # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
100
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
101
+ # commonly ignored for libraries.
102
+ # uv.lock
103
+
104
+ # poetry
105
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
106
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
107
+ # commonly ignored for libraries.
108
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
109
+ # poetry.lock
110
+ # poetry.toml
111
+
112
+ # pdm
113
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
114
+ # pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
115
+ # https://pdm-project.org/en/latest/usage/project/#working-with-version-control
116
+ # pdm.lock
117
+ # pdm.toml
118
+ .pdm-python
119
+ .pdm-build/
120
+
121
+ # pixi
122
+ # Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
123
+ # pixi.lock
124
+ # Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
125
+ # in the .venv directory. It is recommended not to include this directory in version control.
126
+ .pixi/*
127
+ !.pixi/config.toml
128
+
129
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
130
+ __pypackages__/
131
+
132
+ # Celery stuff
133
+ celerybeat-schedule*
134
+ celerybeat.pid
135
+
136
+ # Redis
137
+ *.rdb
138
+ *.aof
139
+ *.pid
140
+
141
+ # RabbitMQ
142
+ mnesia/
143
+ rabbitmq/
144
+ rabbitmq-data/
145
+
146
+ # ActiveMQ
147
+ activemq-data/
148
+
149
+ # SageMath parsed files
150
+ *.sage.py
151
+
152
+ # Environments
153
+ .env
154
+ .envrc
155
+ .venv
156
+ env/
157
+ venv/
158
+ ENV/
159
+ env.bak/
160
+ venv.bak/
161
+
162
+ # Spyder project settings
163
+ .spyderproject
164
+ .spyproject
165
+
166
+ # Rope project settings
167
+ .ropeproject
168
+
169
+ # mkdocs documentation
170
+ /site
171
+
172
+ # mypy
173
+ .mypy_cache/
174
+ .dmypy.json
175
+ dmypy.json
176
+
177
+ # Pyre type checker
178
+ .pyre/
179
+
180
+ # pytype static type analyzer
181
+ .pytype/
182
+
183
+ # Cython debug symbols
184
+ cython_debug/
185
+
186
+ # PyCharm
187
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
188
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
189
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
190
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
191
+ # .idea/
192
+
193
+ # Abstra
194
+ # Abstra is an AI-powered process automation framework.
195
+ # Ignore directories containing user credentials, local state, and settings.
196
+ # Learn more at https://abstra.io/docs
197
+ .abstra/
198
+
199
+ # Visual Studio Code
200
+ # Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
201
+ # that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
202
+ # and can be added to the global gitignore or merged into this file. However, if you prefer,
203
+ # you could uncomment the following to ignore the entire vscode folder
204
+ # .vscode/
205
+ # Temporary file for partial code execution
206
+ tempCodeRunnerFile.py
207
+
208
+ # Ruff stuff:
209
+ .ruff_cache/
210
+
211
+ # PyPI configuration file
212
+ .pypirc
213
+
214
+ # Marimo
215
+ marimo/_static/
216
+ marimo/_lsp/
217
+ __marimo__/
218
+
219
+ # Streamlit
220
+ .streamlit/secrets.toml
@@ -0,0 +1,212 @@
1
+ When implementing a function for a RPC method in the HeliusClient class, read the docs for the specific RPC method. For example, for the get_supply function (getSupply RPC method) you should read https://www.helius.dev/docs/rpc/guides/getsupply and https://www.helius.dev/docs/api-reference/rpc/http/getsupply.
2
+
3
+ # API Reference
4
+
5
+ The API reference is generated from **Google-style docstrings** on every public symbol in `src/helius/`. Whenever you add or modify a public method, model, or class, you MUST write or update its docstring following the rules below. The README's "Supported methods" table is a quick index only — the docstring is the source of truth.
6
+
7
+ ## Where docstrings live
8
+
9
+ - **Client methods** (`HeliusClient.get_*`, `is_*`, `request_*`, etc.) — every public method gets a docstring. Private methods (`_send`, dunders) do not need one.
10
+ - **Models** (`src/helius/models.py`) — every public model class gets a docstring describing what it represents. Individual fields don't need per-field docstrings if their names and types are self-explanatory; only document fields where the meaning, units, or nullability isn't obvious from the type alone.
11
+ - **Builders / helpers** (`RpcRequest`) — class docstring describing purpose, plus one-line docstrings on each public method.
12
+
13
+ ## Client method docstring format
14
+
15
+ Use Google-style sections. Order matters; omit any section that doesn't apply.
16
+
17
+ ```python
18
+ def method_name(self, ...) -> ReturnType:
19
+ """One-line summary in the imperative mood, ending with a period.
20
+
21
+ Optional longer description: a paragraph or two on what the method does,
22
+ when to use it, and any non-obvious behavior. Keep this short — link to
23
+ the upstream Helius docs rather than restating them.
24
+
25
+ Args:
26
+ param_one: Description of the first parameter, including units
27
+ (lamports vs. SOL, slot vs. block height) when relevant. Mention
28
+ the upstream JSON field name only if it differs in a non-obvious
29
+ way from the snake_case Python name.
30
+ param_two: Description. Note constraints like "must be base-58
31
+ encoded" or "max 500_000 slots from `start_slot`".
32
+ commitment: Optional commitment level. Defaults to the node's default
33
+ when omitted.
34
+
35
+ Returns:
36
+ Describe the return shape. For tuples, describe each element in
37
+ order. For models, name the model and what it represents. For
38
+ primitives, name the unit (e.g. "Balance in lamports.").
39
+
40
+ Raises:
41
+ ValueError: When the arguments violate the documented constraints
42
+ (e.g. mutually exclusive params, mismatched pairs).
43
+
44
+ Note:
45
+ Only available on Devnet and Testnet, not Mainnet Beta.
46
+
47
+ See Also:
48
+ - Helius guide: https://www.helius.dev/docs/rpc/guides/<method>
49
+ - Helius API reference: https://www.helius.dev/docs/api-reference/rpc/http/<method>
50
+ """
51
+ ```
52
+
53
+ Rules:
54
+
55
+ - **Summary line** is one sentence, imperative mood, ≤ 88 chars, ends with a period. Example: `"Return the SOL balance of an account in lamports."`
56
+ - **`Args:`** documents every parameter, even `commitment` and `min_context_slot`. One entry per param. Don't re-state the type — basedpyright already shows it.
57
+ - **`Returns:`** is mandatory unless the method returns `None`.
58
+ - **`Raises:`** is required if the method calls `raise` directly. Don't document exceptions that bubble up from `httpx` — those are covered by the library-wide error-handling docs.
59
+ - **`Note:`** for network restrictions, version requirements, pagination limits, deprecation warnings, etc. One section per concern.
60
+ - **`See Also:`** ALWAYS includes the Helius guide and API reference URLs for the underlying RPC method. This is the contract for an RPC wrapper — the docstring tells you what we do, the upstream docs tell you what the network does.
61
+ - Keep prose tight. The docstring should be readable in `help(client.method)` without scrolling forever.
62
+
63
+ ## Model docstring format
64
+
65
+ ```python
66
+ class Supply(BaseModel):
67
+ """Total, circulating, and non-circulating SOL supply, in lamports.
68
+
69
+ Returned as the `value` field of `getSupply`. All amounts are in
70
+ lamports (1 SOL = 1_000_000_000 lamports).
71
+
72
+ See Also:
73
+ - Helius API reference: https://www.helius.dev/docs/api-reference/rpc/http/getsupply
74
+ """
75
+ ...
76
+ ```
77
+
78
+ Rules:
79
+
80
+ - One-line summary + optional paragraph + `See Also:` linking the upstream docs that define the shape.
81
+ - If a field has surprising semantics (e.g. `ui_amount` can be `None` when the mint has too many decimals, `non_circulating_accounts` is only populated when not excluded), document it inline with `Field(..., description="...")` or in the class docstring.
82
+
83
+ ## Conventions
84
+
85
+ - Use **double-quoted triple strings** (`"""..."""`).
86
+ - Wrap docstring lines at 88 columns.
87
+ - Refer to parameters in backticks: `` `commitment` ``, `` `min_context_slot` ``.
88
+ - Refer to other client methods with their snake_case name in backticks: `` `get_balance` ``.
89
+ - Do NOT include the upstream JSON-RPC method name in the summary — that's already in the See Also URLs.
90
+ - Do NOT copy-paste large chunks from the Helius docs. Summarize and link.
91
+ - Examples (`Example:` section) are encouraged for methods with non-trivial argument combinations (e.g. `get_block_production`, `get_token_accounts_by_owner`), optional for everything else.
92
+
93
+ ## Implementation conventions
94
+
95
+ - **If the RPC returns an `RpcResponse` wrapper (`{context, value}`), the Python method MUST return `(context, value)`** — never silently drop `context`. For methods whose `value` is itself a small composite, flatten the tuple (e.g. `get_latest_blockhash` returns `tuple[dict, str, int]`, not `tuple[dict, tuple[str, int]]`). Check the upstream Helius API reference page to see whether the response is wrapped.
96
+ - Type-annotate the return shape exactly. `tuple[dict, X]`, not bare `tuple`, and not the unwrapped `X`. Mismatches between annotation and runtime shape break the docstring contract.
97
+ - `value` can be `null` for some wrapped methods (e.g. `getAccountInfo` when the account doesn't exist, `getMultipleAccounts` entries for closed accounts). Reflect that in the return type with `| None` and handle it before calling `Model.model_validate(...)`.
98
+
99
+ ## Checklist for adding a new client method
100
+
101
+ 1. Read both Helius doc URLs for the RPC method (see the top of this file).
102
+ 2. Implement the method, following the **Implementation conventions** above — in particular, return `(context, value)` if the upstream response is wrapped.
103
+ 3. Add a docstring with `Args`, `Returns`, `Raises` (if any), `Note` (if any), and `See Also` with both Helius URLs.
104
+ 4. Add the method to the "Supported methods" table in `README.md`.
105
+ 5. Add tests per the Testing section.
106
+
107
+ # Testing
108
+
109
+ ## Stack
110
+
111
+ - `pytest` as the test runner.
112
+ - `respx` for mocking the `httpx` transport. Do NOT use `unittest.mock` to patch `httpx` — always mock at the HTTP layer with `respx`.
113
+ - No live network calls. Do NOT make real requests to `mainnet.helius-rpc.com`, `devnet.helius-rpc.com`, or any other Helius endpoint in tests. Devnet integration tests are explicitly out of scope for now.
114
+
115
+ Add `pytest` and `respx` to a `[project.optional-dependencies] dev` table in `pyproject.toml` if not already present.
116
+
117
+ ## Layout
118
+
119
+ ```
120
+ tests/
121
+ conftest.py # shared fixtures (client factory, sample responses)
122
+ fixtures/ # captured JSON-RPC response bodies, one file per shape
123
+ unit/
124
+ test_rpc_request.py # RpcRequest builder
125
+ test_models.py # pydantic model validation against fixtures
126
+ test_client.py # one test (or small group) per client method
127
+ ```
128
+
129
+ ## Three Layers
130
+
131
+ ### 1. `RpcRequest` builder — pure unit tests
132
+
133
+ `RpcRequest` is pure logic with no I/O. Cover:
134
+
135
+ - `add(value)` skips `None` unless `can_be_none=True`.
136
+ - `set(key, value)` skips `None` unless `can_be_none=True`.
137
+ - Positional params come before the config dict.
138
+ - The config dict is appended as the last element of `params` only when it's non-empty.
139
+ - `params` is omitted entirely from the payload when there are no positional or config values.
140
+ - `method`, `id`, and `jsonrpc` are passed through correctly.
141
+
142
+ These tests would have caught the current bug where `jsonrpc` is never added to the built payload. Fix bugs you find this way as separate commits, not as part of the test PR.
143
+
144
+ ### 2. Pydantic models — fixture-based unit tests
145
+
146
+ For each model in `src/helius/models.py`:
147
+
148
+ - Capture a real JSON-RPC `result` body once (manually, from the Helius docs' example responses or a one-off live call) and save it under `tests/fixtures/`.
149
+ - Write a test that loads the fixture and calls `Model.model_validate(...)`. Assert a couple of representative fields parsed correctly (especially camelCase → snake_case via the alias generator).
150
+
151
+ One fixture per model is enough. The goal is to catch schema mismatches (missing fields, wrong optionality, typos like `foudnation`), not to exhaustively assert every field.
152
+
153
+ **Fixture keys must come from the Helius docs, not from the model.** If you write the fixture by reading the Python field names and camelCasing them, the test only proves the model agrees with itself — typos like `loaderScheduleSlotOffset` (should be `leaderScheduleSlotOffset`) will pass. Always copy the JSON keys verbatim from the upstream Helius example response.
154
+
155
+ ### 3. Client methods — `respx`-mocked tests
156
+
157
+ For each method on `HeliusClient`, write at least one test that asserts **both** sides of the wire:
158
+
159
+ - **Outgoing request:** the JSON body sent to Helius matches the JSON-RPC payload you expect — correct `method`, correct positional `params`, correct config object with snake → camel mapping, and optional arguments omitted when `None`.
160
+ - **Return value:** the method correctly parses a canned response into the documented return shape (model, tuple, primitive, etc.).
161
+
162
+ Also assert that the `api-key` query parameter is present on the request URL.
163
+
164
+ **The mocked response body must mirror the real upstream shape.** Copy the `result` payload from the Helius docs' example response — do not invent a flatter shape by reading what the Python method indexes into. In particular, if the upstream method returns an `RpcResponse` wrapper (`{"context": {...}, "value": ...}`), the mock must include that wrapper, even if the client method only returns `value`. Otherwise a bug that reads `result["foo"]` instead of `result["value"]["foo"]` will pass the test and fail in production.
165
+
166
+ Skeleton:
167
+
168
+ ```python
169
+ import json
170
+ import httpx
171
+ import respx
172
+ from helius import HeliusClient
173
+
174
+ @respx.mock
175
+ def test_get_balance():
176
+ route = respx.post("https://mainnet.helius-rpc.com/").mock(
177
+ return_value=httpx.Response(
178
+ 200,
179
+ json={
180
+ "jsonrpc": "2.0",
181
+ "id": 1,
182
+ "result": {"context": {"slot": 1}, "value": 42},
183
+ },
184
+ )
185
+ )
186
+ with HeliusClient(api_key="test") as c:
187
+ assert c.get_balance("So11...112", commitment="finalized") == 42
188
+
189
+ sent = route.calls.last.request
190
+ assert sent.url.params["api-key"] == "test"
191
+ body = json.loads(sent.content)
192
+ assert body["method"] == "getBalance"
193
+ assert body["params"] == ["So11...112", {"commitment": "finalized"}]
194
+ ```
195
+
196
+ For methods with branching logic (e.g. `get_block_production`, `get_token_accounts_by_owner`'s `mint` vs `program_id` validation, `get_account_info`'s `data_slice` pairing), add tests for each branch — including the `ValueError`s on invalid input combinations.
197
+
198
+ ## Conventions
199
+
200
+ - Construct `HeliusClient` in tests with an explicit `api_key="test"` (or similar). Never rely on a real `.env` file.
201
+ - Use the context-manager form (`with HeliusClient(...) as c:`) in tests so the `httpx.Client` is closed cleanly.
202
+ - Group tests in `tests/unit/test_client.py` by method, but a single file is fine until it grows unwieldy.
203
+ - Test names should describe the behavior, not the implementation: `test_get_balance_includes_commitment_in_config`, not `test_get_balance_calls_set`.
204
+ - When adding a new client method, the PR must include: (a) a `respx` test asserting the request payload, and (b) a fixture-based model test if the method introduces or uses a model. This is enforced in `CONTRIBUTING.md`.
205
+
206
+ ## Running
207
+
208
+ ```bash
209
+ pytest
210
+ ```
211
+
212
+ All tests must pass and there must be no real network traffic. If a test fails because it tried to hit the network, that's a bug in the test — add the missing `@respx.mock` or `respx` route.
@@ -0,0 +1 @@
1
+ @AGENTS.md
@@ -0,0 +1,116 @@
1
+ # Contributing
2
+
3
+ Contributions to `helius-python` are very welcome! This project aims to be the
4
+ **complete, typed Python client for [Helius](https://helius.dev)** and there
5
+ is a lot of surface area still to cover. Every issue closed, RPC method added,
6
+ typo fixed, and example improved moves the library closer to that goal.
7
+
8
+ ## Project Goals
9
+
10
+ Before contributing, please read the [Goals section of the README](README.md#goals).
11
+ Every change should serve at least one of:
12
+
13
+ 1. **Completeness** — 1:1 coverage of the entire Helius API surface.
14
+ 2. **Type safety** — fully typed parameters and responses.
15
+ 3. **Pythonic ergonomics** — `snake_case` names, context managers, sensible
16
+ defaults.
17
+ 4. **Zero magic** — thin, predictable wrappers that map directly to the
18
+ documented Helius API.
19
+
20
+ If a change doesn't clearly support one of these goals, it probably isn't a
21
+ good fit. When in doubt, open an issue first to discuss it.
22
+
23
+ ## Ways to Contribute
24
+
25
+ There is no shortage of things to do. A few ideas, roughly ordered from
26
+ easiest to most involved:
27
+
28
+ - **Fix a bug.** Reproduce, write the fix, send the PR.
29
+ - **Add a missing standard Solana JSON-RPC method.** Check the
30
+ [supported methods table in the README](README.md#supported-methods) — anything
31
+ in the [Solana JSON-RPC spec](https://solana.com/docs/rpc) that isn't listed
32
+ is fair game.
33
+ - **Add a Helius-specific RPC extension** — enhanced transactions, DAS
34
+ (Digital Asset Standard) methods, priority fee estimation, etc.
35
+ - **Add a Helius REST endpoint** — Enhanced Transactions API, Webhooks API,
36
+ Mint API, token metadata, address lookups, and more.
37
+ - **Improve typing.** Tightening a `dict` return into a proper `pydantic`
38
+ model, narrowing a `str` into a `Literal`, or replacing `Any` with a real
39
+ type are all great contributions.
40
+ - **Improve error handling.** A consistent exception hierarchy for transport
41
+ errors and Helius/Solana RPC errors is a known gap.
42
+ - **Add streaming / websocket support** once the synchronous surface is
43
+ fleshed out.
44
+ - **Improve docs and examples.** Clearer docstrings, better README snippets,
45
+ more realistic examples.
46
+
47
+ If you're not sure where to start, browse the
48
+ [open issues](https://github.com/markosnarinian/helius-python/issues).
49
+
50
+ ## Before You Start a Large Change
51
+
52
+ **Please open an issue before working on anything non-trivial.** This includes:
53
+
54
+ - Architectural changes or refactors that span multiple files.
55
+ - New public APIs that aren't just wrapping an existing Helius/Solana endpoint.
56
+ - Changes to the existing public method signatures or behavior.
57
+ - Pulling in new runtime dependencies.
58
+ - Anything you expect to take more than an afternoon.
59
+
60
+ A quick conversation up-front saves everyone time and avoids the awkward case
61
+ of a large PR that has to be redesigned or rejected. Small, focused PRs — one
62
+ new RPC method, one bug fix, one model improvement — usually don't need
63
+ prior discussion; just send them.
64
+
65
+ ## Codebase Conventions
66
+
67
+ Please match the existing style of the codebase. Skim
68
+ [`src/helius/client.py`](src/helius/client.py) and
69
+ [`src/helius/models.py`](src/helius/models.py) before writing new code. In
70
+ particular:
71
+
72
+ - **Method names** are `snake_case` versions of the upstream RPC method
73
+ (`getAccountInfo` → `get_account_info`).
74
+ - **Parameter names** are `snake_case` versions of the upstream JSON field
75
+ names (`minContextSlot` → `min_context_slot`).
76
+ - **Use the `RpcRequest` builder** to construct request payloads — `add(...)`
77
+ for positional params, `set(key, value)` for fields inside the config
78
+ object. Don't build the JSON dict by hand.
79
+ - **Type everything.** Parameters get explicit types, including `Literal`s
80
+ for fixed string options (`commitment`, `encoding`, etc.). Return types are
81
+ always declared.
82
+ - **Model responses with `pydantic`.** Add a model in
83
+ [`src/helius/models.py`](src/helius/models.py) using the existing
84
+ `AliasGenerator(validation_alias=to_camel)` pattern instead of returning a
85
+ raw `dict`.
86
+ - **Follow the docs.** When implementing a new RPC method, read both the
87
+ Helius guide and API reference for that method (see
88
+ [`AGENTS.md`](AGENTS.md)) and mirror the documented parameters and response
89
+ shape.
90
+ - **Keep wrappers thin.** No surprise retries, caching, or transformations.
91
+ If the upstream API returns `{ context, value }`, return `(context, value)`
92
+ — don't flatten it.
93
+
94
+ ## Format and Lint Before Opening a PR
95
+
96
+ Run the formatters and type checker before pushing. PRs that aren't formatted
97
+ will be asked to reformat before review.
98
+
99
+ ```bash
100
+ isort src
101
+ black src
102
+ basedpyright src
103
+ ```
104
+
105
+ Make sure your change at least imports cleanly and the method you added
106
+ actually works against a real Helius endpoint.
107
+
108
+ ## Pull Requests
109
+
110
+ - Keep PRs focused. One method, one bug fix, or one refactor per PR.
111
+ - Write a clear PR description: what changed, why, and a link to the relevant
112
+ Helius/Solana docs for any new endpoint.
113
+ - Reference the issue your PR addresses (`Closes #123`).
114
+ - Be patient — reviews happen as time allows.
115
+
116
+ Thanks for contributing!
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Markos Narinian
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.