opentargets-py 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 (34) hide show
  1. opentargets_py-0.1.0/.github/workflows/ci.yml +46 -0
  2. opentargets_py-0.1.0/.github/workflows/publish.yml +32 -0
  3. opentargets_py-0.1.0/.gitignore +81 -0
  4. opentargets_py-0.1.0/CHANGELOG.md +15 -0
  5. opentargets_py-0.1.0/CLAUDE.md +50 -0
  6. opentargets_py-0.1.0/LICENSE +181 -0
  7. opentargets_py-0.1.0/PKG-INFO +120 -0
  8. opentargets_py-0.1.0/README.md +84 -0
  9. opentargets_py-0.1.0/docs/api-reference.md +77 -0
  10. opentargets_py-0.1.0/docs/quickstart.md +42 -0
  11. opentargets_py-0.1.0/examples/basic_usage.py +40 -0
  12. opentargets_py-0.1.0/examples/batch_query.py +16 -0
  13. opentargets_py-0.1.0/examples/network_analysis.py +24 -0
  14. opentargets_py-0.1.0/pyproject.toml +78 -0
  15. opentargets_py-0.1.0/src/opentargets/__init__.py +38 -0
  16. opentargets_py-0.1.0/src/opentargets/_cache.py +57 -0
  17. opentargets_py-0.1.0/src/opentargets/_graphql.py +139 -0
  18. opentargets_py-0.1.0/src/opentargets/_queries/__init__.py +1 -0
  19. opentargets_py-0.1.0/src/opentargets/_queries/association.py +21 -0
  20. opentargets_py-0.1.0/src/opentargets/_queries/disease.py +40 -0
  21. opentargets_py-0.1.0/src/opentargets/_queries/drug.py +34 -0
  22. opentargets_py-0.1.0/src/opentargets/_queries/search.py +16 -0
  23. opentargets_py-0.1.0/src/opentargets/_queries/target.py +74 -0
  24. opentargets_py-0.1.0/src/opentargets/_retry.py +64 -0
  25. opentargets_py-0.1.0/src/opentargets/client.py +506 -0
  26. opentargets_py-0.1.0/src/opentargets/exceptions.py +63 -0
  27. opentargets_py-0.1.0/src/opentargets/models.py +153 -0
  28. opentargets_py-0.1.0/src/opentargets/py.typed +0 -0
  29. opentargets_py-0.1.0/tests/conftest.py +107 -0
  30. opentargets_py-0.1.0/tests/test_cache.py +50 -0
  31. opentargets_py-0.1.0/tests/test_client.py +157 -0
  32. opentargets_py-0.1.0/tests/test_exceptions.py +45 -0
  33. opentargets_py-0.1.0/tests/test_models.py +78 -0
  34. opentargets_py-0.1.0/tests/test_retry.py +64 -0
@@ -0,0 +1,46 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ test:
11
+ name: Python ${{ matrix.python-version }}
12
+ runs-on: ubuntu-latest
13
+ strategy:
14
+ fail-fast: false
15
+ matrix:
16
+ python-version: ["3.9", "3.11", "3.13"]
17
+
18
+ steps:
19
+ - uses: actions/checkout@v4
20
+
21
+ - name: Set up Python ${{ matrix.python-version }}
22
+ uses: actions/setup-python@v5
23
+ with:
24
+ python-version: ${{ matrix.python-version }}
25
+
26
+ - name: Install dependencies
27
+ run: |
28
+ pip install -e ".[dev,pandas]"
29
+
30
+ - name: Lint (ruff)
31
+ run: ruff check src tests
32
+
33
+ - name: Format check (ruff)
34
+ run: ruff format --check src tests
35
+
36
+ - name: Type check (mypy)
37
+ run: mypy src/opentargets
38
+
39
+ - name: Run tests
40
+ run: pytest --cov=opentargets --cov-report=xml -v -m "not integration"
41
+
42
+ - name: Upload coverage
43
+ uses: codecov/codecov-action@v4
44
+ if: matrix.python-version == '3.11'
45
+ with:
46
+ files: coverage.xml
@@ -0,0 +1,32 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*"
7
+
8
+ jobs:
9
+ build:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - uses: actions/checkout@v4
13
+
14
+ - name: Set up Python
15
+ uses: actions/setup-python@v5
16
+ with:
17
+ python-version: "3.11"
18
+
19
+ - name: Install build tools
20
+ run: pip install build twine
21
+
22
+ - name: Build package
23
+ run: python -m build
24
+
25
+ - name: Check distribution
26
+ run: twine check dist/*
27
+
28
+ - name: Publish to PyPI
29
+ env:
30
+ TWINE_USERNAME: __token__
31
+ TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}
32
+ run: twine upload dist/*
@@ -0,0 +1,81 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *$py.class
4
+ *.so
5
+ .Python
6
+ build/
7
+ develop-eggs/
8
+ dist/
9
+ downloads/
10
+ eggs/
11
+ .eggs/
12
+ lib/
13
+ lib64/
14
+ parts/
15
+ sdist/
16
+ var/
17
+ wheels/
18
+ share/python-wheels/
19
+ *.egg-info/
20
+ .installed.cfg
21
+ *.egg
22
+ MANIFEST
23
+ *.manifest
24
+ *.spec
25
+ pip-log.txt
26
+ pip-delete-this-directory.txt
27
+ htmlcov/
28
+ .tox/
29
+ .nox/
30
+ .coverage
31
+ .coverage.*
32
+ .cache
33
+ nosetests.xml
34
+ coverage.xml
35
+ *.cover
36
+ *.py,cover
37
+ .hypothesis/
38
+ .pytest_cache/
39
+ cover/
40
+ *.mo
41
+ *.pot
42
+ *.log
43
+ local_settings.py
44
+ db.sqlite3
45
+ db.sqlite3-journal
46
+ instance/
47
+ .webassets-cache
48
+ .scrapy
49
+ docs/_build/
50
+ .pybuilder/
51
+ target/
52
+ .ipynb_checkpoints
53
+ profile_default/
54
+ ipython_config.py
55
+ .pdm.toml
56
+ .pdm-python
57
+ .pdm-build/
58
+ __pypackages__/
59
+ celerybeat-schedule
60
+ celerybeat.pid
61
+ *.sage.py
62
+ .env
63
+ .venv
64
+ env/
65
+ venv/
66
+ ENV/
67
+ env.bak/
68
+ venv.bak/
69
+ .spyderproject.db
70
+ .spyproject
71
+ .ropeproject
72
+ /site
73
+ .mypy_cache/
74
+ .dmypy.json
75
+ dmypy.json
76
+ .pyre/
77
+ .pytype/
78
+ cython_debug/
79
+ .idea/
80
+ .vscode/
81
+ *.iml
@@ -0,0 +1,15 @@
1
+ # Changelog
2
+
3
+ ## [0.1.0] - 2026-04-19
4
+
5
+ ### Added
6
+ - Initial release
7
+ - `OpenTargetsClient` with sync support
8
+ - Target, disease, drug, association, and search queries
9
+ - Auto-pagination for association endpoints
10
+ - Symbol-to-Ensembl ID resolution with caching
11
+ - In-memory LRU cache with TTL
12
+ - Exponential backoff retry (no third-party dependencies)
13
+ - Pydantic v2 response models (frozen, fully typed)
14
+ - Optional pandas DataFrame output
15
+ - GitHub Actions CI (Python 3.9, 3.11, 3.13) and PyPI publish workflow
@@ -0,0 +1,50 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## Commands
6
+
7
+ ```bash
8
+ # Install all dependencies (from repo root)
9
+ pip install -e ".[dev,pandas]"
10
+
11
+ # Run tests (no real API calls)
12
+ pytest
13
+
14
+ # Run a single test file
15
+ pytest tests/test_client.py -v
16
+
17
+ # Run a single test
18
+ pytest tests/test_client.py::test_get_target_by_ensembl_id -v
19
+
20
+ # Run integration tests (hits the real API)
21
+ pytest -m integration
22
+
23
+ # Lint + format check
24
+ ruff check src tests
25
+ ruff format --check src tests
26
+
27
+ # Type check
28
+ mypy src/opentargets
29
+ ```
30
+
31
+ ## Architecture
32
+
33
+ The package lives under `src/opentargets/` (PEP 517 src layout).
34
+
35
+ **Request flow:**
36
+ `OpenTargetsClient` (public API) → `GraphQLClient` (`_graphql.py`) → `with_retry()` → `httpx`
37
+
38
+ **Key design decisions:**
39
+
40
+ - `client.py` contains all public methods and delegates to `_graphql.py` for HTTP. Parse helpers (`_parse_target`, `_parse_disease`, etc.) live at the bottom of `client.py` to keep method bodies short.
41
+ - `_graphql.py` has two entry points: `execute()` for single queries and `paginate()` for cursor-based pagination. Pagination injects `index`/`size` variables and walks pages until `count` is exhausted.
42
+ - `_queries/` holds only GraphQL string constants — no logic. One module per entity type.
43
+ - `_retry.py` implements backoff without `tenacity`. It wraps a zero-argument callable, so it's usable with any function via a lambda.
44
+ - `_cache.py` is a standalone LRU+TTL cache. `OpenTargetsClient` uses two instances: one for symbol→Ensembl ID mapping (`_symbol_cache`) and one for full entity responses (`_result_cache`). Passing `cache=False` swaps both for `_NoCache` (same interface, no-ops).
45
+ - Symbol resolution: if `target_id` starts with `ENSG`, it's used directly. Otherwise the search endpoint is called and the result cached.
46
+ - Models in `models.py` use Pydantic v2 `model_validate()` with `populate_by_name=True` so both camelCase API fields and snake_case aliases work.
47
+
48
+ ## Testing
49
+
50
+ Tests use `respx` to mock `httpx` — no real API calls unless `@pytest.mark.integration`. Fixtures in `conftest.py` provide raw API response dicts that mirror the actual GraphQL schema shape.
@@ -0,0 +1,181 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship made available under
36
+ the License, as indicated by a copyright notice that is included in
37
+ or attached to the work (an example is provided in the Appendix below).
38
+
39
+ "Derivative Works" shall mean any work, whether in Source or Object
40
+ form, that is based on (or derived from) the Work and for which the
41
+ editorial revisions, annotations, elaborations, or other transformations
42
+ represent, as a whole, an original work of authorship. For the purposes
43
+ of this License, Derivative Works shall not include works that remain
44
+ separable from, or merely link (or bind by name) to the interfaces of,
45
+ the Work and Derivative Works thereof.
46
+
47
+ "Contribution" shall mean, as submitted to the Licensor for inclusion
48
+ in the Work by the copyright owner or by an individual or Legal Entity
49
+ authorized to submit on behalf of the copyright owner. For the purposes
50
+ of this definition, "submitted" means any form of electronic, verbal,
51
+ or written communication sent to the Licensor or its representatives,
52
+ including but not limited to communication on electronic mailing lists,
53
+ source code control systems, and issue tracking systems that are managed
54
+ by, or on behalf of, the Licensor for the purpose of recording and
55
+ discussing modifications to the Work, but excluding communication that
56
+ is conspicuously marked or designated in writing by the copyright owner
57
+ as "Not a Contribution."
58
+
59
+ "Contributor" shall mean Licensor and any Legal Entity on behalf of
60
+ whom a Contribution has been received by the Licensor and included
61
+ within the Work.
62
+
63
+ 2. Grant of Copyright License. Subject to the terms and conditions of
64
+ this License, each Contributor hereby grants to You a perpetual,
65
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
66
+ copyright license to reproduce, prepare Derivative Works of,
67
+ publicly display, publicly perform, sublicense, and distribute the
68
+ Work and such Derivative Works in Source or Object form.
69
+
70
+ 3. Grant of Patent License. Subject to the terms and conditions of
71
+ this License, each Contributor hereby grants to You a perpetual,
72
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
73
+ (except as stated in this section) patent license to make, have made,
74
+ use, offer to sell, sell, import, and otherwise transfer the Work,
75
+ where such license applies only to those patent claims licensable
76
+ by such Contributor that are necessarily infringed by their
77
+ Contribution(s) alone or by the combined work (in which case, such
78
+ patent license in respect to that Contribution shall terminate as of
79
+ the date such litigation is filed).
80
+
81
+ 4. Redistribution. You may reproduce and distribute copies of the
82
+ Work or Derivative Works thereof in any medium, with or without
83
+ modifications, and in Source or Object form, provided that You
84
+ meet the following conditions:
85
+
86
+ (a) You must give any other recipients of the Work or Derivative
87
+ Works a copy of this License; and
88
+
89
+ (b) You must cause any modified files to carry prominent notices
90
+ stating that You changed the files; and
91
+
92
+ (c) You must retain, in all form of the Work or Derivative
93
+ Works that You distribute, all copyright, patent, trademark, and
94
+ attribution notices from the Source form of the Work,
95
+ excluding those notices that do not pertain to any part of
96
+ the Derivative Works; and
97
+
98
+ (d) If the Work includes a "NOTICE" text file as part of its
99
+ distribution, You must include a readable copy of the attribution
100
+ notices contained within such NOTICE file, in at least one
101
+ of the following places: within a NOTICE text file distributed
102
+ as part of the Derivative Works; within the Source form or
103
+ documentation, if provided along with the Derivative Works; or,
104
+ within a display generated by the Derivative Works, if and
105
+ wherever such third-party notices normally appear. The contents
106
+ of the NOTICE file are for informational purposes only and
107
+ do not modify the License. You may add Your own attribution
108
+ notices within Derivative Works that You distribute, alongside
109
+ or as an addendum to the NOTICE text from the Work, provided
110
+ that such additional attribution notices cannot be construed
111
+ as modifying the License.
112
+
113
+ You may add Your own license statement for Your modifications and
114
+ may provide additional grant of rights to use, copy, modify, merge,
115
+ publish, distribute, sublicense, and/or sell copies of Your
116
+ modifications, or for such Derivative Works as a whole, under
117
+ the terms and conditions of this License, provided Your use,
118
+ reproduction, and distribution of the Work otherwise complies with
119
+ the conditions stated in this License.
120
+
121
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
122
+ any Contribution intentionally submitted for inclusion in the Work
123
+ by You to the Licensor shall be under the terms and conditions of
124
+ this License, without any additional terms or conditions.
125
+ Notwithstanding the above, nothing herein shall supersede or modify
126
+ the terms of any separate license agreement you may have executed
127
+ with Licensor regarding such Contributions.
128
+
129
+ 6. Trademarks. This License does not grant permission to use the trade
130
+ names, trademarks, service marks, or product names of the Licensor,
131
+ except as required for reasonable and customary use in describing the
132
+ origin of the Work and reproducing the content of the NOTICE file.
133
+
134
+ 7. Disclaimer of Warranty. Unless required by applicable law or
135
+ agreed to in writing, Licensor provides the Work (and each
136
+ Contributor provides its Contributions) on an "AS IS" BASIS,
137
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
138
+ implied, including, without limitation, any warranties or conditions
139
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
140
+ PARTICULAR PURPOSE. You are solely responsible for determining the
141
+ appropriateness of using or reproducing the Work and assume any
142
+ risks associated with Your exercise of permissions under this License.
143
+
144
+ 8. Limitation of Liability. In no event and under no legal theory,
145
+ whether in tort (including negligence), contract, or otherwise,
146
+ unless required by applicable law (such as deliberate and grossly
147
+ negligent acts) or agreed to in writing, shall any Contributor be
148
+ liable to You for damages, including any direct, indirect, special,
149
+ incidental, or exemplary damages of any character arising as a
150
+ result of this License or out of the use or inability to use the
151
+ Work (including but not limited to damages for loss of goodwill,
152
+ work stoppage, computer failure or malfunction, or all other
153
+ commercial damages or losses), even if such Contributor has been
154
+ advised of the possibility of such damages.
155
+
156
+ 9. Accepting Warranty or Liability. While redistributing the Work or
157
+ Derivative Works thereof, You may choose to offer, and charge a fee
158
+ for, acceptance of support, warranty, indemnity, or other liability
159
+ obligations and/or rights consistent with this License. However, in
160
+ accepting such obligations, You may offer such conditions only on
161
+ Your own behalf and on a sole responsibility basis, not on behalf
162
+ of any other Contributor, and only if You agree to indemnify,
163
+ defend, and hold each Contributor harmless for any liability
164
+ incurred by, or claims asserted against, such Contributor by reason
165
+ of your accepting any such warranty or additional liability.
166
+
167
+ END OF TERMS AND CONDITIONS
168
+
169
+ Copyright 2024 Göknur Arıcan
170
+
171
+ Licensed under the Apache License, Version 2.0 (the "License");
172
+ you may not use this file except in compliance with the License.
173
+ You may obtain a copy of the License at
174
+
175
+ http://www.apache.org/licenses/LICENSE-2.0
176
+
177
+ Unless required by applicable law or agreed to in writing, software
178
+ distributed under the License is distributed on an "AS IS" BASIS,
179
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
180
+ See the License for the specific language governing permissions and
181
+ limitations under the License.
@@ -0,0 +1,120 @@
1
+ Metadata-Version: 2.4
2
+ Name: opentargets-py
3
+ Version: 0.1.0
4
+ Summary: Unofficial community-maintained Python client for the Open Targets Platform GraphQL API
5
+ Project-URL: Homepage, https://github.com/goknurarican/opentargets-py
6
+ Project-URL: Documentation, https://opentargets-py.readthedocs.io
7
+ Project-URL: Repository, https://github.com/goknurarican/opentargets-py
8
+ Project-URL: Issues, https://github.com/goknurarican/opentargets-py/issues
9
+ Author-email: Göknur Arıcan <gknrperiarican@gmail.com>
10
+ License-Expression: Apache-2.0
11
+ License-File: LICENSE
12
+ Keywords: bioinformatics,drug-discovery,genomics,graphql,opentargets,python-client,sdk,target-identification
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Intended Audience :: Science/Research
15
+ Classifier: License :: OSI Approved :: Apache Software License
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.9
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
23
+ Classifier: Typing :: Typed
24
+ Requires-Python: >=3.9
25
+ Requires-Dist: httpx>=0.24
26
+ Requires-Dist: pydantic>=2.0
27
+ Provides-Extra: dev
28
+ Requires-Dist: mypy>=1.0; extra == 'dev'
29
+ Requires-Dist: pytest-cov; extra == 'dev'
30
+ Requires-Dist: pytest>=7.0; extra == 'dev'
31
+ Requires-Dist: respx>=0.20; extra == 'dev'
32
+ Requires-Dist: ruff>=0.1; extra == 'dev'
33
+ Provides-Extra: pandas
34
+ Requires-Dist: pandas>=1.5; extra == 'pandas'
35
+ Description-Content-Type: text/markdown
36
+
37
+ # opentargets-py
38
+
39
+ [![PyPI version](https://badge.fury.io/py/opentargets-py.svg)](https://pypi.org/project/opentargets-py/)
40
+ [![Python versions](https://img.shields.io/pypi/pyversions/opentargets-py)](https://pypi.org/project/opentargets-py/)
41
+ [![CI](https://github.com/goknurarican/opentargets-py/actions/workflows/ci.yml/badge.svg)](https://github.com/goknurarican/opentargets-py/actions/workflows/ci.yml)
42
+ [![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](LICENSE)
43
+
44
+ Modern Python client for the [Open Targets Platform](https://platform.opentargets.org) GraphQL API.
45
+
46
+ > **Disclaimer:** This is an **unofficial, community-maintained** client and is not affiliated with, endorsed by, or supported by the Open Targets consortium. For the official platform, visit [platform.opentargets.org](https://platform.opentargets.org).
47
+
48
+ The official `opentargets` package was deprecated when Open Targets migrated to GraphQL in 2021 and has since been removed from PyPI. This library fills that gap — it is the only Python SDK targeting the current GraphQL API.
49
+
50
+ ## Installation
51
+
52
+ ```bash
53
+ pip install opentargets-py
54
+ ```
55
+
56
+ With pandas support:
57
+
58
+ ```bash
59
+ pip install opentargets-py[pandas]
60
+ ```
61
+
62
+ ## Quick Start
63
+
64
+ ```python
65
+ from opentargets import OpenTargetsClient
66
+
67
+ client = OpenTargetsClient()
68
+
69
+ # Look up a target by gene symbol
70
+ target = client.get_target("EGFR")
71
+ print(target.approved_name) # epidermal growth factor receptor
72
+
73
+ # Get associated diseases
74
+ associations = client.get_target_associations("EGFR", limit=10)
75
+ for a in associations:
76
+ print(a.disease_name, a.score)
77
+
78
+ # Get drugs for a target
79
+ drugs = client.get_target_drugs("EGFR")
80
+
81
+ # Look up a disease
82
+ disease = client.get_disease("EFO_0003060")
83
+
84
+ # Search across the platform
85
+ results = client.search("lung cancer", entity_type="disease", limit=5)
86
+ ```
87
+
88
+ ## Features
89
+
90
+ - **Type-safe** — full Pydantic v2 models, `py.typed` marker, `mypy --strict` compliant
91
+ - **Symbol resolution** — pass `"EGFR"` instead of `"ENSG00000146648"`
92
+ - **Auto-pagination** — fetches all pages transparently
93
+ - **In-memory cache** — LRU cache with TTL, reduces redundant API calls
94
+ - **Retry with backoff** — automatic retries on 429/5xx with exponential backoff
95
+ - **Pandas integration** — `as_dataframe=True` on any list method
96
+ - **Minimal dependencies** — only `httpx` and `pydantic`
97
+
98
+ ## More Examples
99
+
100
+ See the [`examples/`](examples/) directory:
101
+
102
+ - [`basic_usage.py`](examples/basic_usage.py) — targets, diseases, drugs, search
103
+ - [`batch_query.py`](examples/batch_query.py) — batch fetch + DataFrame output
104
+ - [`network_analysis.py`](examples/network_analysis.py) — build a target–disease network
105
+
106
+ ## API Reference
107
+
108
+ See [`docs/api-reference.md`](docs/api-reference.md).
109
+
110
+ ## Contributing
111
+
112
+ 1. Fork the repo and create a feature branch.
113
+ 2. Install dev dependencies: `pip install -e ".[dev,pandas]"`
114
+ 3. Run tests: `pytest`
115
+ 4. Run linting: `ruff check src tests && ruff format src tests`
116
+ 5. Open a pull request.
117
+
118
+ ## License
119
+
120
+ Apache 2.0 — see [LICENSE](LICENSE).
@@ -0,0 +1,84 @@
1
+ # opentargets-py
2
+
3
+ [![PyPI version](https://badge.fury.io/py/opentargets-py.svg)](https://pypi.org/project/opentargets-py/)
4
+ [![Python versions](https://img.shields.io/pypi/pyversions/opentargets-py)](https://pypi.org/project/opentargets-py/)
5
+ [![CI](https://github.com/goknurarican/opentargets-py/actions/workflows/ci.yml/badge.svg)](https://github.com/goknurarican/opentargets-py/actions/workflows/ci.yml)
6
+ [![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](LICENSE)
7
+
8
+ Modern Python client for the [Open Targets Platform](https://platform.opentargets.org) GraphQL API.
9
+
10
+ > **Disclaimer:** This is an **unofficial, community-maintained** client and is not affiliated with, endorsed by, or supported by the Open Targets consortium. For the official platform, visit [platform.opentargets.org](https://platform.opentargets.org).
11
+
12
+ The official `opentargets` package was deprecated when Open Targets migrated to GraphQL in 2021 and has since been removed from PyPI. This library fills that gap — it is the only Python SDK targeting the current GraphQL API.
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ pip install opentargets-py
18
+ ```
19
+
20
+ With pandas support:
21
+
22
+ ```bash
23
+ pip install opentargets-py[pandas]
24
+ ```
25
+
26
+ ## Quick Start
27
+
28
+ ```python
29
+ from opentargets import OpenTargetsClient
30
+
31
+ client = OpenTargetsClient()
32
+
33
+ # Look up a target by gene symbol
34
+ target = client.get_target("EGFR")
35
+ print(target.approved_name) # epidermal growth factor receptor
36
+
37
+ # Get associated diseases
38
+ associations = client.get_target_associations("EGFR", limit=10)
39
+ for a in associations:
40
+ print(a.disease_name, a.score)
41
+
42
+ # Get drugs for a target
43
+ drugs = client.get_target_drugs("EGFR")
44
+
45
+ # Look up a disease
46
+ disease = client.get_disease("EFO_0003060")
47
+
48
+ # Search across the platform
49
+ results = client.search("lung cancer", entity_type="disease", limit=5)
50
+ ```
51
+
52
+ ## Features
53
+
54
+ - **Type-safe** — full Pydantic v2 models, `py.typed` marker, `mypy --strict` compliant
55
+ - **Symbol resolution** — pass `"EGFR"` instead of `"ENSG00000146648"`
56
+ - **Auto-pagination** — fetches all pages transparently
57
+ - **In-memory cache** — LRU cache with TTL, reduces redundant API calls
58
+ - **Retry with backoff** — automatic retries on 429/5xx with exponential backoff
59
+ - **Pandas integration** — `as_dataframe=True` on any list method
60
+ - **Minimal dependencies** — only `httpx` and `pydantic`
61
+
62
+ ## More Examples
63
+
64
+ See the [`examples/`](examples/) directory:
65
+
66
+ - [`basic_usage.py`](examples/basic_usage.py) — targets, diseases, drugs, search
67
+ - [`batch_query.py`](examples/batch_query.py) — batch fetch + DataFrame output
68
+ - [`network_analysis.py`](examples/network_analysis.py) — build a target–disease network
69
+
70
+ ## API Reference
71
+
72
+ See [`docs/api-reference.md`](docs/api-reference.md).
73
+
74
+ ## Contributing
75
+
76
+ 1. Fork the repo and create a feature branch.
77
+ 2. Install dev dependencies: `pip install -e ".[dev,pandas]"`
78
+ 3. Run tests: `pytest`
79
+ 4. Run linting: `ruff check src tests && ruff format src tests`
80
+ 5. Open a pull request.
81
+
82
+ ## License
83
+
84
+ Apache 2.0 — see [LICENSE](LICENSE).
@@ -0,0 +1,77 @@
1
+ # API Reference
2
+
3
+ ## OpenTargetsClient
4
+
5
+ ```python
6
+ OpenTargetsClient(
7
+ base_url: str = "https://api.platform.opentargets.org/api/v4/graphql",
8
+ timeout: float = 30.0,
9
+ cache: bool = True,
10
+ cache_ttl: float = 300.0,
11
+ )
12
+ ```
13
+
14
+ ### Target methods
15
+
16
+ | Method | Returns |
17
+ |---|---|
18
+ | `get_target(target_id)` | `Target` |
19
+ | `get_targets(target_ids)` | `list[Target]` |
20
+ | `get_target_associations(target_id, limit, as_dataframe)` | `list[Association]` or `DataFrame` |
21
+ | `get_target_drugs(target_id)` | `list[Drug]` |
22
+
23
+ ### Disease methods
24
+
25
+ | Method | Returns |
26
+ |---|---|
27
+ | `get_disease(disease_id)` | `Disease` |
28
+ | `get_disease_targets(disease_id, limit, as_dataframe)` | `list[Association]` or `DataFrame` |
29
+
30
+ ### Drug methods
31
+
32
+ | Method | Returns |
33
+ |---|---|
34
+ | `get_drug(drug_id)` | `Drug` |
35
+ | `get_drug_indications(drug_id)` | `list[DrugIndication]` |
36
+
37
+ ### Search
38
+
39
+ | Method | Returns |
40
+ |---|---|
41
+ | `search(query_string, entity_type, limit)` | `list[SearchResult]` |
42
+
43
+ ### Associations
44
+
45
+ | Method | Returns |
46
+ |---|---|
47
+ | `get_associations(target_id, disease_id)` | `Association \| None` |
48
+
49
+ ## Models
50
+
51
+ ### Target
52
+ `id`, `approved_symbol`, `approved_name`, `biotype`, `description`, `function_descriptions`
53
+
54
+ ### Disease
55
+ `id`, `name`, `description`, `therapeutic_areas`, `db_x_refs`
56
+
57
+ ### Drug
58
+ `id`, `name`, `drug_type`, `mechanism_of_action`, `synonyms`, `trade_names`, `max_clinical_trial_phase`
59
+
60
+ ### Association
61
+ `target_id`, `target_symbol`, `disease_id`, `disease_name`, `score`, `datasource_scores`, `evidence_count`
62
+
63
+ ### SearchResult
64
+ `id`, `name`, `entity_type`, `description`, `score`
65
+
66
+ ### DrugIndication
67
+ `disease_id`, `disease_name`, `max_phase_for_indication`
68
+
69
+ ## Exceptions
70
+
71
+ | Exception | When |
72
+ |---|---|
73
+ | `OpenTargetsError` | Base class |
74
+ | `APIError` | HTTP error (non-2xx) |
75
+ | `QueryError` | GraphQL `errors` in response |
76
+ | `NotFoundError` | Entity not found |
77
+ | `RateLimitError` | HTTP 429 |