uaregistry 1.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,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 UARegistry
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,235 @@
1
+ Metadata-Version: 2.4
2
+ Name: uaregistry
3
+ Version: 1.0.0
4
+ Summary: Dependency-free Python client for the UARegistry EPP service (RFC 5730-5734 over TLS).
5
+ Author: UARegistry
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/uaregistry/python-sdk
8
+ Project-URL: Repository, https://github.com/uaregistry/python-sdk
9
+ Project-URL: Issues, https://github.com/uaregistry/python-sdk/issues
10
+ Keywords: epp,registry,domains,rfc5730,uaregistry
11
+ Classifier: Development Status :: 5 - Production/Stable
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.8
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Topic :: Internet :: Name Service (DNS)
22
+ Requires-Python: >=3.8
23
+ Description-Content-Type: text/markdown
24
+ License-File: LICENSE
25
+ Dynamic: license-file
26
+
27
+ # UARegistry EPP SDK (Python)
28
+
29
+ A small, **dependency-free** Python client for the **UARegistry** EPP service — standard
30
+ **RFC 5730–5734** EPP over **TLS on port 700**. It speaks the wire protocol directly
31
+ (no framework, no server-side code), so you can drop it into any Python 3.8+ project.
32
+ Every command frame is standard, schema-valid EPP.
33
+
34
+ - TLS transport with correct RFC 5734 framing (4-byte length prefix, UTF-8 byte-safe).
35
+ - Session: `connect` / `login` / `logout`, with the login services taken from the server
36
+ greeting automatically (never rejected for an unsupported service).
37
+ - Full object commands: **domain**, **contact**, **host** (check / info / create / update /
38
+ delete / transfer / renew), plus **poll** and **balance**.
39
+ - Extensions: **secDNS** (RFC 5910), **RGP restore** (RFC 3915), and the UARegistry native
40
+ **.ua trademark licence**.
41
+ - Clean `Response` objects (result code, message, availability map, value getters) and typed
42
+ exceptions.
43
+
44
+ ## Install
45
+
46
+ ```bash
47
+ pip install git+https://github.com/uaregistry/python-sdk
48
+ ```
49
+
50
+ Or pin a released tag:
51
+
52
+ ```bash
53
+ pip install "uaregistry @ git+https://github.com/uaregistry/python-sdk@v1.0.0"
54
+ ```
55
+
56
+ No packaging at all? Copy the `uaregistry/` package folder next to your code and
57
+ `import uaregistry`. The SDK requires only the Python standard library
58
+ (`ssl`, `socket`, `xml.etree`).
59
+
60
+ ## Quick start
61
+
62
+ ```python
63
+ from uaregistry import Client, Config
64
+ from uaregistry.exceptions import EppException
65
+
66
+ client = Client(Config(
67
+ host="uaregistry.com",
68
+ clid="UAR0001",
69
+ password="your-secret",
70
+ port=700, # default; override only if the endpoint moves
71
+ lang="uk", # localized result messages: en | uk | ua | ru
72
+ # ca_file="/path/to/ca.pem", # for a private-CA / self-signed endpoint
73
+ ))
74
+
75
+ try:
76
+ client.connect() # TLS + read <greeting>
77
+ client.login()
78
+
79
+ avail = client.domain.check(["example.com.ua"]).availability()
80
+ # => {"example.com.ua": True}
81
+
82
+ info = client.domain.info("example.com.ua")
83
+ print(info.value("exDate"))
84
+
85
+ client.logout()
86
+ except EppException as exc:
87
+ print("EPP error:", exc)
88
+ finally:
89
+ client.disconnect()
90
+ ```
91
+
92
+ `Client` is also a context manager (`with Client(cfg) as client: ...`) that disconnects on exit.
93
+
94
+ ## TLS notes
95
+
96
+ | Scenario | Config |
97
+ |---|---|
98
+ | Public, browser-trusted cert | defaults (`verify_peer=True`, `verify_peer_name=True`) |
99
+ | Private-CA / self-signed endpoint | set `ca_file` to the CA `.pem` |
100
+ | Hostname mismatch (dev) | `verify_peer_name=False` |
101
+ | Mutual-TLS endpoint | `client_cert` + `client_key` (+ `client_key_passphrase` if the key is encrypted) |
102
+
103
+ The public endpoint on `uaregistry.com:700` is strict RFC EPP and needs **no client
104
+ certificate** — auth is clID + password (over TLS) with an IP allowlist.
105
+
106
+ ## Commands
107
+
108
+ ```python
109
+ # Session
110
+ client.connect(); client.login(); client.logout(); client.disconnect()
111
+ client.login("new-password") # rotate the EPP password during login
112
+ client.hello() # re-read the greeting / keep-alive
113
+
114
+ # Domain
115
+ client.domain.check(["a.com.ua", "b.com.ua"])
116
+ client.domain.info("a.com.ua", "pw")
117
+ client.domain.create("a.com.ua",
118
+ years=1, registrant="C1", contacts={"admin": "C1", "tech": "C2"},
119
+ nameservers=["ns1.x.ua", "ns2.x.ua"], auth_info="pw",
120
+ license="TM-123", # second-level .ua only
121
+ sec_dns={"ds_data": [{"key_tag": 12345, "alg": 8, "digest_type": 2, "digest": "ABCD..."}]})
122
+ client.domain.update("a.com.ua",
123
+ add={"ns": ["ns3.x.ua"], "statuses": ["clientHold"]},
124
+ rem={"statuses": ["clientHold"]},
125
+ chg={"registrant": "C9", "auth_info": "newpw"},
126
+ # DNSSEC (RFC 5910): sec_dns={"add": {"ds_data": [...]}, "rem_all": True, "max_sig_life": 1209600}
127
+ )
128
+ client.domain.renew("a.com.ua", "2027-01-15", 1)
129
+ client.domain.restore("a.com.ua") # RGP restore (op="request")
130
+ client.domain.delete("a.com.ua")
131
+ client.domain.transfer("request", "a.com.ua", "pw", 1)
132
+
133
+ # Contact
134
+ client.contact.check(["c1"])
135
+ client.contact.info("c1", "pw")
136
+ client.contact.create("c1", name="ACME", city="Kyiv", cc="UA", email="a@b.ua", auth_info="pw",
137
+ # postal_infos=[{"type": "int", ...}, {"type": "loc", ...}], # int + localized
138
+ # disclose={"flag": False, "addr": ["int"], "voice": True}, # RFC 5733 privacy
139
+ )
140
+ client.contact.update("c1", chg={"email": "new@b.ua"},
141
+ add_statuses=["clientUpdateProhibited"])
142
+ client.contact.delete("c1")
143
+ client.contact.transfer("request", "c1", "pw")
144
+
145
+ # Host
146
+ client.host.check(["ns1.x.ua"])
147
+ client.host.info("ns1.x.ua")
148
+ client.host.create("ns1.x.ua", ["203.0.113.10", "2001:db8::1"]) # v4/v6 auto-detected
149
+ client.host.update("ns1.x.ua", add_addresses=["203.0.113.11"])
150
+ client.host.delete("ns1.x.ua")
151
+
152
+ # Poll & balance
153
+ msg = client.poll.request() # 1301 with a message, 1300 when empty
154
+ if msg.message_id() is not None: # message_count() = how many remain
155
+ client.poll.ack(msg.message_id())
156
+ b = client.balance().balance() # {"creditLimit": ..., "balance": ..., "availableCredit": ...}
157
+ ```
158
+
159
+ ## Responses
160
+
161
+ Every command returns a `Response`:
162
+
163
+ ```python
164
+ r.code() # int EPP result code (1000, 1001, 2303, ...)
165
+ r.is_success() # True for 1xxx
166
+ r.is_pending() # True for 1001 (registry resolves via a poll message)
167
+ r.message() # human-readable <msg>
168
+ r.message_lang() # "en" | "uk" | "ua" | "ru"
169
+ r.availability() # {name: bool} for *:check
170
+ r.statuses() # ["ok"] or ["clientHold", ...]
171
+ r.value("exDate") # first element with that local name
172
+ r.values("ns") # all elements with that local name
173
+ r.balance() # {"creditLimit": ..., "balance": ..., "availableCredit": ...} or None
174
+ r.prices() # {"renewal": {"value": ..., "currency": "UAH"}, ...}
175
+ r.license() # .ua trademark/licence number, or None
176
+ r.rgp_status() # ["redemptionPeriod"], ...
177
+ r.transfer_status() # "pending" | "serverApproved" | ... or None
178
+ r.ds_records() # [{"keyTag":..,"alg":..,"digestType":..,"digest":..}, ...]
179
+ r.key_records() # [{"flags":..,"protocol":..,"alg":..,"pubKey":..}, ...]
180
+ r.is_signed() # bool: any DNSSEC data present
181
+ r.message_id() # poll: id to pass to poll().ack(); message_count() = queue size
182
+ r.error_reasons() # extra <extValue><reason> text on a failed command
183
+ r.sv_trid() # server transaction id
184
+ r.raw # the raw XML
185
+ r.root # the parsed ElementTree root, for anything bespoke
186
+ ```
187
+
188
+ ## Error handling
189
+
190
+ By default any EPP error code (>= 2000) raises `CommandException` (with `.epp_code` and
191
+ `.response`). Login failures raise `AuthenticationException`; transport problems raise
192
+ `ConnectionException`. All extend `EppException`.
193
+
194
+ ```python
195
+ from uaregistry.exceptions import CommandException
196
+ from uaregistry import ResultCode
197
+
198
+ try:
199
+ client.domain.create("taken.com.ua", years=1, registrant="C1",
200
+ contacts={"admin": "C1", "tech": "C2"}, nameservers=["ns1.x.ua"])
201
+ except CommandException as exc:
202
+ if exc.epp_code == ResultCode.OBJECT_EXISTS: # 2302
203
+ ...
204
+
205
+ # Prefer branching on codes yourself?
206
+ client.throw_on_failure(False)
207
+ resp = client.domain.info("maybe.com.ua")
208
+ if resp.code() == ResultCode.OBJECT_DOES_NOT_EXIST:
209
+ ...
210
+ ```
211
+
212
+ ## Custom frames
213
+
214
+ Anything the high-level API doesn't cover can be built with `Frame` and sent raw:
215
+
216
+ ```python
217
+ from uaregistry import Frame, Namespaces
218
+
219
+ frame = Frame.command("my-trid-1")
220
+ check = frame.ns(frame.verb("check"), Namespaces.DOMAIN, "domain:check")
221
+ frame.ns(check, Namespaces.DOMAIN, "domain:name", "x.com.ua")
222
+ resp = client.request(frame) # or client.request(raw_xml_string)
223
+ ```
224
+
225
+ ## Testing
226
+
227
+ A no-dependency offline self-test (frame building + response parsing, no server, no network):
228
+
229
+ ```bash
230
+ python tests/offline_test.py
231
+ ```
232
+
233
+ ## License
234
+
235
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,209 @@
1
+ # UARegistry EPP SDK (Python)
2
+
3
+ A small, **dependency-free** Python client for the **UARegistry** EPP service — standard
4
+ **RFC 5730–5734** EPP over **TLS on port 700**. It speaks the wire protocol directly
5
+ (no framework, no server-side code), so you can drop it into any Python 3.8+ project.
6
+ Every command frame is standard, schema-valid EPP.
7
+
8
+ - TLS transport with correct RFC 5734 framing (4-byte length prefix, UTF-8 byte-safe).
9
+ - Session: `connect` / `login` / `logout`, with the login services taken from the server
10
+ greeting automatically (never rejected for an unsupported service).
11
+ - Full object commands: **domain**, **contact**, **host** (check / info / create / update /
12
+ delete / transfer / renew), plus **poll** and **balance**.
13
+ - Extensions: **secDNS** (RFC 5910), **RGP restore** (RFC 3915), and the UARegistry native
14
+ **.ua trademark licence**.
15
+ - Clean `Response` objects (result code, message, availability map, value getters) and typed
16
+ exceptions.
17
+
18
+ ## Install
19
+
20
+ ```bash
21
+ pip install git+https://github.com/uaregistry/python-sdk
22
+ ```
23
+
24
+ Or pin a released tag:
25
+
26
+ ```bash
27
+ pip install "uaregistry @ git+https://github.com/uaregistry/python-sdk@v1.0.0"
28
+ ```
29
+
30
+ No packaging at all? Copy the `uaregistry/` package folder next to your code and
31
+ `import uaregistry`. The SDK requires only the Python standard library
32
+ (`ssl`, `socket`, `xml.etree`).
33
+
34
+ ## Quick start
35
+
36
+ ```python
37
+ from uaregistry import Client, Config
38
+ from uaregistry.exceptions import EppException
39
+
40
+ client = Client(Config(
41
+ host="uaregistry.com",
42
+ clid="UAR0001",
43
+ password="your-secret",
44
+ port=700, # default; override only if the endpoint moves
45
+ lang="uk", # localized result messages: en | uk | ua | ru
46
+ # ca_file="/path/to/ca.pem", # for a private-CA / self-signed endpoint
47
+ ))
48
+
49
+ try:
50
+ client.connect() # TLS + read <greeting>
51
+ client.login()
52
+
53
+ avail = client.domain.check(["example.com.ua"]).availability()
54
+ # => {"example.com.ua": True}
55
+
56
+ info = client.domain.info("example.com.ua")
57
+ print(info.value("exDate"))
58
+
59
+ client.logout()
60
+ except EppException as exc:
61
+ print("EPP error:", exc)
62
+ finally:
63
+ client.disconnect()
64
+ ```
65
+
66
+ `Client` is also a context manager (`with Client(cfg) as client: ...`) that disconnects on exit.
67
+
68
+ ## TLS notes
69
+
70
+ | Scenario | Config |
71
+ |---|---|
72
+ | Public, browser-trusted cert | defaults (`verify_peer=True`, `verify_peer_name=True`) |
73
+ | Private-CA / self-signed endpoint | set `ca_file` to the CA `.pem` |
74
+ | Hostname mismatch (dev) | `verify_peer_name=False` |
75
+ | Mutual-TLS endpoint | `client_cert` + `client_key` (+ `client_key_passphrase` if the key is encrypted) |
76
+
77
+ The public endpoint on `uaregistry.com:700` is strict RFC EPP and needs **no client
78
+ certificate** — auth is clID + password (over TLS) with an IP allowlist.
79
+
80
+ ## Commands
81
+
82
+ ```python
83
+ # Session
84
+ client.connect(); client.login(); client.logout(); client.disconnect()
85
+ client.login("new-password") # rotate the EPP password during login
86
+ client.hello() # re-read the greeting / keep-alive
87
+
88
+ # Domain
89
+ client.domain.check(["a.com.ua", "b.com.ua"])
90
+ client.domain.info("a.com.ua", "pw")
91
+ client.domain.create("a.com.ua",
92
+ years=1, registrant="C1", contacts={"admin": "C1", "tech": "C2"},
93
+ nameservers=["ns1.x.ua", "ns2.x.ua"], auth_info="pw",
94
+ license="TM-123", # second-level .ua only
95
+ sec_dns={"ds_data": [{"key_tag": 12345, "alg": 8, "digest_type": 2, "digest": "ABCD..."}]})
96
+ client.domain.update("a.com.ua",
97
+ add={"ns": ["ns3.x.ua"], "statuses": ["clientHold"]},
98
+ rem={"statuses": ["clientHold"]},
99
+ chg={"registrant": "C9", "auth_info": "newpw"},
100
+ # DNSSEC (RFC 5910): sec_dns={"add": {"ds_data": [...]}, "rem_all": True, "max_sig_life": 1209600}
101
+ )
102
+ client.domain.renew("a.com.ua", "2027-01-15", 1)
103
+ client.domain.restore("a.com.ua") # RGP restore (op="request")
104
+ client.domain.delete("a.com.ua")
105
+ client.domain.transfer("request", "a.com.ua", "pw", 1)
106
+
107
+ # Contact
108
+ client.contact.check(["c1"])
109
+ client.contact.info("c1", "pw")
110
+ client.contact.create("c1", name="ACME", city="Kyiv", cc="UA", email="a@b.ua", auth_info="pw",
111
+ # postal_infos=[{"type": "int", ...}, {"type": "loc", ...}], # int + localized
112
+ # disclose={"flag": False, "addr": ["int"], "voice": True}, # RFC 5733 privacy
113
+ )
114
+ client.contact.update("c1", chg={"email": "new@b.ua"},
115
+ add_statuses=["clientUpdateProhibited"])
116
+ client.contact.delete("c1")
117
+ client.contact.transfer("request", "c1", "pw")
118
+
119
+ # Host
120
+ client.host.check(["ns1.x.ua"])
121
+ client.host.info("ns1.x.ua")
122
+ client.host.create("ns1.x.ua", ["203.0.113.10", "2001:db8::1"]) # v4/v6 auto-detected
123
+ client.host.update("ns1.x.ua", add_addresses=["203.0.113.11"])
124
+ client.host.delete("ns1.x.ua")
125
+
126
+ # Poll & balance
127
+ msg = client.poll.request() # 1301 with a message, 1300 when empty
128
+ if msg.message_id() is not None: # message_count() = how many remain
129
+ client.poll.ack(msg.message_id())
130
+ b = client.balance().balance() # {"creditLimit": ..., "balance": ..., "availableCredit": ...}
131
+ ```
132
+
133
+ ## Responses
134
+
135
+ Every command returns a `Response`:
136
+
137
+ ```python
138
+ r.code() # int EPP result code (1000, 1001, 2303, ...)
139
+ r.is_success() # True for 1xxx
140
+ r.is_pending() # True for 1001 (registry resolves via a poll message)
141
+ r.message() # human-readable <msg>
142
+ r.message_lang() # "en" | "uk" | "ua" | "ru"
143
+ r.availability() # {name: bool} for *:check
144
+ r.statuses() # ["ok"] or ["clientHold", ...]
145
+ r.value("exDate") # first element with that local name
146
+ r.values("ns") # all elements with that local name
147
+ r.balance() # {"creditLimit": ..., "balance": ..., "availableCredit": ...} or None
148
+ r.prices() # {"renewal": {"value": ..., "currency": "UAH"}, ...}
149
+ r.license() # .ua trademark/licence number, or None
150
+ r.rgp_status() # ["redemptionPeriod"], ...
151
+ r.transfer_status() # "pending" | "serverApproved" | ... or None
152
+ r.ds_records() # [{"keyTag":..,"alg":..,"digestType":..,"digest":..}, ...]
153
+ r.key_records() # [{"flags":..,"protocol":..,"alg":..,"pubKey":..}, ...]
154
+ r.is_signed() # bool: any DNSSEC data present
155
+ r.message_id() # poll: id to pass to poll().ack(); message_count() = queue size
156
+ r.error_reasons() # extra <extValue><reason> text on a failed command
157
+ r.sv_trid() # server transaction id
158
+ r.raw # the raw XML
159
+ r.root # the parsed ElementTree root, for anything bespoke
160
+ ```
161
+
162
+ ## Error handling
163
+
164
+ By default any EPP error code (>= 2000) raises `CommandException` (with `.epp_code` and
165
+ `.response`). Login failures raise `AuthenticationException`; transport problems raise
166
+ `ConnectionException`. All extend `EppException`.
167
+
168
+ ```python
169
+ from uaregistry.exceptions import CommandException
170
+ from uaregistry import ResultCode
171
+
172
+ try:
173
+ client.domain.create("taken.com.ua", years=1, registrant="C1",
174
+ contacts={"admin": "C1", "tech": "C2"}, nameservers=["ns1.x.ua"])
175
+ except CommandException as exc:
176
+ if exc.epp_code == ResultCode.OBJECT_EXISTS: # 2302
177
+ ...
178
+
179
+ # Prefer branching on codes yourself?
180
+ client.throw_on_failure(False)
181
+ resp = client.domain.info("maybe.com.ua")
182
+ if resp.code() == ResultCode.OBJECT_DOES_NOT_EXIST:
183
+ ...
184
+ ```
185
+
186
+ ## Custom frames
187
+
188
+ Anything the high-level API doesn't cover can be built with `Frame` and sent raw:
189
+
190
+ ```python
191
+ from uaregistry import Frame, Namespaces
192
+
193
+ frame = Frame.command("my-trid-1")
194
+ check = frame.ns(frame.verb("check"), Namespaces.DOMAIN, "domain:check")
195
+ frame.ns(check, Namespaces.DOMAIN, "domain:name", "x.com.ua")
196
+ resp = client.request(frame) # or client.request(raw_xml_string)
197
+ ```
198
+
199
+ ## Testing
200
+
201
+ A no-dependency offline self-test (frame building + response parsing, no server, no network):
202
+
203
+ ```bash
204
+ python tests/offline_test.py
205
+ ```
206
+
207
+ ## License
208
+
209
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,35 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "uaregistry"
7
+ version = "1.0.0"
8
+ description = "Dependency-free Python client for the UARegistry EPP service (RFC 5730-5734 over TLS)."
9
+ readme = "README.md"
10
+ requires-python = ">=3.8"
11
+ license = { text = "MIT" }
12
+ authors = [{ name = "UARegistry" }]
13
+ keywords = ["epp", "registry", "domains", "rfc5730", "uaregistry"]
14
+ classifiers = [
15
+ "Development Status :: 5 - Production/Stable",
16
+ "Intended Audience :: Developers",
17
+ "License :: OSI Approved :: MIT License",
18
+ "Programming Language :: Python :: 3",
19
+ "Programming Language :: Python :: 3.8",
20
+ "Programming Language :: Python :: 3.9",
21
+ "Programming Language :: Python :: 3.10",
22
+ "Programming Language :: Python :: 3.11",
23
+ "Programming Language :: Python :: 3.12",
24
+ "Programming Language :: Python :: 3.13",
25
+ "Topic :: Internet :: Name Service (DNS)",
26
+ ]
27
+ dependencies = []
28
+
29
+ [project.urls]
30
+ Homepage = "https://github.com/uaregistry/python-sdk"
31
+ Repository = "https://github.com/uaregistry/python-sdk"
32
+ Issues = "https://github.com/uaregistry/python-sdk/issues"
33
+
34
+ [tool.setuptools]
35
+ packages = ["uaregistry"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,53 @@
1
+ """UARegistry EPP SDK (Python).
2
+
3
+ A small, dependency-free client for the UARegistry EPP service — standard RFC 5730-5734
4
+ EPP over TLS on port 700. Speaks the wire protocol directly (no framework, no server code).
5
+
6
+ from uaregistry import Client, Config
7
+
8
+ client = Client(Config(host="uaregistry.com", clid="UAR0001", password="secret"))
9
+ client.connect()
10
+ client.login()
11
+ print(client.domain.check(["example.com.ua"]).availability())
12
+ client.logout()
13
+ client.disconnect()
14
+ """
15
+
16
+ from . import namespaces as Namespaces
17
+ from .client import Client
18
+ from .commands import Contact, Domain, Host, Poll
19
+ from .config import Config
20
+ from .exceptions import (
21
+ AuthenticationException,
22
+ CommandException,
23
+ ConfigException,
24
+ ConnectionException,
25
+ EppException,
26
+ )
27
+ from .frame import Frame
28
+ from .response import Response
29
+ from .result_code import ResultCode
30
+ from .transport import Connection, Transport
31
+
32
+ __version__ = "1.0.0"
33
+
34
+ __all__ = [
35
+ "Client",
36
+ "Config",
37
+ "Frame",
38
+ "Response",
39
+ "ResultCode",
40
+ "Namespaces",
41
+ "Transport",
42
+ "Connection",
43
+ "Domain",
44
+ "Contact",
45
+ "Host",
46
+ "Poll",
47
+ "EppException",
48
+ "ConnectionException",
49
+ "ConfigException",
50
+ "CommandException",
51
+ "AuthenticationException",
52
+ "__version__",
53
+ ]