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.
@@ -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,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -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,9 @@
1
+ README.md
2
+ pyproject.toml
3
+ src/a3rbly/__init__.py
4
+ src/a3rbly/client.py
5
+ src/a3rbly/exceptions.py
6
+ src/a3rbly_api.egg-info/PKG-INFO
7
+ src/a3rbly_api.egg-info/SOURCES.txt
8
+ src/a3rbly_api.egg-info/dependency_links.txt
9
+ src/a3rbly_api.egg-info/top_level.txt