a3rbly 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-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,124 @@
1
+ Metadata-Version: 2.4
2
+ Name: a3rbly
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
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
+ On Debian or Ubuntu, install into a virtual environment rather than the system Python:
37
+
38
+ ```bash
39
+ python3 -m venv .venv
40
+ source .venv/bin/activate
41
+ python -m pip install a3rbly
42
+ ```
43
+
44
+ ## Quick start
45
+
46
+ Pass the key to the client:
47
+
48
+ ```python
49
+ from a3rbly import A3rblyClient
50
+
51
+ client = A3rblyClient(api_key="YOUR_A3RBLY_API_KEY")
52
+
53
+ parsed = client.parse("قرأ الطالب الكتاب")
54
+ print(parsed)
55
+
56
+ vocalized = client.diacritize("قرأ الطالب الكتاب")
57
+ print(vocalized)
58
+ ```
59
+
60
+ Or set an environment variable so the key stays out of your source code:
61
+
62
+ ```bash
63
+ export A3RBLY_API_KEY="YOUR_A3RBLY_API_KEY"
64
+ ```
65
+
66
+ ```python
67
+ from a3rbly import A3rblyClient
68
+
69
+ client = A3rblyClient()
70
+ print(client.i3rab("قرأ الطالب الكتاب"))
71
+ ```
72
+
73
+ ## API methods
74
+
75
+ | Python method | HTTP request | Description |
76
+ | --- | --- | --- |
77
+ | `client.parse(sentence)` | `POST /i3rab` | Parses a sentence. Sends `{"prompt": "..."}`. |
78
+ | `client.i3rab(sentence)` | `POST /i3rab` | Alias for `parse`. |
79
+ | `client.diacritize(text)` | `GET /diacritize?text=...` | Adds diacritics to Arabic text. |
80
+
81
+ The base URL defaults to `https://api.a3rbly.com`. Each method returns the
82
+ decoded JSON response as a Python dictionary. The client sends the key in both
83
+ the `x-api-key` and `Authorization: Bearer ...` headers.
84
+
85
+ ## Errors
86
+
87
+ All client errors derive from `A3rblyError`:
88
+
89
+ - `A3rblyAuthenticationError` for HTTP 401 or 403
90
+ - `A3rblyRateLimitError` for HTTP 429
91
+ - `A3rblyAPIError` for other unsuccessful or malformed API responses
92
+ - `A3rblyConnectionError` when the API cannot be reached
93
+
94
+ ```python
95
+ from a3rbly import A3rblyAPIError, A3rblyClient
96
+
97
+ client = A3rblyClient() # Reads A3RBLY_API_KEY from the environment
98
+
99
+ try:
100
+ result = client.parse("الطالب مجتهد")
101
+ except A3rblyAPIError as error:
102
+ print(error.status_code, error.code, error)
103
+ ```
104
+
105
+ The request timeout defaults to 30 seconds and can be changed when creating
106
+ the client: `A3rblyClient(timeout=10)`.
107
+
108
+ ## Build for PyPI
109
+
110
+ From this directory, build the wheel and source archive with:
111
+
112
+ ```bash
113
+ python -m pip install build
114
+ python -m build
115
+ ```
116
+
117
+ Choose the package license and PyPI account credentials before publishing the
118
+ generated files in `dist/`.
119
+
120
+ ## API reference
121
+
122
+ The live API schema is available at
123
+ [api.a3rbly.com/openapi.json](https://api.a3rbly.com/openapi.json).
124
+
a3rbly-0.1.0/README.md ADDED
@@ -0,0 +1,101 @@
1
+ # a3rbly
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
+ On Debian or Ubuntu, install into a virtual environment rather than the system Python:
14
+
15
+ ```bash
16
+ python3 -m venv .venv
17
+ source .venv/bin/activate
18
+ python -m pip install a3rbly
19
+ ```
20
+
21
+ ## Quick start
22
+
23
+ Pass the key to the client:
24
+
25
+ ```python
26
+ from a3rbly import A3rblyClient
27
+
28
+ client = A3rblyClient(api_key="YOUR_A3RBLY_API_KEY")
29
+
30
+ parsed = client.parse("قرأ الطالب الكتاب")
31
+ print(parsed)
32
+
33
+ vocalized = client.diacritize("قرأ الطالب الكتاب")
34
+ print(vocalized)
35
+ ```
36
+
37
+ Or set an environment variable so the key stays out of your source code:
38
+
39
+ ```bash
40
+ export A3RBLY_API_KEY="YOUR_A3RBLY_API_KEY"
41
+ ```
42
+
43
+ ```python
44
+ from a3rbly import A3rblyClient
45
+
46
+ client = A3rblyClient()
47
+ print(client.i3rab("قرأ الطالب الكتاب"))
48
+ ```
49
+
50
+ ## API methods
51
+
52
+ | Python method | HTTP request | Description |
53
+ | --- | --- | --- |
54
+ | `client.parse(sentence)` | `POST /i3rab` | Parses a sentence. Sends `{"prompt": "..."}`. |
55
+ | `client.i3rab(sentence)` | `POST /i3rab` | Alias for `parse`. |
56
+ | `client.diacritize(text)` | `GET /diacritize?text=...` | Adds diacritics to Arabic text. |
57
+
58
+ The base URL defaults to `https://api.a3rbly.com`. Each method returns the
59
+ decoded JSON response as a Python dictionary. The client sends the key in both
60
+ the `x-api-key` and `Authorization: Bearer ...` headers.
61
+
62
+ ## Errors
63
+
64
+ All client errors derive from `A3rblyError`:
65
+
66
+ - `A3rblyAuthenticationError` for HTTP 401 or 403
67
+ - `A3rblyRateLimitError` for HTTP 429
68
+ - `A3rblyAPIError` for other unsuccessful or malformed API responses
69
+ - `A3rblyConnectionError` when the API cannot be reached
70
+
71
+ ```python
72
+ from a3rbly import A3rblyAPIError, A3rblyClient
73
+
74
+ client = A3rblyClient() # Reads A3RBLY_API_KEY from the environment
75
+
76
+ try:
77
+ result = client.parse("الطالب مجتهد")
78
+ except A3rblyAPIError as error:
79
+ print(error.status_code, error.code, error)
80
+ ```
81
+
82
+ The request timeout defaults to 30 seconds and can be changed when creating
83
+ the client: `A3rblyClient(timeout=10)`.
84
+
85
+ ## Build for PyPI
86
+
87
+ From this directory, build the wheel and source archive with:
88
+
89
+ ```bash
90
+ python -m pip install build
91
+ python -m build
92
+ ```
93
+
94
+ Choose the package license and PyPI account credentials before publishing the
95
+ generated files in `dist/`.
96
+
97
+ ## API reference
98
+
99
+ The live API schema is available at
100
+ [api.a3rbly.com/openapi.json](https://api.a3rbly.com/openapi.json).
101
+
@@ -0,0 +1,36 @@
1
+ [build-system]
2
+ requires = ["setuptools>=77", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "a3rbly"
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"]
a3rbly-0.1.0/setup.cfg ADDED
@@ -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-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,124 @@
1
+ Metadata-Version: 2.4
2
+ Name: a3rbly
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
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
+ On Debian or Ubuntu, install into a virtual environment rather than the system Python:
37
+
38
+ ```bash
39
+ python3 -m venv .venv
40
+ source .venv/bin/activate
41
+ python -m pip install a3rbly
42
+ ```
43
+
44
+ ## Quick start
45
+
46
+ Pass the key to the client:
47
+
48
+ ```python
49
+ from a3rbly import A3rblyClient
50
+
51
+ client = A3rblyClient(api_key="YOUR_A3RBLY_API_KEY")
52
+
53
+ parsed = client.parse("قرأ الطالب الكتاب")
54
+ print(parsed)
55
+
56
+ vocalized = client.diacritize("قرأ الطالب الكتاب")
57
+ print(vocalized)
58
+ ```
59
+
60
+ Or set an environment variable so the key stays out of your source code:
61
+
62
+ ```bash
63
+ export A3RBLY_API_KEY="YOUR_A3RBLY_API_KEY"
64
+ ```
65
+
66
+ ```python
67
+ from a3rbly import A3rblyClient
68
+
69
+ client = A3rblyClient()
70
+ print(client.i3rab("قرأ الطالب الكتاب"))
71
+ ```
72
+
73
+ ## API methods
74
+
75
+ | Python method | HTTP request | Description |
76
+ | --- | --- | --- |
77
+ | `client.parse(sentence)` | `POST /i3rab` | Parses a sentence. Sends `{"prompt": "..."}`. |
78
+ | `client.i3rab(sentence)` | `POST /i3rab` | Alias for `parse`. |
79
+ | `client.diacritize(text)` | `GET /diacritize?text=...` | Adds diacritics to Arabic text. |
80
+
81
+ The base URL defaults to `https://api.a3rbly.com`. Each method returns the
82
+ decoded JSON response as a Python dictionary. The client sends the key in both
83
+ the `x-api-key` and `Authorization: Bearer ...` headers.
84
+
85
+ ## Errors
86
+
87
+ All client errors derive from `A3rblyError`:
88
+
89
+ - `A3rblyAuthenticationError` for HTTP 401 or 403
90
+ - `A3rblyRateLimitError` for HTTP 429
91
+ - `A3rblyAPIError` for other unsuccessful or malformed API responses
92
+ - `A3rblyConnectionError` when the API cannot be reached
93
+
94
+ ```python
95
+ from a3rbly import A3rblyAPIError, A3rblyClient
96
+
97
+ client = A3rblyClient() # Reads A3RBLY_API_KEY from the environment
98
+
99
+ try:
100
+ result = client.parse("الطالب مجتهد")
101
+ except A3rblyAPIError as error:
102
+ print(error.status_code, error.code, error)
103
+ ```
104
+
105
+ The request timeout defaults to 30 seconds and can be changed when creating
106
+ the client: `A3rblyClient(timeout=10)`.
107
+
108
+ ## Build for PyPI
109
+
110
+ From this directory, build the wheel and source archive with:
111
+
112
+ ```bash
113
+ python -m pip install build
114
+ python -m build
115
+ ```
116
+
117
+ Choose the package license and PyPI account credentials before publishing the
118
+ generated files in `dist/`.
119
+
120
+ ## API reference
121
+
122
+ The live API schema is available at
123
+ [api.a3rbly.com/openapi.json](https://api.a3rbly.com/openapi.json).
124
+
@@ -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.egg-info/PKG-INFO
7
+ src/a3rbly.egg-info/SOURCES.txt
8
+ src/a3rbly.egg-info/dependency_links.txt
9
+ src/a3rbly.egg-info/top_level.txt
@@ -0,0 +1 @@
1
+ a3rbly