lanscape 1.5.0__tar.gz → 2.0.0a1__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.

Potentially problematic release.


This version of lanscape might be problematic. Click here for more details.

Files changed (91) hide show
  1. {lanscape-1.5.0/lanscape.egg-info → lanscape-2.0.0a1}/PKG-INFO +7 -2
  2. {lanscape-1.5.0 → lanscape-2.0.0a1}/lanscape/__init__.py +5 -4
  3. {lanscape-1.5.0 → lanscape-2.0.0a1}/lanscape/__main__.py +1 -0
  4. {lanscape-1.5.0/lanscape/libraries → lanscape-2.0.0a1/lanscape/core}/app_scope.py +1 -0
  5. {lanscape-1.5.0/lanscape/libraries → lanscape-2.0.0a1/lanscape/core}/decorators.py +85 -51
  6. {lanscape-1.5.0/lanscape/libraries → lanscape-2.0.0a1/lanscape/core}/device_alive.py +4 -3
  7. {lanscape-1.5.0/lanscape/libraries → lanscape-2.0.0a1/lanscape/core}/errors.py +1 -0
  8. {lanscape-1.5.0/lanscape/libraries → lanscape-2.0.0a1/lanscape/core}/ip_parser.py +2 -1
  9. {lanscape-1.5.0/lanscape/libraries → lanscape-2.0.0a1/lanscape/core}/logger.py +1 -0
  10. {lanscape-1.5.0/lanscape/libraries → lanscape-2.0.0a1/lanscape/core}/mac_lookup.py +1 -0
  11. {lanscape-1.5.0/lanscape/libraries → lanscape-2.0.0a1/lanscape/core}/net_tools.py +7 -6
  12. {lanscape-1.5.0/lanscape/libraries → lanscape-2.0.0a1/lanscape/core}/port_manager.py +1 -0
  13. {lanscape-1.5.0/lanscape/libraries → lanscape-2.0.0a1/lanscape/core}/runtime_args.py +1 -0
  14. {lanscape-1.5.0/lanscape/libraries → lanscape-2.0.0a1/lanscape/core}/scan_config.py +3 -2
  15. {lanscape-1.5.0/lanscape/libraries → lanscape-2.0.0a1/lanscape/core}/service_scan.py +3 -2
  16. {lanscape-1.5.0/lanscape/libraries → lanscape-2.0.0a1/lanscape/core}/subnet_scan.py +6 -5
  17. {lanscape-1.5.0/lanscape/libraries → lanscape-2.0.0a1/lanscape/core}/version_manager.py +3 -2
  18. {lanscape-1.5.0/lanscape/libraries → lanscape-2.0.0a1/lanscape/core}/web_browser.py +1 -0
  19. {lanscape-1.5.0 → lanscape-2.0.0a1}/lanscape/resources/mac_addresses/convert_csv.py +1 -0
  20. {lanscape-1.5.0 → lanscape-2.0.0a1}/lanscape/resources/ports/convert_csv.py +1 -0
  21. {lanscape-1.5.0 → lanscape-2.0.0a1}/lanscape/ui/app.py +5 -4
  22. {lanscape-1.5.0 → lanscape-2.0.0a1}/lanscape/ui/blueprints/__init__.py +2 -1
  23. {lanscape-1.5.0 → lanscape-2.0.0a1}/lanscape/ui/blueprints/api/__init__.py +1 -0
  24. {lanscape-1.5.0 → lanscape-2.0.0a1}/lanscape/ui/blueprints/api/port.py +2 -1
  25. {lanscape-1.5.0 → lanscape-2.0.0a1}/lanscape/ui/blueprints/api/scan.py +2 -1
  26. {lanscape-1.5.0 → lanscape-2.0.0a1}/lanscape/ui/blueprints/api/tools.py +5 -4
  27. {lanscape-1.5.0 → lanscape-2.0.0a1}/lanscape/ui/blueprints/web/__init__.py +1 -0
  28. {lanscape-1.5.0 → lanscape-2.0.0a1}/lanscape/ui/blueprints/web/routes.py +2 -1
  29. {lanscape-1.5.0 → lanscape-2.0.0a1}/lanscape/ui/main.py +5 -4
  30. {lanscape-1.5.0 → lanscape-2.0.0a1}/lanscape/ui/shutdown_handler.py +2 -1
  31. {lanscape-1.5.0 → lanscape-2.0.0a1/lanscape.egg-info}/PKG-INFO +7 -2
  32. {lanscape-1.5.0 → lanscape-2.0.0a1}/lanscape.egg-info/SOURCES.txt +17 -16
  33. lanscape-2.0.0a1/lanscape.egg-info/entry_points.txt +2 -0
  34. {lanscape-1.5.0 → lanscape-2.0.0a1}/pyproject.toml +10 -2
  35. {lanscape-1.5.0 → lanscape-2.0.0a1}/tests/test_api.py +2 -1
  36. lanscape-2.0.0a1/tests/test_decorators.py +283 -0
  37. {lanscape-1.5.0 → lanscape-2.0.0a1}/tests/test_env.py +4 -3
  38. {lanscape-1.5.0 → lanscape-2.0.0a1}/tests/test_library.py +4 -3
  39. {lanscape-1.5.0 → lanscape-2.0.0a1}/tests/test_logging.py +3 -2
  40. {lanscape-1.5.0 → lanscape-2.0.0a1}/tests/test_port_scan.py +4 -3
  41. {lanscape-1.5.0 → lanscape-2.0.0a1}/tests/test_service_scan.py +3 -2
  42. {lanscape-1.5.0 → lanscape-2.0.0a1}/tests/test_utils.py +6 -5
  43. lanscape-1.5.0/tests/test_decorators.py +0 -29
  44. {lanscape-1.5.0 → lanscape-2.0.0a1}/LICENSE +0 -0
  45. {lanscape-1.5.0 → lanscape-2.0.0a1}/MANIFEST.in +0 -0
  46. {lanscape-1.5.0 → lanscape-2.0.0a1}/README.md +0 -0
  47. {lanscape-1.5.0/lanscape/libraries → lanscape-2.0.0a1/lanscape/core}/__init__.py +0 -0
  48. {lanscape-1.5.0 → lanscape-2.0.0a1}/lanscape/resources/mac_addresses/mac_db.json +0 -0
  49. {lanscape-1.5.0 → lanscape-2.0.0a1}/lanscape/resources/ports/full.json +0 -0
  50. {lanscape-1.5.0 → lanscape-2.0.0a1}/lanscape/resources/ports/large.json +0 -0
  51. {lanscape-1.5.0 → lanscape-2.0.0a1}/lanscape/resources/ports/medium.json +0 -0
  52. {lanscape-1.5.0 → lanscape-2.0.0a1}/lanscape/resources/ports/small.json +0 -0
  53. {lanscape-1.5.0 → lanscape-2.0.0a1}/lanscape/resources/services/definitions.jsonc +0 -0
  54. {lanscape-1.5.0 → lanscape-2.0.0a1}/lanscape/ui/__init__.py +0 -0
  55. {lanscape-1.5.0 → lanscape-2.0.0a1}/lanscape/ui/static/css/style.css +0 -0
  56. {lanscape-1.5.0 → lanscape-2.0.0a1}/lanscape/ui/static/img/ico/android-chrome-192x192.png +0 -0
  57. {lanscape-1.5.0 → lanscape-2.0.0a1}/lanscape/ui/static/img/ico/android-chrome-512x512.png +0 -0
  58. {lanscape-1.5.0 → lanscape-2.0.0a1}/lanscape/ui/static/img/ico/apple-touch-icon.png +0 -0
  59. {lanscape-1.5.0 → lanscape-2.0.0a1}/lanscape/ui/static/img/ico/favicon-16x16.png +0 -0
  60. {lanscape-1.5.0 → lanscape-2.0.0a1}/lanscape/ui/static/img/ico/favicon-32x32.png +0 -0
  61. {lanscape-1.5.0 → lanscape-2.0.0a1}/lanscape/ui/static/img/ico/favicon.ico +0 -0
  62. {lanscape-1.5.0 → lanscape-2.0.0a1}/lanscape/ui/static/img/ico/site.webmanifest +0 -0
  63. {lanscape-1.5.0 → lanscape-2.0.0a1}/lanscape/ui/static/js/core.js +0 -0
  64. {lanscape-1.5.0 → lanscape-2.0.0a1}/lanscape/ui/static/js/layout-sizing.js +0 -0
  65. {lanscape-1.5.0 → lanscape-2.0.0a1}/lanscape/ui/static/js/main.js +0 -0
  66. {lanscape-1.5.0 → lanscape-2.0.0a1}/lanscape/ui/static/js/on-tab-close.js +0 -0
  67. {lanscape-1.5.0 → lanscape-2.0.0a1}/lanscape/ui/static/js/quietReload.js +0 -0
  68. {lanscape-1.5.0 → lanscape-2.0.0a1}/lanscape/ui/static/js/scan-config.js +0 -0
  69. {lanscape-1.5.0 → lanscape-2.0.0a1}/lanscape/ui/static/js/shutdown-server.js +0 -0
  70. {lanscape-1.5.0 → lanscape-2.0.0a1}/lanscape/ui/static/js/subnet-info.js +0 -0
  71. {lanscape-1.5.0 → lanscape-2.0.0a1}/lanscape/ui/static/js/subnet-selector.js +0 -0
  72. {lanscape-1.5.0 → lanscape-2.0.0a1}/lanscape/ui/static/lanscape.webmanifest +0 -0
  73. {lanscape-1.5.0 → lanscape-2.0.0a1}/lanscape/ui/templates/base.html +0 -0
  74. {lanscape-1.5.0 → lanscape-2.0.0a1}/lanscape/ui/templates/core/head.html +0 -0
  75. {lanscape-1.5.0 → lanscape-2.0.0a1}/lanscape/ui/templates/core/scripts.html +0 -0
  76. {lanscape-1.5.0 → lanscape-2.0.0a1}/lanscape/ui/templates/error.html +0 -0
  77. {lanscape-1.5.0 → lanscape-2.0.0a1}/lanscape/ui/templates/info.html +0 -0
  78. {lanscape-1.5.0 → lanscape-2.0.0a1}/lanscape/ui/templates/main.html +0 -0
  79. {lanscape-1.5.0 → lanscape-2.0.0a1}/lanscape/ui/templates/scan/config.html +0 -0
  80. {lanscape-1.5.0 → lanscape-2.0.0a1}/lanscape/ui/templates/scan/device-detail.html +0 -0
  81. {lanscape-1.5.0 → lanscape-2.0.0a1}/lanscape/ui/templates/scan/export.html +0 -0
  82. {lanscape-1.5.0 → lanscape-2.0.0a1}/lanscape/ui/templates/scan/ip-table-row.html +0 -0
  83. {lanscape-1.5.0 → lanscape-2.0.0a1}/lanscape/ui/templates/scan/ip-table.html +0 -0
  84. {lanscape-1.5.0 → lanscape-2.0.0a1}/lanscape/ui/templates/scan/overview.html +0 -0
  85. {lanscape-1.5.0 → lanscape-2.0.0a1}/lanscape/ui/templates/scan/scan-error.html +0 -0
  86. {lanscape-1.5.0 → lanscape-2.0.0a1}/lanscape/ui/templates/scan.html +0 -0
  87. {lanscape-1.5.0 → lanscape-2.0.0a1}/lanscape/ui/templates/shutdown.html +0 -0
  88. {lanscape-1.5.0 → lanscape-2.0.0a1}/lanscape.egg-info/dependency_links.txt +0 -0
  89. {lanscape-1.5.0 → lanscape-2.0.0a1}/lanscape.egg-info/requires.txt +0 -0
  90. {lanscape-1.5.0 → lanscape-2.0.0a1}/lanscape.egg-info/top_level.txt +0 -0
  91. {lanscape-1.5.0 → lanscape-2.0.0a1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lanscape
3
- Version: 1.5.0
3
+ Version: 2.0.0a1
4
4
  Summary: A python based local network scanner
5
5
  Author-email: Michael Dennis <michael@dipduo.com>
6
6
  License-Expression: MIT
@@ -8,8 +8,13 @@ Project-URL: Homepage, https://github.com/mdennis281/py-lanscape
8
8
  Project-URL: Issues, https://github.com/mdennis281/py-lanscape/issues
9
9
  Keywords: network,scanner,lan,local,python
10
10
  Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.10
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Programming Language :: Python :: 3.13
15
+ Classifier: Programming Language :: Python :: 3.14
11
16
  Classifier: Operating System :: OS Independent
12
- Requires-Python: >=3.8
17
+ Requires-Python: >=3.10
13
18
  Description-Content-Type: text/markdown
14
19
  License-File: LICENSE
15
20
  Requires-Dist: Flask<5.0,>=3.0
@@ -1,13 +1,13 @@
1
1
  """
2
2
  Local network scanner
3
3
  """
4
- from lanscape.libraries.subnet_scan import (
4
+ from lanscape.core.subnet_scan import (
5
5
  SubnetScanner,
6
6
  ScannerResults,
7
7
  ScanManager
8
8
  )
9
9
 
10
- from lanscape.libraries.scan_config import (
10
+ from lanscape.core.scan_config import (
11
11
  ScanConfig,
12
12
  ArpConfig,
13
13
  PingConfig,
@@ -19,6 +19,7 @@ from lanscape.libraries.scan_config import (
19
19
  ScanType
20
20
  )
21
21
 
22
- from lanscape.libraries.port_manager import PortManager
22
+ from lanscape.core.port_manager import PortManager
23
+
24
+ from lanscape.core import net_tools
23
25
 
24
- from lanscape.libraries import net_tools
@@ -7,3 +7,4 @@ from lanscape.ui.main import main
7
7
 
8
8
  if __name__ == "__main__":
9
9
  main()
10
+
@@ -90,3 +90,4 @@ def is_local_run() -> bool:
90
90
  if any(parts):
91
91
  return False
92
92
  return True # Installed package
93
+
@@ -2,13 +2,11 @@
2
2
  """Decorators and job tracking utilities for Lanscape."""
3
3
 
4
4
  from time import time
5
- from dataclasses import dataclass, field
6
- from typing import DefaultDict
7
5
  from collections import defaultdict
8
- import inspect
9
6
  import functools
10
7
  import concurrent.futures
11
8
  import logging
9
+ import threading
12
10
  from tabulate import tabulate
13
11
 
14
12
 
@@ -39,31 +37,74 @@ def run_once(func):
39
37
  return wrapper
40
38
 
41
39
 
42
- @dataclass
43
40
  class JobStats:
44
41
  """
42
+ Thread-safe singleton for tracking job statistics across all classes.
45
43
  Tracks statistics for job execution, including running, finished, and timing data.
46
44
  """
47
- running: DefaultDict[str, int] = field(
48
- default_factory=lambda: defaultdict(int))
49
- finished: DefaultDict[str, int] = field(
50
- default_factory=lambda: defaultdict(int))
51
- timing: DefaultDict[str, float] = field(
52
- default_factory=lambda: defaultdict(float))
53
45
 
54
46
  _instance = None
47
+ _lock = threading.Lock()
48
+
49
+ def __new__(cls):
50
+ if cls._instance is None:
51
+ with cls._lock:
52
+ if cls._instance is None: # Double-checked locking
53
+ cls._instance = super().__new__(cls)
54
+ return cls._instance
55
55
 
56
56
  def __init__(self):
57
- # Only initialize once
58
- if not hasattr(self, "running"):
57
+ if not hasattr(self, '_initialized'):
58
+ self._stats_lock = threading.RLock()
59
59
  self.running = defaultdict(int)
60
60
  self.finished = defaultdict(int)
61
61
  self.timing = defaultdict(float)
62
-
63
- def __new__(cls, *args, **kwargs):
64
- if cls._instance is None:
65
- cls._instance = super(JobStats, cls).__new__(cls)
66
- return cls._instance
62
+ self._initialized = True
63
+
64
+ def start_job(self, func_name: str):
65
+ """Thread-safe increment of running counter."""
66
+ with self._stats_lock:
67
+ self.running[func_name] += 1
68
+
69
+ def finish_job(self, func_name: str, elapsed_time: float):
70
+ """Thread-safe update of job completion and timing."""
71
+ with self._stats_lock:
72
+ self.running[func_name] -= 1
73
+ self.finished[func_name] += 1
74
+
75
+ # Calculate running average
76
+ count = self.finished[func_name]
77
+ old_avg = self.timing[func_name]
78
+ new_avg = (old_avg * (count - 1) + elapsed_time) / count
79
+ self.timing[func_name] = round(new_avg, 4)
80
+
81
+ # Cleanup running if zero
82
+ if self.running[func_name] <= 0:
83
+ self.running.pop(func_name, None)
84
+
85
+ def clear_stats(self):
86
+ """Clear all statistics (useful between scans)."""
87
+ with self._stats_lock:
88
+ self.running.clear()
89
+ self.finished.clear()
90
+ self.timing.clear()
91
+
92
+ def get_stats_copy(self) -> dict:
93
+ """Get a thread-safe copy of current statistics."""
94
+ with self._stats_lock:
95
+ return {
96
+ 'running': dict(self.running),
97
+ 'finished': dict(self.finished),
98
+ 'timing': dict(self.timing)
99
+ }
100
+
101
+ @classmethod
102
+ def reset_for_testing(cls):
103
+ """Reset singleton instance for testing purposes only."""
104
+ with cls._lock:
105
+ if cls._instance:
106
+ cls._instance.clear_stats()
107
+ cls._instance = None
67
108
 
68
109
  def __str__(self):
69
110
  """Return a formatted string representation of the job statistics."""
@@ -106,48 +147,40 @@ def job_tracker(func):
106
147
  Return the function name with the class name prepended if available.
107
148
  """
108
149
  qual_parts = func.__qualname__.split(".")
109
- cls_name = qual_parts[-2] if len(qual_parts) > 1 else None
110
- cls_obj = None # resolved lazily
111
- if cls_obj is None and cls_name:
112
- mod = inspect.getmodule(func)
113
- cls_obj = getattr(mod, cls_name, None)
114
- if cls_obj and first_arg is not None:
115
- if (first_arg is cls_obj or isinstance(first_arg, cls_obj)):
116
- return f"{cls_name}.{func.__name__}"
150
+
151
+ # If function has class context (e.g., "ClassName.method_name")
152
+ if len(qual_parts) > 1:
153
+ cls_name = qual_parts[-2]
154
+
155
+ # Check if first_arg is an instance and has the expected class name
156
+ if first_arg is not None and hasattr(first_arg, '__class__'):
157
+ if first_arg.__class__.__name__ == cls_name:
158
+ return f"{cls_name}.{func.__name__}"
159
+
117
160
  return func.__name__
118
161
 
162
+ @functools.wraps(func)
119
163
  def wrapper(*args, **kwargs):
120
164
  """Wrap the function to update job statistics before and after execution."""
121
- class_instance = args[0]
122
165
  job_stats = JobStats()
123
- fxn = get_fxn_src_name(
124
- func,
125
- class_instance
126
- )
127
-
128
- # Increment running counter and track execution time
129
- job_stats.running[fxn] += 1
130
- start = time()
131
166
 
132
- result = func(*args, **kwargs) # Execute the wrapped function
167
+ # Determine function name for tracking
168
+ if args:
169
+ fxn = get_fxn_src_name(func, args[0])
170
+ else:
171
+ fxn = func.__name__
133
172
 
134
- # Update statistics after function execution
135
- elapsed = time() - start
136
- job_stats.running[fxn] -= 1
137
- job_stats.finished[fxn] += 1
138
-
139
- # Calculate the new average timing for the function
140
- job_stats.timing[fxn] = round(
141
- ((job_stats.finished[fxn] - 1) * job_stats.timing[fxn] + elapsed)
142
- / job_stats.finished[fxn],
143
- 4
144
- )
145
-
146
- # Clean up if no more running instances of this function
147
- if job_stats.running[fxn] == 0:
148
- job_stats.running.pop(fxn)
173
+ # Start job tracking
174
+ job_stats.start_job(fxn)
175
+ start = time()
149
176
 
150
- return result
177
+ try:
178
+ result = func(*args, **kwargs) # Execute the wrapped function
179
+ return result
180
+ finally:
181
+ # Always update statistics, even if function raises exception
182
+ elapsed = time() - start
183
+ job_stats.finish_job(fxn, elapsed)
151
184
 
152
185
  return wrapper
153
186
 
@@ -196,3 +229,4 @@ def timeout_enforcer(timeout: int, raise_on_timeout: bool = True):
196
229
  return None # Return None if not raising an exception
197
230
  return wrapper
198
231
  return decorator
232
+
@@ -13,12 +13,12 @@ from scapy.sendrecv import srp
13
13
  from scapy.layers.l2 import ARP, Ether
14
14
  from icmplib import ping
15
15
 
16
- from lanscape.libraries.net_tools import Device
17
- from lanscape.libraries.scan_config import (
16
+ from lanscape.core.net_tools import Device
17
+ from lanscape.core.scan_config import (
18
18
  ScanConfig, ScanType, PingConfig,
19
19
  ArpConfig, PokeConfig, ArpCacheConfig
20
20
  )
21
- from lanscape.libraries.decorators import timeout_enforcer, job_tracker
21
+ from lanscape.core.decorators import timeout_enforcer, job_tracker
22
22
 
23
23
 
24
24
  def is_device_alive(device: Device, scan_config: ScanConfig) -> bool:
@@ -227,3 +227,4 @@ class Poker():
227
227
  sock.close()
228
228
 
229
229
  do_poke()
230
+
@@ -40,3 +40,4 @@ class DeviceError(Exception):
40
40
 
41
41
  def __str__(self):
42
42
  return f'Error(source={self.method}, msg={self.base})'
43
+
@@ -12,7 +12,7 @@ It also includes validation to prevent processing excessively large IP ranges.
12
12
  import ipaddress
13
13
  import re
14
14
 
15
- from lanscape.libraries.errors import SubnetTooLargeError
15
+ from lanscape.core.errors import SubnetTooLargeError
16
16
 
17
17
  MAX_IPS_ALLOWED = 100000
18
18
 
@@ -139,3 +139,4 @@ def ip_range_to_list(start_ip, end_ip):
139
139
  # Yield the range of IPs
140
140
  for ip_int in range(int(start_ip), int(end_ip) + 1):
141
141
  yield ipaddress.IPv4Address(ip_int)
142
+
@@ -72,3 +72,4 @@ def disable_flask_logging() -> None:
72
72
  werkzeug_log.setLevel(logging.ERROR)
73
73
 
74
74
  override_click_logging()
75
+
@@ -105,3 +105,4 @@ def lookup_mac(mac: str) -> Optional[str]:
105
105
  def get_macs(ip: str) -> List[str]:
106
106
  """Backward compatibility function for MAC resolution."""
107
107
  return MacResolver().get_macs(ip)
108
+
@@ -29,12 +29,12 @@ else:
29
29
  COMPUTED_FIELD = computed_field # pylint: disable=invalid-name
30
30
  MODEL_SERIALIZER = model_serializer # pylint: disable=invalid-name
31
31
 
32
- from lanscape.libraries.service_scan import scan_service
33
- from lanscape.libraries.mac_lookup import MacLookup, get_macs
34
- from lanscape.libraries.ip_parser import get_address_count, MAX_IPS_ALLOWED
35
- from lanscape.libraries.errors import DeviceError
36
- from lanscape.libraries.decorators import job_tracker, run_once, timeout_enforcer
37
- from lanscape.libraries.scan_config import ServiceScanConfig, PortScanConfig
32
+ from lanscape.core.service_scan import scan_service
33
+ from lanscape.core.mac_lookup import MacLookup, get_macs
34
+ from lanscape.core.ip_parser import get_address_count, MAX_IPS_ALLOWED
35
+ from lanscape.core.errors import DeviceError
36
+ from lanscape.core.decorators import job_tracker, run_once, timeout_enforcer
37
+ from lanscape.core.scan_config import ServiceScanConfig, PortScanConfig
38
38
 
39
39
  log = logging.getLogger('NetTools')
40
40
  mac_lookup = MacLookup()
@@ -566,3 +566,4 @@ def is_arp_supported():
566
566
  return True
567
567
  except (Scapy_Exception, PermissionError, RuntimeError):
568
568
  return False
569
+
@@ -148,3 +148,4 @@ class PortManager:
148
148
  return True
149
149
  except BaseException:
150
150
  return False
151
+
@@ -63,3 +63,4 @@ def parse_args() -> RuntimeArgs:
63
63
 
64
64
  # Return the dataclass instance with the dynamically assigned values
65
65
  return RuntimeArgs(**filtered_args)
66
+
@@ -11,8 +11,8 @@ from enum import Enum
11
11
 
12
12
  from pydantic import BaseModel, Field
13
13
 
14
- from lanscape.libraries.port_manager import PortManager
15
- from lanscape.libraries.ip_parser import parse_ip_input
14
+ from lanscape.core.port_manager import PortManager
15
+ from lanscape.core.ip_parser import parse_ip_input
16
16
 
17
17
 
18
18
  class PingConfig(BaseModel):
@@ -395,3 +395,4 @@ DEFAULT_CONFIGS: Dict[str, ScanConfig] = {
395
395
  )
396
396
  )
397
397
  }
398
+
@@ -7,8 +7,8 @@ import asyncio
7
7
  import logging
8
8
  import traceback
9
9
 
10
- from lanscape.libraries.app_scope import ResourceManager
11
- from lanscape.libraries.scan_config import ServiceScanConfig, ServiceScanStrategy
10
+ from lanscape.core.app_scope import ResourceManager
11
+ from lanscape.core.scan_config import ServiceScanConfig, ServiceScanStrategy
12
12
 
13
13
  log = logging.getLogger('ServiceScan')
14
14
  SERVICES = ResourceManager('services').get_jsonc('definitions.jsonc')
@@ -202,3 +202,4 @@ def asyncio_logger_suppression():
202
202
 
203
203
 
204
204
  asyncio_logger_suppression()
205
+
@@ -20,11 +20,11 @@ from concurrent.futures import ThreadPoolExecutor, as_completed
20
20
  from tabulate import tabulate
21
21
 
22
22
  # Local imports
23
- from lanscape.libraries.scan_config import ScanConfig
24
- from lanscape.libraries.decorators import job_tracker, terminator, JobStats
25
- from lanscape.libraries.net_tools import Device
26
- from lanscape.libraries.errors import SubnetScanTerminationFailure
27
- from lanscape.libraries.device_alive import is_device_alive
23
+ from lanscape.core.scan_config import ScanConfig
24
+ from lanscape.core.decorators import job_tracker, terminator, JobStats
25
+ from lanscape.core.net_tools import Device
26
+ from lanscape.core.errors import SubnetScanTerminationFailure
27
+ from lanscape.core.device_alive import is_device_alive
28
28
 
29
29
 
30
30
  class SubnetScanner():
@@ -428,3 +428,4 @@ class ScanManager:
428
428
  t = threading.Thread(target=scan.start)
429
429
  t.start()
430
430
  return t
431
+
@@ -11,8 +11,8 @@ from random import randint
11
11
 
12
12
  import requests
13
13
 
14
- from lanscape.libraries.app_scope import is_local_run
15
- from lanscape.libraries.decorators import run_once
14
+ from lanscape.core.app_scope import is_local_run
15
+ from lanscape.core.decorators import run_once
16
16
 
17
17
  log = logging.getLogger('VersionManager')
18
18
 
@@ -95,3 +95,4 @@ def get_installed_version(package=PACKAGE):
95
95
  log.debug(traceback.format_exc())
96
96
  log.warning(f'Cannot find {package} installation')
97
97
  return LOCAL_VERSION
98
+
@@ -208,3 +208,4 @@ def windows_get_browser_from_registry() -> Optional[str]:
208
208
  system_browser = get_system_default_browser()
209
209
  if system_browser:
210
210
  return extract_executable(system_browser)
211
+
@@ -38,3 +38,4 @@ def csv_to_dict(data):
38
38
 
39
39
 
40
40
  main()
41
+
@@ -8,12 +8,12 @@ import logging
8
8
  from flask import Flask, render_template
9
9
  from lanscape.ui.blueprints.web import web_bp, routes # pylint: disable=unused-import
10
10
  from lanscape.ui.blueprints.api import api_bp, tools, port, scan # pylint: disable=unused-import
11
- from lanscape.libraries.runtime_args import RuntimeArgs, parse_args
12
- from lanscape.libraries.version_manager import (
11
+ from lanscape.core.runtime_args import RuntimeArgs, parse_args
12
+ from lanscape.core.version_manager import (
13
13
  is_update_available, get_installed_version, lookup_latest_version
14
14
  )
15
- from lanscape.libraries.app_scope import is_local_run
16
- from lanscape.libraries.net_tools import is_arp_supported
15
+ from lanscape.core.app_scope import is_local_run
16
+ from lanscape.core.net_tools import is_arp_supported
17
17
  from lanscape.ui.shutdown_handler import FlaskShutdownHandler
18
18
 
19
19
  app = Flask(
@@ -122,3 +122,4 @@ def start_webserver(args: RuntimeArgs) -> int:
122
122
  'use_reloader': args.reloader
123
123
  }
124
124
  app.run(**run_args)
125
+
@@ -1,10 +1,11 @@
1
1
  """Source for all things blueprint related in LANscape UI"""
2
2
  import logging
3
3
 
4
- from lanscape.libraries.subnet_scan import ScanManager
4
+ from lanscape.core.subnet_scan import ScanManager
5
5
 
6
6
  # defining here so blueprints can access the same
7
7
  # manager instance
8
8
  scan_manager = ScanManager()
9
9
 
10
10
  log = logging.getLogger('Blueprints')
11
+
@@ -3,3 +3,4 @@
3
3
  from flask import Blueprint
4
4
 
5
5
  api_bp = Blueprint('api', __name__)
6
+
@@ -4,7 +4,7 @@ Provides CRUD operations for managing port lists used in network scans.
4
4
  """
5
5
  from flask import request, jsonify
6
6
  from lanscape.ui.blueprints.api import api_bp
7
- from lanscape.libraries.port_manager import PortManager
7
+ from lanscape.core.port_manager import PortManager
8
8
 
9
9
  # Port Manager API
10
10
  ############################################
@@ -77,3 +77,4 @@ def delete_port_list(port_list):
77
77
  JSON response indicating success or failure
78
78
  """
79
79
  return jsonify(PortManager().delete_port_list(port_list))
80
+
@@ -9,7 +9,7 @@ import traceback
9
9
  from flask import request, jsonify
10
10
 
11
11
  from lanscape.ui.blueprints.api import api_bp
12
- from lanscape.libraries.subnet_scan import ScanConfig
12
+ from lanscape.core.subnet_scan import ScanConfig
13
13
  from lanscape.ui.blueprints import scan_manager
14
14
 
15
15
  # Subnet Scanner API
@@ -121,3 +121,4 @@ def get_scan_config():
121
121
  """
122
122
  data = request.get_json()
123
123
  return ScanConfig.from_dict(data)
124
+
@@ -5,10 +5,10 @@ API endpoints for subnet testing and listing.
5
5
  import traceback
6
6
  from flask import request, jsonify
7
7
  from lanscape.ui.blueprints.api import api_bp
8
- from lanscape.libraries.net_tools import get_all_network_subnets, is_arp_supported
9
- from lanscape.libraries.ip_parser import parse_ip_input
10
- from lanscape.libraries.errors import SubnetTooLargeError
11
- from lanscape.libraries.scan_config import DEFAULT_CONFIGS
8
+ from lanscape.core.net_tools import get_all_network_subnets, is_arp_supported
9
+ from lanscape.core.ip_parser import parse_ip_input
10
+ from lanscape.core.errors import SubnetTooLargeError
11
+ from lanscape.core.scan_config import DEFAULT_CONFIGS
12
12
 
13
13
 
14
14
  @api_bp.route('/api/tools/subnet/test')
@@ -69,3 +69,4 @@ def get_default_configs():
69
69
  configs[key] = config_dict
70
70
 
71
71
  return jsonify(configs)
72
+
@@ -5,3 +5,4 @@ Blueprint for web-related routes and views.
5
5
  from flask import Blueprint
6
6
 
7
7
  web_bp = Blueprint('web', __name__)
8
+
@@ -4,7 +4,7 @@ Handles UI views including the main dashboard, scan results, error display, and
4
4
  """
5
5
  from flask import render_template, request, redirect, url_for
6
6
  from lanscape.ui.blueprints.web import web_bp
7
- from lanscape.libraries.net_tools import (
7
+ from lanscape.core.net_tools import (
8
8
  get_all_network_subnets,
9
9
  smart_select_primary_subnet
10
10
  )
@@ -150,3 +150,4 @@ def app_info():
150
150
  Rendered info template
151
151
  """
152
152
  return render_template('info.html')
153
+
@@ -9,10 +9,10 @@ import traceback
9
9
  import os
10
10
  import requests
11
11
 
12
- from lanscape.libraries.logger import configure_logging
13
- from lanscape.libraries.runtime_args import parse_args
14
- from lanscape.libraries.web_browser import open_webapp
15
- from lanscape.libraries.version_manager import get_installed_version, is_update_available
12
+ from lanscape.core.logger import configure_logging
13
+ from lanscape.core.runtime_args import parse_args
14
+ from lanscape.core.web_browser import open_webapp
15
+ from lanscape.core.version_manager import get_installed_version, is_update_available
16
16
  from lanscape.ui.app import start_webserver_daemon, start_webserver
17
17
  # do this so any logs generated on import are displayed
18
18
  args = parse_args()
@@ -136,3 +136,4 @@ def terminate():
136
136
 
137
137
  if __name__ == "__main__":
138
138
  main()
139
+
@@ -5,7 +5,7 @@ import os
5
5
  from flask import request
6
6
 
7
7
 
8
- from lanscape.libraries.runtime_args import parse_args
8
+ from lanscape.core.runtime_args import parse_args
9
9
 
10
10
 
11
11
  log = logging.getLogger('shutdown_handler')
@@ -55,3 +55,4 @@ class FlaskShutdownHandler:
55
55
  """Exits the application if a shutdown request has been made."""
56
56
  if self._exiting:
57
57
  os._exit(0)
58
+
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lanscape
3
- Version: 1.5.0
3
+ Version: 2.0.0a1
4
4
  Summary: A python based local network scanner
5
5
  Author-email: Michael Dennis <michael@dipduo.com>
6
6
  License-Expression: MIT
@@ -8,8 +8,13 @@ Project-URL: Homepage, https://github.com/mdennis281/py-lanscape
8
8
  Project-URL: Issues, https://github.com/mdennis281/py-lanscape/issues
9
9
  Keywords: network,scanner,lan,local,python
10
10
  Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.10
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Programming Language :: Python :: 3.13
15
+ Classifier: Programming Language :: Python :: 3.14
11
16
  Classifier: Operating System :: OS Independent
12
- Requires-Python: >=3.8
17
+ Requires-Python: >=3.10
13
18
  Description-Content-Type: text/markdown
14
19
  License-File: LICENSE
15
20
  Requires-Dist: Flask<5.0,>=3.0
@@ -7,24 +7,25 @@ lanscape/__main__.py
7
7
  lanscape.egg-info/PKG-INFO
8
8
  lanscape.egg-info/SOURCES.txt
9
9
  lanscape.egg-info/dependency_links.txt
10
+ lanscape.egg-info/entry_points.txt
10
11
  lanscape.egg-info/requires.txt
11
12
  lanscape.egg-info/top_level.txt
12
- lanscape/libraries/__init__.py
13
- lanscape/libraries/app_scope.py
14
- lanscape/libraries/decorators.py
15
- lanscape/libraries/device_alive.py
16
- lanscape/libraries/errors.py
17
- lanscape/libraries/ip_parser.py
18
- lanscape/libraries/logger.py
19
- lanscape/libraries/mac_lookup.py
20
- lanscape/libraries/net_tools.py
21
- lanscape/libraries/port_manager.py
22
- lanscape/libraries/runtime_args.py
23
- lanscape/libraries/scan_config.py
24
- lanscape/libraries/service_scan.py
25
- lanscape/libraries/subnet_scan.py
26
- lanscape/libraries/version_manager.py
27
- lanscape/libraries/web_browser.py
13
+ lanscape/core/__init__.py
14
+ lanscape/core/app_scope.py
15
+ lanscape/core/decorators.py
16
+ lanscape/core/device_alive.py
17
+ lanscape/core/errors.py
18
+ lanscape/core/ip_parser.py
19
+ lanscape/core/logger.py
20
+ lanscape/core/mac_lookup.py
21
+ lanscape/core/net_tools.py
22
+ lanscape/core/port_manager.py
23
+ lanscape/core/runtime_args.py
24
+ lanscape/core/scan_config.py
25
+ lanscape/core/service_scan.py
26
+ lanscape/core/subnet_scan.py
27
+ lanscape/core/version_manager.py
28
+ lanscape/core/web_browser.py
28
29
  lanscape/resources/mac_addresses/convert_csv.py
29
30
  lanscape/resources/mac_addresses/mac_db.json
30
31
  lanscape/resources/ports/convert_csv.py
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ lanscape = lanscape.ui.main:main