netstate 0.1.0__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.
- netstate-0.1.0/License.md +21 -0
- netstate-0.1.0/PKG-INFO +118 -0
- netstate-0.1.0/README.md +99 -0
- netstate-0.1.0/netstate/__init__.py +3 -0
- netstate-0.1.0/netstate/collectors/networkData.py +140 -0
- netstate-0.1.0/netstate/collectors/publicIpData.py +58 -0
- netstate-0.1.0/netstate/collectors/systemData.py +31 -0
- netstate-0.1.0/netstate/exception.py +40 -0
- netstate-0.1.0/netstate/models.py +19 -0
- netstate-0.1.0/netstate/network_info.py +48 -0
- netstate-0.1.0/netstate.egg-info/PKG-INFO +118 -0
- netstate-0.1.0/netstate.egg-info/SOURCES.txt +16 -0
- netstate-0.1.0/netstate.egg-info/dependency_links.txt +1 -0
- netstate-0.1.0/netstate.egg-info/requires.txt +1 -0
- netstate-0.1.0/netstate.egg-info/top_level.txt +1 -0
- netstate-0.1.0/pyproject.toml +41 -0
- netstate-0.1.0/setup.cfg +4 -0
- netstate-0.1.0/tests/test_netstate.py +24 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 IMON MALLIK
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
netstate-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: netstate
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Windows network and system snapshot collector
|
|
5
|
+
Author: Imon Mallik
|
|
6
|
+
License: MIT
|
|
7
|
+
Keywords: network,system-info,windows,ip,network-monitoring
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
10
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Topic :: System :: Networking
|
|
14
|
+
Requires-Python: >=3.9
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
License-File: License.md
|
|
17
|
+
Requires-Dist: requests>=2.0
|
|
18
|
+
Dynamic: license-file
|
|
19
|
+
|
|
20
|
+
# NetState
|
|
21
|
+
|
|
22
|
+
NetState is a Python package for collecting structured system and
|
|
23
|
+
network information on Windows machines.
|
|
24
|
+
|
|
25
|
+
It provides a clean API to retrieve:
|
|
26
|
+
|
|
27
|
+
- Operating system details
|
|
28
|
+
- Active private network adapter information
|
|
29
|
+
- Public IP and ISP information
|
|
30
|
+
- JSON-serializable network snapshots
|
|
31
|
+
|
|
32
|
+
This package is intended to be used as a **library**, not a standalone
|
|
33
|
+
application.
|
|
34
|
+
|
|
35
|
+
------------------------------------------------------------------------
|
|
36
|
+
|
|
37
|
+
## Installation
|
|
38
|
+
|
|
39
|
+
After publishing to PyPI:
|
|
40
|
+
|
|
41
|
+
``` bash
|
|
42
|
+
pip install netstate
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
For local development:
|
|
46
|
+
|
|
47
|
+
``` bash
|
|
48
|
+
pip install -e .
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
------------------------------------------------------------------------
|
|
52
|
+
|
|
53
|
+
## Basic Usage
|
|
54
|
+
|
|
55
|
+
``` python
|
|
56
|
+
from netstate.network_info import get_network_info
|
|
57
|
+
|
|
58
|
+
snapshot = get_network_info()
|
|
59
|
+
|
|
60
|
+
print(snapshot.system)
|
|
61
|
+
print(snapshot.private_network)
|
|
62
|
+
print(snapshot.public_network)
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
------------------------------------------------------------------------
|
|
66
|
+
|
|
67
|
+
## JSON Output
|
|
68
|
+
|
|
69
|
+
``` python
|
|
70
|
+
from netstate.network_info import get_network_info_json
|
|
71
|
+
|
|
72
|
+
json_output = get_network_info_json()
|
|
73
|
+
print(json_output)
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
------------------------------------------------------------------------
|
|
77
|
+
|
|
78
|
+
## Returned Data Structure
|
|
79
|
+
|
|
80
|
+
`get_network_info()` returns a `NetStateSnapshot` dataclass containing:
|
|
81
|
+
|
|
82
|
+
- platform (str)
|
|
83
|
+
- system (SystemData)
|
|
84
|
+
- private_network (List\[NetworkData\] \| None)
|
|
85
|
+
- public_network (PublicNetworkData \| None)
|
|
86
|
+
- record_time (datetime)
|
|
87
|
+
|
|
88
|
+
All models are defined using Python dataclasses.
|
|
89
|
+
|
|
90
|
+
------------------------------------------------------------------------
|
|
91
|
+
|
|
92
|
+
## Requirements
|
|
93
|
+
|
|
94
|
+
- Python 3.9+
|
|
95
|
+
- Windows OS
|
|
96
|
+
- requests
|
|
97
|
+
|
|
98
|
+
------------------------------------------------------------------------
|
|
99
|
+
|
|
100
|
+
## Design Goals
|
|
101
|
+
|
|
102
|
+
- Clean modular architecture
|
|
103
|
+
- Structured dataclass models
|
|
104
|
+
- Graceful failure handling
|
|
105
|
+
- Easy JSON serialization
|
|
106
|
+
- Extensible collector design
|
|
107
|
+
|
|
108
|
+
------------------------------------------------------------------------
|
|
109
|
+
|
|
110
|
+
## License
|
|
111
|
+
|
|
112
|
+
MIT License
|
|
113
|
+
|
|
114
|
+
------------------------------------------------------------------------
|
|
115
|
+
|
|
116
|
+
## Author
|
|
117
|
+
|
|
118
|
+
Imon Mallik
|
netstate-0.1.0/README.md
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# NetState
|
|
2
|
+
|
|
3
|
+
NetState is a Python package for collecting structured system and
|
|
4
|
+
network information on Windows machines.
|
|
5
|
+
|
|
6
|
+
It provides a clean API to retrieve:
|
|
7
|
+
|
|
8
|
+
- Operating system details
|
|
9
|
+
- Active private network adapter information
|
|
10
|
+
- Public IP and ISP information
|
|
11
|
+
- JSON-serializable network snapshots
|
|
12
|
+
|
|
13
|
+
This package is intended to be used as a **library**, not a standalone
|
|
14
|
+
application.
|
|
15
|
+
|
|
16
|
+
------------------------------------------------------------------------
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
After publishing to PyPI:
|
|
21
|
+
|
|
22
|
+
``` bash
|
|
23
|
+
pip install netstate
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
For local development:
|
|
27
|
+
|
|
28
|
+
``` bash
|
|
29
|
+
pip install -e .
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
------------------------------------------------------------------------
|
|
33
|
+
|
|
34
|
+
## Basic Usage
|
|
35
|
+
|
|
36
|
+
``` python
|
|
37
|
+
from netstate.network_info import get_network_info
|
|
38
|
+
|
|
39
|
+
snapshot = get_network_info()
|
|
40
|
+
|
|
41
|
+
print(snapshot.system)
|
|
42
|
+
print(snapshot.private_network)
|
|
43
|
+
print(snapshot.public_network)
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
------------------------------------------------------------------------
|
|
47
|
+
|
|
48
|
+
## JSON Output
|
|
49
|
+
|
|
50
|
+
``` python
|
|
51
|
+
from netstate.network_info import get_network_info_json
|
|
52
|
+
|
|
53
|
+
json_output = get_network_info_json()
|
|
54
|
+
print(json_output)
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
------------------------------------------------------------------------
|
|
58
|
+
|
|
59
|
+
## Returned Data Structure
|
|
60
|
+
|
|
61
|
+
`get_network_info()` returns a `NetStateSnapshot` dataclass containing:
|
|
62
|
+
|
|
63
|
+
- platform (str)
|
|
64
|
+
- system (SystemData)
|
|
65
|
+
- private_network (List\[NetworkData\] \| None)
|
|
66
|
+
- public_network (PublicNetworkData \| None)
|
|
67
|
+
- record_time (datetime)
|
|
68
|
+
|
|
69
|
+
All models are defined using Python dataclasses.
|
|
70
|
+
|
|
71
|
+
------------------------------------------------------------------------
|
|
72
|
+
|
|
73
|
+
## Requirements
|
|
74
|
+
|
|
75
|
+
- Python 3.9+
|
|
76
|
+
- Windows OS
|
|
77
|
+
- requests
|
|
78
|
+
|
|
79
|
+
------------------------------------------------------------------------
|
|
80
|
+
|
|
81
|
+
## Design Goals
|
|
82
|
+
|
|
83
|
+
- Clean modular architecture
|
|
84
|
+
- Structured dataclass models
|
|
85
|
+
- Graceful failure handling
|
|
86
|
+
- Easy JSON serialization
|
|
87
|
+
- Extensible collector design
|
|
88
|
+
|
|
89
|
+
------------------------------------------------------------------------
|
|
90
|
+
|
|
91
|
+
## License
|
|
92
|
+
|
|
93
|
+
MIT License
|
|
94
|
+
|
|
95
|
+
------------------------------------------------------------------------
|
|
96
|
+
|
|
97
|
+
## Author
|
|
98
|
+
|
|
99
|
+
Imon Mallik
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import subprocess
|
|
2
|
+
import re
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
from typing import Optional
|
|
6
|
+
from netstate.exception import PrivateNetworkUnavailableError
|
|
7
|
+
|
|
8
|
+
@dataclass(frozen=True)
|
|
9
|
+
class NetworkData:
|
|
10
|
+
adapter_name: str
|
|
11
|
+
adapter_type: str
|
|
12
|
+
|
|
13
|
+
ipv4: Optional[str]
|
|
14
|
+
subnet_mask: Optional[str]
|
|
15
|
+
mac_address: Optional[str]
|
|
16
|
+
|
|
17
|
+
dhcp_enabled: Optional[bool]
|
|
18
|
+
dhcp_server: Optional[str]
|
|
19
|
+
dns_servers: Optional[str]
|
|
20
|
+
default_gateway: Optional[str]
|
|
21
|
+
|
|
22
|
+
lease_obtained: Optional[datetime]
|
|
23
|
+
lease_expires: Optional[datetime]
|
|
24
|
+
|
|
25
|
+
description: Optional[str]
|
|
26
|
+
record_time: datetime
|
|
27
|
+
|
|
28
|
+
_FIELD_MAP = {
|
|
29
|
+
"type": "type",
|
|
30
|
+
"IPv4 Address": "IPv4",
|
|
31
|
+
"DHCP Enabled": "DHCP_Enable",
|
|
32
|
+
"DHCP Server": "DHCP_Server",
|
|
33
|
+
"DNS Servers": "DNS_Servers",
|
|
34
|
+
"Default Gateway": "Default_Gateway",
|
|
35
|
+
"Physical Address": "MAC_Address",
|
|
36
|
+
"Subnet Mask": "Subnet_Mask",
|
|
37
|
+
"Lease Expires": "Lease_Expires",
|
|
38
|
+
"Lease Obtained": "Lease_Obtained",
|
|
39
|
+
"Description": "Description",
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
def _clean_ipv4(ip: str) -> str:
|
|
43
|
+
if not ip:
|
|
44
|
+
return ""
|
|
45
|
+
return ip.replace("(Preferred)", "").strip()
|
|
46
|
+
|
|
47
|
+
def _parse_windows_datetime(dt_str: str):
|
|
48
|
+
if not dt_str:
|
|
49
|
+
return None
|
|
50
|
+
|
|
51
|
+
return datetime.strptime(dt_str,"%A, %B %d, %Y %I:%M:%S %p")
|
|
52
|
+
|
|
53
|
+
def to_isoformat(dt_str: str):
|
|
54
|
+
dt = _parse_windows_datetime(dt_str)
|
|
55
|
+
return dt.isoformat() if dt else None
|
|
56
|
+
|
|
57
|
+
def _parse_ipconfig(output: str) -> dict:
|
|
58
|
+
adapters = {}
|
|
59
|
+
current_adapter = None
|
|
60
|
+
|
|
61
|
+
adapter_header = re.compile(r"^(Ethernet|Wireless LAN|Unknown) adapter (.+):$")
|
|
62
|
+
key_value = re.compile(r"^\s+(.+?)\s*:\s*(.*)$")
|
|
63
|
+
|
|
64
|
+
for line in output.splitlines():
|
|
65
|
+
line = line.rstrip()
|
|
66
|
+
|
|
67
|
+
header_match = adapter_header.match(line)
|
|
68
|
+
if header_match:
|
|
69
|
+
adapter_type, adapter_name = header_match.groups()
|
|
70
|
+
|
|
71
|
+
current_adapter = adapter_name.strip()
|
|
72
|
+
|
|
73
|
+
adapters[current_adapter] = {
|
|
74
|
+
"type": adapter_type,
|
|
75
|
+
'Media State': True,
|
|
76
|
+
}
|
|
77
|
+
continue
|
|
78
|
+
|
|
79
|
+
if current_adapter:
|
|
80
|
+
kv_match = key_value.match(line)
|
|
81
|
+
|
|
82
|
+
if kv_match:
|
|
83
|
+
key, value = kv_match.groups()
|
|
84
|
+
key = key[0:key.index('.')].strip()
|
|
85
|
+
|
|
86
|
+
value = value.strip()
|
|
87
|
+
|
|
88
|
+
if value.lower() in ("yes", "no"):
|
|
89
|
+
value = value.lower() == "yes"
|
|
90
|
+
|
|
91
|
+
if(key == "Media State" and value =='Media disconnected' ):
|
|
92
|
+
value=False
|
|
93
|
+
|
|
94
|
+
adapters[current_adapter][key] = value
|
|
95
|
+
|
|
96
|
+
return adapters
|
|
97
|
+
|
|
98
|
+
def _filter_active_networks(data : dict) -> dict:
|
|
99
|
+
filtered_networks={}
|
|
100
|
+
|
|
101
|
+
for key,value in data.items():
|
|
102
|
+
if value["Media State"]==True and len(value['Default Gateway'])!=0:
|
|
103
|
+
filtered_networks[key]=value
|
|
104
|
+
|
|
105
|
+
return filtered_networks
|
|
106
|
+
|
|
107
|
+
def get_network_data() -> list[NetworkData]:
|
|
108
|
+
try:
|
|
109
|
+
output = subprocess.check_output(["ipconfig", "/all"], text=True)
|
|
110
|
+
|
|
111
|
+
parsed = _parse_ipconfig(output)
|
|
112
|
+
filtered = _filter_active_networks(parsed)
|
|
113
|
+
|
|
114
|
+
if not filtered:
|
|
115
|
+
raise RuntimeError("No active network adapter found")
|
|
116
|
+
|
|
117
|
+
results = []
|
|
118
|
+
|
|
119
|
+
for adapter_name, filtered_data in filtered.items():
|
|
120
|
+
results.append(
|
|
121
|
+
NetworkData(
|
|
122
|
+
adapter_name=adapter_name,
|
|
123
|
+
adapter_type=filtered_data.get("type"),
|
|
124
|
+
ipv4=_clean_ipv4(filtered_data.get("IPv4 Address")),
|
|
125
|
+
subnet_mask=filtered_data.get("Subnet Mask"),
|
|
126
|
+
mac_address=filtered_data.get("Physical Address"),
|
|
127
|
+
dhcp_enabled=filtered_data.get("DHCP Enabled"),
|
|
128
|
+
dhcp_server=filtered_data.get("DHCP Server"),
|
|
129
|
+
dns_servers=filtered_data.get("DNS Servers"),
|
|
130
|
+
default_gateway=filtered_data.get("Default Gateway"),
|
|
131
|
+
lease_obtained=_parse_windows_datetime(filtered_data.get("Lease Obtained")),
|
|
132
|
+
lease_expires=_parse_windows_datetime(filtered_data.get("Lease Expires")),
|
|
133
|
+
description=filtered_data.get("Description"),
|
|
134
|
+
record_time=datetime.now().astimezone()
|
|
135
|
+
)
|
|
136
|
+
)
|
|
137
|
+
return results
|
|
138
|
+
|
|
139
|
+
except Exception:
|
|
140
|
+
raise PrivateNetworkUnavailableError("Private network not available")
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from typing import Optional
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
import requests
|
|
5
|
+
from datetime import datetime
|
|
6
|
+
from netstate.exception import NetStateError, PublicNetworkUnavailableError
|
|
7
|
+
@dataclass(frozen=True)
|
|
8
|
+
class PublicNetworkData:
|
|
9
|
+
public_ip: str
|
|
10
|
+
isp: Optional[str]
|
|
11
|
+
|
|
12
|
+
country: Optional[str]
|
|
13
|
+
region: Optional[str]
|
|
14
|
+
city: Optional[str]
|
|
15
|
+
pincode: Optional[str]
|
|
16
|
+
|
|
17
|
+
latitude: Optional[float]
|
|
18
|
+
longitude: Optional[float]
|
|
19
|
+
|
|
20
|
+
record_time: datetime
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
IFCONFIG_URL = "https://ifconfig.me/all.json"
|
|
24
|
+
IP_API_URL = "http://ip-api.com/json/"
|
|
25
|
+
|
|
26
|
+
def get_public_network_data() -> PublicNetworkData:
|
|
27
|
+
try:
|
|
28
|
+
r1 = requests.get(IFCONFIG_URL, timeout=5)
|
|
29
|
+
r1.raise_for_status()
|
|
30
|
+
ip_data = r1.json()
|
|
31
|
+
public_ip = ip_data.get("ip_addr")
|
|
32
|
+
except Exception as e:
|
|
33
|
+
print("unable to fetch public network ip")
|
|
34
|
+
raise PublicNetworkUnavailableError("public network not available")
|
|
35
|
+
|
|
36
|
+
try:
|
|
37
|
+
r2 = requests.get(IP_API_URL + public_ip, timeout=5)
|
|
38
|
+
r2.raise_for_status()
|
|
39
|
+
geo = r2.json()
|
|
40
|
+
except Exception as e:
|
|
41
|
+
print("Unable to fetch public network ip data")
|
|
42
|
+
raise PublicNetworkUnavailableError("Unable to fetch public network ip data")
|
|
43
|
+
|
|
44
|
+
return PublicNetworkData(
|
|
45
|
+
public_ip=public_ip,
|
|
46
|
+
isp=geo.get("isp"),
|
|
47
|
+
|
|
48
|
+
country=geo.get("country"),
|
|
49
|
+
region=geo.get("regionName"),
|
|
50
|
+
city=geo.get("city"),
|
|
51
|
+
pincode=geo.get("zip"),
|
|
52
|
+
|
|
53
|
+
latitude=geo.get("lat"),
|
|
54
|
+
longitude=geo.get("lon"),
|
|
55
|
+
|
|
56
|
+
record_time=datetime.now().astimezone()
|
|
57
|
+
)
|
|
58
|
+
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import platform
|
|
2
|
+
import socket
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from datetime import datetime, timezone
|
|
5
|
+
from netstate.exception import SystemDetailsUnavailableError
|
|
6
|
+
|
|
7
|
+
@dataclass(frozen=True)
|
|
8
|
+
class SystemData:
|
|
9
|
+
os_name: str
|
|
10
|
+
os_release_name: str
|
|
11
|
+
os_version_no: str
|
|
12
|
+
os_full_detail: str
|
|
13
|
+
host_name: str
|
|
14
|
+
record_time: datetime
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def get_system_data() -> SystemData:
|
|
18
|
+
"""
|
|
19
|
+
Collect system-level metadata and return it as an immutable snapshot.
|
|
20
|
+
"""
|
|
21
|
+
try:
|
|
22
|
+
return SystemData(
|
|
23
|
+
os_name=platform.system(),
|
|
24
|
+
os_release_name=platform.release(),
|
|
25
|
+
os_version_no=platform.version(),
|
|
26
|
+
os_full_detail=platform.platform(),
|
|
27
|
+
host_name=socket.gethostname(),
|
|
28
|
+
record_time=datetime.now().astimezone()
|
|
29
|
+
)
|
|
30
|
+
except Exception:
|
|
31
|
+
raise SystemDetailsUnavailableError("System details cannot be fetched")
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
class NetStateError(Exception):
|
|
2
|
+
"""
|
|
3
|
+
Base exception for netstate package.
|
|
4
|
+
"""
|
|
5
|
+
def __init__(self, message):
|
|
6
|
+
super().__init__(message)
|
|
7
|
+
self.message = message
|
|
8
|
+
|
|
9
|
+
def __str__(self):
|
|
10
|
+
return f"NetStateError : {self.message}"
|
|
11
|
+
|
|
12
|
+
class SystemDetailsUnavailableError(NetStateError):
|
|
13
|
+
"""
|
|
14
|
+
Raised when System information cannot be retrieved.
|
|
15
|
+
"""
|
|
16
|
+
def __init__(self, message):
|
|
17
|
+
super().__init__(message)
|
|
18
|
+
|
|
19
|
+
def __str__(self):
|
|
20
|
+
return f"SystemDetailsUnavailableError : {self.message}"
|
|
21
|
+
|
|
22
|
+
class PrivateNetworkUnavailableError(NetStateError):
|
|
23
|
+
"""
|
|
24
|
+
Raised when private network information cannot be retrieved.
|
|
25
|
+
"""
|
|
26
|
+
def __init__(self, message):
|
|
27
|
+
super().__init__(message)
|
|
28
|
+
|
|
29
|
+
def __str__(self):
|
|
30
|
+
return f"PrivateNetworkUnavailableError : {self.message}"
|
|
31
|
+
|
|
32
|
+
class PublicNetworkUnavailableError(NetStateError):
|
|
33
|
+
"""
|
|
34
|
+
Raised when public network information cannot be retrieved.
|
|
35
|
+
"""
|
|
36
|
+
def __init__(self, message):
|
|
37
|
+
super().__init__(message)
|
|
38
|
+
|
|
39
|
+
def __str__(self):
|
|
40
|
+
return f"PublicNetworkUnavailableError : {self.message}"
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from datetime import datetime
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
from netstate.collectors.systemData import SystemData
|
|
6
|
+
from netstate.collectors.networkData import NetworkData
|
|
7
|
+
from netstate.collectors.publicIpData import PublicNetworkData
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@dataclass(frozen=True)
|
|
11
|
+
class NetStateSnapshot:
|
|
12
|
+
"""
|
|
13
|
+
Final aggregated snapshot returned to the user.
|
|
14
|
+
"""
|
|
15
|
+
platform: str
|
|
16
|
+
system: SystemData
|
|
17
|
+
private_network: NetworkData
|
|
18
|
+
public_network: Optional[PublicNetworkData]
|
|
19
|
+
record_time: datetime
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import platform
|
|
2
|
+
from datetime import datetime
|
|
3
|
+
import json
|
|
4
|
+
from dataclasses import asdict
|
|
5
|
+
|
|
6
|
+
from netstate.models import NetStateSnapshot
|
|
7
|
+
from netstate.collectors.systemData import get_system_data
|
|
8
|
+
from netstate.collectors.networkData import get_network_data
|
|
9
|
+
from netstate.collectors.publicIpData import get_public_network_data
|
|
10
|
+
from netstate.exception import PublicNetworkUnavailableError, NetStateError, PrivateNetworkUnavailableError
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def get_network_info() -> NetStateSnapshot:
|
|
14
|
+
"""
|
|
15
|
+
Return current system and network information (Windows only).
|
|
16
|
+
"""
|
|
17
|
+
if platform.system().lower() != "windows":
|
|
18
|
+
raise NotImplementedError("netstate currently supports Windows only")
|
|
19
|
+
|
|
20
|
+
system_data = get_system_data()
|
|
21
|
+
try:
|
|
22
|
+
private_network_data = get_network_data()
|
|
23
|
+
except PrivateNetworkUnavailableError as e:
|
|
24
|
+
private_network_data=None
|
|
25
|
+
except RuntimeError:
|
|
26
|
+
private_network_data=None
|
|
27
|
+
try:
|
|
28
|
+
public_network_data = get_public_network_data()
|
|
29
|
+
except PublicNetworkUnavailableError as e:
|
|
30
|
+
public_network_data=None
|
|
31
|
+
record_time_data = datetime.now().astimezone()
|
|
32
|
+
return NetStateSnapshot(
|
|
33
|
+
platform="windows",
|
|
34
|
+
system=system_data,
|
|
35
|
+
private_network=private_network_data,
|
|
36
|
+
public_network=public_network_data,
|
|
37
|
+
record_time=record_time_data
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
if __name__ == "__main__":
|
|
41
|
+
try:
|
|
42
|
+
print(get_network_info())
|
|
43
|
+
except:
|
|
44
|
+
print("some error occured")
|
|
45
|
+
|
|
46
|
+
def get_network_info_json():
|
|
47
|
+
snapshot = get_network_info()
|
|
48
|
+
return json.dumps(asdict(snapshot), indent=4, default=str)
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: netstate
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Windows network and system snapshot collector
|
|
5
|
+
Author: Imon Mallik
|
|
6
|
+
License: MIT
|
|
7
|
+
Keywords: network,system-info,windows,ip,network-monitoring
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
10
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Topic :: System :: Networking
|
|
14
|
+
Requires-Python: >=3.9
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
License-File: License.md
|
|
17
|
+
Requires-Dist: requests>=2.0
|
|
18
|
+
Dynamic: license-file
|
|
19
|
+
|
|
20
|
+
# NetState
|
|
21
|
+
|
|
22
|
+
NetState is a Python package for collecting structured system and
|
|
23
|
+
network information on Windows machines.
|
|
24
|
+
|
|
25
|
+
It provides a clean API to retrieve:
|
|
26
|
+
|
|
27
|
+
- Operating system details
|
|
28
|
+
- Active private network adapter information
|
|
29
|
+
- Public IP and ISP information
|
|
30
|
+
- JSON-serializable network snapshots
|
|
31
|
+
|
|
32
|
+
This package is intended to be used as a **library**, not a standalone
|
|
33
|
+
application.
|
|
34
|
+
|
|
35
|
+
------------------------------------------------------------------------
|
|
36
|
+
|
|
37
|
+
## Installation
|
|
38
|
+
|
|
39
|
+
After publishing to PyPI:
|
|
40
|
+
|
|
41
|
+
``` bash
|
|
42
|
+
pip install netstate
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
For local development:
|
|
46
|
+
|
|
47
|
+
``` bash
|
|
48
|
+
pip install -e .
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
------------------------------------------------------------------------
|
|
52
|
+
|
|
53
|
+
## Basic Usage
|
|
54
|
+
|
|
55
|
+
``` python
|
|
56
|
+
from netstate.network_info import get_network_info
|
|
57
|
+
|
|
58
|
+
snapshot = get_network_info()
|
|
59
|
+
|
|
60
|
+
print(snapshot.system)
|
|
61
|
+
print(snapshot.private_network)
|
|
62
|
+
print(snapshot.public_network)
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
------------------------------------------------------------------------
|
|
66
|
+
|
|
67
|
+
## JSON Output
|
|
68
|
+
|
|
69
|
+
``` python
|
|
70
|
+
from netstate.network_info import get_network_info_json
|
|
71
|
+
|
|
72
|
+
json_output = get_network_info_json()
|
|
73
|
+
print(json_output)
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
------------------------------------------------------------------------
|
|
77
|
+
|
|
78
|
+
## Returned Data Structure
|
|
79
|
+
|
|
80
|
+
`get_network_info()` returns a `NetStateSnapshot` dataclass containing:
|
|
81
|
+
|
|
82
|
+
- platform (str)
|
|
83
|
+
- system (SystemData)
|
|
84
|
+
- private_network (List\[NetworkData\] \| None)
|
|
85
|
+
- public_network (PublicNetworkData \| None)
|
|
86
|
+
- record_time (datetime)
|
|
87
|
+
|
|
88
|
+
All models are defined using Python dataclasses.
|
|
89
|
+
|
|
90
|
+
------------------------------------------------------------------------
|
|
91
|
+
|
|
92
|
+
## Requirements
|
|
93
|
+
|
|
94
|
+
- Python 3.9+
|
|
95
|
+
- Windows OS
|
|
96
|
+
- requests
|
|
97
|
+
|
|
98
|
+
------------------------------------------------------------------------
|
|
99
|
+
|
|
100
|
+
## Design Goals
|
|
101
|
+
|
|
102
|
+
- Clean modular architecture
|
|
103
|
+
- Structured dataclass models
|
|
104
|
+
- Graceful failure handling
|
|
105
|
+
- Easy JSON serialization
|
|
106
|
+
- Extensible collector design
|
|
107
|
+
|
|
108
|
+
------------------------------------------------------------------------
|
|
109
|
+
|
|
110
|
+
## License
|
|
111
|
+
|
|
112
|
+
MIT License
|
|
113
|
+
|
|
114
|
+
------------------------------------------------------------------------
|
|
115
|
+
|
|
116
|
+
## Author
|
|
117
|
+
|
|
118
|
+
Imon Mallik
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
License.md
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
netstate/__init__.py
|
|
5
|
+
netstate/exception.py
|
|
6
|
+
netstate/models.py
|
|
7
|
+
netstate/network_info.py
|
|
8
|
+
netstate.egg-info/PKG-INFO
|
|
9
|
+
netstate.egg-info/SOURCES.txt
|
|
10
|
+
netstate.egg-info/dependency_links.txt
|
|
11
|
+
netstate.egg-info/requires.txt
|
|
12
|
+
netstate.egg-info/top_level.txt
|
|
13
|
+
netstate/collectors/networkData.py
|
|
14
|
+
netstate/collectors/publicIpData.py
|
|
15
|
+
netstate/collectors/systemData.py
|
|
16
|
+
tests/test_netstate.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
requests>=2.0
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
netstate
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "netstate"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Windows network and system snapshot collector"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
|
|
13
|
+
authors = [
|
|
14
|
+
{ name = "Imon Mallik" }
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
dependencies = [
|
|
18
|
+
"requests>=2.0"
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
keywords = [
|
|
22
|
+
"network",
|
|
23
|
+
"system-info",
|
|
24
|
+
"windows",
|
|
25
|
+
"ip",
|
|
26
|
+
"network-monitoring"
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
classifiers = [
|
|
30
|
+
"Programming Language :: Python :: 3",
|
|
31
|
+
"Programming Language :: Python :: 3.9",
|
|
32
|
+
"Operating System :: Microsoft :: Windows",
|
|
33
|
+
"License :: OSI Approved :: MIT License",
|
|
34
|
+
"Intended Audience :: Developers",
|
|
35
|
+
"Topic :: System :: Networking",
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
[tool.setuptools.packages.find]
|
|
39
|
+
where = ["."]
|
|
40
|
+
include = ["netstate*"]
|
|
41
|
+
exclude = ["tests*"]
|
netstate-0.1.0/setup.cfg
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from netstate import get_network_info
|
|
2
|
+
from netstate import get_network_info_json
|
|
3
|
+
from pprint import pprint
|
|
4
|
+
|
|
5
|
+
def main():
|
|
6
|
+
snapshot = get_network_info()
|
|
7
|
+
|
|
8
|
+
print("===== SYSTEM =====")
|
|
9
|
+
pprint(snapshot.system)
|
|
10
|
+
|
|
11
|
+
print("\n===== PRIVATE NETWORK =====")
|
|
12
|
+
pprint(snapshot.private_network)
|
|
13
|
+
|
|
14
|
+
print("\n===== PUBLIC NETWORK =====")
|
|
15
|
+
pprint(snapshot.public_network)
|
|
16
|
+
|
|
17
|
+
print("\n===== RECORD TIME =====")
|
|
18
|
+
pprint(snapshot.record_time)
|
|
19
|
+
|
|
20
|
+
json_output = get_network_info_json()
|
|
21
|
+
print(json_output)
|
|
22
|
+
|
|
23
|
+
if __name__ == "__main__":
|
|
24
|
+
main()
|