astrocoins 2.0.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,6 @@
1
+ Metadata-Version: 2.4
2
+ Name: astrocoins
3
+ Version: 2.0.0
4
+ Summary: Client SDK for the AstroCoins economy API
5
+ Requires-Python: >=3.9
6
+ Requires-Dist: requests>=2.31
@@ -0,0 +1,21 @@
1
+ from .client import AstroCoinsClient
2
+ from .exceptions import (
3
+ AstroCoinsError,
4
+ ConfigurationError,
5
+ APIError,
6
+ InsufficientFundsError,
7
+ RateLimitError,
8
+ AuthenticationError,
9
+ )
10
+
11
+ __all__ = [
12
+ "AstroCoinsClient",
13
+ "AstroCoinsError",
14
+ "ConfigurationError",
15
+ "APIError",
16
+ "InsufficientFundsError",
17
+ "RateLimitError",
18
+ "AuthenticationError",
19
+ ]
20
+
21
+ __version__ = "2.0.0"
@@ -0,0 +1,92 @@
1
+ from __future__ import annotations
2
+
3
+ import os
4
+ from typing import Optional
5
+
6
+ import requests
7
+
8
+ from .exceptions import (
9
+ AuthenticationError,
10
+ ConfigurationError,
11
+ InsufficientFundsError,
12
+ RateLimitError,
13
+ APIError,
14
+ )
15
+
16
+ _ENV_API_KEY = "ASTROCOINS_API_KEY"
17
+ _ENV_BASE_URL = "ASTROCOINS_BASE_URL"
18
+
19
+ _DEFAULT_BASE_URL = "https://astrobot.adevs.site/api/coins"
20
+
21
+
22
+ class AstroCoinsClient:
23
+ def __init__(
24
+ self,
25
+ api_key: Optional[str] = None,
26
+ *,
27
+ base_url: Optional[str] = None,
28
+ timeout: float = 8.0,
29
+ ):
30
+ self.api_key = api_key or os.environ.get(_ENV_API_KEY)
31
+ if not self.api_key:
32
+ raise ConfigurationError(
33
+ "An API key is required: pass api_key=... or set the "
34
+ f"{_ENV_API_KEY} environment variable. You can get a key "
35
+ "from an AstroCoins administrator."
36
+ )
37
+ self.base_url = (base_url or os.environ.get(_ENV_BASE_URL) or _DEFAULT_BASE_URL).rstrip("/")
38
+ self._timeout = timeout
39
+ self._session = requests.Session()
40
+ self._session.headers.update({"X-API-Key": self.api_key})
41
+
42
+ def _request(self, method: str, path: str, **kwargs) -> dict:
43
+ try:
44
+ resp = self._session.request(
45
+ method, f"{self.base_url}{path}", timeout=self._timeout, **kwargs
46
+ )
47
+ except requests.RequestException as exc:
48
+ raise APIError(0, f"Could not connect to the AstroCoins server: {exc}") from exc
49
+
50
+ if resp.status_code == 401:
51
+ raise AuthenticationError("The API key is invalid or has been revoked.")
52
+ if resp.status_code == 429:
53
+ raise RateLimitError("Daily limit for this key has been exceeded.")
54
+ if resp.status_code == 400 and "user_id" in kwargs.get("json", {}):
55
+ body = self._safe_json(resp)
56
+ raise InsufficientFundsError(
57
+ kwargs["json"]["user_id"],
58
+ kwargs["json"].get("amount", 0),
59
+ body.get("current_balance", 0),
60
+ )
61
+ if not resp.ok:
62
+ body = self._safe_json(resp)
63
+ raise APIError(resp.status_code, body.get("detail", resp.text))
64
+
65
+ return self._safe_json(resp)
66
+
67
+ @staticmethod
68
+ def _safe_json(resp) -> dict:
69
+ try:
70
+ return resp.json()
71
+ except ValueError:
72
+ return {}
73
+
74
+ def get_balance(self, user_id: int) -> int:
75
+ data = self._request("GET", f"/balance/{int(user_id)}")
76
+ return int(data.get("balance", 0))
77
+
78
+ def add_coins(self, user_id: int, amount: int, reason: str = "") -> int:
79
+ data = self._request(
80
+ "POST",
81
+ "/add",
82
+ json={"user_id": int(user_id), "amount": int(amount), "reason": reason},
83
+ )
84
+ return int(data.get("balance", 0))
85
+
86
+ def remove_coins(self, user_id: int, amount: int, reason: str = "") -> int:
87
+ data = self._request(
88
+ "POST",
89
+ "/remove",
90
+ json={"user_id": int(user_id), "amount": int(amount), "reason": reason},
91
+ )
92
+ return int(data.get("balance", 0))
@@ -0,0 +1,32 @@
1
+ class AstroCoinsError(Exception):
2
+ pass
3
+
4
+
5
+ class ConfigurationError(AstroCoinsError):
6
+ pass
7
+
8
+
9
+ class AuthenticationError(AstroCoinsError):
10
+ pass
11
+
12
+
13
+ class InsufficientFundsError(AstroCoinsError):
14
+ def __init__(self, user_id: int, requested: int, available: int):
15
+ self.user_id = user_id
16
+ self.requested = requested
17
+ self.available = available
18
+ super().__init__(
19
+ f"User {user_id} has {available} coins, which is not enough "
20
+ f"to cover {requested}."
21
+ )
22
+
23
+
24
+ class RateLimitError(AstroCoinsError):
25
+ pass
26
+
27
+
28
+ class APIError(AstroCoinsError):
29
+ def __init__(self, status_code: int, detail: str):
30
+ self.status_code = status_code
31
+ self.detail = detail
32
+ super().__init__(f"AstroCoins API error ({status_code}): {detail}")
@@ -0,0 +1,6 @@
1
+ Metadata-Version: 2.4
2
+ Name: astrocoins
3
+ Version: 2.0.0
4
+ Summary: Client SDK for the AstroCoins economy API
5
+ Requires-Python: >=3.9
6
+ Requires-Dist: requests>=2.31
@@ -0,0 +1,9 @@
1
+ pyproject.toml
2
+ astrocoins/__init__.py
3
+ astrocoins/client.py
4
+ astrocoins/exceptions.py
5
+ astrocoins.egg-info/PKG-INFO
6
+ astrocoins.egg-info/SOURCES.txt
7
+ astrocoins.egg-info/dependency_links.txt
8
+ astrocoins.egg-info/requires.txt
9
+ astrocoins.egg-info/top_level.txt
@@ -0,0 +1 @@
1
+ requests>=2.31
@@ -0,0 +1 @@
1
+ astrocoins
@@ -0,0 +1,15 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "astrocoins"
7
+ version = "2.0.0"
8
+ description = "Client SDK for the AstroCoins economy API"
9
+ requires-python = ">=3.9"
10
+ dependencies = [
11
+ "requests>=2.31",
12
+ ]
13
+
14
+ [tool.setuptools]
15
+ packages = ["astrocoins"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+