namecheap-python 1.0.1__tar.gz → 1.0.3__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.3/.github/cliff.toml +34 -0
- {namecheap_python-1.0.1 → namecheap_python-1.0.3}/.github/workflows/release.yml +52 -7
- {namecheap_python-1.0.1 → namecheap_python-1.0.3}/.pre-commit-config.yaml +0 -12
- {namecheap_python-1.0.1 → namecheap_python-1.0.3}/PKG-INFO +1 -7
- {namecheap_python-1.0.1 → namecheap_python-1.0.3}/examples/quickstart.py +3 -1
- {namecheap_python-1.0.1 → namecheap_python-1.0.3}/pyproject.toml +3 -33
- {namecheap_python-1.0.1 → namecheap_python-1.0.3}/src/namecheap/_api/base.py +5 -2
- {namecheap_python-1.0.1 → namecheap_python-1.0.3}/src/namecheap/_api/dns.py +10 -2
- {namecheap_python-1.0.1 → namecheap_python-1.0.3}/src/namecheap/_api/domains.py +24 -8
- {namecheap_python-1.0.1 → namecheap_python-1.0.3}/src/namecheap/logging.py +12 -4
- {namecheap_python-1.0.1 → namecheap_python-1.0.3}/src/namecheap/models.py +5 -3
- {namecheap_python-1.0.1 → namecheap_python-1.0.3}/src/namecheap_cli/__main__.py +91 -37
- {namecheap_python-1.0.1 → namecheap_python-1.0.3}/src/namecheap_dns_tui/__main__.py +27 -9
- {namecheap_python-1.0.1 → namecheap_python-1.0.3}/uv.lock +236 -232
- namecheap_python-1.0.1/.github/workflows/lint.yml +0 -33
- {namecheap_python-1.0.1 → namecheap_python-1.0.3}/.env.example +0 -0
- {namecheap_python-1.0.1 → namecheap_python-1.0.3}/.gitignore +0 -0
- {namecheap_python-1.0.1 → namecheap_python-1.0.3}/CLI.md +0 -0
- {namecheap_python-1.0.1 → namecheap_python-1.0.3}/LICENSE +0 -0
- {namecheap_python-1.0.1 → namecheap_python-1.0.3}/MANIFEST.in +0 -0
- {namecheap_python-1.0.1 → namecheap_python-1.0.3}/README.md +0 -0
- {namecheap_python-1.0.1 → namecheap_python-1.0.3}/docs/dev/README.md +0 -0
- {namecheap_python-1.0.1 → namecheap_python-1.0.3}/examples/README.md +0 -0
- {namecheap_python-1.0.1 → namecheap_python-1.0.3}/pending.md +0 -0
- {namecheap_python-1.0.1 → namecheap_python-1.0.3}/src/namecheap/__init__.py +0 -0
- {namecheap_python-1.0.1 → namecheap_python-1.0.3}/src/namecheap/_api/__init__.py +0 -0
- {namecheap_python-1.0.1 → namecheap_python-1.0.3}/src/namecheap/client.py +0 -0
- {namecheap_python-1.0.1 → namecheap_python-1.0.3}/src/namecheap/errors.py +0 -0
- {namecheap_python-1.0.1 → namecheap_python-1.0.3}/src/namecheap_cli/README.md +0 -0
- {namecheap_python-1.0.1 → namecheap_python-1.0.3}/src/namecheap_cli/__init__.py +0 -0
- {namecheap_python-1.0.1 → namecheap_python-1.0.3}/src/namecheap_cli/completion.py +0 -0
- {namecheap_python-1.0.1 → namecheap_python-1.0.3}/src/namecheap_dns_tui/README.md +0 -0
- {namecheap_python-1.0.1 → namecheap_python-1.0.3}/src/namecheap_dns_tui/__init__.py +0 -0
- {namecheap_python-1.0.1 → namecheap_python-1.0.3}/src/namecheap_dns_tui/assets/screenshot1.png +0 -0
- {namecheap_python-1.0.1 → namecheap_python-1.0.3}/src/namecheap_dns_tui/assets/screenshot2.png +0 -0
- {namecheap_python-1.0.1 → namecheap_python-1.0.3}/src/namecheap_dns_tui/assets/screenshot3.png +0 -0
- {namecheap_python-1.0.1 → namecheap_python-1.0.3}/src/namecheap_dns_tui/assets/screenshot4.png +0 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
[changelog]
|
|
2
|
+
body = """
|
|
3
|
+
{%- macro remote_url() -%}
|
|
4
|
+
https://github.com/{{ remote.github.owner }}/{{ remote.github.repo }}
|
|
5
|
+
{%- endmacro -%}
|
|
6
|
+
|
|
7
|
+
{% for group, commits in commits | group_by(attribute="group") %}
|
|
8
|
+
### {{ group | striptags | trim | upper_first }}
|
|
9
|
+
{% for commit in commits %}
|
|
10
|
+
- {% if commit.scope %}*({{ commit.scope }})* {% endif %}{% if commit.breaking %}[**breaking**] {% endif %}{{ commit.message | upper_first }} - ([{{ commit.id | truncate(length=7, end="") }}]({{ self::remote_url() }}/commit/{{ commit.id }}))
|
|
11
|
+
{%- endfor %}
|
|
12
|
+
{% endfor %}
|
|
13
|
+
"""
|
|
14
|
+
trim = true
|
|
15
|
+
|
|
16
|
+
[git]
|
|
17
|
+
conventional_commits = true
|
|
18
|
+
filter_unconventional = true
|
|
19
|
+
protect_breaking_commits = true
|
|
20
|
+
commit_parsers = [
|
|
21
|
+
{ message = "^feat", group = "✨ Features" },
|
|
22
|
+
{ message = "^fix", group = "🐛 Bug Fixes" },
|
|
23
|
+
{ message = "^doc", group = "📚 Documentation" },
|
|
24
|
+
{ message = "^perf", group = "⚡ Performance" },
|
|
25
|
+
{ message = "^refactor", group = "♻️ Refactor" },
|
|
26
|
+
{ message = "^style", group = "🎨 Styling" },
|
|
27
|
+
{ message = "^test", group = "🧪 Testing" },
|
|
28
|
+
{ message = "^chore\\(release\\): prepare for", skip = true },
|
|
29
|
+
{ message = "^chore\\(deps.*\\)", skip = true },
|
|
30
|
+
{ message = "^chore", group = "🧹 Miscellaneous Tasks" },
|
|
31
|
+
{ message = "^ci|^cd", group = "🏭 CI/CD" },
|
|
32
|
+
{ body = ".*security", group = "🛡️ Security" },
|
|
33
|
+
{ message = "^revert", group = "⏪ Revert" },
|
|
34
|
+
]
|
|
@@ -1,20 +1,45 @@
|
|
|
1
|
-
name:
|
|
1
|
+
name: Python CI/CD
|
|
2
2
|
|
|
3
3
|
on:
|
|
4
4
|
push:
|
|
5
5
|
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
6
8
|
|
|
7
9
|
jobs:
|
|
10
|
+
lint:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v4
|
|
14
|
+
|
|
15
|
+
- name: Install uv
|
|
16
|
+
uses: astral-sh/setup-uv@v5
|
|
17
|
+
with:
|
|
18
|
+
enable-cache: true
|
|
19
|
+
|
|
20
|
+
- name: Set up Python
|
|
21
|
+
run: uv python install 3.12
|
|
22
|
+
|
|
23
|
+
- name: Install dependencies
|
|
24
|
+
run: uv sync --all-extras
|
|
25
|
+
|
|
26
|
+
- name: Run ruff check
|
|
27
|
+
run: uv run ruff check
|
|
28
|
+
|
|
29
|
+
- name: Run ruff format check
|
|
30
|
+
run: uv run ruff format --check
|
|
31
|
+
|
|
8
32
|
publish:
|
|
33
|
+
needs: lint
|
|
34
|
+
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
|
9
35
|
runs-on: ubuntu-latest
|
|
10
|
-
environment:
|
|
11
|
-
name: pypi
|
|
12
|
-
url: https://pypi.org/p/namecheap-python
|
|
13
36
|
permissions:
|
|
14
37
|
id-token: write
|
|
15
38
|
contents: write
|
|
16
39
|
steps:
|
|
17
40
|
- uses: actions/checkout@v4
|
|
41
|
+
with:
|
|
42
|
+
fetch-depth: 0
|
|
18
43
|
|
|
19
44
|
- name: Set up Python
|
|
20
45
|
uses: actions/setup-python@v5
|
|
@@ -64,10 +89,30 @@ jobs:
|
|
|
64
89
|
git tag -a "v$VERSION" -m "Release v$VERSION"
|
|
65
90
|
git push origin "v$VERSION"
|
|
66
91
|
|
|
67
|
-
- name:
|
|
92
|
+
- name: Check for cliff.toml
|
|
68
93
|
if: steps.check.outputs.exists == 'false'
|
|
94
|
+
id: check-cliff
|
|
95
|
+
run: |
|
|
96
|
+
if [ -f .github/cliff.toml ]; then
|
|
97
|
+
echo "has_cliff=true" >> $GITHUB_OUTPUT
|
|
98
|
+
else
|
|
99
|
+
echo "has_cliff=false" >> $GITHUB_OUTPUT
|
|
100
|
+
fi
|
|
101
|
+
|
|
102
|
+
- name: Generate Changelog
|
|
103
|
+
if: steps.check.outputs.exists == 'false' && steps.check-cliff.outputs.has_cliff == 'true'
|
|
104
|
+
id: git-cliff
|
|
105
|
+
uses: orhun/git-cliff-action@v4
|
|
106
|
+
with:
|
|
107
|
+
config: .github/cliff.toml
|
|
108
|
+
args: --latest
|
|
109
|
+
env:
|
|
110
|
+
OUTPUT: CHANGELOG.md
|
|
111
|
+
GITHUB_REPO: ${{ github.repository }}
|
|
112
|
+
|
|
113
|
+
- name: Create GitHub Release
|
|
114
|
+
if: steps.check.outputs.exists == 'false' && steps.check-cliff.outputs.has_cliff == 'true'
|
|
69
115
|
uses: softprops/action-gh-release@v2
|
|
70
116
|
with:
|
|
71
117
|
tag_name: v${{ steps.check.outputs.version }}
|
|
72
|
-
|
|
73
|
-
generate_release_notes: true
|
|
118
|
+
body: ${{ steps.git-cliff.outputs.content }}
|
|
@@ -18,15 +18,3 @@ repos:
|
|
|
18
18
|
args: [--fix]
|
|
19
19
|
- id: ruff-format
|
|
20
20
|
|
|
21
|
-
- repo: https://github.com/pre-commit/mirrors-mypy
|
|
22
|
-
rev: v1.11.0
|
|
23
|
-
hooks:
|
|
24
|
-
- id: mypy
|
|
25
|
-
args: [--strict]
|
|
26
|
-
additional_dependencies:
|
|
27
|
-
- pydantic>=2.5.0
|
|
28
|
-
- httpx>=0.27.0
|
|
29
|
-
- types-xmltodict>=0.13.0
|
|
30
|
-
- python-dotenv>=1.0.0
|
|
31
|
-
- tldextract>=5.0.0
|
|
32
|
-
files: ^src/
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: namecheap-python
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.3
|
|
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
|
|
@@ -47,7 +47,9 @@ print("🌐 DNS Management example:")
|
|
|
47
47
|
try:
|
|
48
48
|
# Get current DNS records for a domain
|
|
49
49
|
# Use the first domain from your account, or specify one
|
|
50
|
-
domain_name =
|
|
50
|
+
domain_name = (
|
|
51
|
+
my_domains[0].name if my_domains else "example.com"
|
|
52
|
+
) # Replace with your domain
|
|
51
53
|
print(f"Current DNS records for {domain_name}:")
|
|
52
54
|
|
|
53
55
|
records = nc.dns.get(domain_name)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "namecheap-python"
|
|
3
|
-
version = "1.0.
|
|
3
|
+
version = "1.0.3"
|
|
4
4
|
description = "A friendly Python SDK for Namecheap API"
|
|
5
5
|
authors = [{name = "Adrian Galilea Delgado", email = "adriangalilea@gmail.com"}]
|
|
6
6
|
readme = "README.md"
|
|
@@ -50,13 +50,7 @@ all = [
|
|
|
50
50
|
"textual>=0.47.0",
|
|
51
51
|
]
|
|
52
52
|
dev = [
|
|
53
|
-
"pytest>=8.0.0",
|
|
54
|
-
"pytest-asyncio>=0.23.0",
|
|
55
|
-
"pytest-cov>=5.0.0",
|
|
56
|
-
"pytest-httpx>=0.30.0",
|
|
57
53
|
"ruff>=0.7.0",
|
|
58
|
-
"mypy>=1.11.0",
|
|
59
|
-
"types-xmltodict>=0.13.0",
|
|
60
54
|
]
|
|
61
55
|
|
|
62
56
|
[project.scripts]
|
|
@@ -72,7 +66,6 @@ packages = ["src/namecheap", "src/namecheap_cli", "src/namecheap_dns_tui"]
|
|
|
72
66
|
|
|
73
67
|
[tool.ruff]
|
|
74
68
|
target-version = "py312"
|
|
75
|
-
line-length = 100
|
|
76
69
|
src = ["src"]
|
|
77
70
|
|
|
78
71
|
[tool.ruff.lint]
|
|
@@ -88,36 +81,13 @@ select = [
|
|
|
88
81
|
"RET", # flake8-return
|
|
89
82
|
"SIM", # flake8-simplify
|
|
90
83
|
]
|
|
84
|
+
# Ignore line length
|
|
85
|
+
extend-ignore = ["E501"]
|
|
91
86
|
ignore = [
|
|
92
87
|
"S101", # Use of assert detected - reasonable for tests and validation
|
|
93
88
|
"SIM110", # Use any() - no current violations, keeping for edge cases
|
|
94
89
|
"SIM118", # Use `key in dict` instead of `key in dict.keys()` - no current violations
|
|
95
90
|
]
|
|
96
91
|
|
|
97
|
-
[tool.mypy]
|
|
98
|
-
python_version = "3.12"
|
|
99
|
-
strict = true
|
|
100
|
-
pretty = true
|
|
101
|
-
show_error_codes = true
|
|
102
|
-
show_error_context = true
|
|
103
92
|
|
|
104
|
-
[tool.pytest.ini_options]
|
|
105
|
-
minversion = "8.0"
|
|
106
|
-
testpaths = ["tests"]
|
|
107
|
-
addopts = "-ra --cov=namecheap --cov-report=term-missing"
|
|
108
93
|
|
|
109
|
-
[tool.coverage.run]
|
|
110
|
-
source = ["src/namecheap"]
|
|
111
|
-
|
|
112
|
-
[tool.coverage.report]
|
|
113
|
-
exclude_lines = [
|
|
114
|
-
"pragma: no cover",
|
|
115
|
-
"def __repr__",
|
|
116
|
-
"if TYPE_CHECKING:",
|
|
117
|
-
"raise NotImplementedError",
|
|
118
|
-
]
|
|
119
|
-
|
|
120
|
-
[dependency-groups]
|
|
121
|
-
dev = [
|
|
122
|
-
"types-pyyaml>=6.0.12.20250516",
|
|
123
|
-
]
|
|
@@ -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(
|
|
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
|
|
75
|
+
normalize_xml_response(item) if isinstance(item, dict) else item
|
|
76
|
+
for item in value
|
|
74
77
|
]
|
|
75
78
|
|
|
76
79
|
return normalized
|
|
@@ -35,7 +35,9 @@ class DNSRecordBuilder:
|
|
|
35
35
|
Self for chaining
|
|
36
36
|
"""
|
|
37
37
|
self._records.append(
|
|
38
|
-
DNSRecord.model_validate(
|
|
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
|
-
{
|
|
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
|
|
@@ -17,7 +17,9 @@ from .base import BaseAPI
|
|
|
17
17
|
class DomainsAPI(BaseAPI):
|
|
18
18
|
"""Domain management operations."""
|
|
19
19
|
|
|
20
|
-
def check(
|
|
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 =
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
428
|
+
"retail_price": Decimal(
|
|
429
|
+
retail_price
|
|
430
|
+
)
|
|
415
431
|
if retail_price
|
|
416
432
|
else None,
|
|
417
433
|
}
|
|
@@ -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(
|
|
78
|
-
|
|
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(
|
|
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(
|
|
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
|
)
|
|
@@ -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(
|
|
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"] =
|
|
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)
|