namecheap-python 1.0.4__tar.gz → 1.0.6__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.
- {namecheap_python-1.0.4 → namecheap_python-1.0.6}/CLI.md +3 -1
- {namecheap_python-1.0.4 → namecheap_python-1.0.6}/PKG-INFO +20 -2
- {namecheap_python-1.0.4 → namecheap_python-1.0.6}/README.md +19 -1
- {namecheap_python-1.0.4 → namecheap_python-1.0.6}/pyproject.toml +1 -1
- {namecheap_python-1.0.4 → namecheap_python-1.0.6}/src/namecheap/__init__.py +1 -1
- {namecheap_python-1.0.4 → namecheap_python-1.0.6}/src/namecheap/_api/dns.py +14 -14
- {namecheap_python-1.0.4 → namecheap_python-1.0.6}/src/namecheap/models.py +9 -6
- {namecheap_python-1.0.4 → namecheap_python-1.0.6}/src/namecheap_cli/__main__.py +7 -2
- {namecheap_python-1.0.4 → namecheap_python-1.0.6}/src/namecheap_dns_tui/__main__.py +3 -3
- {namecheap_python-1.0.4 → namecheap_python-1.0.6}/uv.lock +1 -1
- {namecheap_python-1.0.4 → namecheap_python-1.0.6}/.env.example +0 -0
- {namecheap_python-1.0.4 → namecheap_python-1.0.6}/.github/cliff.toml +0 -0
- {namecheap_python-1.0.4 → namecheap_python-1.0.6}/.github/workflows/release.yml +0 -0
- {namecheap_python-1.0.4 → namecheap_python-1.0.6}/.gitignore +0 -0
- {namecheap_python-1.0.4 → namecheap_python-1.0.6}/.pre-commit-config.yaml +0 -0
- {namecheap_python-1.0.4 → namecheap_python-1.0.6}/LICENSE +0 -0
- {namecheap_python-1.0.4 → namecheap_python-1.0.6}/MANIFEST.in +0 -0
- {namecheap_python-1.0.4 → namecheap_python-1.0.6}/docs/dev/README.md +0 -0
- {namecheap_python-1.0.4 → namecheap_python-1.0.6}/examples/README.md +0 -0
- {namecheap_python-1.0.4 → namecheap_python-1.0.6}/examples/quickstart.py +0 -0
- {namecheap_python-1.0.4 → namecheap_python-1.0.6}/pending.md +0 -0
- {namecheap_python-1.0.4 → namecheap_python-1.0.6}/src/namecheap/_api/__init__.py +0 -0
- {namecheap_python-1.0.4 → namecheap_python-1.0.6}/src/namecheap/_api/base.py +0 -0
- {namecheap_python-1.0.4 → namecheap_python-1.0.6}/src/namecheap/_api/domains.py +0 -0
- {namecheap_python-1.0.4 → namecheap_python-1.0.6}/src/namecheap/client.py +0 -0
- {namecheap_python-1.0.4 → namecheap_python-1.0.6}/src/namecheap/errors.py +0 -0
- {namecheap_python-1.0.4 → namecheap_python-1.0.6}/src/namecheap/logging.py +0 -0
- {namecheap_python-1.0.4 → namecheap_python-1.0.6}/src/namecheap_cli/README.md +0 -0
- {namecheap_python-1.0.4 → namecheap_python-1.0.6}/src/namecheap_cli/__init__.py +0 -0
- {namecheap_python-1.0.4 → namecheap_python-1.0.6}/src/namecheap_cli/completion.py +0 -0
- {namecheap_python-1.0.4 → namecheap_python-1.0.6}/src/namecheap_dns_tui/README.md +0 -0
- {namecheap_python-1.0.4 → namecheap_python-1.0.6}/src/namecheap_dns_tui/__init__.py +0 -0
- {namecheap_python-1.0.4 → namecheap_python-1.0.6}/src/namecheap_dns_tui/assets/screenshot1.png +0 -0
- {namecheap_python-1.0.4 → namecheap_python-1.0.6}/src/namecheap_dns_tui/assets/screenshot2.png +0 -0
- {namecheap_python-1.0.4 → namecheap_python-1.0.6}/src/namecheap_dns_tui/assets/screenshot3.png +0 -0
- {namecheap_python-1.0.4 → namecheap_python-1.0.6}/src/namecheap_dns_tui/assets/screenshot4.png +0 -0
|
@@ -144,10 +144,12 @@ nc dns add example.com TXT @ "v=spf1 include:_spf.google.com ~all"
|
|
|
144
144
|
# Add URL redirect
|
|
145
145
|
nc dns add example.com URL301 www https://newsite.com
|
|
146
146
|
|
|
147
|
-
# Custom TTL
|
|
147
|
+
# Custom TTL (default is 1799 = "Automatic" in Namecheap UI)
|
|
148
148
|
nc dns add example.com A www 192.0.2.1 --ttl 300
|
|
149
149
|
```
|
|
150
150
|
|
|
151
|
+
**Note:** The default TTL is 1799 seconds, which displays as "Automatic" in the Namecheap web interface.
|
|
152
|
+
|
|
151
153
|
### Delete DNS Records
|
|
152
154
|
|
|
153
155
|
```bash
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: namecheap-python
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.6
|
|
4
4
|
Summary: A friendly Python SDK for Namecheap API
|
|
5
5
|
Project-URL: Homepage, https://github.com/adriangalilea/namecheap-python
|
|
6
6
|
Project-URL: Repository, https://github.com/adriangalilea/namecheap-python
|
|
@@ -300,6 +300,8 @@ nc.dns.set("example.com",
|
|
|
300
300
|
)
|
|
301
301
|
```
|
|
302
302
|
|
|
303
|
+
**Note on TTL:** The default TTL is **1799 seconds**, which displays as **"Automatic"** in the Namecheap web interface. This is an undocumented Namecheap API behavior. You can specify custom TTL values (60-86400 seconds) in any DNS method.
|
|
304
|
+
|
|
303
305
|
### Domain Management
|
|
304
306
|
|
|
305
307
|
```python
|
|
@@ -357,12 +359,28 @@ except NamecheapError as e:
|
|
|
357
359
|
print(f"💡 Tip: {e.help}")
|
|
358
360
|
```
|
|
359
361
|
|
|
362
|
+
## ⚠️ Namecheap API Quirks
|
|
363
|
+
|
|
364
|
+
This section documents undocumented or unusual Namecheap API behaviors we've discovered:
|
|
365
|
+
|
|
366
|
+
### TTL "Automatic" = 1799 seconds
|
|
367
|
+
|
|
368
|
+
The Namecheap web interface displays TTL as **"Automatic"** when the value is exactly **1799 seconds**, but shows **"30 min"** when it's **1800 seconds**. This behavior is completely undocumented in their official API documentation.
|
|
369
|
+
|
|
370
|
+
Their API docs state TTL defaults to 1800 when omitted, but the UI treats 1799 specially. This SDK defaults to 1799 to match the "Automatic" behavior users see in the web interface.
|
|
371
|
+
|
|
372
|
+
```python
|
|
373
|
+
# Both are valid, but display differently in Namecheap UI:
|
|
374
|
+
nc.dns.builder().a("www", "192.0.2.1", ttl=1799) # Shows as "Automatic"
|
|
375
|
+
nc.dns.builder().a("www", "192.0.2.1", ttl=1800) # Shows as "30 min"
|
|
376
|
+
```
|
|
377
|
+
|
|
360
378
|
## 🚧 Pending Features
|
|
361
379
|
|
|
362
380
|
The following Namecheap API features are planned for future releases:
|
|
363
381
|
|
|
364
382
|
- **SSL API** - Certificate management
|
|
365
|
-
- **Domain Transfer API** - Transfer domains between registrars
|
|
383
|
+
- **Domain Transfer API** - Transfer domains between registrars
|
|
366
384
|
- **Domain NS API** - Custom nameserver management
|
|
367
385
|
- **Users API** - Account management and balance checking
|
|
368
386
|
- **Whois API** - WHOIS information lookups
|
|
@@ -258,6 +258,8 @@ nc.dns.set("example.com",
|
|
|
258
258
|
)
|
|
259
259
|
```
|
|
260
260
|
|
|
261
|
+
**Note on TTL:** The default TTL is **1799 seconds**, which displays as **"Automatic"** in the Namecheap web interface. This is an undocumented Namecheap API behavior. You can specify custom TTL values (60-86400 seconds) in any DNS method.
|
|
262
|
+
|
|
261
263
|
### Domain Management
|
|
262
264
|
|
|
263
265
|
```python
|
|
@@ -315,12 +317,28 @@ except NamecheapError as e:
|
|
|
315
317
|
print(f"💡 Tip: {e.help}")
|
|
316
318
|
```
|
|
317
319
|
|
|
320
|
+
## ⚠️ Namecheap API Quirks
|
|
321
|
+
|
|
322
|
+
This section documents undocumented or unusual Namecheap API behaviors we've discovered:
|
|
323
|
+
|
|
324
|
+
### TTL "Automatic" = 1799 seconds
|
|
325
|
+
|
|
326
|
+
The Namecheap web interface displays TTL as **"Automatic"** when the value is exactly **1799 seconds**, but shows **"30 min"** when it's **1800 seconds**. This behavior is completely undocumented in their official API documentation.
|
|
327
|
+
|
|
328
|
+
Their API docs state TTL defaults to 1800 when omitted, but the UI treats 1799 specially. This SDK defaults to 1799 to match the "Automatic" behavior users see in the web interface.
|
|
329
|
+
|
|
330
|
+
```python
|
|
331
|
+
# Both are valid, but display differently in Namecheap UI:
|
|
332
|
+
nc.dns.builder().a("www", "192.0.2.1", ttl=1799) # Shows as "Automatic"
|
|
333
|
+
nc.dns.builder().a("www", "192.0.2.1", ttl=1800) # Shows as "30 min"
|
|
334
|
+
```
|
|
335
|
+
|
|
318
336
|
## 🚧 Pending Features
|
|
319
337
|
|
|
320
338
|
The following Namecheap API features are planned for future releases:
|
|
321
339
|
|
|
322
340
|
- **SSL API** - Certificate management
|
|
323
|
-
- **Domain Transfer API** - Transfer domains between registrars
|
|
341
|
+
- **Domain Transfer API** - Transfer domains between registrars
|
|
324
342
|
- **Domain NS API** - Custom nameserver management
|
|
325
343
|
- **Users API** - Account management and balance checking
|
|
326
344
|
- **Whois API** - WHOIS information lookups
|
|
@@ -14,7 +14,7 @@ from .client import Namecheap
|
|
|
14
14
|
from .errors import ConfigurationError, NamecheapError, ValidationError
|
|
15
15
|
from .models import Contact, DNSRecord, Domain, DomainCheck
|
|
16
16
|
|
|
17
|
-
__version__ = "1.0.
|
|
17
|
+
__version__ = "1.0.5"
|
|
18
18
|
__all__ = [
|
|
19
19
|
"ConfigurationError",
|
|
20
20
|
"Contact",
|
|
@@ -22,14 +22,14 @@ class DNSRecordBuilder:
|
|
|
22
22
|
"""Initialize empty builder."""
|
|
23
23
|
self._records: list[DNSRecord] = []
|
|
24
24
|
|
|
25
|
-
def a(self, name: str, ip: str, ttl: int =
|
|
25
|
+
def a(self, name: str, ip: str, ttl: int = 1799) -> Self:
|
|
26
26
|
"""
|
|
27
27
|
Add an A record.
|
|
28
28
|
|
|
29
29
|
Args:
|
|
30
30
|
name: Record name (@ for root)
|
|
31
31
|
ip: IPv4 address
|
|
32
|
-
ttl: Time to live in seconds (60-86400, default:
|
|
32
|
+
ttl: Time to live in seconds (60-86400, default: 1799 = "Automatic")
|
|
33
33
|
|
|
34
34
|
Returns:
|
|
35
35
|
Self for chaining
|
|
@@ -41,14 +41,14 @@ class DNSRecordBuilder:
|
|
|
41
41
|
)
|
|
42
42
|
return self
|
|
43
43
|
|
|
44
|
-
def aaaa(self, name: str, ipv6: str, ttl: int =
|
|
44
|
+
def aaaa(self, name: str, ipv6: str, ttl: int = 1799) -> Self:
|
|
45
45
|
"""
|
|
46
46
|
Add an AAAA record.
|
|
47
47
|
|
|
48
48
|
Args:
|
|
49
49
|
name: Record name (@ for root)
|
|
50
50
|
ipv6: IPv6 address
|
|
51
|
-
ttl: Time to live in seconds
|
|
51
|
+
ttl: Time to live in seconds (default: 1799 = "Automatic")
|
|
52
52
|
|
|
53
53
|
Returns:
|
|
54
54
|
Self for chaining
|
|
@@ -60,14 +60,14 @@ class DNSRecordBuilder:
|
|
|
60
60
|
)
|
|
61
61
|
return self
|
|
62
62
|
|
|
63
|
-
def cname(self, name: str, target: str, ttl: int =
|
|
63
|
+
def cname(self, name: str, target: str, ttl: int = 1799) -> Self:
|
|
64
64
|
"""
|
|
65
65
|
Add a CNAME record.
|
|
66
66
|
|
|
67
67
|
Args:
|
|
68
68
|
name: Record name (cannot be @)
|
|
69
69
|
target: Target domain
|
|
70
|
-
ttl: Time to live in seconds
|
|
70
|
+
ttl: Time to live in seconds (default: 1799 = "Automatic")
|
|
71
71
|
|
|
72
72
|
Returns:
|
|
73
73
|
Self for chaining
|
|
@@ -81,7 +81,7 @@ class DNSRecordBuilder:
|
|
|
81
81
|
)
|
|
82
82
|
return self
|
|
83
83
|
|
|
84
|
-
def mx(self, name: str, server: str, priority: int = 10, ttl: int =
|
|
84
|
+
def mx(self, name: str, server: str, priority: int = 10, ttl: int = 1799) -> Self:
|
|
85
85
|
"""
|
|
86
86
|
Add an MX record.
|
|
87
87
|
|
|
@@ -89,7 +89,7 @@ class DNSRecordBuilder:
|
|
|
89
89
|
name: Record name (@ for root)
|
|
90
90
|
server: Mail server hostname
|
|
91
91
|
priority: MX priority (lower = higher priority)
|
|
92
|
-
ttl: Time to live in seconds
|
|
92
|
+
ttl: Time to live in seconds (default: 1799 = "Automatic")
|
|
93
93
|
|
|
94
94
|
Returns:
|
|
95
95
|
Self for chaining
|
|
@@ -107,14 +107,14 @@ class DNSRecordBuilder:
|
|
|
107
107
|
)
|
|
108
108
|
return self
|
|
109
109
|
|
|
110
|
-
def txt(self, name: str, value: str, ttl: int =
|
|
110
|
+
def txt(self, name: str, value: str, ttl: int = 1799) -> Self:
|
|
111
111
|
"""
|
|
112
112
|
Add a TXT record.
|
|
113
113
|
|
|
114
114
|
Args:
|
|
115
115
|
name: Record name (@ for root)
|
|
116
116
|
value: Text value
|
|
117
|
-
ttl: Time to live in seconds
|
|
117
|
+
ttl: Time to live in seconds (default: 1799 = "Automatic")
|
|
118
118
|
|
|
119
119
|
Returns:
|
|
120
120
|
Self for chaining
|
|
@@ -126,14 +126,14 @@ class DNSRecordBuilder:
|
|
|
126
126
|
)
|
|
127
127
|
return self
|
|
128
128
|
|
|
129
|
-
def ns(self, name: str, nameserver: str, ttl: int =
|
|
129
|
+
def ns(self, name: str, nameserver: str, ttl: int = 1799) -> Self:
|
|
130
130
|
"""
|
|
131
131
|
Add an NS record.
|
|
132
132
|
|
|
133
133
|
Args:
|
|
134
134
|
name: Record name
|
|
135
135
|
nameserver: Nameserver hostname
|
|
136
|
-
ttl: Time to live in seconds
|
|
136
|
+
ttl: Time to live in seconds (default: 1799 = "Automatic")
|
|
137
137
|
|
|
138
138
|
Returns:
|
|
139
139
|
Self for chaining
|
|
@@ -151,7 +151,7 @@ class DNSRecordBuilder:
|
|
|
151
151
|
url: str,
|
|
152
152
|
*,
|
|
153
153
|
redirect_type: Literal["301", "frame"] = "301",
|
|
154
|
-
ttl: int =
|
|
154
|
+
ttl: int = 1799,
|
|
155
155
|
) -> Self:
|
|
156
156
|
"""
|
|
157
157
|
Add a URL redirect record.
|
|
@@ -160,7 +160,7 @@ class DNSRecordBuilder:
|
|
|
160
160
|
name: Record name (@ for root)
|
|
161
161
|
url: Target URL
|
|
162
162
|
redirect_type: "301" for permanent redirect, "frame" for masked
|
|
163
|
-
ttl: Time to live in seconds
|
|
163
|
+
ttl: Time to live in seconds (default: 1799 = "Automatic")
|
|
164
164
|
|
|
165
165
|
Returns:
|
|
166
166
|
Self for chaining
|
|
@@ -188,7 +188,7 @@ class DNSRecord(XMLModel):
|
|
|
188
188
|
Field(alias="@Type")
|
|
189
189
|
)
|
|
190
190
|
value: str = Field(alias="@Address")
|
|
191
|
-
ttl: int = Field(alias="@TTL", default=
|
|
191
|
+
ttl: int = Field(alias="@TTL", default=1799) # 1799 = "Automatic" in Namecheap UI
|
|
192
192
|
priority: int | None = Field(alias="@MXPref", default=None)
|
|
193
193
|
|
|
194
194
|
@field_validator("ttl", mode="before")
|
|
@@ -196,9 +196,9 @@ class DNSRecord(XMLModel):
|
|
|
196
196
|
def parse_ttl(cls, v: Any) -> int:
|
|
197
197
|
"""Ensure TTL is within valid range."""
|
|
198
198
|
try:
|
|
199
|
-
ttl = int(v) if v else
|
|
199
|
+
ttl = int(v) if v else 1799
|
|
200
200
|
except (ValueError, TypeError):
|
|
201
|
-
ttl =
|
|
201
|
+
ttl = 1799
|
|
202
202
|
return max(60, min(86400, ttl))
|
|
203
203
|
|
|
204
204
|
@field_validator("priority", mode="before")
|
|
@@ -239,12 +239,15 @@ class Domain(XMLModel):
|
|
|
239
239
|
@field_validator("created", "expires", mode="before")
|
|
240
240
|
@classmethod
|
|
241
241
|
def parse_datetime(cls, v: Any) -> datetime:
|
|
242
|
-
"""Parse datetime
|
|
242
|
+
"""Parse datetime from Namecheap API or Pydantic serialization."""
|
|
243
243
|
if isinstance(v, datetime):
|
|
244
244
|
return v
|
|
245
245
|
if isinstance(v, str):
|
|
246
|
-
# Namecheap
|
|
247
|
-
|
|
246
|
+
# Namecheap API format (MM/DD/YYYY)
|
|
247
|
+
if "/" in v:
|
|
248
|
+
return datetime.strptime(v, "%m/%d/%Y")
|
|
249
|
+
# Pydantic serialization format (ISO 8601)
|
|
250
|
+
return datetime.fromisoformat(v)
|
|
248
251
|
raise ValueError(f"Cannot parse datetime from {v}")
|
|
249
252
|
|
|
250
253
|
|
|
@@ -512,7 +512,12 @@ def dns_list(config: Config, domain: str, type: str | None, name: str | None) ->
|
|
|
512
512
|
)
|
|
513
513
|
@click.argument("name")
|
|
514
514
|
@click.argument("value")
|
|
515
|
-
@click.option(
|
|
515
|
+
@click.option(
|
|
516
|
+
"--ttl",
|
|
517
|
+
type=int,
|
|
518
|
+
default=1799,
|
|
519
|
+
help="TTL in seconds (60-86400, default: 1799 = Automatic)",
|
|
520
|
+
)
|
|
516
521
|
@click.option("--priority", type=int, help="Priority (required for MX records)")
|
|
517
522
|
@pass_config
|
|
518
523
|
def dns_add(
|
|
@@ -849,7 +854,7 @@ def config_init() -> None:
|
|
|
849
854
|
"color": True,
|
|
850
855
|
"auto_renew": True,
|
|
851
856
|
"whois_privacy": True,
|
|
852
|
-
"dns_ttl":
|
|
857
|
+
"dns_ttl": 1799,
|
|
853
858
|
},
|
|
854
859
|
}
|
|
855
860
|
|
|
@@ -233,9 +233,9 @@ class AddRecordModal(ModalScreen):
|
|
|
233
233
|
with Vertical(classes="field-group"):
|
|
234
234
|
yield Label("TTL (seconds):")
|
|
235
235
|
initial_ttl = (
|
|
236
|
-
str(self.editing_record.ttl) if self.editing_record else "
|
|
236
|
+
str(self.editing_record.ttl) if self.editing_record else "1799"
|
|
237
237
|
)
|
|
238
|
-
yield Input(placeholder="
|
|
238
|
+
yield Input(placeholder="1799", id="record-ttl", value=initial_ttl)
|
|
239
239
|
|
|
240
240
|
with Vertical(classes="field-group", id="priority-group"):
|
|
241
241
|
yield Label("Priority:")
|
|
@@ -296,7 +296,7 @@ class AddRecordModal(ModalScreen):
|
|
|
296
296
|
record_type = self.query_one("#record-type", Select).value
|
|
297
297
|
name = self.query_one("#record-name", Input).value or "@"
|
|
298
298
|
value = self.query_one("#record-value", Input).value
|
|
299
|
-
ttl_str = self.query_one("#record-ttl", Input).value or "
|
|
299
|
+
ttl_str = self.query_one("#record-ttl", Input).value or "1799"
|
|
300
300
|
ttl = max(60, min(86400, int(ttl_str)))
|
|
301
301
|
|
|
302
302
|
priority = None
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{namecheap_python-1.0.4 → namecheap_python-1.0.6}/src/namecheap_dns_tui/assets/screenshot1.png
RENAMED
|
File without changes
|
{namecheap_python-1.0.4 → namecheap_python-1.0.6}/src/namecheap_dns_tui/assets/screenshot2.png
RENAMED
|
File without changes
|
{namecheap_python-1.0.4 → namecheap_python-1.0.6}/src/namecheap_dns_tui/assets/screenshot3.png
RENAMED
|
File without changes
|
{namecheap_python-1.0.4 → namecheap_python-1.0.6}/src/namecheap_dns_tui/assets/screenshot4.png
RENAMED
|
File without changes
|