namecheap-python 1.1.0__py3-none-any.whl → 1.2.0__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.
- namecheap/__init__.py +14 -2
- namecheap/_api/dns.py +35 -1
- namecheap/_api/domains.py +47 -1
- namecheap/_api/users.py +32 -0
- namecheap/client.py +8 -0
- namecheap/models.py +60 -0
- namecheap_cli/__main__.py +86 -50
- {namecheap_python-1.1.0.dist-info → namecheap_python-1.2.0.dist-info}/METADATA +83 -14
- {namecheap_python-1.1.0.dist-info → namecheap_python-1.2.0.dist-info}/RECORD +12 -11
- {namecheap_python-1.1.0.dist-info → namecheap_python-1.2.0.dist-info}/WHEEL +0 -0
- {namecheap_python-1.1.0.dist-info → namecheap_python-1.2.0.dist-info}/entry_points.txt +0 -0
- {namecheap_python-1.1.0.dist-info → namecheap_python-1.2.0.dist-info}/licenses/LICENSE +0 -0
namecheap/__init__.py
CHANGED
|
@@ -12,15 +12,27 @@ from __future__ import annotations
|
|
|
12
12
|
|
|
13
13
|
from .client import Namecheap
|
|
14
14
|
from .errors import ConfigurationError, NamecheapError, ValidationError
|
|
15
|
-
from .models import
|
|
15
|
+
from .models import (
|
|
16
|
+
AccountBalance,
|
|
17
|
+
Contact,
|
|
18
|
+
DNSRecord,
|
|
19
|
+
Domain,
|
|
20
|
+
DomainCheck,
|
|
21
|
+
DomainInfo,
|
|
22
|
+
EmailForward,
|
|
23
|
+
Nameservers,
|
|
24
|
+
)
|
|
16
25
|
|
|
17
|
-
__version__ = "1.
|
|
26
|
+
__version__ = "1.2.0"
|
|
18
27
|
__all__ = [
|
|
28
|
+
"AccountBalance",
|
|
19
29
|
"ConfigurationError",
|
|
20
30
|
"Contact",
|
|
21
31
|
"DNSRecord",
|
|
22
32
|
"Domain",
|
|
23
33
|
"DomainCheck",
|
|
34
|
+
"DomainInfo",
|
|
35
|
+
"EmailForward",
|
|
24
36
|
"Namecheap",
|
|
25
37
|
"NamecheapError",
|
|
26
38
|
"Nameservers",
|
namecheap/_api/dns.py
CHANGED
|
@@ -6,7 +6,7 @@ from typing import TYPE_CHECKING, Any, Literal
|
|
|
6
6
|
|
|
7
7
|
import tldextract
|
|
8
8
|
|
|
9
|
-
from namecheap.models import DNSRecord, Nameservers
|
|
9
|
+
from namecheap.models import DNSRecord, EmailForward, Nameservers
|
|
10
10
|
|
|
11
11
|
from .base import BaseAPI
|
|
12
12
|
|
|
@@ -494,3 +494,37 @@ class DnsAPI(BaseAPI):
|
|
|
494
494
|
nameservers = [ns_data] if isinstance(ns_data, str) else ns_data
|
|
495
495
|
|
|
496
496
|
return Nameservers(is_default=is_default, nameservers=nameservers)
|
|
497
|
+
|
|
498
|
+
def get_email_forwarding(self, domain: str) -> list[EmailForward]:
|
|
499
|
+
"""
|
|
500
|
+
Get email forwarding rules for a domain.
|
|
501
|
+
|
|
502
|
+
Args:
|
|
503
|
+
domain: Domain name
|
|
504
|
+
|
|
505
|
+
Returns:
|
|
506
|
+
List of EmailForward rules
|
|
507
|
+
|
|
508
|
+
Examples:
|
|
509
|
+
>>> rules = nc.dns.get_email_forwarding("example.com")
|
|
510
|
+
>>> for r in rules:
|
|
511
|
+
... print(f"{r.mailbox} -> {r.forward_to}")
|
|
512
|
+
"""
|
|
513
|
+
result: Any = self._request(
|
|
514
|
+
"namecheap.domains.dns.getEmailForwarding",
|
|
515
|
+
{"DomainName": domain},
|
|
516
|
+
path="DomainDNSGetEmailForwardingResult",
|
|
517
|
+
)
|
|
518
|
+
|
|
519
|
+
if not result:
|
|
520
|
+
return []
|
|
521
|
+
|
|
522
|
+
forwards = result.get("Forward", [])
|
|
523
|
+
if isinstance(forwards, dict):
|
|
524
|
+
forwards = [forwards]
|
|
525
|
+
assert isinstance(forwards, list), f"Unexpected Forward type: {type(forwards)}"
|
|
526
|
+
|
|
527
|
+
return [
|
|
528
|
+
EmailForward(mailbox=f.get("@mailbox", ""), forward_to=f.get("#text", ""))
|
|
529
|
+
for f in forwards
|
|
530
|
+
]
|
namecheap/_api/domains.py
CHANGED
|
@@ -9,7 +9,7 @@ from typing import Any
|
|
|
9
9
|
import tldextract
|
|
10
10
|
|
|
11
11
|
from namecheap.logging import logger
|
|
12
|
-
from namecheap.models import Contact, Domain, DomainCheck
|
|
12
|
+
from namecheap.models import Contact, Domain, DomainCheck, DomainInfo
|
|
13
13
|
|
|
14
14
|
from .base import BaseAPI
|
|
15
15
|
|
|
@@ -110,6 +110,52 @@ class DomainsAPI(BaseAPI):
|
|
|
110
110
|
return [results]
|
|
111
111
|
return results if isinstance(results, list) else []
|
|
112
112
|
|
|
113
|
+
def get_info(self, domain: str) -> DomainInfo:
|
|
114
|
+
"""
|
|
115
|
+
Get detailed information about a domain.
|
|
116
|
+
|
|
117
|
+
Args:
|
|
118
|
+
domain: Domain name
|
|
119
|
+
|
|
120
|
+
Returns:
|
|
121
|
+
DomainInfo with status, whoisguard, DNS provider, etc.
|
|
122
|
+
|
|
123
|
+
Examples:
|
|
124
|
+
>>> info = nc.domains.get_info("example.com")
|
|
125
|
+
>>> print(f"{info.domain} status={info.status} whoisguard={info.whoisguard_enabled}")
|
|
126
|
+
"""
|
|
127
|
+
result: Any = self._request(
|
|
128
|
+
"namecheap.domains.getInfo",
|
|
129
|
+
{"DomainName": domain},
|
|
130
|
+
path="DomainGetInfoResult",
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
assert result, f"API returned empty result for {domain} getInfo"
|
|
134
|
+
|
|
135
|
+
# Extract nested fields into flat structure
|
|
136
|
+
domain_details = result.get("DomainDetails", {})
|
|
137
|
+
whoisguard = result.get("Whoisguard", {})
|
|
138
|
+
dns_details = result.get("DnsDetails", {})
|
|
139
|
+
|
|
140
|
+
flat = {
|
|
141
|
+
"@ID": result.get("@ID"),
|
|
142
|
+
"@DomainName": result.get("@DomainName"),
|
|
143
|
+
"@OwnerName": result.get("@OwnerName"),
|
|
144
|
+
"@IsOwner": result.get("@IsOwner"),
|
|
145
|
+
"@IsPremium": result.get("@IsPremium", "false"),
|
|
146
|
+
"@Status": result.get("@Status"),
|
|
147
|
+
"created": domain_details.get("CreatedDate"),
|
|
148
|
+
"expires": domain_details.get("ExpiredDate"),
|
|
149
|
+
"whoisguard_enabled": whoisguard.get("@Enabled", "false").lower() == "true"
|
|
150
|
+
if isinstance(whoisguard, dict)
|
|
151
|
+
else False,
|
|
152
|
+
"dns_provider": dns_details.get("@ProviderType")
|
|
153
|
+
if isinstance(dns_details, dict)
|
|
154
|
+
else None,
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return DomainInfo.model_validate(flat)
|
|
158
|
+
|
|
113
159
|
def register(
|
|
114
160
|
self,
|
|
115
161
|
domain: str,
|
namecheap/_api/users.py
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""Users API."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from namecheap.models import AccountBalance
|
|
8
|
+
|
|
9
|
+
from .base import BaseAPI
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class UsersAPI(BaseAPI):
|
|
13
|
+
"""User account operations."""
|
|
14
|
+
|
|
15
|
+
def get_balances(self) -> AccountBalance:
|
|
16
|
+
"""
|
|
17
|
+
Get account balance information.
|
|
18
|
+
|
|
19
|
+
Returns:
|
|
20
|
+
AccountBalance with available balance, earned amount, etc.
|
|
21
|
+
|
|
22
|
+
Examples:
|
|
23
|
+
>>> bal = nc.users.get_balances()
|
|
24
|
+
>>> print(f"{bal.available_balance} {bal.currency}")
|
|
25
|
+
"""
|
|
26
|
+
result: Any = self._request(
|
|
27
|
+
"namecheap.users.getBalances",
|
|
28
|
+
path="UserGetBalancesResult",
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
assert result, "API returned empty result for getBalances"
|
|
32
|
+
return AccountBalance.model_validate(result)
|
namecheap/client.py
CHANGED
|
@@ -16,6 +16,7 @@ if TYPE_CHECKING:
|
|
|
16
16
|
|
|
17
17
|
from ._api.dns import DnsAPI
|
|
18
18
|
from ._api.domains import DomainsAPI
|
|
19
|
+
from ._api.users import UsersAPI
|
|
19
20
|
|
|
20
21
|
|
|
21
22
|
class Namecheap:
|
|
@@ -110,6 +111,13 @@ class Namecheap:
|
|
|
110
111
|
|
|
111
112
|
return DnsAPI(self)
|
|
112
113
|
|
|
114
|
+
@cached_property
|
|
115
|
+
def users(self) -> UsersAPI:
|
|
116
|
+
"""User account operations."""
|
|
117
|
+
from ._api.users import UsersAPI
|
|
118
|
+
|
|
119
|
+
return UsersAPI(self)
|
|
120
|
+
|
|
113
121
|
def __enter__(self) -> Self:
|
|
114
122
|
"""Enter context manager."""
|
|
115
123
|
return self
|
namecheap/models.py
CHANGED
|
@@ -251,6 +251,66 @@ class Domain(XMLModel):
|
|
|
251
251
|
raise ValueError(f"Cannot parse datetime from {v}")
|
|
252
252
|
|
|
253
253
|
|
|
254
|
+
class AccountBalance(BaseModel):
|
|
255
|
+
"""Account balance information."""
|
|
256
|
+
|
|
257
|
+
currency: str = Field(alias="@Currency")
|
|
258
|
+
available_balance: Decimal = Field(alias="@AvailableBalance")
|
|
259
|
+
account_balance: Decimal = Field(alias="@AccountBalance")
|
|
260
|
+
earned_amount: Decimal = Field(alias="@EarnedAmount")
|
|
261
|
+
withdrawable_amount: Decimal = Field(alias="@WithdrawableAmount")
|
|
262
|
+
funds_required_for_auto_renew: Decimal = Field(alias="@FundsRequiredForAutoRenew")
|
|
263
|
+
|
|
264
|
+
model_config = ConfigDict(populate_by_name=True)
|
|
265
|
+
|
|
266
|
+
@field_validator(
|
|
267
|
+
"available_balance",
|
|
268
|
+
"account_balance",
|
|
269
|
+
"earned_amount",
|
|
270
|
+
"withdrawable_amount",
|
|
271
|
+
"funds_required_for_auto_renew",
|
|
272
|
+
mode="before",
|
|
273
|
+
)
|
|
274
|
+
@classmethod
|
|
275
|
+
def parse_decimal(cls, v: Any) -> Decimal:
|
|
276
|
+
return Decimal(str(v)) if v is not None else Decimal("0")
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
class DomainInfo(BaseModel):
|
|
280
|
+
"""Detailed domain information from getInfo."""
|
|
281
|
+
|
|
282
|
+
id: int = Field(alias="@ID")
|
|
283
|
+
domain: str = Field(alias="@DomainName")
|
|
284
|
+
owner: str = Field(alias="@OwnerName")
|
|
285
|
+
is_owner: bool = Field(alias="@IsOwner")
|
|
286
|
+
is_premium: bool = Field(alias="@IsPremium", default=False)
|
|
287
|
+
status: str = Field(alias="@Status")
|
|
288
|
+
created: str | None = Field(default=None)
|
|
289
|
+
expires: str | None = Field(default=None)
|
|
290
|
+
whoisguard_enabled: bool = Field(default=False)
|
|
291
|
+
dns_provider: str | None = Field(default=None)
|
|
292
|
+
|
|
293
|
+
model_config = ConfigDict(populate_by_name=True)
|
|
294
|
+
|
|
295
|
+
@field_validator("is_owner", "is_premium", mode="before")
|
|
296
|
+
@classmethod
|
|
297
|
+
def parse_bool(cls, v: Any) -> bool:
|
|
298
|
+
if isinstance(v, bool):
|
|
299
|
+
return v
|
|
300
|
+
if isinstance(v, str):
|
|
301
|
+
return v.lower() == "true"
|
|
302
|
+
return False
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
class EmailForward(BaseModel):
|
|
306
|
+
"""Email forwarding rule."""
|
|
307
|
+
|
|
308
|
+
mailbox: str = Field(alias="@mailbox")
|
|
309
|
+
forward_to: str
|
|
310
|
+
|
|
311
|
+
model_config = ConfigDict(populate_by_name=True)
|
|
312
|
+
|
|
313
|
+
|
|
254
314
|
class Nameservers(BaseModel):
|
|
255
315
|
"""Current nameserver configuration for a domain."""
|
|
256
316
|
|
namecheap_cli/__main__.py
CHANGED
|
@@ -367,57 +367,31 @@ def domain_info(config: Config, domain: str) -> None:
|
|
|
367
367
|
nc = config.init_client()
|
|
368
368
|
|
|
369
369
|
try:
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
370
|
+
with Progress(
|
|
371
|
+
SpinnerColumn(),
|
|
372
|
+
TextColumn("[progress.description]{task.description}"),
|
|
373
|
+
transient=True,
|
|
374
|
+
) as progress:
|
|
375
|
+
progress.add_task(f"Getting info for {domain}...", total=None)
|
|
376
|
+
info = nc.domains.get_info(domain)
|
|
376
377
|
|
|
377
378
|
if config.output_format == "table":
|
|
378
379
|
console.print(f"\n[bold cyan]Domain Information: {domain}[/bold cyan]\n")
|
|
379
|
-
console.print(
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
f"[bold]
|
|
385
|
-
)
|
|
386
|
-
console.print(
|
|
387
|
-
f"[bold]Expires:[/bold] {domain_obj.expires.strftime('%Y-%m-%d')}"
|
|
388
|
-
)
|
|
389
|
-
console.print(
|
|
390
|
-
f"[bold]Auto-Renew:[/bold] {'✓ Enabled' if domain_obj.auto_renew else '✗ Disabled'}"
|
|
391
|
-
)
|
|
392
|
-
console.print(
|
|
393
|
-
f"[bold]Locked:[/bold] {'🔒 Yes' if domain_obj.is_locked else '🔓 No'}"
|
|
394
|
-
)
|
|
380
|
+
console.print(f"[bold]Status:[/bold] {info.status}")
|
|
381
|
+
console.print(f"[bold]Owner:[/bold] {info.owner}")
|
|
382
|
+
if info.created:
|
|
383
|
+
console.print(f"[bold]Created:[/bold] {info.created}")
|
|
384
|
+
if info.expires:
|
|
385
|
+
console.print(f"[bold]Expires:[/bold] {info.expires}")
|
|
386
|
+
console.print(f"[bold]Premium:[/bold] {'Yes' if info.is_premium else 'No'}")
|
|
395
387
|
console.print(
|
|
396
388
|
f"[bold]WHOIS Guard:[/bold] "
|
|
397
|
-
f"{'✓ Enabled' if
|
|
389
|
+
f"{'✓ Enabled' if info.whoisguard_enabled else '✗ Disabled'}"
|
|
398
390
|
)
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
days_left = (domain_obj.expires - datetime.now()).days
|
|
402
|
-
if days_left < 30:
|
|
403
|
-
console.print(
|
|
404
|
-
f"\n⚠️ [yellow]Domain expires in {days_left} days![/yellow]"
|
|
405
|
-
)
|
|
406
|
-
elif days_left < 60:
|
|
407
|
-
console.print(f"\n📅 Domain expires in {days_left} days")
|
|
408
|
-
|
|
391
|
+
if info.dns_provider:
|
|
392
|
+
console.print(f"[bold]DNS Provider:[/bold] {info.dns_provider}")
|
|
409
393
|
else:
|
|
410
|
-
|
|
411
|
-
"domain": domain_obj.name,
|
|
412
|
-
"status": "active" if not domain_obj.is_expired else "expired",
|
|
413
|
-
"created": domain_obj.created.isoformat(),
|
|
414
|
-
"expires": domain_obj.expires.isoformat(),
|
|
415
|
-
"auto_renew": domain_obj.auto_renew,
|
|
416
|
-
"locked": domain_obj.is_locked,
|
|
417
|
-
"whois_guard": domain_obj.whois_guard,
|
|
418
|
-
"days_until_expiration": (domain_obj.expires - datetime.now()).days,
|
|
419
|
-
}
|
|
420
|
-
output_formatter(data, config.output_format)
|
|
394
|
+
output_formatter(info.model_dump(), config.output_format)
|
|
421
395
|
|
|
422
396
|
except NamecheapError as e:
|
|
423
397
|
console.print(f"[red]❌ Error: {e}[/red]")
|
|
@@ -906,6 +880,45 @@ def dns_export(config: Config, domain: str, format: str, output) -> None:
|
|
|
906
880
|
sys.exit(1)
|
|
907
881
|
|
|
908
882
|
|
|
883
|
+
@dns_group.command("email-forwarding")
|
|
884
|
+
@click.argument("domain")
|
|
885
|
+
@pass_config
|
|
886
|
+
def dns_email_forwarding(config: Config, domain: str) -> None:
|
|
887
|
+
"""Show email forwarding rules for a domain."""
|
|
888
|
+
nc = config.init_client()
|
|
889
|
+
|
|
890
|
+
try:
|
|
891
|
+
with Progress(
|
|
892
|
+
SpinnerColumn(),
|
|
893
|
+
TextColumn("[progress.description]{task.description}"),
|
|
894
|
+
transient=True,
|
|
895
|
+
) as progress:
|
|
896
|
+
progress.add_task(f"Getting email forwarding for {domain}...", total=None)
|
|
897
|
+
rules = nc.dns.get_email_forwarding(domain)
|
|
898
|
+
|
|
899
|
+
if config.output_format == "table":
|
|
900
|
+
if not rules:
|
|
901
|
+
console.print(
|
|
902
|
+
f"\n[yellow]No email forwarding rules for {domain}[/yellow]"
|
|
903
|
+
)
|
|
904
|
+
return
|
|
905
|
+
|
|
906
|
+
table = Table(title=f"Email Forwarding for {domain}")
|
|
907
|
+
table.add_column("Mailbox", style="cyan")
|
|
908
|
+
table.add_column("Forwards To", style="green")
|
|
909
|
+
|
|
910
|
+
for rule in rules:
|
|
911
|
+
table.add_row(f"{rule.mailbox}@{domain}", rule.forward_to)
|
|
912
|
+
|
|
913
|
+
console.print(table)
|
|
914
|
+
else:
|
|
915
|
+
output_formatter([r.model_dump() for r in rules], config.output_format)
|
|
916
|
+
|
|
917
|
+
except NamecheapError as e:
|
|
918
|
+
console.print(f"[red]❌ Error: {e}[/red]")
|
|
919
|
+
sys.exit(1)
|
|
920
|
+
|
|
921
|
+
|
|
909
922
|
@cli.group("account")
|
|
910
923
|
def account_group() -> None:
|
|
911
924
|
"""Account management commands."""
|
|
@@ -916,14 +929,37 @@ def account_group() -> None:
|
|
|
916
929
|
@pass_config
|
|
917
930
|
def account_balance(config: Config) -> None:
|
|
918
931
|
"""Check account balance."""
|
|
919
|
-
config.init_client()
|
|
932
|
+
nc = config.init_client()
|
|
920
933
|
|
|
921
934
|
try:
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
"[
|
|
925
|
-
|
|
926
|
-
|
|
935
|
+
with Progress(
|
|
936
|
+
SpinnerColumn(),
|
|
937
|
+
TextColumn("[progress.description]{task.description}"),
|
|
938
|
+
transient=True,
|
|
939
|
+
) as progress:
|
|
940
|
+
progress.add_task("Getting account balance...", total=None)
|
|
941
|
+
bal = nc.users.get_balances()
|
|
942
|
+
|
|
943
|
+
if config.output_format == "table":
|
|
944
|
+
table = Table(title="Account Balance")
|
|
945
|
+
table.add_column("Field", style="cyan")
|
|
946
|
+
table.add_column("Amount", style="green", justify="right")
|
|
947
|
+
|
|
948
|
+
table.add_row(
|
|
949
|
+
"Available Balance", f"{bal.available_balance} {bal.currency}"
|
|
950
|
+
)
|
|
951
|
+
table.add_row("Account Balance", f"{bal.account_balance} {bal.currency}")
|
|
952
|
+
table.add_row("Earned Amount", f"{bal.earned_amount} {bal.currency}")
|
|
953
|
+
table.add_row("Withdrawable", f"{bal.withdrawable_amount} {bal.currency}")
|
|
954
|
+
if bal.funds_required_for_auto_renew > 0:
|
|
955
|
+
table.add_row(
|
|
956
|
+
"Auto-Renew Required",
|
|
957
|
+
f"{bal.funds_required_for_auto_renew} {bal.currency}",
|
|
958
|
+
)
|
|
959
|
+
|
|
960
|
+
console.print(table)
|
|
961
|
+
else:
|
|
962
|
+
output_formatter(bal.model_dump(mode="json"), config.output_format)
|
|
927
963
|
|
|
928
964
|
except NamecheapError as e:
|
|
929
965
|
console.print(f"[red]❌ Error: {e}[/red]")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: namecheap-python
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.2.0
|
|
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
|
|
@@ -42,6 +42,12 @@ Description-Content-Type: text/markdown
|
|
|
42
42
|
|
|
43
43
|
# Namecheap Python SDK
|
|
44
44
|
|
|
45
|
+
[](https://pypi.org/project/namecheap-python/)
|
|
46
|
+
[](https://pepy.tech/project/namecheap-python)
|
|
47
|
+
[](https://pepy.tech/project/namecheap-python)
|
|
48
|
+
[](https://pypi.org/project/namecheap-python/)
|
|
49
|
+
[](https://opensource.org/licenses/MIT)
|
|
50
|
+
|
|
45
51
|
A modern, friendly Python SDK for the Namecheap API with comprehensive CLI and TUI tools.
|
|
46
52
|
|
|
47
53
|
## 🚀 Features
|
|
@@ -206,6 +212,38 @@ Adding CNAME record to tdo.garden...
|
|
|
206
212
|
```
|
|
207
213
|
|
|
208
214
|
|
|
215
|
+
Check account balance:
|
|
216
|
+
|
|
217
|
+
```bash
|
|
218
|
+
❯ namecheap-cli account balance
|
|
219
|
+
Account Balance
|
|
220
|
+
┏━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━┓
|
|
221
|
+
┃ Field ┃ Amount ┃
|
|
222
|
+
┡━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━┩
|
|
223
|
+
│ Available Balance │ 0.00 USD │
|
|
224
|
+
│ Account Balance │ 0.00 USD │
|
|
225
|
+
│ Earned Amount │ 0.00 USD │
|
|
226
|
+
│ Withdrawable │ 0.00 USD │
|
|
227
|
+
│ Auto-Renew Required │ 20.16 USD │
|
|
228
|
+
└─────────────────────┴───────────┘
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
Get detailed domain info:
|
|
232
|
+
|
|
233
|
+
```bash
|
|
234
|
+
❯ namecheap-cli domain info self.fm
|
|
235
|
+
|
|
236
|
+
Domain Information: self.fm
|
|
237
|
+
|
|
238
|
+
Status: Ok
|
|
239
|
+
Owner: adriangalilea
|
|
240
|
+
Created: 07/15/2023
|
|
241
|
+
Expires: 07/15/2026
|
|
242
|
+
Premium: No
|
|
243
|
+
WHOIS Guard: ✓ Enabled
|
|
244
|
+
DNS Provider: CUSTOM
|
|
245
|
+
```
|
|
246
|
+
|
|
209
247
|
You can also export DNS records:
|
|
210
248
|
|
|
211
249
|
```bash
|
|
@@ -320,6 +358,33 @@ nc.dns.set_custom_nameservers("example.com", [
|
|
|
320
358
|
nc.dns.set_default_nameservers("example.com")
|
|
321
359
|
```
|
|
322
360
|
|
|
361
|
+
### Domain Info
|
|
362
|
+
|
|
363
|
+
```python
|
|
364
|
+
info = nc.domains.get_info("example.com")
|
|
365
|
+
print(info.status) # 'Ok'
|
|
366
|
+
print(info.whoisguard_enabled) # True
|
|
367
|
+
print(info.dns_provider) # 'CUSTOM'
|
|
368
|
+
print(info.created) # '07/15/2023'
|
|
369
|
+
print(info.expires) # '07/15/2026'
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
### Account Balance
|
|
373
|
+
|
|
374
|
+
```python
|
|
375
|
+
bal = nc.users.get_balances()
|
|
376
|
+
print(f"{bal.available_balance} {bal.currency}") # '4932.96 USD'
|
|
377
|
+
print(bal.funds_required_for_auto_renew) # Decimal('20.16')
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
### Email Forwarding
|
|
381
|
+
|
|
382
|
+
```python
|
|
383
|
+
rules = nc.dns.get_email_forwarding("example.com")
|
|
384
|
+
for r in rules:
|
|
385
|
+
print(f"{r.mailbox} -> {r.forward_to}")
|
|
386
|
+
```
|
|
387
|
+
|
|
323
388
|
### Domain Management
|
|
324
389
|
|
|
325
390
|
```python
|
|
@@ -393,22 +458,24 @@ nc.dns.builder().a("www", "192.0.2.1", ttl=1799) # Shows as "Automatic"
|
|
|
393
458
|
nc.dns.builder().a("www", "192.0.2.1", ttl=1800) # Shows as "30 min"
|
|
394
459
|
```
|
|
395
460
|
|
|
396
|
-
##
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
461
|
+
## 📊 [API Coverage](https://www.namecheap.com/support/api/methods/)
|
|
462
|
+
|
|
463
|
+
| API | Status | Methods |
|
|
464
|
+
|-----|--------|---------|
|
|
465
|
+
| `namecheap.domains.*` | ✅ Done | `check`, `list`, `getInfo`, `register`, `renew`, `setContacts`, `lock`/`unlock` |
|
|
466
|
+
| `namecheap.domains.dns.*` | ✅ Done | `getHosts`, `setHosts` (builder pattern), `add`, `delete`, `export`, `getList`, `setCustom`, `setDefault`, `getEmailForwarding` |
|
|
467
|
+
| `namecheap.users.*` | ⚠️ Partial | `getBalances`, `getPricing` (needs debugging). Planned: `changePassword`, `update`, `create`, `login`, `resetPassword` |
|
|
468
|
+
| `namecheap.domains.*` | 🚧 Planned | `getContacts`, `getTldList`, `reactivate` |
|
|
469
|
+
| `namecheap.domains.dns.*` | 🚧 Planned | `setEmailForwarding` |
|
|
470
|
+
| `namecheap.users.address.*` | 🚧 Planned | `create`, `delete`, `getInfo`, `getList`, `setDefault`, `update` |
|
|
471
|
+
| `namecheap.ssl.*` | 🚧 Planned | `create`, `activate`, `renew`, `revoke`, `getList`, `getInfo`, `parseCSR`, `reissue`, and more |
|
|
472
|
+
| `namecheap.domains.transfer.*` | 🚧 Planned | `create`, `getStatus`, `updateStatus`, `getList` |
|
|
473
|
+
| `namecheap.domains.ns.*` | 🚧 Planned | Glue records — `create`, `delete`, `getInfo`, `update` |
|
|
474
|
+
| `namecheap.domainprivacy.*` | 🚧 Planned | `enable`, `disable`, `renew`, `getList`, `changeemailaddress` |
|
|
408
475
|
|
|
409
476
|
## 🛠️ Development
|
|
410
477
|
|
|
411
|
-
See [
|
|
478
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for setup and development guidelines.
|
|
412
479
|
|
|
413
480
|
## 📝 License
|
|
414
481
|
|
|
@@ -420,4 +487,6 @@ Contributions are welcome! Please feel free to submit a Pull Request. See the [D
|
|
|
420
487
|
|
|
421
488
|
### Contributors
|
|
422
489
|
|
|
490
|
+
- [@huntertur](https://github.com/huntertur) — Rich dependency fix
|
|
491
|
+
- [@jeffmcadams](https://github.com/jeffmcadams) — Domain serialization round-trip
|
|
423
492
|
- [@cosmin](https://github.com/cosmin) — Nameserver management
|
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
namecheap/__init__.py,sha256=
|
|
2
|
-
namecheap/client.py,sha256=
|
|
1
|
+
namecheap/__init__.py,sha256=S-84LTSVWDXJeqvDoUoSsq84250m5J0MXYEPJ6xH3kw,837
|
|
2
|
+
namecheap/client.py,sha256=KesIaZVa9HpXvlp-hc3nr2x-sqzMPiHEa8NibiPq580,6644
|
|
3
3
|
namecheap/errors.py,sha256=5bGbV1e4_jkK8YXZXbLF6GJCVUTKw1CtMl9-mz7ogZg,5010
|
|
4
4
|
namecheap/logging.py,sha256=lMR1fr1dWWz3z2NFEY-vl8b52FmmhH76R2NjyifSdYA,3396
|
|
5
|
-
namecheap/models.py,sha256=
|
|
5
|
+
namecheap/models.py,sha256=t4xloDJOgKeoERujhMRtTR0-B--ENzQsAn1WyFHyNbE,14261
|
|
6
6
|
namecheap/_api/__init__.py,sha256=ymQxKCySphoeoo4s_J0tLziXttLNhOQ8AZbCzFcuAHs,36
|
|
7
7
|
namecheap/_api/base.py,sha256=FoczO1Q860PaFUFv-S3IoIV2xaGVJAlchkWnmTI6dlw,6121
|
|
8
|
-
namecheap/_api/dns.py,sha256=
|
|
9
|
-
namecheap/_api/domains.py,sha256=
|
|
8
|
+
namecheap/_api/dns.py,sha256=MtOHr0AOUgS_Vv7U8WkLBw7xuU0XWbjAF6ptitteNmk,15827
|
|
9
|
+
namecheap/_api/domains.py,sha256=bEPshE2GN6ubd0otTwLdZCpKVT9ErmDRy8fYxS2hkIY,18272
|
|
10
|
+
namecheap/_api/users.py,sha256=CCXSZJiPkQiLHYRAlYKTBCDG3-JSPdNkNWWww71JXV0,795
|
|
10
11
|
namecheap_cli/README.md,sha256=liduIiGr8DHXGTht5swrYnvtAlcdCMQOnSdCD61g4Vw,7337
|
|
11
12
|
namecheap_cli/__init__.py,sha256=nGRHc_CkO4xKhSQdAVG-koEffP8VS0TvbfbZkg7Jg4k,108
|
|
12
|
-
namecheap_cli/__main__.py,sha256=
|
|
13
|
+
namecheap_cli/__main__.py,sha256=ZOmdVQZWkA3SHw7_nGCp_j5RdJCQff4NO6h_nIjgDnY,36425
|
|
13
14
|
namecheap_cli/completion.py,sha256=JTEMnceQli7TombjZkHh-IcZKW4RFRI8Yk5VynxPsEA,2777
|
|
14
15
|
namecheap_dns_tui/README.md,sha256=It16ZiZh0haEeaENfF5HX0Ec4dBawdTYiAi-TiG9wi0,1690
|
|
15
16
|
namecheap_dns_tui/__init__.py,sha256=-yL_1Ha41FlQcmjG-raUrZP9CjTJD3d0w2BW2X-twJg,106
|
|
@@ -18,8 +19,8 @@ namecheap_dns_tui/assets/screenshot1.png,sha256=OXO2P80ll5WRzLYgaakcNnzos8svlJoX
|
|
|
18
19
|
namecheap_dns_tui/assets/screenshot2.png,sha256=5VN_qDMNhWEyrOqKw7vxl1h-TgmZQ_V9aph3Xmf_AFg,279194
|
|
19
20
|
namecheap_dns_tui/assets/screenshot3.png,sha256=h39wSKxx1JCkgeAB7Q3_JlBcAtX1vsRFKtWtOwbBVso,220625
|
|
20
21
|
namecheap_dns_tui/assets/screenshot4.png,sha256=J4nCOW16z3vaRiPbcMiiIRgV7q3XFbi_1N1ivD1Pa4Y,238068
|
|
21
|
-
namecheap_python-1.
|
|
22
|
-
namecheap_python-1.
|
|
23
|
-
namecheap_python-1.
|
|
24
|
-
namecheap_python-1.
|
|
25
|
-
namecheap_python-1.
|
|
22
|
+
namecheap_python-1.2.0.dist-info/METADATA,sha256=R44Jl31VrMFE8lzs_YxqgGuv7sHvN0rIj9qjgdvKyv0,18433
|
|
23
|
+
namecheap_python-1.2.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
24
|
+
namecheap_python-1.2.0.dist-info/entry_points.txt,sha256=AyhiXroLUpM0Vdo_-RvH0S8o4XDPsDlsEl_65vm6DEk,96
|
|
25
|
+
namecheap_python-1.2.0.dist-info/licenses/LICENSE,sha256=pemTblFP6BBje3bBv_yL_sr2iAqB2H0-LdWMvVIR42o,1062
|
|
26
|
+
namecheap_python-1.2.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|