a3rbly-api 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.
- a3rbly_api-0.1.0/PKG-INFO +120 -0
- a3rbly_api-0.1.0/README.md +97 -0
- a3rbly_api-0.1.0/pyproject.toml +36 -0
- a3rbly_api-0.1.0/setup.cfg +4 -0
- a3rbly_api-0.1.0/src/a3rbly/__init__.py +21 -0
- a3rbly_api-0.1.0/src/a3rbly/client.py +164 -0
- a3rbly_api-0.1.0/src/a3rbly/exceptions.py +38 -0
- a3rbly_api-0.1.0/src/a3rbly_api.egg-info/PKG-INFO +120 -0
- a3rbly_api-0.1.0/src/a3rbly_api.egg-info/SOURCES.txt +9 -0
- a3rbly_api-0.1.0/src/a3rbly_api.egg-info/dependency_links.txt +1 -0
- a3rbly_api-0.1.0/src/a3rbly_api.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: a3rbly-api
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python client for the A3rbly Arabic grammar and diacritization API
|
|
5
|
+
Project-URL: Homepage, https://a3rbly.com
|
|
6
|
+
Project-URL: API, https://api.a3rbly.com
|
|
7
|
+
Project-URL: Documentation, https://api.a3rbly.com/openapi.json
|
|
8
|
+
Keywords: a3rbly,arabic,i3rab,diacritization,api
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Topic :: Internet :: WWW/HTTP
|
|
20
|
+
Classifier: Topic :: Text Processing :: Linguistic
|
|
21
|
+
Requires-Python: >=3.9
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
|
|
24
|
+
# a3rbly-api
|
|
25
|
+
|
|
26
|
+
A small Python client for the A3rbly Arabic grammar parsing and diacritization API.
|
|
27
|
+
It uses the standard library and works with Python 3.9 and newer.
|
|
28
|
+
|
|
29
|
+
## Get an API key
|
|
30
|
+
|
|
31
|
+
Get your API key from [a3rbly.com](https://a3rbly.com). Keep it private; do not
|
|
32
|
+
commit it to source control or place it in client-side code.
|
|
33
|
+
|
|
34
|
+
## Install
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
pip install a3rbly-api
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Quick start
|
|
41
|
+
|
|
42
|
+
Pass the key to the client:
|
|
43
|
+
|
|
44
|
+
```python
|
|
45
|
+
from a3rbly import A3rblyClient
|
|
46
|
+
|
|
47
|
+
client = A3rblyClient(api_key="YOUR_A3RBLY_API_KEY")
|
|
48
|
+
|
|
49
|
+
parsed = client.parse("قرأ الطالب الكتاب")
|
|
50
|
+
print(parsed)
|
|
51
|
+
|
|
52
|
+
vocalized = client.diacritize("قرأ الطالب الكتاب")
|
|
53
|
+
print(vocalized)
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Or set an environment variable so the key stays out of your source code:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
export A3RBLY_API_KEY="YOUR_A3RBLY_API_KEY"
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
from a3rbly import A3rblyClient
|
|
64
|
+
|
|
65
|
+
client = A3rblyClient()
|
|
66
|
+
print(client.i3rab("قرأ الطالب الكتاب"))
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## API methods
|
|
70
|
+
|
|
71
|
+
| Python method | HTTP request | Description |
|
|
72
|
+
| --- | --- | --- |
|
|
73
|
+
| `client.parse(sentence)` | `POST /i3rab` | Parses a sentence. Sends `{"prompt": "..."}`. |
|
|
74
|
+
| `client.i3rab(sentence)` | `POST /i3rab` | Alias for `parse`. |
|
|
75
|
+
| `client.diacritize(text)` | `GET /diacritize?text=...` | Adds diacritics to Arabic text. |
|
|
76
|
+
|
|
77
|
+
The base URL defaults to `https://api.a3rbly.com`. Each method returns the
|
|
78
|
+
decoded JSON response as a Python dictionary. The client sends the key in both
|
|
79
|
+
the `x-api-key` and `Authorization: Bearer ...` headers.
|
|
80
|
+
|
|
81
|
+
## Errors
|
|
82
|
+
|
|
83
|
+
All client errors derive from `A3rblyError`:
|
|
84
|
+
|
|
85
|
+
- `A3rblyAuthenticationError` for HTTP 401 or 403
|
|
86
|
+
- `A3rblyRateLimitError` for HTTP 429
|
|
87
|
+
- `A3rblyAPIError` for other unsuccessful or malformed API responses
|
|
88
|
+
- `A3rblyConnectionError` when the API cannot be reached
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
from a3rbly import A3rblyAPIError, A3rblyClient
|
|
92
|
+
|
|
93
|
+
client = A3rblyClient() # Reads A3RBLY_API_KEY from the environment
|
|
94
|
+
|
|
95
|
+
try:
|
|
96
|
+
result = client.parse("الطالب مجتهد")
|
|
97
|
+
except A3rblyAPIError as error:
|
|
98
|
+
print(error.status_code, error.code, error)
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
The request timeout defaults to 30 seconds and can be changed when creating
|
|
102
|
+
the client: `A3rblyClient(timeout=10)`.
|
|
103
|
+
|
|
104
|
+
## Build for PyPI
|
|
105
|
+
|
|
106
|
+
From this directory, build the wheel and source archive with:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
python -m pip install build
|
|
110
|
+
python -m build
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Choose the package license and PyPI account credentials before publishing the
|
|
114
|
+
generated files in `dist/`.
|
|
115
|
+
|
|
116
|
+
## API reference
|
|
117
|
+
|
|
118
|
+
The live API schema is available at
|
|
119
|
+
[api.a3rbly.com/openapi.json](https://api.a3rbly.com/openapi.json).
|
|
120
|
+
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# a3rbly-api
|
|
2
|
+
|
|
3
|
+
A small Python client for the A3rbly Arabic grammar parsing and diacritization API.
|
|
4
|
+
It uses the standard library and works with Python 3.9 and newer.
|
|
5
|
+
|
|
6
|
+
## Get an API key
|
|
7
|
+
|
|
8
|
+
Get your API key from [a3rbly.com](https://a3rbly.com). Keep it private; do not
|
|
9
|
+
commit it to source control or place it in client-side code.
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pip install a3rbly-api
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Quick start
|
|
18
|
+
|
|
19
|
+
Pass the key to the client:
|
|
20
|
+
|
|
21
|
+
```python
|
|
22
|
+
from a3rbly import A3rblyClient
|
|
23
|
+
|
|
24
|
+
client = A3rblyClient(api_key="YOUR_A3RBLY_API_KEY")
|
|
25
|
+
|
|
26
|
+
parsed = client.parse("قرأ الطالب الكتاب")
|
|
27
|
+
print(parsed)
|
|
28
|
+
|
|
29
|
+
vocalized = client.diacritize("قرأ الطالب الكتاب")
|
|
30
|
+
print(vocalized)
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Or set an environment variable so the key stays out of your source code:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
export A3RBLY_API_KEY="YOUR_A3RBLY_API_KEY"
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
```python
|
|
40
|
+
from a3rbly import A3rblyClient
|
|
41
|
+
|
|
42
|
+
client = A3rblyClient()
|
|
43
|
+
print(client.i3rab("قرأ الطالب الكتاب"))
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## API methods
|
|
47
|
+
|
|
48
|
+
| Python method | HTTP request | Description |
|
|
49
|
+
| --- | --- | --- |
|
|
50
|
+
| `client.parse(sentence)` | `POST /i3rab` | Parses a sentence. Sends `{"prompt": "..."}`. |
|
|
51
|
+
| `client.i3rab(sentence)` | `POST /i3rab` | Alias for `parse`. |
|
|
52
|
+
| `client.diacritize(text)` | `GET /diacritize?text=...` | Adds diacritics to Arabic text. |
|
|
53
|
+
|
|
54
|
+
The base URL defaults to `https://api.a3rbly.com`. Each method returns the
|
|
55
|
+
decoded JSON response as a Python dictionary. The client sends the key in both
|
|
56
|
+
the `x-api-key` and `Authorization: Bearer ...` headers.
|
|
57
|
+
|
|
58
|
+
## Errors
|
|
59
|
+
|
|
60
|
+
All client errors derive from `A3rblyError`:
|
|
61
|
+
|
|
62
|
+
- `A3rblyAuthenticationError` for HTTP 401 or 403
|
|
63
|
+
- `A3rblyRateLimitError` for HTTP 429
|
|
64
|
+
- `A3rblyAPIError` for other unsuccessful or malformed API responses
|
|
65
|
+
- `A3rblyConnectionError` when the API cannot be reached
|
|
66
|
+
|
|
67
|
+
```python
|
|
68
|
+
from a3rbly import A3rblyAPIError, A3rblyClient
|
|
69
|
+
|
|
70
|
+
client = A3rblyClient() # Reads A3RBLY_API_KEY from the environment
|
|
71
|
+
|
|
72
|
+
try:
|
|
73
|
+
result = client.parse("الطالب مجتهد")
|
|
74
|
+
except A3rblyAPIError as error:
|
|
75
|
+
print(error.status_code, error.code, error)
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
The request timeout defaults to 30 seconds and can be changed when creating
|
|
79
|
+
the client: `A3rblyClient(timeout=10)`.
|
|
80
|
+
|
|
81
|
+
## Build for PyPI
|
|
82
|
+
|
|
83
|
+
From this directory, build the wheel and source archive with:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
python -m pip install build
|
|
87
|
+
python -m build
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Choose the package license and PyPI account credentials before publishing the
|
|
91
|
+
generated files in `dist/`.
|
|
92
|
+
|
|
93
|
+
## API reference
|
|
94
|
+
|
|
95
|
+
The live API schema is available at
|
|
96
|
+
[api.a3rbly.com/openapi.json](https://api.a3rbly.com/openapi.json).
|
|
97
|
+
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=77", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "a3rbly-api"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Python client for the A3rbly Arabic grammar and diacritization API"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
keywords = ["a3rbly", "arabic", "i3rab", "diacritization", "api"]
|
|
12
|
+
classifiers = [
|
|
13
|
+
"Development Status :: 3 - Alpha",
|
|
14
|
+
"Intended Audience :: Developers",
|
|
15
|
+
"Operating System :: OS Independent",
|
|
16
|
+
"Programming Language :: Python :: 3",
|
|
17
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
18
|
+
"Programming Language :: Python :: 3.9",
|
|
19
|
+
"Programming Language :: Python :: 3.10",
|
|
20
|
+
"Programming Language :: Python :: 3.11",
|
|
21
|
+
"Programming Language :: Python :: 3.12",
|
|
22
|
+
"Programming Language :: Python :: 3.13",
|
|
23
|
+
"Topic :: Internet :: WWW/HTTP",
|
|
24
|
+
"Topic :: Text Processing :: Linguistic",
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
[project.urls]
|
|
28
|
+
Homepage = "https://a3rbly.com"
|
|
29
|
+
API = "https://api.a3rbly.com"
|
|
30
|
+
Documentation = "https://api.a3rbly.com/openapi.json"
|
|
31
|
+
|
|
32
|
+
[tool.setuptools]
|
|
33
|
+
package-dir = { "" = "src" }
|
|
34
|
+
|
|
35
|
+
[tool.setuptools.packages.find]
|
|
36
|
+
where = ["src"]
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""Python client for the A3rbly Arabic language API."""
|
|
2
|
+
|
|
3
|
+
from .client import A3rblyClient
|
|
4
|
+
from .exceptions import (
|
|
5
|
+
A3rblyAPIError,
|
|
6
|
+
A3rblyAuthenticationError,
|
|
7
|
+
A3rblyConnectionError,
|
|
8
|
+
A3rblyError,
|
|
9
|
+
A3rblyRateLimitError,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"A3rblyClient",
|
|
14
|
+
"A3rblyError",
|
|
15
|
+
"A3rblyAPIError",
|
|
16
|
+
"A3rblyAuthenticationError",
|
|
17
|
+
"A3rblyRateLimitError",
|
|
18
|
+
"A3rblyConnectionError",
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
__version__ = "0.1.0"
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
"""Synchronous HTTP client for the A3rbly API."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import os
|
|
7
|
+
from typing import Any
|
|
8
|
+
from urllib.error import HTTPError, URLError
|
|
9
|
+
from urllib.parse import urlencode
|
|
10
|
+
from urllib.request import Request, urlopen
|
|
11
|
+
|
|
12
|
+
from .exceptions import (
|
|
13
|
+
A3rblyAPIError,
|
|
14
|
+
A3rblyAuthenticationError,
|
|
15
|
+
A3rblyConnectionError,
|
|
16
|
+
A3rblyRateLimitError,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class A3rblyClient:
|
|
21
|
+
"""Call A3rbly's Arabic grammar and diacritization endpoints.
|
|
22
|
+
|
|
23
|
+
Pass ``api_key`` directly, or set the ``A3RBLY_API_KEY`` environment
|
|
24
|
+
variable. The client never contains a built-in API key.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
API_KEY_URL = "https://a3rbly.com"
|
|
28
|
+
DEFAULT_BASE_URL = "https://api.a3rbly.com"
|
|
29
|
+
|
|
30
|
+
def __init__(
|
|
31
|
+
self,
|
|
32
|
+
api_key: str | None = None,
|
|
33
|
+
*,
|
|
34
|
+
base_url: str = DEFAULT_BASE_URL,
|
|
35
|
+
timeout: float = 30.0,
|
|
36
|
+
) -> None:
|
|
37
|
+
key = api_key or os.getenv("A3RBLY_API_KEY")
|
|
38
|
+
if not key or not key.strip():
|
|
39
|
+
raise ValueError(
|
|
40
|
+
"An A3rbly API key is required. Get one at "
|
|
41
|
+
f"{self.API_KEY_URL} or set the A3RBLY_API_KEY environment variable."
|
|
42
|
+
)
|
|
43
|
+
if timeout <= 0:
|
|
44
|
+
raise ValueError("timeout must be greater than zero")
|
|
45
|
+
|
|
46
|
+
self._api_key = key.strip()
|
|
47
|
+
self.base_url = base_url.rstrip("/")
|
|
48
|
+
self.timeout = timeout
|
|
49
|
+
|
|
50
|
+
def parse(self, sentence: str) -> dict[str, Any]:
|
|
51
|
+
"""Parse an Arabic sentence with ``POST /i3rab``.
|
|
52
|
+
|
|
53
|
+
Returns the decoded JSON object from the API. The API commonly
|
|
54
|
+
returns parsed words under ``data.words``.
|
|
55
|
+
"""
|
|
56
|
+
sentence = self._validate_text(sentence, "sentence")
|
|
57
|
+
return self._request(
|
|
58
|
+
"POST",
|
|
59
|
+
"/i3rab",
|
|
60
|
+
payload={"prompt": sentence},
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
def i3rab(self, sentence: str) -> dict[str, Any]:
|
|
64
|
+
"""Alias for :meth:`parse`."""
|
|
65
|
+
return self.parse(sentence)
|
|
66
|
+
|
|
67
|
+
def diacritize(self, text: str) -> dict[str, Any]:
|
|
68
|
+
"""Add Arabic diacritics with ``GET /diacritize``.
|
|
69
|
+
|
|
70
|
+
Returns the decoded JSON object from the API. Depending on the
|
|
71
|
+
response, the resulting text may be in ``diacritized_text``,
|
|
72
|
+
``result``, or ``text``.
|
|
73
|
+
"""
|
|
74
|
+
text = self._validate_text(text, "text")
|
|
75
|
+
return self._request("GET", "/diacritize", query={"text": text})
|
|
76
|
+
|
|
77
|
+
@staticmethod
|
|
78
|
+
def _validate_text(value: str, field: str) -> str:
|
|
79
|
+
if not isinstance(value, str) or not value.strip():
|
|
80
|
+
raise ValueError(f"{field} must be a non-empty string")
|
|
81
|
+
return value.strip()
|
|
82
|
+
|
|
83
|
+
def _request(
|
|
84
|
+
self,
|
|
85
|
+
method: str,
|
|
86
|
+
path: str,
|
|
87
|
+
*,
|
|
88
|
+
payload: dict[str, Any] | None = None,
|
|
89
|
+
query: dict[str, str] | None = None,
|
|
90
|
+
) -> dict[str, Any]:
|
|
91
|
+
url = f"{self.base_url}{path}"
|
|
92
|
+
if query:
|
|
93
|
+
url = f"{url}?{urlencode(query)}"
|
|
94
|
+
|
|
95
|
+
headers = {
|
|
96
|
+
"Accept": "application/json",
|
|
97
|
+
"x-api-key": self._api_key,
|
|
98
|
+
"Authorization": f"Bearer {self._api_key}",
|
|
99
|
+
"User-Agent": "a3rbly-api-python/0.1.0",
|
|
100
|
+
}
|
|
101
|
+
body = None
|
|
102
|
+
if payload is not None:
|
|
103
|
+
body = json.dumps(payload, ensure_ascii=False).encode("utf-8")
|
|
104
|
+
headers["Content-Type"] = "application/json"
|
|
105
|
+
|
|
106
|
+
request = Request(url, data=body, headers=headers, method=method)
|
|
107
|
+
|
|
108
|
+
try:
|
|
109
|
+
with urlopen(request, timeout=self.timeout) as response:
|
|
110
|
+
raw_body = response.read()
|
|
111
|
+
status_code = response.status
|
|
112
|
+
except HTTPError as error:
|
|
113
|
+
raw_body = error.read()
|
|
114
|
+
raise self._api_exception(error.code, raw_body) from None
|
|
115
|
+
except (URLError, TimeoutError, OSError) as error:
|
|
116
|
+
reason = getattr(error, "reason", error)
|
|
117
|
+
raise A3rblyConnectionError(
|
|
118
|
+
f"Could not connect to {self.base_url}: {reason}"
|
|
119
|
+
) from error
|
|
120
|
+
|
|
121
|
+
try:
|
|
122
|
+
decoded = json.loads(raw_body.decode("utf-8"))
|
|
123
|
+
except (UnicodeDecodeError, json.JSONDecodeError) as error:
|
|
124
|
+
raise A3rblyAPIError(
|
|
125
|
+
status_code,
|
|
126
|
+
"A3rbly returned a response that was not valid JSON.",
|
|
127
|
+
) from error
|
|
128
|
+
|
|
129
|
+
if not isinstance(decoded, dict):
|
|
130
|
+
raise A3rblyAPIError(
|
|
131
|
+
status_code,
|
|
132
|
+
"A3rbly returned JSON in an unexpected format.",
|
|
133
|
+
)
|
|
134
|
+
return decoded
|
|
135
|
+
|
|
136
|
+
@staticmethod
|
|
137
|
+
def _api_exception(status_code: int, raw_body: bytes) -> A3rblyAPIError:
|
|
138
|
+
try:
|
|
139
|
+
response = json.loads(raw_body.decode("utf-8"))
|
|
140
|
+
except (UnicodeDecodeError, json.JSONDecodeError):
|
|
141
|
+
response = {}
|
|
142
|
+
if not isinstance(response, dict):
|
|
143
|
+
response = {}
|
|
144
|
+
|
|
145
|
+
message = (
|
|
146
|
+
response.get("detail")
|
|
147
|
+
or response.get("error")
|
|
148
|
+
or response.get("title")
|
|
149
|
+
or f"A3rbly API request failed with HTTP {status_code}."
|
|
150
|
+
)
|
|
151
|
+
code = response.get("code")
|
|
152
|
+
|
|
153
|
+
error_type = A3rblyAPIError
|
|
154
|
+
if status_code in (401, 403):
|
|
155
|
+
error_type = A3rblyAuthenticationError
|
|
156
|
+
elif status_code == 429:
|
|
157
|
+
error_type = A3rblyRateLimitError
|
|
158
|
+
|
|
159
|
+
return error_type(
|
|
160
|
+
status_code,
|
|
161
|
+
str(message),
|
|
162
|
+
code=str(code) if code is not None else None,
|
|
163
|
+
response=response,
|
|
164
|
+
)
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"""Exceptions raised by the A3rbly client."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any, Mapping
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class A3rblyError(Exception):
|
|
9
|
+
"""Base exception for errors raised by this package."""
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class A3rblyAPIError(A3rblyError):
|
|
13
|
+
"""An unsuccessful response returned by the A3rbly API."""
|
|
14
|
+
|
|
15
|
+
def __init__(
|
|
16
|
+
self,
|
|
17
|
+
status_code: int,
|
|
18
|
+
message: str,
|
|
19
|
+
*,
|
|
20
|
+
code: str | None = None,
|
|
21
|
+
response: Mapping[str, Any] | None = None,
|
|
22
|
+
) -> None:
|
|
23
|
+
self.status_code = status_code
|
|
24
|
+
self.code = code
|
|
25
|
+
self.response = dict(response or {})
|
|
26
|
+
super().__init__(message)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class A3rblyAuthenticationError(A3rblyAPIError):
|
|
30
|
+
"""The API key is missing, invalid, or not authorized."""
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class A3rblyRateLimitError(A3rblyAPIError):
|
|
34
|
+
"""The API rejected a request because a usage limit was reached."""
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class A3rblyConnectionError(A3rblyError):
|
|
38
|
+
"""The client could not connect to the A3rbly API."""
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: a3rbly-api
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python client for the A3rbly Arabic grammar and diacritization API
|
|
5
|
+
Project-URL: Homepage, https://a3rbly.com
|
|
6
|
+
Project-URL: API, https://api.a3rbly.com
|
|
7
|
+
Project-URL: Documentation, https://api.a3rbly.com/openapi.json
|
|
8
|
+
Keywords: a3rbly,arabic,i3rab,diacritization,api
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Topic :: Internet :: WWW/HTTP
|
|
20
|
+
Classifier: Topic :: Text Processing :: Linguistic
|
|
21
|
+
Requires-Python: >=3.9
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
|
|
24
|
+
# a3rbly-api
|
|
25
|
+
|
|
26
|
+
A small Python client for the A3rbly Arabic grammar parsing and diacritization API.
|
|
27
|
+
It uses the standard library and works with Python 3.9 and newer.
|
|
28
|
+
|
|
29
|
+
## Get an API key
|
|
30
|
+
|
|
31
|
+
Get your API key from [a3rbly.com](https://a3rbly.com). Keep it private; do not
|
|
32
|
+
commit it to source control or place it in client-side code.
|
|
33
|
+
|
|
34
|
+
## Install
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
pip install a3rbly-api
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Quick start
|
|
41
|
+
|
|
42
|
+
Pass the key to the client:
|
|
43
|
+
|
|
44
|
+
```python
|
|
45
|
+
from a3rbly import A3rblyClient
|
|
46
|
+
|
|
47
|
+
client = A3rblyClient(api_key="YOUR_A3RBLY_API_KEY")
|
|
48
|
+
|
|
49
|
+
parsed = client.parse("قرأ الطالب الكتاب")
|
|
50
|
+
print(parsed)
|
|
51
|
+
|
|
52
|
+
vocalized = client.diacritize("قرأ الطالب الكتاب")
|
|
53
|
+
print(vocalized)
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Or set an environment variable so the key stays out of your source code:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
export A3RBLY_API_KEY="YOUR_A3RBLY_API_KEY"
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
from a3rbly import A3rblyClient
|
|
64
|
+
|
|
65
|
+
client = A3rblyClient()
|
|
66
|
+
print(client.i3rab("قرأ الطالب الكتاب"))
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## API methods
|
|
70
|
+
|
|
71
|
+
| Python method | HTTP request | Description |
|
|
72
|
+
| --- | --- | --- |
|
|
73
|
+
| `client.parse(sentence)` | `POST /i3rab` | Parses a sentence. Sends `{"prompt": "..."}`. |
|
|
74
|
+
| `client.i3rab(sentence)` | `POST /i3rab` | Alias for `parse`. |
|
|
75
|
+
| `client.diacritize(text)` | `GET /diacritize?text=...` | Adds diacritics to Arabic text. |
|
|
76
|
+
|
|
77
|
+
The base URL defaults to `https://api.a3rbly.com`. Each method returns the
|
|
78
|
+
decoded JSON response as a Python dictionary. The client sends the key in both
|
|
79
|
+
the `x-api-key` and `Authorization: Bearer ...` headers.
|
|
80
|
+
|
|
81
|
+
## Errors
|
|
82
|
+
|
|
83
|
+
All client errors derive from `A3rblyError`:
|
|
84
|
+
|
|
85
|
+
- `A3rblyAuthenticationError` for HTTP 401 or 403
|
|
86
|
+
- `A3rblyRateLimitError` for HTTP 429
|
|
87
|
+
- `A3rblyAPIError` for other unsuccessful or malformed API responses
|
|
88
|
+
- `A3rblyConnectionError` when the API cannot be reached
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
from a3rbly import A3rblyAPIError, A3rblyClient
|
|
92
|
+
|
|
93
|
+
client = A3rblyClient() # Reads A3RBLY_API_KEY from the environment
|
|
94
|
+
|
|
95
|
+
try:
|
|
96
|
+
result = client.parse("الطالب مجتهد")
|
|
97
|
+
except A3rblyAPIError as error:
|
|
98
|
+
print(error.status_code, error.code, error)
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
The request timeout defaults to 30 seconds and can be changed when creating
|
|
102
|
+
the client: `A3rblyClient(timeout=10)`.
|
|
103
|
+
|
|
104
|
+
## Build for PyPI
|
|
105
|
+
|
|
106
|
+
From this directory, build the wheel and source archive with:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
python -m pip install build
|
|
110
|
+
python -m build
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Choose the package license and PyPI account credentials before publishing the
|
|
114
|
+
generated files in `dist/`.
|
|
115
|
+
|
|
116
|
+
## API reference
|
|
117
|
+
|
|
118
|
+
The live API schema is available at
|
|
119
|
+
[api.a3rbly.com/openapi.json](https://api.a3rbly.com/openapi.json).
|
|
120
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
a3rbly
|