rowan-python 2.1.11__py3-none-any.whl

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.
rowan/user.py ADDED
@@ -0,0 +1,137 @@
1
+ from pydantic import BaseModel
2
+
3
+ from .utils import api_client
4
+
5
+
6
+ class Organization(BaseModel):
7
+ """
8
+ A Rowan organization
9
+
10
+ :ivar name: The name of the organization.
11
+ :ivar weekly_credits: The weekly credits of the organization.
12
+ :ivar credits: The credits of the organization.
13
+ """
14
+
15
+ name: str
16
+ weekly_credits: float | None = None
17
+ credits: float | None = None
18
+
19
+
20
+ class OrganizationRole(BaseModel):
21
+ """
22
+ A Rowan organization role
23
+
24
+ :ivar name: The name of the organization role.
25
+ """
26
+
27
+ name: str
28
+
29
+
30
+ class SubscriptionPlan(BaseModel):
31
+ """
32
+ A Rowan subscription plan
33
+
34
+ :ivar name: The name of the subscription plan.
35
+ """
36
+
37
+ name: str
38
+
39
+
40
+ class IndividualSubscription(BaseModel):
41
+ """
42
+ A Rowan individual subscription
43
+
44
+ :ivar subscription_plan: The subscription plan of the individual subscription.
45
+ """
46
+
47
+ subscription_plan: SubscriptionPlan
48
+
49
+
50
+ class User(BaseModel):
51
+ """
52
+ A Rowan user
53
+
54
+ :ivar uuid: The UUID of the user.
55
+ :ivar username: The username of the user.
56
+ :ivar email: The email of the user.
57
+ :ivar firstname: The first name of the user.
58
+ :ivar lastname: The last name of the user.
59
+ :ivar weekly_credits: The weekly credits of the user.
60
+ :ivar credits: The credits of the user.
61
+ :ivar billing_name: The billing name of the user.
62
+ :ivar billing_address: The billing address of the user.
63
+ :ivar credit_balance_warning: The credit balance warning of the user.
64
+ :ivar organization: The organization of the user.
65
+ :ivar organization_role: The organization role of the user.
66
+ :ivar individual_subscription: The individual subscription of the user.
67
+ """
68
+
69
+ uuid: str
70
+ username: str
71
+ email: str
72
+ firstname: str | None = None
73
+ lastname: str | None = None
74
+ weekly_credits: float | None = None
75
+ credits: float | None = None
76
+ billing_name: str | None = None
77
+ billing_address: str | None = None
78
+ credit_balance_warning: float | None = None
79
+ organization: Organization | None = None
80
+ organization_role: OrganizationRole | None = None
81
+ individual_subscription: IndividualSubscription | None = None
82
+
83
+ @property
84
+ def name(self) -> str:
85
+ return f"{self.firstname or ''} {self.lastname or ''}".strip()
86
+
87
+ @property
88
+ def organization_name(self) -> str | None:
89
+ return self.organization.name if self.organization else None
90
+
91
+ @property
92
+ def organization_weekly_credits(self) -> float | None:
93
+ return self.organization.weekly_credits if self.organization else None
94
+
95
+ @property
96
+ def organization_credits(self) -> float | None:
97
+ return self.organization.credits if self.organization else None
98
+
99
+ @property
100
+ def organization_role_name(self) -> str | None:
101
+ return self.organization_role.name if self.organization_role else None
102
+
103
+ @property
104
+ def subscription_plan_name(self) -> str | None:
105
+ return (
106
+ self.individual_subscription.subscription_plan.name
107
+ if self.individual_subscription
108
+ else None
109
+ )
110
+
111
+ def credits_available_string(self) -> str:
112
+ """
113
+ Returns a string showing available credits, including organization credits if applicable
114
+
115
+ :return: A string showing available credits
116
+ """
117
+ individual_credits = f"Weekly Credits: {self.weekly_credits}\nCredits: {self.credits}"
118
+ if self.organization is not None:
119
+ return (
120
+ individual_credits
121
+ + f"\nOrganization Weekly Credits: {self.organization_weekly_credits}\n"
122
+ f"Organization Credits: {self.organization_credits}"
123
+ )
124
+
125
+ return individual_credits
126
+
127
+
128
+ def whoami() -> User:
129
+ """
130
+ Returns the current user
131
+ """
132
+
133
+ with api_client() as client:
134
+ response = client.get("/user/me")
135
+ response.raise_for_status()
136
+
137
+ return User(**response.json())
rowan/utils.py ADDED
@@ -0,0 +1,174 @@
1
+ import os
2
+ from contextlib import contextmanager
3
+ from typing import Generator
4
+
5
+ import httpx
6
+ import stjames
7
+
8
+ import rowan
9
+
10
+ from .constants import API_URL
11
+
12
+
13
+ def get_api_key() -> str:
14
+ """
15
+ Get the API key from the environment variable ROWAN_API_KEY or the module-level attribute
16
+ rowan.api_key.
17
+
18
+ If neither of these are set, raise a ValueError with a helpful message.
19
+
20
+ :return: The API key.
21
+ """
22
+ if hasattr(rowan, "api_key") and rowan.api_key:
23
+ return rowan.api_key
24
+ elif (api_key := os.environ.get("ROWAN_API_KEY")) is not None:
25
+ return api_key
26
+
27
+ raise ValueError(
28
+ "No API key provided. You can set your API key using 'rowan.api_key = <API-KEY>',"
29
+ + " or you can set the environment variable ROWAN_API_KEY=<API-KEY>)."
30
+ )
31
+
32
+
33
+ def smiles_to_stjames(smiles: str) -> stjames.Molecule:
34
+ """
35
+ Convert a SMILES string to a `stjames.Molecule` object.
36
+
37
+ :param smiles: A string representing the SMILES notation of the molecule.
38
+ :return: A `stjames.Molecule` object created from the given SMILES string.
39
+ """
40
+
41
+ return stjames.Molecule.from_smiles(smiles)
42
+
43
+
44
+ @contextmanager
45
+ def api_client() -> Generator[httpx.Client, None, None]:
46
+ """Wraps `httpx.Client` with Rowan-specific kwargs."""
47
+ with httpx.Client(
48
+ base_url=API_URL,
49
+ headers={"X-API-Key": get_api_key()},
50
+ timeout=30,
51
+ ) as client:
52
+ yield client
53
+
54
+
55
+ ATOMIC_NUMBER_TO_ATOMIC_SYMBOL = {
56
+ "1": "H",
57
+ "2": "He",
58
+ "3": "Li",
59
+ "4": "Be",
60
+ "5": "B",
61
+ "6": "C",
62
+ "7": "N",
63
+ "8": "O",
64
+ "9": "F",
65
+ "10": "Ne",
66
+ "11": "Na",
67
+ "12": "Mg",
68
+ "13": "Al",
69
+ "14": "Si",
70
+ "15": "P",
71
+ "16": "S",
72
+ "17": "Cl",
73
+ "18": "Ar",
74
+ "19": "K",
75
+ "20": "Ca",
76
+ "21": "Sc",
77
+ "22": "Ti",
78
+ "23": "V",
79
+ "24": "Cr",
80
+ "25": "Mn",
81
+ "26": "Fe",
82
+ "27": "Co",
83
+ "28": "Ni",
84
+ "29": "Cu",
85
+ "30": "Zn",
86
+ "31": "Ga",
87
+ "32": "Ge",
88
+ "33": "As",
89
+ "34": "Se",
90
+ "35": "Br",
91
+ "36": "Kr",
92
+ "37": "Rb",
93
+ "38": "Sr",
94
+ "39": "Y",
95
+ "40": "Zr",
96
+ "41": "Nb",
97
+ "42": "Mo",
98
+ "43": "Tc",
99
+ "44": "Ru",
100
+ "45": "Rh",
101
+ "46": "Pd",
102
+ "47": "Ag",
103
+ "48": "Cd",
104
+ "49": "In",
105
+ "50": "Sn",
106
+ "51": "Sb",
107
+ "52": "Te",
108
+ "53": "I",
109
+ "54": "Xe",
110
+ "55": "Cs",
111
+ "56": "Ba",
112
+ "57": "La",
113
+ "58": "Ce",
114
+ "59": "Pr",
115
+ "60": "Nd",
116
+ "61": "Pm",
117
+ "62": "Sm",
118
+ "63": "Eu",
119
+ "64": "Gd",
120
+ "65": "Tb",
121
+ "66": "Dy",
122
+ "67": "Ho",
123
+ "68": "Er",
124
+ "69": "Tm",
125
+ "70": "Yb",
126
+ "71": "Lu",
127
+ "72": "Hf",
128
+ "73": "Ta",
129
+ "74": "W",
130
+ "75": "Re",
131
+ "76": "Os",
132
+ "77": "Ir",
133
+ "78": "Pt",
134
+ "79": "Au",
135
+ "80": "Hg",
136
+ "81": "Tl",
137
+ "82": "Pb",
138
+ "83": "Bi",
139
+ "84": "Po",
140
+ "85": "At",
141
+ "86": "Rn",
142
+ "87": "Fr",
143
+ "88": "Ra",
144
+ "89": "Ac",
145
+ "90": "Th",
146
+ "91": "Pa",
147
+ "92": "U",
148
+ "93": "Np",
149
+ "94": "Pu",
150
+ "95": "Am",
151
+ "96": "Cm",
152
+ "97": "Bk",
153
+ "98": "Cf",
154
+ "99": "Es",
155
+ "100": "Fm",
156
+ "101": "Md",
157
+ "102": "No",
158
+ "103": "Lr",
159
+ "104": "Rf",
160
+ "105": "Db",
161
+ "106": "Sg",
162
+ "107": "Bh",
163
+ "108": "Hs",
164
+ "109": "Mt",
165
+ "110": "Ds",
166
+ "111": "Rg",
167
+ "112": "Cn",
168
+ "113": "Nh",
169
+ "114": "Fl",
170
+ "115": "Mc",
171
+ "116": "Lv",
172
+ "117": "Ts",
173
+ "118": "Og",
174
+ }