bibleql 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,22 @@
1
+ # Byte-compiled / cache
2
+ __pycache__/
3
+ *.py[cod]
4
+ .pytest_cache/
5
+ .ruff_cache/
6
+ .mypy_cache/
7
+
8
+ # Build artifacts
9
+ dist/
10
+ build/
11
+ *.egg-info/
12
+
13
+ # Virtual environments
14
+ .venv/
15
+
16
+ # Editors / OS
17
+ .vscode/
18
+ .idea/
19
+ .DS_Store
20
+
21
+ # Secrets
22
+ .env
@@ -0,0 +1,12 @@
1
+ # Changelog
2
+
3
+ ## [Unreleased]
4
+
5
+ ## [0.1.0] - 2026-10-18
6
+
7
+ - Initial release.
8
+ - `Client` with API key from argument or `BIBLEQL_API_KEY`, configurable default translation, API URL and timeout; usable as a context manager.
9
+ - Queries: `translations`, `translation`, `books`, `languages`, `passage`, `chapter`, `verse`, `random_verse`, `verse_of_the_day`, `bible_index`, `search`, `semantic_search`.
10
+ - Concordance: `concordance` (one page), `iter_concordance` (lazy auto-pagination), `concordance_index`, and the `Testament` enum.
11
+ - Immutable, typed dataclass models (`py.typed` included).
12
+ - Error hierarchy rooted at `BibleQLError`. HTTP errors include the server's message, and "Couldn't find ..." GraphQL errors raise `NotFoundError`.
bibleql-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2026 Luis Porras
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
13
+ all 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
21
+ THE SOFTWARE.
bibleql-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,271 @@
1
+ Metadata-Version: 2.5
2
+ Name: bibleql
3
+ Version: 0.1.0
4
+ Summary: Python client for the BibleQL GraphQL API
5
+ Project-URL: Homepage, https://bibleql.org
6
+ Project-URL: Documentation, https://docs.bibleql.org
7
+ Project-URL: Source, https://github.com/lporras/bibleql-python
8
+ Project-URL: Changelog, https://github.com/lporras/bibleql-python/blob/main/CHANGELOG.md
9
+ Author-email: Luis Porras <lporras16@gmail.com>
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: api,bible,bibleql,client,graphql
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Programming Language :: Python :: 3.14
22
+ Classifier: Programming Language :: Python :: 3.15
23
+ Classifier: Typing :: Typed
24
+ Requires-Python: >=3.10
25
+ Requires-Dist: httpx<2,>=0.27
26
+ Provides-Extra: dev
27
+ Requires-Dist: build; extra == 'dev'
28
+ Requires-Dist: graphql-core>=3.2; extra == 'dev'
29
+ Requires-Dist: pytest>=8; extra == 'dev'
30
+ Requires-Dist: python-dotenv>=1.0; extra == 'dev'
31
+ Requires-Dist: respx>=0.22; extra == 'dev'
32
+ Requires-Dist: ruff>=0.6; extra == 'dev'
33
+ Requires-Dist: twine; extra == 'dev'
34
+ Description-Content-Type: text/markdown
35
+
36
+ # BibleQL Python
37
+
38
+ [![CI](https://github.com/lporras/bibleql-python/actions/workflows/ci.yml/badge.svg)](https://github.com/lporras/bibleql-python/actions/workflows/ci.yml)
39
+ [![PyPI](https://img.shields.io/pypi/v/bibleql.svg)](https://pypi.org/project/bibleql/)
40
+ [![Python versions](https://img.shields.io/pypi/pyversions/bibleql.svg)](https://pypi.org/project/bibleql/)
41
+
42
+ A typed Python client for the [BibleQL](https://bibleql.org) GraphQL API. Query Bible verses, passages, translations, search and concordance across 47 translations in 31 languages, without writing GraphQL.
43
+
44
+ ## Installation
45
+
46
+ ```bash
47
+ pip install bibleql
48
+ ```
49
+
50
+ Requires Python 3.10+.
51
+
52
+ ## Quick start
53
+
54
+ ```python
55
+ import bibleql
56
+
57
+ with bibleql.Client(api_key="bql_live_...") as client:
58
+ passage = client.passage("John 3:16")
59
+ print(passage.reference) # John 3:16
60
+ print(passage.text) # For God so loved the world...
61
+ ```
62
+
63
+ Get an API key at [bibleql.org](https://bibleql.org), and try queries in the [playground](https://bibleql.org/playground).
64
+
65
+ ## Configuration
66
+
67
+ ```python
68
+ client = bibleql.Client(
69
+ api_key="bql_live_...", # or set the BIBLEQL_API_KEY environment variable
70
+ default_translation="spa-bes", # optional, defaults to "eng-web"
71
+ api_url="https://custom-host.com/graphql", # optional, defaults to https://bibleql.org/graphql
72
+ timeout=60, # optional, seconds, defaults to 30
73
+ )
74
+ ```
75
+
76
+ If `api_key` is omitted, the client reads `BIBLEQL_API_KEY`:
77
+
78
+ ```bash
79
+ export BIBLEQL_API_KEY=bql_live_...
80
+ ```
81
+
82
+ ```python
83
+ client = bibleql.Client()
84
+ ```
85
+
86
+ Use the client as a context manager (`with ... as client:`) or call `client.close()` when done, so its connection pool is released.
87
+
88
+ Every method that takes `translation=` falls back to `default_translation` when it's omitted. The exception is `semantic_search`, which lets the API pick a translation that has embeddings.
89
+
90
+ ## Usage
91
+
92
+ ### Passages
93
+
94
+ ```python
95
+ passage = client.passage("John 3:16")
96
+ passage.reference # "John 3:16"
97
+ passage.text # "For God so loved the world..."
98
+ passage.translation_id # "eng-web"
99
+ passage.verses # [Verse(book_id='JHN', book_name='John', chapter=3, verse=16, text='...')]
100
+
101
+ client.passage("John 3:16-18")
102
+ client.passage("Matthew 25:31-33,46")
103
+ client.passage("Genesis 1")
104
+ client.passage("Mateo 28:18-20", translation="spa-bes")
105
+ ```
106
+
107
+ ### Verses and chapters
108
+
109
+ ```python
110
+ verse = client.verse("MAT", 5, 3)
111
+ verse.book_name # "Matthew"
112
+ verse.text # "Blessed are the poor in spirit..."
113
+
114
+ verses = client.chapter("GEN", 1) # list[Verse]
115
+ ```
116
+
117
+ ### Random verse
118
+
119
+ ```python
120
+ client.random_verse()
121
+ client.random_verse(testament="NT") # "OT" or "NT"
122
+ client.random_verse(books=["PSA", "PRO"]) # or books="PSA,PRO"
123
+ ```
124
+
125
+ ### Verse of the day
126
+
127
+ ```python
128
+ import datetime
129
+
130
+ client.verse_of_the_day()
131
+ client.verse_of_the_day(date=datetime.date(2026, 1, 1)) # or date="2026-01-01"
132
+ ```
133
+
134
+ ### Search
135
+
136
+ Case-insensitive substring search, with no stemming ("love" won't match "loved"):
137
+
138
+ ```python
139
+ for verse in client.search("love", limit=5):
140
+ print(verse.book_name, verse.chapter, verse.verse, verse.text)
141
+ ```
142
+
143
+ Semantic search finds verses by meaning, using AI embeddings:
144
+
145
+ ```python
146
+ for result in client.semantic_search("fe y esperanza", limit=5):
147
+ print(f"{result.similarity:.2f}", result.verse.text)
148
+ ```
149
+
150
+ ### Concordance
151
+
152
+ Exhaustive, canonically ordered occurrences of a word, with per-book and per-testament totals:
153
+
154
+ ```python
155
+ page = client.concordance("misericordia", translation="spa-rv1909", first=10)
156
+ page.total_count # total occurrences
157
+ page.entry.surface_forms # ["misericordia", "misericordias", ...]
158
+ page.entry.occurrences_by_testament.old # verses in the Old Testament
159
+ for occurrence in page.occurrences:
160
+ print(occurrence.verse.book_name, occurrence.context) # context has <mark> tags
161
+
162
+ # Next page
163
+ if page.has_next_page:
164
+ page = client.concordance("misericordia", translation="spa-rv1909", after=page.end_cursor)
165
+
166
+ # Or let the client paginate for you (pages are fetched lazily)
167
+ for occurrence in client.iter_concordance("misericordia", translation="spa-rv1909"):
168
+ ...
169
+
170
+ # Filters
171
+ client.concordance("misericordia", translation="spa-rv1909", book="Salmos")
172
+ client.concordance("misericordia", translation="spa-rv1909", testament=bibleql.Testament.NEW)
173
+
174
+ # Alphabetical word-frequency index
175
+ client.concordance_index(translation="spa-rv1909", prefix="mis", min_occurrences=5)
176
+ ```
177
+
178
+ The `context` field contains `<mark>` HTML tags around the match, so sanitize it before rendering it as HTML.
179
+
180
+ ### Translations, languages, books
181
+
182
+ ```python
183
+ client.translations() # list[Translation]
184
+ t = client.translation("eng-web")
185
+ t.name, t.abbrev # "World English Bible", "WEB"
186
+ t.books # list[LocalizedBook]
187
+
188
+ client.languages() # list[Language], each with .translations
189
+ client.books() # list[Book], the 66 canonical books
190
+ ```
191
+
192
+ ### Bible index
193
+
194
+ ```python
195
+ index = client.bible_index()
196
+ index[0].name # "Genesis"
197
+ index[0].chapters[0].verse_count # 31
198
+ ```
199
+
200
+ ### Models
201
+
202
+ All results are immutable dataclasses with snake_case attributes. To convert one to a dict:
203
+
204
+ ```python
205
+ import dataclasses
206
+
207
+ dataclasses.asdict(client.verse("JHN", 3, 16))
208
+ ```
209
+
210
+ ## Error handling
211
+
212
+ Every error inherits from `bibleql.BibleQLError`:
213
+
214
+ ```
215
+ BibleQLError
216
+ ├── ConfigurationError no API key
217
+ ├── NetworkError no response (DNS, connection refused, ...)
218
+ │ └── RequestTimeoutError
219
+ ├── APIError (.status, .body) non-2xx HTTP response
220
+ │ ├── AuthenticationError 401
221
+ │ ├── RateLimitError 429
222
+ │ └── ServerError 5xx
223
+ └── QueryError (.errors) GraphQL errors in the response
224
+ └── NotFoundError
225
+ ```
226
+
227
+ ```python
228
+ try:
229
+ client.passage("Hezekiah 1:1")
230
+ except bibleql.NotFoundError as e:
231
+ print(f"Not found: {e}")
232
+ except bibleql.AuthenticationError:
233
+ print("Invalid API key")
234
+ except bibleql.RateLimitError:
235
+ print("Too many requests")
236
+ except bibleql.RequestTimeoutError:
237
+ print("Request timed out")
238
+ except bibleql.NetworkError:
239
+ print("Connection failed")
240
+ except bibleql.QueryError as e:
241
+ print(f"GraphQL error: {e}")
242
+ print(e.errors) # raw error list from the API
243
+ ```
244
+
245
+ ## Development
246
+
247
+ ```bash
248
+ asdf install # Python version from .tool-versions
249
+ python -m venv .venv && source .venv/bin/activate
250
+ python -m pip install -e ".[dev]"
251
+
252
+ pytest # run tests (HTTP is mocked with respx, no network needed)
253
+ ruff check . && ruff format . # lint and format
254
+ ```
255
+
256
+ `tests/fixtures/schema.graphql` is a snapshot of the API schema, and every query is validated against it. Refresh it from the API repo (`docs/generated/schema.graphql`) when the schema changes.
257
+
258
+ ### Testing against the live API
259
+
260
+ The test suite never touches the network. To check the client against the real API, put your key in a `.env` file (gitignored) and run the smoke test, which loads it with [python-dotenv](https://pypi.org/project/python-dotenv/):
261
+
262
+ ```bash
263
+ cp .env.example .env # then set BIBLEQL_API_KEY in .env
264
+ python scripts/smoke_test.py # calls every method and prints the results
265
+ ```
266
+
267
+ The library itself never reads `.env` files. In your own app, load them yourself (for example with `dotenv.load_dotenv()`) before creating a `Client()`.
268
+
269
+ ## License
270
+
271
+ Released under the [MIT License](LICENSE).
@@ -0,0 +1,236 @@
1
+ # BibleQL Python
2
+
3
+ [![CI](https://github.com/lporras/bibleql-python/actions/workflows/ci.yml/badge.svg)](https://github.com/lporras/bibleql-python/actions/workflows/ci.yml)
4
+ [![PyPI](https://img.shields.io/pypi/v/bibleql.svg)](https://pypi.org/project/bibleql/)
5
+ [![Python versions](https://img.shields.io/pypi/pyversions/bibleql.svg)](https://pypi.org/project/bibleql/)
6
+
7
+ A typed Python client for the [BibleQL](https://bibleql.org) GraphQL API. Query Bible verses, passages, translations, search and concordance across 47 translations in 31 languages, without writing GraphQL.
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ pip install bibleql
13
+ ```
14
+
15
+ Requires Python 3.10+.
16
+
17
+ ## Quick start
18
+
19
+ ```python
20
+ import bibleql
21
+
22
+ with bibleql.Client(api_key="bql_live_...") as client:
23
+ passage = client.passage("John 3:16")
24
+ print(passage.reference) # John 3:16
25
+ print(passage.text) # For God so loved the world...
26
+ ```
27
+
28
+ Get an API key at [bibleql.org](https://bibleql.org), and try queries in the [playground](https://bibleql.org/playground).
29
+
30
+ ## Configuration
31
+
32
+ ```python
33
+ client = bibleql.Client(
34
+ api_key="bql_live_...", # or set the BIBLEQL_API_KEY environment variable
35
+ default_translation="spa-bes", # optional, defaults to "eng-web"
36
+ api_url="https://custom-host.com/graphql", # optional, defaults to https://bibleql.org/graphql
37
+ timeout=60, # optional, seconds, defaults to 30
38
+ )
39
+ ```
40
+
41
+ If `api_key` is omitted, the client reads `BIBLEQL_API_KEY`:
42
+
43
+ ```bash
44
+ export BIBLEQL_API_KEY=bql_live_...
45
+ ```
46
+
47
+ ```python
48
+ client = bibleql.Client()
49
+ ```
50
+
51
+ Use the client as a context manager (`with ... as client:`) or call `client.close()` when done, so its connection pool is released.
52
+
53
+ Every method that takes `translation=` falls back to `default_translation` when it's omitted. The exception is `semantic_search`, which lets the API pick a translation that has embeddings.
54
+
55
+ ## Usage
56
+
57
+ ### Passages
58
+
59
+ ```python
60
+ passage = client.passage("John 3:16")
61
+ passage.reference # "John 3:16"
62
+ passage.text # "For God so loved the world..."
63
+ passage.translation_id # "eng-web"
64
+ passage.verses # [Verse(book_id='JHN', book_name='John', chapter=3, verse=16, text='...')]
65
+
66
+ client.passage("John 3:16-18")
67
+ client.passage("Matthew 25:31-33,46")
68
+ client.passage("Genesis 1")
69
+ client.passage("Mateo 28:18-20", translation="spa-bes")
70
+ ```
71
+
72
+ ### Verses and chapters
73
+
74
+ ```python
75
+ verse = client.verse("MAT", 5, 3)
76
+ verse.book_name # "Matthew"
77
+ verse.text # "Blessed are the poor in spirit..."
78
+
79
+ verses = client.chapter("GEN", 1) # list[Verse]
80
+ ```
81
+
82
+ ### Random verse
83
+
84
+ ```python
85
+ client.random_verse()
86
+ client.random_verse(testament="NT") # "OT" or "NT"
87
+ client.random_verse(books=["PSA", "PRO"]) # or books="PSA,PRO"
88
+ ```
89
+
90
+ ### Verse of the day
91
+
92
+ ```python
93
+ import datetime
94
+
95
+ client.verse_of_the_day()
96
+ client.verse_of_the_day(date=datetime.date(2026, 1, 1)) # or date="2026-01-01"
97
+ ```
98
+
99
+ ### Search
100
+
101
+ Case-insensitive substring search, with no stemming ("love" won't match "loved"):
102
+
103
+ ```python
104
+ for verse in client.search("love", limit=5):
105
+ print(verse.book_name, verse.chapter, verse.verse, verse.text)
106
+ ```
107
+
108
+ Semantic search finds verses by meaning, using AI embeddings:
109
+
110
+ ```python
111
+ for result in client.semantic_search("fe y esperanza", limit=5):
112
+ print(f"{result.similarity:.2f}", result.verse.text)
113
+ ```
114
+
115
+ ### Concordance
116
+
117
+ Exhaustive, canonically ordered occurrences of a word, with per-book and per-testament totals:
118
+
119
+ ```python
120
+ page = client.concordance("misericordia", translation="spa-rv1909", first=10)
121
+ page.total_count # total occurrences
122
+ page.entry.surface_forms # ["misericordia", "misericordias", ...]
123
+ page.entry.occurrences_by_testament.old # verses in the Old Testament
124
+ for occurrence in page.occurrences:
125
+ print(occurrence.verse.book_name, occurrence.context) # context has <mark> tags
126
+
127
+ # Next page
128
+ if page.has_next_page:
129
+ page = client.concordance("misericordia", translation="spa-rv1909", after=page.end_cursor)
130
+
131
+ # Or let the client paginate for you (pages are fetched lazily)
132
+ for occurrence in client.iter_concordance("misericordia", translation="spa-rv1909"):
133
+ ...
134
+
135
+ # Filters
136
+ client.concordance("misericordia", translation="spa-rv1909", book="Salmos")
137
+ client.concordance("misericordia", translation="spa-rv1909", testament=bibleql.Testament.NEW)
138
+
139
+ # Alphabetical word-frequency index
140
+ client.concordance_index(translation="spa-rv1909", prefix="mis", min_occurrences=5)
141
+ ```
142
+
143
+ The `context` field contains `<mark>` HTML tags around the match, so sanitize it before rendering it as HTML.
144
+
145
+ ### Translations, languages, books
146
+
147
+ ```python
148
+ client.translations() # list[Translation]
149
+ t = client.translation("eng-web")
150
+ t.name, t.abbrev # "World English Bible", "WEB"
151
+ t.books # list[LocalizedBook]
152
+
153
+ client.languages() # list[Language], each with .translations
154
+ client.books() # list[Book], the 66 canonical books
155
+ ```
156
+
157
+ ### Bible index
158
+
159
+ ```python
160
+ index = client.bible_index()
161
+ index[0].name # "Genesis"
162
+ index[0].chapters[0].verse_count # 31
163
+ ```
164
+
165
+ ### Models
166
+
167
+ All results are immutable dataclasses with snake_case attributes. To convert one to a dict:
168
+
169
+ ```python
170
+ import dataclasses
171
+
172
+ dataclasses.asdict(client.verse("JHN", 3, 16))
173
+ ```
174
+
175
+ ## Error handling
176
+
177
+ Every error inherits from `bibleql.BibleQLError`:
178
+
179
+ ```
180
+ BibleQLError
181
+ ├── ConfigurationError no API key
182
+ ├── NetworkError no response (DNS, connection refused, ...)
183
+ │ └── RequestTimeoutError
184
+ ├── APIError (.status, .body) non-2xx HTTP response
185
+ │ ├── AuthenticationError 401
186
+ │ ├── RateLimitError 429
187
+ │ └── ServerError 5xx
188
+ └── QueryError (.errors) GraphQL errors in the response
189
+ └── NotFoundError
190
+ ```
191
+
192
+ ```python
193
+ try:
194
+ client.passage("Hezekiah 1:1")
195
+ except bibleql.NotFoundError as e:
196
+ print(f"Not found: {e}")
197
+ except bibleql.AuthenticationError:
198
+ print("Invalid API key")
199
+ except bibleql.RateLimitError:
200
+ print("Too many requests")
201
+ except bibleql.RequestTimeoutError:
202
+ print("Request timed out")
203
+ except bibleql.NetworkError:
204
+ print("Connection failed")
205
+ except bibleql.QueryError as e:
206
+ print(f"GraphQL error: {e}")
207
+ print(e.errors) # raw error list from the API
208
+ ```
209
+
210
+ ## Development
211
+
212
+ ```bash
213
+ asdf install # Python version from .tool-versions
214
+ python -m venv .venv && source .venv/bin/activate
215
+ python -m pip install -e ".[dev]"
216
+
217
+ pytest # run tests (HTTP is mocked with respx, no network needed)
218
+ ruff check . && ruff format . # lint and format
219
+ ```
220
+
221
+ `tests/fixtures/schema.graphql` is a snapshot of the API schema, and every query is validated against it. Refresh it from the API repo (`docs/generated/schema.graphql`) when the schema changes.
222
+
223
+ ### Testing against the live API
224
+
225
+ The test suite never touches the network. To check the client against the real API, put your key in a `.env` file (gitignored) and run the smoke test, which loads it with [python-dotenv](https://pypi.org/project/python-dotenv/):
226
+
227
+ ```bash
228
+ cp .env.example .env # then set BIBLEQL_API_KEY in .env
229
+ python scripts/smoke_test.py # calls every method and prints the results
230
+ ```
231
+
232
+ The library itself never reads `.env` files. In your own app, load them yourself (for example with `dotenv.load_dotenv()`) before creating a `Client()`.
233
+
234
+ ## License
235
+
236
+ Released under the [MIT License](LICENSE).
@@ -0,0 +1,74 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "bibleql"
7
+ dynamic = ["version"]
8
+ description = "Python client for the BibleQL GraphQL API"
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = "MIT"
12
+ license-files = ["LICENSE"]
13
+ authors = [{ name = "Luis Porras", email = "lporras16@gmail.com" }]
14
+ keywords = ["bible", "graphql", "api", "client", "bibleql"]
15
+ classifiers = [
16
+ "Development Status :: 3 - Alpha",
17
+ "Intended Audience :: Developers",
18
+ "Operating System :: OS Independent",
19
+ "Programming Language :: Python :: 3",
20
+ "Programming Language :: Python :: 3.10",
21
+ "Programming Language :: Python :: 3.11",
22
+ "Programming Language :: Python :: 3.12",
23
+ "Programming Language :: Python :: 3.13",
24
+ "Programming Language :: Python :: 3.14",
25
+ "Programming Language :: Python :: 3.15",
26
+ "Typing :: Typed",
27
+ ]
28
+ dependencies = [
29
+ "httpx>=0.27,<2",
30
+ ]
31
+
32
+ [project.optional-dependencies]
33
+ dev = [
34
+ "pytest>=8",
35
+ "respx>=0.22",
36
+ "ruff>=0.6",
37
+ "graphql-core>=3.2",
38
+ "python-dotenv>=1.0",
39
+ "build",
40
+ "twine",
41
+ ]
42
+
43
+ [project.urls]
44
+ Homepage = "https://bibleql.org"
45
+ Documentation = "https://docs.bibleql.org"
46
+ Source = "https://github.com/lporras/bibleql-python"
47
+ Changelog = "https://github.com/lporras/bibleql-python/blob/main/CHANGELOG.md"
48
+
49
+ # Read the version from __version__ in _version.py (like version.rb)
50
+ [tool.hatch.version]
51
+ path = "src/bibleql/_version.py"
52
+
53
+ # Allowlist for the source archive (.tar.gz), so local files such as .env or
54
+ # editor/agent settings can never be published, whatever is in .gitignore.
55
+ [tool.hatch.build.targets.sdist]
56
+ include = [
57
+ "src/bibleql",
58
+ "tests",
59
+ "CHANGELOG.md",
60
+ "LICENSE",
61
+ "README.md",
62
+ "pyproject.toml",
63
+ ]
64
+
65
+ [tool.pytest.ini_options]
66
+ testpaths = ["tests"]
67
+
68
+ [tool.ruff]
69
+ line-length = 100
70
+ target-version = "py310"
71
+
72
+ [tool.ruff.lint]
73
+ # E/F = pycodestyle/pyflakes, I = import sorting, UP = modern syntax, B = common bugs
74
+ select = ["E", "F", "I", "UP", "B"]