namecheap-python 1.0.1__py3-none-any.whl → 1.0.2__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/_api/base.py CHANGED
@@ -56,7 +56,9 @@ def normalize_xml_response(data: dict[str, Any]) -> dict[str, Any]:
56
56
  # Fix known typos from Namecheap
57
57
  if key == "@YourAdditonalCost": # Their typo (missing 'i' in Additional)
58
58
  normalized["@YourAdditionalCost"] = value # Correct spelling
59
- logger.debug("Fixed Namecheap typo: @YourAdditonalCost -> @YourAdditionalCost")
59
+ logger.debug(
60
+ "Fixed Namecheap typo: @YourAdditonalCost -> @YourAdditionalCost"
61
+ )
60
62
 
61
63
  # Debug canary: Alert if they have both versions (means they're fixing it)
62
64
  if "@YourAdditionalCost" in data and "@YourAdditonalCost" in data:
@@ -70,7 +72,8 @@ def normalize_xml_response(data: dict[str, Any]) -> dict[str, Any]:
70
72
  normalized[key] = normalize_xml_response(value)
71
73
  elif isinstance(value, list):
72
74
  normalized[key] = [
73
- normalize_xml_response(item) if isinstance(item, dict) else item for item in value
75
+ normalize_xml_response(item) if isinstance(item, dict) else item
76
+ for item in value
74
77
  ]
75
78
 
76
79
  return normalized
namecheap/_api/dns.py CHANGED
@@ -35,7 +35,9 @@ class DNSRecordBuilder:
35
35
  Self for chaining
36
36
  """
37
37
  self._records.append(
38
- DNSRecord.model_validate({"@Name": name, "@Type": "A", "@Address": ip, "@TTL": ttl})
38
+ DNSRecord.model_validate(
39
+ {"@Name": name, "@Type": "A", "@Address": ip, "@TTL": ttl}
40
+ )
39
41
  )
40
42
  return self
41
43
 
@@ -94,7 +96,13 @@ class DNSRecordBuilder:
94
96
  """
95
97
  self._records.append(
96
98
  DNSRecord.model_validate(
97
- {"@Name": name, "@Type": "MX", "@Address": server, "@TTL": ttl, "@MXPref": priority}
99
+ {
100
+ "@Name": name,
101
+ "@Type": "MX",
102
+ "@Address": server,
103
+ "@TTL": ttl,
104
+ "@MXPref": priority,
105
+ }
98
106
  )
99
107
  )
100
108
  return self
namecheap/_api/domains.py CHANGED
@@ -17,7 +17,9 @@ from .base import BaseAPI
17
17
  class DomainsAPI(BaseAPI):
18
18
  """Domain management operations."""
19
19
 
20
- def check(self, *domains: str, include_pricing: bool = False) -> builtins.list[DomainCheck]:
20
+ def check(
21
+ self, *domains: str, include_pricing: bool = False
22
+ ) -> builtins.list[DomainCheck]:
21
23
  """
22
24
  Check domain availability.
23
25
 
@@ -158,7 +160,9 @@ class DomainsAPI(BaseAPI):
158
160
 
159
161
  # Add contact info if provided
160
162
  if contact:
161
- contact_data = contact.model_dump() if isinstance(contact, Contact) else contact
163
+ contact_data = (
164
+ contact.model_dump() if isinstance(contact, Contact) else contact
165
+ )
162
166
  # Add contact fields for all types (Registrant, Tech, Admin, AuxBilling)
163
167
  for contact_type in ["Registrant", "Tech", "Admin", "AuxBilling"]:
164
168
  for field, value in contact_data.items():
@@ -284,7 +288,9 @@ class DomainsAPI(BaseAPI):
284
288
  assert isinstance(result, dict)
285
289
  return bool(result)
286
290
 
287
- def _get_pricing(self, domains: builtins.list[str]) -> dict[str, dict[str, Decimal | None]]:
291
+ def _get_pricing(
292
+ self, domains: builtins.list[str]
293
+ ) -> dict[str, dict[str, Decimal | None]]:
288
294
  """
289
295
  Get pricing information for domains.
290
296
 
@@ -362,7 +368,9 @@ class DomainsAPI(BaseAPI):
362
368
  if not isinstance(products, list):
363
369
  products = [products] if products else []
364
370
 
365
- logger.debug(f"Found {len(products)} products in REGISTER category")
371
+ logger.debug(
372
+ f"Found {len(products)} products in REGISTER category"
373
+ )
366
374
 
367
375
  # Find the product matching our TLD
368
376
  for product in products:
@@ -370,7 +378,9 @@ class DomainsAPI(BaseAPI):
370
378
  continue
371
379
 
372
380
  product_name = product.get("@Name", "")
373
- logger.debug(f"Checking product: {product_name} vs {tld}")
381
+ logger.debug(
382
+ f"Checking product: {product_name} vs {tld}"
383
+ )
374
384
 
375
385
  if product_name.lower() == tld.lower():
376
386
  # Get price list
@@ -378,7 +388,9 @@ class DomainsAPI(BaseAPI):
378
388
  if not isinstance(price_info, list):
379
389
  price_info = [price_info] if price_info else []
380
390
 
381
- logger.debug(f"Found {len(price_info)} price entries for {tld}")
391
+ logger.debug(
392
+ f"Found {len(price_info)} price entries for {tld}"
393
+ )
382
394
 
383
395
  # Find 1 year price
384
396
  for price in price_info:
@@ -405,13 +417,17 @@ class DomainsAPI(BaseAPI):
405
417
  # Apply to all domains with this TLD
406
418
  for domain in domain_list:
407
419
  pricing[domain] = {
408
- "regular_price": Decimal(regular_price)
420
+ "regular_price": Decimal(
421
+ regular_price
422
+ )
409
423
  if regular_price
410
424
  else None,
411
425
  "your_price": Decimal(your_price)
412
426
  if your_price
413
427
  else None,
414
- "retail_price": Decimal(retail_price)
428
+ "retail_price": Decimal(
429
+ retail_price
430
+ )
415
431
  if retail_price
416
432
  else None,
417
433
  }
namecheap/logging.py CHANGED
@@ -74,13 +74,21 @@ class ErrorDisplay:
74
74
 
75
75
  if hasattr(error, "_ip_help") and error._ip_help is not None:
76
76
  console.print("\n[yellow]🔍 IP Configuration Issue[/yellow]")
77
- console.print(f" Your current IP: [cyan]{error._ip_help['actual_ip']}[/cyan]")
78
- console.print(f" Configured IP: [cyan]{error._ip_help['configured_ip']}[/cyan]")
77
+ console.print(
78
+ f" Your current IP: [cyan]{error._ip_help['actual_ip']}[/cyan]"
79
+ )
80
+ console.print(
81
+ f" Configured IP: [cyan]{error._ip_help['configured_ip']}[/cyan]"
82
+ )
79
83
  console.print("\n[yellow]💡 To fix this:[/yellow]")
80
- console.print(" 1. Log in to [link=https://www.namecheap.com]Namecheap[/link]")
84
+ console.print(
85
+ " 1. Log in to [link=https://www.namecheap.com]Namecheap[/link]"
86
+ )
81
87
  console.print(" 2. Go to Profile → Tools → API Access")
82
88
  actual_ip = error._ip_help["actual_ip"]
83
- console.print(f" 3. Add this IP to whitelist: [cyan]{actual_ip}[/cyan]")
89
+ console.print(
90
+ f" 3. Add this IP to whitelist: [cyan]{actual_ip}[/cyan]"
91
+ )
84
92
  console.print(
85
93
  f" 4. Update your .env file: [cyan]NAMECHEAP_CLIENT_IP={actual_ip}[/cyan]"
86
94
  )
namecheap/models.py CHANGED
@@ -89,7 +89,9 @@ class DomainCheck(XMLModel):
89
89
  """
90
90
 
91
91
  domain: str = Field(alias="@Domain", description="Domain name checked")
92
- available: bool = Field(alias="@Available", description="Whether domain is available")
92
+ available: bool = Field(
93
+ alias="@Available", description="Whether domain is available"
94
+ )
93
95
  premium: bool = Field(
94
96
  default=False,
95
97
  alias="@IsPremiumName",
@@ -182,8 +184,8 @@ class DNSRecord(XMLModel):
182
184
  """A DNS record."""
183
185
 
184
186
  name: str = Field(alias="@Name", default="@")
185
- type: Literal["A", "AAAA", "CNAME", "MX", "NS", "TXT", "URL", "URL301", "FRAME"] = Field(
186
- alias="@Type"
187
+ type: Literal["A", "AAAA", "CNAME", "MX", "NS", "TXT", "URL", "URL301", "FRAME"] = (
188
+ Field(alias="@Type")
187
189
  )
188
190
  value: str = Field(alias="@Address")
189
191
  ttl: int = Field(alias="@TTL", default=1800)
namecheap_cli/__main__.py CHANGED
@@ -23,23 +23,24 @@ from .completion import get_completion_script
23
23
 
24
24
  console = Console()
25
25
 
26
+
26
27
  # Configuration
27
28
  def get_config_dir() -> Path:
28
29
  """Get config directory, using XDG on Unix-like systems."""
29
- import sys
30
30
  import os
31
-
31
+ import sys
32
+
32
33
  if sys.platform == "win32":
33
34
  # Windows: use platformdirs for proper Windows paths
34
35
  from platformdirs import user_config_dir
36
+
35
37
  return Path(user_config_dir("namecheap"))
36
- else:
37
- # Linux/macOS: use XDG
38
- xdg_config = os.environ.get("XDG_CONFIG_HOME")
39
- if xdg_config:
40
- return Path(xdg_config) / "namecheap"
41
- else:
42
- return Path.home() / ".config" / "namecheap"
38
+ # Linux/macOS: use XDG
39
+ xdg_config = os.environ.get("XDG_CONFIG_HOME")
40
+ if xdg_config:
41
+ return Path(xdg_config) / "namecheap"
42
+ return Path.home() / ".config" / "namecheap"
43
+
43
44
 
44
45
  CONFIG_DIR = get_config_dir()
45
46
  CONFIG_FILE = CONFIG_DIR / "config.yaml"
@@ -74,8 +75,12 @@ class Config:
74
75
  # Check if config file exists
75
76
  if not CONFIG_FILE.exists():
76
77
  console.print("[red]❌ Configuration not found![/red]")
77
- console.print(f"\nPlease run [bold cyan]namecheap-cli config init[/bold cyan] to set up your configuration.")
78
- console.print(f"\nThis will create a config file at: [dim]{CONFIG_FILE}[/dim]")
78
+ console.print(
79
+ "\nPlease run [bold cyan]namecheap-cli config init[/bold cyan] to set up your configuration."
80
+ )
81
+ console.print(
82
+ f"\nThis will create a config file at: [dim]{CONFIG_FILE}[/dim]"
83
+ )
79
84
  sys.exit(1)
80
85
 
81
86
  config = self.load_config()
@@ -83,9 +88,15 @@ class Config:
83
88
 
84
89
  # Check if profile exists
85
90
  if not profile_config:
86
- console.print(f"[red]❌ Profile '{self.profile}' not found in configuration![/red]")
87
- console.print(f"\nAvailable profiles: {', '.join(config.get('profiles', {}).keys()) or 'none'}")
88
- console.print(f"\nRun [bold cyan]namecheap-cli config init[/bold cyan] to create a new profile.")
91
+ console.print(
92
+ f"[red]❌ Profile '{self.profile}' not found in configuration![/red]"
93
+ )
94
+ console.print(
95
+ f"\nAvailable profiles: {', '.join(config.get('profiles', {}).keys()) or 'none'}"
96
+ )
97
+ console.print(
98
+ "\nRun [bold cyan]namecheap-cli config init[/bold cyan] to create a new profile."
99
+ )
89
100
  sys.exit(1)
90
101
 
91
102
  # Override sandbox if specified
@@ -98,10 +109,17 @@ class Config:
98
109
  except Exception as e:
99
110
  # Check for common configuration errors
100
111
  error_msg = str(e)
101
- if "Parameter APIUser is missing" in error_msg or "Parameter APIKey is missing" in error_msg:
112
+ if (
113
+ "Parameter APIUser is missing" in error_msg
114
+ or "Parameter APIKey is missing" in error_msg
115
+ ):
102
116
  console.print("[red]❌ Invalid or incomplete configuration![/red]")
103
- console.print(f"\nYour configuration appears to be missing required fields.")
104
- console.print(f"Please run [bold cyan]namecheap-cli config init[/bold cyan] to reconfigure.")
117
+ console.print(
118
+ "\nYour configuration appears to be missing required fields."
119
+ )
120
+ console.print(
121
+ "Please run [bold cyan]namecheap-cli config init[/bold cyan] to reconfigure."
122
+ )
105
123
  else:
106
124
  console.print(f"[red]❌ Error initializing client: {e}[/red]")
107
125
  sys.exit(1)
@@ -131,7 +149,9 @@ def output_formatter(data: Any, format: str, headers: list[str] | None = None) -
131
149
 
132
150
 
133
151
  @click.group()
134
- @click.option("--config", "config_path", type=click.Path(exists=True), help="Config file path")
152
+ @click.option(
153
+ "--config", "config_path", type=click.Path(exists=True), help="Config file path"
154
+ )
135
155
  @click.option("--profile", default="default", help="Config profile to use")
136
156
  @click.option("--sandbox", is_flag=True, help="Use sandbox API")
137
157
  @click.option(
@@ -146,7 +166,9 @@ def output_formatter(data: Any, format: str, headers: list[str] | None = None) -
146
166
  @click.option("--verbose", "-v", is_flag=True, help="Verbose output")
147
167
  @click.version_option()
148
168
  @pass_config
149
- def cli(config: Config, config_path, profile, sandbox, output, no_color, quiet, verbose) -> None:
169
+ def cli(
170
+ config: Config, config_path, profile, sandbox, output, no_color, quiet, verbose
171
+ ) -> None:
150
172
  """Namecheap CLI - Manage domains and DNS records."""
151
173
  config.output_format = output
152
174
  config.no_color = no_color
@@ -167,10 +189,14 @@ def domain_group() -> None:
167
189
 
168
190
  @domain_group.command("list")
169
191
  @click.option("--status", type=click.Choice(["active", "expired", "locked"]))
170
- @click.option("--sort", type=click.Choice(["name", "expires", "created"]), default="name")
192
+ @click.option(
193
+ "--sort", type=click.Choice(["name", "expires", "created"]), default="name"
194
+ )
171
195
  @click.option("--expiring-in", type=int, help="Show domains expiring within N days")
172
196
  @pass_config
173
- def domain_list(config: Config, status: str | None, sort: str, expiring_in: int | None) -> None:
197
+ def domain_list(
198
+ config: Config, status: str | None, sort: str, expiring_in: int | None
199
+ ) -> None:
174
200
  """List all domains."""
175
201
  nc = config.init_client()
176
202
 
@@ -293,7 +319,7 @@ def domain_check(config: Config, domains: tuple[str, ...], file) -> None:
293
319
  row = [
294
320
  result.domain,
295
321
  f"[{available_style}]{available_text}[/{available_style}]",
296
- price_text
322
+ price_text,
297
323
  ]
298
324
 
299
325
  table.add_row(*row)
@@ -354,12 +380,18 @@ def domain_info(config: Config, domain: str) -> None:
354
380
  f"[bold]Status:[/bold] "
355
381
  f"{'Active' if not domain_obj.is_expired else '[red]Expired[/red]'}"
356
382
  )
357
- console.print(f"[bold]Created:[/bold] {domain_obj.created.strftime('%Y-%m-%d')}")
358
- console.print(f"[bold]Expires:[/bold] {domain_obj.expires.strftime('%Y-%m-%d')}")
383
+ console.print(
384
+ f"[bold]Created:[/bold] {domain_obj.created.strftime('%Y-%m-%d')}"
385
+ )
386
+ console.print(
387
+ f"[bold]Expires:[/bold] {domain_obj.expires.strftime('%Y-%m-%d')}"
388
+ )
359
389
  console.print(
360
390
  f"[bold]Auto-Renew:[/bold] {'✓ Enabled' if domain_obj.auto_renew else '✗ Disabled'}"
361
391
  )
362
- console.print(f"[bold]Locked:[/bold] {'🔒 Yes' if domain_obj.is_locked else '🔓 No'}")
392
+ console.print(
393
+ f"[bold]Locked:[/bold] {'🔒 Yes' if domain_obj.is_locked else '🔓 No'}"
394
+ )
363
395
  console.print(
364
396
  f"[bold]WHOIS Guard:[/bold] "
365
397
  f"{'✓ Enabled' if domain_obj.whois_guard else '✗ Disabled'}"
@@ -368,7 +400,9 @@ def domain_info(config: Config, domain: str) -> None:
368
400
  # Calculate days until expiration
369
401
  days_left = (domain_obj.expires - datetime.now()).days
370
402
  if days_left < 30:
371
- console.print(f"\n⚠️ [yellow]Domain expires in {days_left} days![/yellow]")
403
+ console.print(
404
+ f"\n⚠️ [yellow]Domain expires in {days_left} days![/yellow]"
405
+ )
372
406
  elif days_left < 60:
373
407
  console.print(f"\n📅 Domain expires in {days_left} days")
374
408
 
@@ -501,7 +535,9 @@ def dns_add(
501
535
 
502
536
  try:
503
537
  # Create the new record
504
- new_record = DNSRecord(name=name, type=record_type, value=value, ttl=ttl, priority=priority)
538
+ new_record = DNSRecord(
539
+ name=name, type=record_type, value=value, ttl=ttl, priority=priority
540
+ )
505
541
 
506
542
  # Get existing records
507
543
  if not config.quiet:
@@ -572,7 +608,9 @@ def dns_delete(
572
608
  nc = config.init_client()
573
609
 
574
610
  if all and not (type or name or value) and not yes:
575
- console.print(f"[red]⚠️ Warning: This will delete ALL DNS records for {domain}[/red]")
611
+ console.print(
612
+ f"[red]⚠️ Warning: This will delete ALL DNS records for {domain}[/red]"
613
+ )
576
614
  if not Confirm.ask("Are you sure?", default=False):
577
615
  console.print("[yellow]Cancelled[/yellow]")
578
616
  return
@@ -609,7 +647,9 @@ def dns_delete(
609
647
 
610
648
  # Show what will be deleted
611
649
  if not yes and not config.quiet:
612
- console.print(f"[yellow]Will delete {len(records_to_delete)} record(s):[/yellow]")
650
+ console.print(
651
+ f"[yellow]Will delete {len(records_to_delete)} record(s):[/yellow]"
652
+ )
613
653
  for r in records_to_delete:
614
654
  console.print(f" • {r.type} {r.name} → {r.value}")
615
655
 
@@ -664,7 +704,9 @@ def dns_delete(
664
704
  default="yaml",
665
705
  help="Export format",
666
706
  )
667
- @click.option("--output", "-o", type=click.File("w"), help="Output file (default: stdout)")
707
+ @click.option(
708
+ "--output", "-o", type=click.File("w"), help="Output file (default: stdout)"
709
+ )
668
710
  @pass_config
669
711
  def dns_export(config: Config, domain: str, format: str, output) -> None:
670
712
  """Export DNS records."""
@@ -679,7 +721,9 @@ def dns_export(config: Config, domain: str, format: str, output) -> None:
679
721
 
680
722
  for r in sorted(records, key=lambda x: (x.type, x.name)):
681
723
  if r.type == "MX":
682
- lines.append(f"{r.name}\t{r.ttl}\tIN\t{r.type}\t{r.priority}\t{r.value}")
724
+ lines.append(
725
+ f"{r.name}\t{r.ttl}\tIN\t{r.type}\t{r.priority}\t{r.value}"
726
+ )
683
727
  else:
684
728
  lines.append(f"{r.name}\t{r.ttl}\tIN\t{r.type}\t{r.value}")
685
729
 
@@ -721,7 +765,9 @@ def dns_export(config: Config, domain: str, format: str, output) -> None:
721
765
  if output:
722
766
  output.write(content)
723
767
  if not config.quiet:
724
- console.print(f"[green]✅ Exported {len(records)} records to {output.name}[/green]")
768
+ console.print(
769
+ f"[green]✅ Exported {len(records)} records to {output.name}[/green]"
770
+ )
725
771
  else:
726
772
  click.echo(content)
727
773
 
@@ -744,7 +790,9 @@ def account_balance(config: Config) -> None:
744
790
 
745
791
  try:
746
792
  # This would need to be implemented in the SDK
747
- console.print("[yellow]Account balance check not yet implemented in SDK[/yellow]")
793
+ console.print(
794
+ "[yellow]Account balance check not yet implemented in SDK[/yellow]"
795
+ )
748
796
  console.print("This feature requires the users.getBalances API method")
749
797
 
750
798
  except NamecheapError as e:
@@ -770,9 +818,11 @@ def config_init() -> None:
770
818
  return
771
819
 
772
820
  console.print("\n[bold cyan]Namecheap CLI Configuration Wizard[/bold cyan]\n")
773
-
821
+
774
822
  console.print("[dim]To get your API key:[/dim]")
775
- console.print("1. Go to [link=https://ap.www.namecheap.com/settings/tools/apiaccess/]https://ap.www.namecheap.com/settings/tools/apiaccess/[/link]")
823
+ console.print(
824
+ "1. Go to [link=https://ap.www.namecheap.com/settings/tools/apiaccess/]https://ap.www.namecheap.com/settings/tools/apiaccess/[/link]"
825
+ )
776
826
  console.print("2. Enable API access")
777
827
  console.print("3. Whitelist your IP address")
778
828
  console.print("4. Generate your API key\n")
@@ -812,7 +862,9 @@ def config_init() -> None:
812
862
 
813
863
  console.print(f"\n[green]✅ Configuration saved to {CONFIG_FILE}[/green]")
814
864
  console.print("\n💡 Tips:")
815
- console.print(" • You can also use environment variables (NAMECHEAP_API_KEY, etc.)")
865
+ console.print(
866
+ " • You can also use environment variables (NAMECHEAP_API_KEY, etc.)"
867
+ )
816
868
  console.print(" • Add more profiles with: nc config add-profile <name>")
817
869
  console.print(" • Use a profile with: nc --profile <name> <command>")
818
870
 
@@ -839,7 +891,9 @@ def completion(shell: str) -> None:
839
891
  console.print("[dim]nc completion zsh >> ~/.zshrc[/dim]")
840
892
  elif shell == "fish":
841
893
  console.print("[dim]# Add to fish config:[/dim]")
842
- console.print("[dim]nc completion fish > ~/.config/fish/completions/nc.fish[/dim]")
894
+ console.print(
895
+ "[dim]nc completion fish > ~/.config/fish/completions/nc.fish[/dim]"
896
+ )
843
897
 
844
898
 
845
899
  def main() -> None:
@@ -189,7 +189,9 @@ class AddRecordModal(ModalScreen):
189
189
  with ScrollableContainer(id="form-scroll"):
190
190
  with Vertical(classes="field-group"):
191
191
  yield Label("Record Type:")
192
- initial_type = self.editing_record.type if self.editing_record else "A"
192
+ initial_type = (
193
+ self.editing_record.type if self.editing_record else "A"
194
+ )
193
195
  yield Select(
194
196
  [
195
197
  ("A - IPv4 Address", "A"),
@@ -208,7 +210,9 @@ class AddRecordModal(ModalScreen):
208
210
 
209
211
  with Vertical(classes="field-group"):
210
212
  yield Label("Name:")
211
- initial_name = self.editing_record.name if self.editing_record else "@"
213
+ initial_name = (
214
+ self.editing_record.name if self.editing_record else "@"
215
+ )
212
216
  yield Input(
213
217
  placeholder="@ for root or subdomain",
214
218
  id="record-name",
@@ -217,7 +221,9 @@ class AddRecordModal(ModalScreen):
217
221
 
218
222
  with Vertical(classes="field-group"):
219
223
  yield Label("Value:")
220
- initial_value = self.editing_record.value if self.editing_record else ""
224
+ initial_value = (
225
+ self.editing_record.value if self.editing_record else ""
226
+ )
221
227
  yield Input(
222
228
  placeholder="Enter value based on record type",
223
229
  id="record-value",
@@ -226,7 +232,9 @@ class AddRecordModal(ModalScreen):
226
232
 
227
233
  with Vertical(classes="field-group"):
228
234
  yield Label("TTL (seconds):")
229
- initial_ttl = str(self.editing_record.ttl) if self.editing_record else "1800"
235
+ initial_ttl = (
236
+ str(self.editing_record.ttl) if self.editing_record else "1800"
237
+ )
230
238
  yield Input(placeholder="1800", id="record-ttl", value=initial_ttl)
231
239
 
232
240
  with Vertical(classes="field-group", id="priority-group"):
@@ -236,7 +244,9 @@ class AddRecordModal(ModalScreen):
236
244
  if self.editing_record and self.editing_record.priority
237
245
  else ""
238
246
  )
239
- yield Input(placeholder="10", id="record-priority", value=initial_priority)
247
+ yield Input(
248
+ placeholder="10", id="record-priority", value=initial_priority
249
+ )
240
250
 
241
251
  with Horizontal(classes="button-row"):
242
252
  button_text = "Save Changes" if self.editing_record else "Add Record"
@@ -482,7 +492,9 @@ class DNSManagerApp(App):
482
492
  str(record.priority) if record.priority else "-",
483
493
  )
484
494
 
485
- self.update_status(f"Loaded {len(self.records)} records for {self.current_domain}")
495
+ self.update_status(
496
+ f"Loaded {len(self.records)} records for {self.current_domain}"
497
+ )
486
498
 
487
499
  def action_refresh(self) -> None:
488
500
  """Refresh records."""
@@ -623,7 +635,9 @@ class DNSManagerApp(App):
623
635
  )
624
636
  builder._records[
625
637
  -1
626
- ].type = "URL" # Override to use URL instead of URL301
638
+ ].type = (
639
+ "URL" # Override to use URL instead of URL301
640
+ )
627
641
  elif rec.type == "URL301":
628
642
  builder.url(
629
643
  rec.name,
@@ -674,7 +688,9 @@ class DNSManagerApp(App):
674
688
  def handle_confirm(confirmed: bool) -> None:
675
689
  """Handle delete confirmation."""
676
690
  if confirmed:
677
- self.update_status(f"Deleting {record.type} record '{record.name}'...")
691
+ self.update_status(
692
+ f"Deleting {record.type} record '{record.name}'..."
693
+ )
678
694
 
679
695
  def delete() -> None:
680
696
  try:
@@ -711,7 +727,9 @@ class DNSManagerApp(App):
711
727
  )
712
728
  builder._records[
713
729
  -1
714
- ].type = "URL" # Override to use URL instead of URL301
730
+ ].type = (
731
+ "URL" # Override to use URL instead of URL301
732
+ )
715
733
  elif rec.type == "URL301":
716
734
  builder.url(
717
735
  rec.name,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: namecheap-python
3
- Version: 1.0.1
3
+ Version: 1.0.2
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
@@ -36,13 +36,7 @@ Requires-Dist: platformdirs>=4.0.0; extra == 'cli'
36
36
  Requires-Dist: pyyaml>=6.0.0; extra == 'cli'
37
37
  Requires-Dist: rich>=13.0.0; extra == 'cli'
38
38
  Provides-Extra: dev
39
- Requires-Dist: mypy>=1.11.0; extra == 'dev'
40
- Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
41
- Requires-Dist: pytest-cov>=5.0.0; extra == 'dev'
42
- Requires-Dist: pytest-httpx>=0.30.0; extra == 'dev'
43
- Requires-Dist: pytest>=8.0.0; extra == 'dev'
44
39
  Requires-Dist: ruff>=0.7.0; extra == 'dev'
45
- Requires-Dist: types-xmltodict>=0.13.0; extra == 'dev'
46
40
  Provides-Extra: tui
47
41
  Requires-Dist: textual>=0.47.0; extra == 'tui'
48
42
  Description-Content-Type: text/markdown
@@ -1,25 +1,25 @@
1
1
  namecheap/__init__.py,sha256=4UD1BF-qTulQicElN3CmB5hUeKnlLPvtpbJD08YZp94,666
2
2
  namecheap/client.py,sha256=wnhCA5zeZMGypD1uNHbMYCGoP9paaZjtYZucBUsEY6k,6441
3
3
  namecheap/errors.py,sha256=5bGbV1e4_jkK8YXZXbLF6GJCVUTKw1CtMl9-mz7ogZg,5010
4
- namecheap/logging.py,sha256=craqZaxecjoxFL6SD6iyvj09VXx8QeivHHYWTeYhhbQ,3244
5
- namecheap/models.py,sha256=rOtPFeEwGaGwA7H0CCbjGSrzrF-wuiaqShV7f-LDgCY,11894
4
+ namecheap/logging.py,sha256=lMR1fr1dWWz3z2NFEY-vl8b52FmmhH76R2NjyifSdYA,3396
5
+ namecheap/models.py,sha256=IUNi103jcQ7T_WgfcqXuXsZokkjUDRNYkPwtr7KJ_qU,11910
6
6
  namecheap/_api/__init__.py,sha256=ymQxKCySphoeoo4s_J0tLziXttLNhOQ8AZbCzFcuAHs,36
7
- namecheap/_api/base.py,sha256=vC0d8csUGMIUEZ1SWLLqJpT3xlQ-2FfJMKs_aFbu4pY,6075
8
- namecheap/_api/dns.py,sha256=Yvx91QIWrDx3ZxxmH_NLo_M9MP55aL71CJ6mXyJZUT0,10813
9
- namecheap/_api/domains.py,sha256=EUXV7R5wQyPHQHfDITe2IWRlPF7V-df-K0q2XnrvshI,16113
7
+ namecheap/_api/base.py,sha256=FoczO1Q860PaFUFv-S3IoIV2xaGVJAlchkWnmTI6dlw,6121
8
+ namecheap/_api/dns.py,sha256=Eibn3NzR1o3p_ukxUFDeaKTrJYgBnIomMBKsp881ZrE,10962
9
+ namecheap/_api/domains.py,sha256=h6cWc03iCwPqOJTfbR8pyom_8MUVPoqSIRJRws1i3UY,16603
10
10
  namecheap_cli/README.md,sha256=liduIiGr8DHXGTht5swrYnvtAlcdCMQOnSdCD61g4Vw,7337
11
11
  namecheap_cli/__init__.py,sha256=nGRHc_CkO4xKhSQdAVG-koEffP8VS0TvbfbZkg7Jg4k,108
12
- namecheap_cli/__main__.py,sha256=l-9egf6_9Gitocq10f2agcyjubd-1KFC76K4kAFGiNQ,30154
12
+ namecheap_cli/__main__.py,sha256=08iIreRm_30z-mmcvqd-qFEaoGWgOJJsCT7UPk7EZ-E,30768
13
13
  namecheap_cli/completion.py,sha256=JTEMnceQli7TombjZkHh-IcZKW4RFRI8Yk5VynxPsEA,2777
14
14
  namecheap_dns_tui/README.md,sha256=It16ZiZh0haEeaENfF5HX0Ec4dBawdTYiAi-TiG9wi0,1690
15
15
  namecheap_dns_tui/__init__.py,sha256=-yL_1Ha41FlQcmjG-raUrZP9CjTJD3d0w2BW2X-twJg,106
16
- namecheap_dns_tui/__main__.py,sha256=xGn07jj7krv_y-WaXWXUafK2R2P1oeFEwDw1L8NLiC4,29568
16
+ namecheap_dns_tui/__main__.py,sha256=DSSNcLAjJvQYlrVtdfped9wwM28kdisbFEZ6oPfD8jA,30034
17
17
  namecheap_dns_tui/assets/screenshot1.png,sha256=OXO2P80ll5WRzLYgaakcNnzos8svlJoX8Ai9eZM3HjE,194120
18
18
  namecheap_dns_tui/assets/screenshot2.png,sha256=5VN_qDMNhWEyrOqKw7vxl1h-TgmZQ_V9aph3Xmf_AFg,279194
19
19
  namecheap_dns_tui/assets/screenshot3.png,sha256=h39wSKxx1JCkgeAB7Q3_JlBcAtX1vsRFKtWtOwbBVso,220625
20
20
  namecheap_dns_tui/assets/screenshot4.png,sha256=J4nCOW16z3vaRiPbcMiiIRgV7q3XFbi_1N1ivD1Pa4Y,238068
21
- namecheap_python-1.0.1.dist-info/METADATA,sha256=BUpPd6I_zUAB0oy3aJ9iwG0iI6T88dHxx2sY1W-BtJI,14130
22
- namecheap_python-1.0.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
23
- namecheap_python-1.0.1.dist-info/entry_points.txt,sha256=AyhiXroLUpM0Vdo_-RvH0S8o4XDPsDlsEl_65vm6DEk,96
24
- namecheap_python-1.0.1.dist-info/licenses/LICENSE,sha256=pemTblFP6BBje3bBv_yL_sr2iAqB2H0-LdWMvVIR42o,1062
25
- namecheap_python-1.0.1.dist-info/RECORD,,
21
+ namecheap_python-1.0.2.dist-info/METADATA,sha256=h9P8gDpU73MAIShvep6h74ideSuHTdvodKjdJvNmvjQ,13831
22
+ namecheap_python-1.0.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
23
+ namecheap_python-1.0.2.dist-info/entry_points.txt,sha256=AyhiXroLUpM0Vdo_-RvH0S8o4XDPsDlsEl_65vm6DEk,96
24
+ namecheap_python-1.0.2.dist-info/licenses/LICENSE,sha256=pemTblFP6BBje3bBv_yL_sr2iAqB2H0-LdWMvVIR42o,1062
25
+ namecheap_python-1.0.2.dist-info/RECORD,,