shadow-tools 0.2.4__tar.gz → 0.2.5__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.
- {shadow_tools-0.2.4 → shadow_tools-0.2.5}/PKG-INFO +4 -3
- {shadow_tools-0.2.4 → shadow_tools-0.2.5}/README.md +3 -2
- {shadow_tools-0.2.4 → shadow_tools-0.2.5}/pyproject.toml +1 -1
- shadow_tools-0.2.5/release-0.2.4/shadow_tools-0.2.4-py3-none-any.whl +0 -0
- shadow_tools-0.2.5/release-0.2.4/shadow_tools-0.2.4.tar.gz +0 -0
- {shadow_tools-0.2.4 → shadow_tools-0.2.5}/src/shadowtools/__init__.py +1 -1
- {shadow_tools-0.2.4 → shadow_tools-0.2.5}/src/shadowtools/network.py +7 -5
- {shadow_tools-0.2.4 → shadow_tools-0.2.5}/tests/test_core.py +3 -2
- {shadow_tools-0.2.4 → shadow_tools-0.2.5}/.gitignore +0 -0
- {shadow_tools-0.2.4 → shadow_tools-0.2.5}/LICENSE +0 -0
- {shadow_tools-0.2.4 → shadow_tools-0.2.5}/release-0.2.0/shadow_tools-0.2.0-py3-none-any.whl +0 -0
- {shadow_tools-0.2.4 → shadow_tools-0.2.5}/release-0.2.0/shadow_tools-0.2.0.tar.gz +0 -0
- {shadow_tools-0.2.4 → shadow_tools-0.2.5}/release-0.2.1/shadow_tools-0.2.1-py3-none-any.whl +0 -0
- {shadow_tools-0.2.4 → shadow_tools-0.2.5}/release-0.2.1/shadow_tools-0.2.1.tar.gz +0 -0
- {shadow_tools-0.2.4 → shadow_tools-0.2.5}/release-0.2.2/shadow_tools-0.2.2-py3-none-any.whl +0 -0
- {shadow_tools-0.2.4 → shadow_tools-0.2.5}/release-0.2.2/shadow_tools-0.2.2.tar.gz +0 -0
- {shadow_tools-0.2.4 → shadow_tools-0.2.5}/release-0.2.3/shadow_tools-0.2.3-py3-none-any.whl +0 -0
- {shadow_tools-0.2.4 → shadow_tools-0.2.5}/release-0.2.3/shadow_tools-0.2.3.tar.gz +0 -0
- {shadow_tools-0.2.4 → shadow_tools-0.2.5}/src/shadowtools/ai.py +0 -0
- {shadow_tools-0.2.4 → shadow_tools-0.2.5}/src/shadowtools/async_tools.py +0 -0
- {shadow_tools-0.2.4 → shadow_tools-0.2.5}/src/shadowtools/cli.py +0 -0
- {shadow_tools-0.2.4 → shadow_tools-0.2.5}/src/shadowtools/data.py +0 -0
- {shadow_tools-0.2.4 → shadow_tools-0.2.5}/src/shadowtools/files.py +0 -0
- {shadow_tools-0.2.4 → shadow_tools-0.2.5}/src/shadowtools/http.py +0 -0
- {shadow_tools-0.2.4 → shadow_tools-0.2.5}/src/shadowtools/validation.py +0 -0
- {shadow_tools-0.2.4 → shadow_tools-0.2.5}/src/shadowtools/websocket.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: shadow-tools
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.5
|
|
4
4
|
Summary: A practical all-in-one Python toolkit for HTTP, WebSockets, files, data, validation, async work, and CLIs.
|
|
5
5
|
Project-URL: Homepage, https://github.com/WilliamLaurento/shadow-tools
|
|
6
6
|
Project-URL: Issues, https://github.com/WilliamLaurento/shadow-tools/issues
|
|
@@ -74,11 +74,12 @@ Reverse-DNS lookup for IP addresses:
|
|
|
74
74
|
```python
|
|
75
75
|
from shadowtools import generate_random_ips, reverse_dns
|
|
76
76
|
|
|
77
|
-
for
|
|
78
|
-
print(
|
|
77
|
+
for result in reverse_dns(generate_random_ips(5)):
|
|
78
|
+
print(result) # only IPs with hostnames are shown
|
|
79
79
|
|
|
80
80
|
# Or look up every generated IP at once.
|
|
81
81
|
print(reverse_dns(generate_random_ips(5)))
|
|
82
|
+
print(reverse_dns(generate_random_ips(5), only_hostnames=False)) # include misses
|
|
82
83
|
```
|
|
83
84
|
|
|
84
85
|
## AI app helpers
|
|
@@ -50,11 +50,12 @@ Reverse-DNS lookup for IP addresses:
|
|
|
50
50
|
```python
|
|
51
51
|
from shadowtools import generate_random_ips, reverse_dns
|
|
52
52
|
|
|
53
|
-
for
|
|
54
|
-
print(
|
|
53
|
+
for result in reverse_dns(generate_random_ips(5)):
|
|
54
|
+
print(result) # only IPs with hostnames are shown
|
|
55
55
|
|
|
56
56
|
# Or look up every generated IP at once.
|
|
57
57
|
print(reverse_dns(generate_random_ips(5)))
|
|
58
|
+
print(reverse_dns(generate_random_ips(5), only_hostnames=False)) # include misses
|
|
58
59
|
```
|
|
59
60
|
|
|
60
61
|
## AI app helpers
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "shadow-tools"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.5"
|
|
8
8
|
description = "A practical all-in-one Python toolkit for HTTP, WebSockets, files, data, validation, async work, and CLIs."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
Binary file
|
|
Binary file
|
|
@@ -6,7 +6,7 @@ from .http import get, request
|
|
|
6
6
|
from .network import generate_random_ips, generate_test_ips, is_subdomain_of, make_subdomain, resolve_dns, reverse_dns
|
|
7
7
|
from .validation import is_email, is_url, require_keys
|
|
8
8
|
|
|
9
|
-
__version__ = "0.2.
|
|
9
|
+
__version__ = "0.2.5"
|
|
10
10
|
|
|
11
11
|
__all__ = [
|
|
12
12
|
"append_text", "ensure_dir", "generate_random_ips", "generate_test_ips", "get", "is_email", "is_subdomain_of", "is_url", "make_subdomain", "read_csv",
|
|
@@ -18,20 +18,22 @@ def resolve_dns(hostname: str) -> dict[str, list[str]]:
|
|
|
18
18
|
return {kind: sorted(addresses) for kind, addresses in results.items()}
|
|
19
19
|
|
|
20
20
|
|
|
21
|
-
def reverse_dns(ip: str | Iterable[str]) -> dict[str, object] | list[dict[str, object]]:
|
|
21
|
+
def reverse_dns(ip: str | Iterable[str], *, only_hostnames: bool = True) -> dict[str, object] | list[dict[str, object]] | None:
|
|
22
22
|
"""Look up DNS names for one IP address or each address in a list.
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
List lookups return only results with a hostname by default. Set
|
|
25
|
+
``only_hostnames=False`` to include addresses without PTR records.
|
|
26
26
|
"""
|
|
27
27
|
if not isinstance(ip, str):
|
|
28
|
-
|
|
28
|
+
results = [reverse_dns(one_ip, only_hostnames=False) for one_ip in ip]
|
|
29
|
+
return [result for result in results if not only_hostnames or result["hostname"]]
|
|
29
30
|
address = ipaddress.ip_address(ip)
|
|
30
31
|
try:
|
|
31
32
|
hostname, aliases, _ = socket.gethostbyaddr(str(address))
|
|
32
33
|
return {"ip": str(address), "hostname": hostname, "aliases": aliases}
|
|
33
34
|
except (socket.herror, socket.gaierror):
|
|
34
|
-
|
|
35
|
+
result = {"ip": str(address), "hostname": None, "aliases": []}
|
|
36
|
+
return None if only_hostnames else result
|
|
35
37
|
|
|
36
38
|
|
|
37
39
|
def is_subdomain_of(hostname: str, domain: str) -> bool:
|
|
@@ -44,7 +44,8 @@ def test_network_and_ai_helpers():
|
|
|
44
44
|
assert generate_test_ips(1)[0].startswith("192.0.2.")
|
|
45
45
|
assert all(ipaddress.ip_address(ip).is_global for ip in generate_random_ips(3))
|
|
46
46
|
assert len(generate_random_ips(2, family=6)) == 2
|
|
47
|
-
assert reverse_dns("0.0.0.0")
|
|
48
|
-
assert
|
|
47
|
+
assert reverse_dns("0.0.0.0") is None
|
|
48
|
+
assert reverse_dns("0.0.0.0", only_hostnames=False)["hostname"] is None
|
|
49
|
+
assert all(item["hostname"] for item in reverse_dns(["0.0.0.0", "127.0.0.1"]))
|
|
49
50
|
assert prompt("Hi {name}", name="Will") == "Hi Will"
|
|
50
51
|
assert tool_schema("lookup_dns", "Lookup DNS", {"host": {"type": "string"}})["name"] == "lookup_dns"
|
|
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
|