atomicshop 3.3.5__py3-none-any.whl → 3.3.6__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.

Potentially problematic release.


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

atomicshop/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
1
  """Atomic Basic functions and classes to make developer life easier"""
2
2
 
3
3
  __author__ = "Den Kras"
4
- __version__ = '3.3.5'
4
+ __version__ = '3.3.6'
atomicshop/networks.py CHANGED
@@ -3,6 +3,7 @@ import time
3
3
  from typing import Union
4
4
  import os
5
5
  import psutil
6
+ import ctypes
6
7
 
7
8
  from icmplib import ping
8
9
  from icmplib.models import Host
@@ -20,9 +21,12 @@ MICROSOFT_LOOPBACK_DEVICE_HARDWARE_ID = "*MSLOOP"
20
21
  GUID_DEVCLASS_NET: str = '{4d36e972-e325-11ce-bfc1-08002be10318}'
21
22
 
22
23
 
23
- def is_ip_alive(ip_address: str, timeout: int = 1) -> bool:
24
+ def is_ip_in_use_ping(ip_address: str, timeout: int = 1) -> bool:
24
25
  """
25
- Returns True if icmplib.models.Host.is_alive returns True.
26
+ Returns True if the IP address is pingable, False otherwise.
27
+ :param ip_address: string, IP address to check.
28
+ :param timeout: int, timeout in seconds. Default is 1 second.
29
+ :return: bool, True if the IP address is pingable, False otherwise.
26
30
  """
27
31
 
28
32
  host_object: Host = ping(ip_address, count=1, timeout=timeout)
@@ -30,15 +34,72 @@ def is_ip_alive(ip_address: str, timeout: int = 1) -> bool:
30
34
  return host_object.is_alive
31
35
 
32
36
 
33
- def get_default_internet_ipv4() -> str:
37
+ def is_ip_in_use_arp(
38
+ ipv4: str,
39
+ gateway_ip: str = None
40
+ ) -> tuple[
41
+ Union[str, None],
42
+ Union[bool, None]
43
+ ]:
34
44
  """
45
+ Windows only.
46
+ Check if an IPv4 address is in use on the local network using ARP.
47
+ :param ipv4: string, IPv4 address to check.
48
+ :param gateway_ip: string, IPv4 address of the default gateway.
49
+ How it works: If you provide the gateway_ip, the function will get yje MAC of the gateway,
50
+ then it will get the MAC of the target IP address. If the MACs are the same, it means that the target IP's
51
+ ARP reply is an ARP proxy reply from the gateway.
52
+ :return: tuple (mac_address: str | None, via_gateway: bool | None)
53
+ If the IP address is in use, mac_address will be the MAC address of the device using the IP address,
54
+ else None. If gateway_ip is provided, via_gateway will be True if the MAC address is the same as the gateway's MAC address,
55
+ False if it's different, and None if gateway_ip is not provided.
56
+ """
57
+
58
+ iphlpapi = ctypes.windll.iphlpapi
59
+ ws2_32 = ctypes.windll.ws2_32
60
+
61
+ def _send_arp(ip: str) -> str | None:
62
+ """Return MAC string like 'aa:bb:cc:dd:ee:ff' if IP is claimed on the LAN, else None."""
63
+ # inet_addr returns DWORD in network byte order
64
+ dest_ip = ws2_32.inet_addr(ip.encode('ascii'))
65
+ if dest_ip == 0xFFFFFFFF: # INVALID
66
+ raise ValueError(f"Bad IPv4 address: {ip}")
67
+
68
+ mac_buf = ctypes.c_uint64(0) # storage for up to 8 bytes
69
+ mac_len = ctypes.c_ulong(ctypes.sizeof(mac_buf)) # in/out len
70
+ # SrcIP=0 lets Windows pick the right interface
71
+ rc = iphlpapi.SendARP(dest_ip, 0, ctypes.byref(mac_buf), ctypes.byref(mac_len))
72
+ if rc != 0: # Non-zero means no ARP reply / not on-link / other error
73
+ return None
74
+
75
+ # Extract the first 6 bytes from little-endian integer
76
+ mac_int = mac_buf.value
77
+ mac_bytes = mac_int.to_bytes(8, 'little')[:6]
78
+ return ':'.join(f'{b:02x}' for b in mac_bytes)
79
+
80
+ mac = _send_arp(ipv4)
81
+ if mac is None:
82
+ return None, None
83
+ via_gateway = None
84
+ if gateway_ip:
85
+ gw_mac = _send_arp(gateway_ip)
86
+ via_gateway = (gw_mac is not None and gw_mac.lower() == mac.lower())
87
+ return mac, via_gateway
88
+
89
+
90
+ def __get_default_internet_ipv4() -> str:
91
+ """
92
+ FOR REFERENCE ONLY, DO NOT USE.
93
+ DOESN'T WORK UNDER ALL CIRCUMSTANCES, CAN'T PINPOINT THE REASON.
94
+
35
95
  Get the default IPv4 address of the interface that is being used for internet.
36
96
  :return: string, default IPv4 address.
37
97
  """
38
98
 
39
99
  return socket.gethostbyname(socket.gethostname())
40
100
 
41
- def get_default_internet_ipv4_by_connect(target: str = "8.8.8.8") -> str:
101
+
102
+ def get_default_internet_ipv4(target: str = "8.8.8.8") -> str:
42
103
  with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
43
104
  s.connect((target, 80)) # no packet sent; OS just chooses a route
44
105
  return s.getsockname()[0] # local address of that route
@@ -296,9 +357,9 @@ def generate_unused_ipv4_addresses_by_vlan(
296
357
  for i in range(number_of_ips):
297
358
  # Create the IP address.
298
359
  while True:
299
- ip_address = f"{vlan}.{counter}"
360
+ ip_address: str = f"{vlan}.{counter}"
300
361
  counter += 1
301
- is_ip_in_use: bool = is_ip_alive(ip_address)
362
+ is_ip_in_use, _ = is_ip_in_use_arp(ip_address)
302
363
  if not is_ip_in_use and not ip_address in skip_ips:
303
364
  # print("[+] Found IP to assign: ", ip_address)
304
365
  generated_ips.append(ip_address)
@@ -506,7 +567,7 @@ def add_virtual_ips_to_default_adapter_by_current_setting(
506
567
  dns_gateways = default_adapter_info['dns_gateways']
507
568
 
508
569
  # We will get the default IP address of the machine.
509
- default_ip_address: str = socket.gethostbyname(socket.gethostname())
570
+ default_ip_address: str = get_default_internet_ipv4()
510
571
  # So we can make it the first IP in the list, but first remove it from the list.
511
572
  _ = ips.pop(ips.index(default_ip_address))
512
573
  # At this point we will copy the list of IPs that we will set the SkipAsSource flag for.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: atomicshop
3
- Version: 3.3.5
3
+ Version: 3.3.6
4
4
  Summary: Atomic functions and classes to make developer life easier
5
5
  Author: Denis Kras
6
6
  License-Expression: MIT
@@ -1,4 +1,4 @@
1
- atomicshop/__init__.py,sha256=lCOFyywOc7EF6Esxu6aQIR9lx9HA8beRu1ut7lEQ3oU,122
1
+ atomicshop/__init__.py,sha256=PKxHKogNO1jVrjMDxPohtYhd5093pVEONPVfmujNgfw,122
2
2
  atomicshop/_basics_temp.py,sha256=6cu2dd6r2dLrd1BRNcVDKTHlsHs_26Gpw8QS6v32lQ0,3699
3
3
  atomicshop/_create_pdf_demo.py,sha256=Yi-PGZuMg0RKvQmLqVeLIZYadqEZwUm-4A9JxBl_vYA,3713
4
4
  atomicshop/_patch_import.py,sha256=ENp55sKVJ0e6-4lBvZnpz9PQCt3Otbur7F6aXDlyje4,6334
@@ -23,7 +23,7 @@ atomicshop/http_parse.py,sha256=1Tna9YbOM0rE3t6i_M-klBlwd1KNSA9skA_BqKGXDFc,1186
23
23
  atomicshop/inspect_wrapper.py,sha256=sGRVQhrJovNygHTydqJj0hxES-aB2Eg9KbIk3G31apw,11429
24
24
  atomicshop/ip_addresses.py,sha256=penRFeJ1-LDVTko4Q0EwK4JiN5cU-KzCBR2VXg9qbUY,1238
25
25
  atomicshop/keyboard_press.py,sha256=1W5kRtOB75fulVx-uF2yarBhW0_IzdI1k73AnvXstk0,452
26
- atomicshop/networks.py,sha256=dTh6T9vAnjYOEPdfpL6W6wN091HwRbVLeNscXWZX_DI,22151
26
+ atomicshop/networks.py,sha256=fwOMMHwn-XMq0WgYCFbo34NXW-Xu-4nDfWl3T5EsE9U,24807
27
27
  atomicshop/on_exit.py,sha256=9XlOnzoAG8zlI8wBF4AB8hyrC6Q1b84gkhqpAhhdN9g,6977
28
28
  atomicshop/pbtkmultifile_argparse.py,sha256=aEk8nhvoQVu-xyfZosK3ma17CwIgOjzO1erXXdjwtS4,4574
29
29
  atomicshop/print_api.py,sha256=SJNQIMqSLlYaPtjHnALySAI-jQYuYHOCGgfP7oe96fU,10957
@@ -58,7 +58,6 @@ atomicshop/a_installs/ubuntu/pycharm.py,sha256=Ld7YQBwPxrjuZcTG1K4kZqjbBdt8aooCV
58
58
  atomicshop/a_installs/win/fibratus.py,sha256=TU4e9gdZ_zI73C40uueJ59pD3qmN-UFGdX5GFoVf6cM,179
59
59
  atomicshop/a_installs/win/mongodb.py,sha256=AqyItXu19aaoe49pppDxtEkXey6PMy0PoT2Y_RmPpPE,179
60
60
  atomicshop/a_installs/win/pycharm.py,sha256=j_RSd7aDOyC3yDd-_GUTMLlQTmDrqtVFG--oUfGLiZk,140
61
- atomicshop/a_installs/win/robocorp.py,sha256=Ob8X9Czwd-OR3pudFIFft1dcUjDM0Pw0X03yfPaf3yw,3280
62
61
  atomicshop/a_installs/win/wsl_ubuntu_lts.py,sha256=dZbPRLNKFeMd6MotjkE6UDY9cOiIaaclIdR1kGYWI50,139
63
62
  atomicshop/a_mains/dns_gateway_setting.py,sha256=ncc2rFQCChxlNP59UshwmTonLqC6MWblrVAzbbz-13M,149
64
63
  atomicshop/a_mains/github_wrapper.py,sha256=F-PoZknVCxWPN0PTO6l7ZNiaYvo7OVFKFI_zlPt56ps,169
@@ -331,9 +330,9 @@ atomicshop/wrappers/socketw/statistics_csv.py,sha256=_gA8bMX6Sw_UCXKi2y9wNAwlqif
331
330
  atomicshop/wrappers/winregw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
332
331
  atomicshop/wrappers/winregw/winreg_installed_software.py,sha256=Qzmyktvob1qp6Tjk2DjLfAqr_yXV0sgWzdMW_9kwNjY,2345
333
332
  atomicshop/wrappers/winregw/winreg_network.py,sha256=ih0BVNwByLvf9F_Lac4EdmDYYJA3PzMvmG0PieDZrsE,9905
334
- atomicshop-3.3.5.dist-info/licenses/LICENSE.txt,sha256=lLU7EYycfYcK2NR_1gfnhnRC8b8ccOTElACYplgZN88,1094
335
- atomicshop-3.3.5.dist-info/METADATA,sha256=QAiSikiYm60q_UBleSyptTY9jvGM6s_7fk2yrncVrec,9311
336
- atomicshop-3.3.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
337
- atomicshop-3.3.5.dist-info/entry_points.txt,sha256=SJEgEP0KoFtfxuGwe5tOzKfXkjR9Dv6YYug33KNYxyY,69
338
- atomicshop-3.3.5.dist-info/top_level.txt,sha256=EgKJB-7xcrAPeqTRF2laD_Np2gNGYkJkd4OyXqpJphA,11
339
- atomicshop-3.3.5.dist-info/RECORD,,
333
+ atomicshop-3.3.6.dist-info/licenses/LICENSE.txt,sha256=lLU7EYycfYcK2NR_1gfnhnRC8b8ccOTElACYplgZN88,1094
334
+ atomicshop-3.3.6.dist-info/METADATA,sha256=IL5-xRKSd3KMQq1-z8F1hdeVTz9jNmhxtEdbXTAeKtM,9311
335
+ atomicshop-3.3.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
336
+ atomicshop-3.3.6.dist-info/entry_points.txt,sha256=SJEgEP0KoFtfxuGwe5tOzKfXkjR9Dv6YYug33KNYxyY,69
337
+ atomicshop-3.3.6.dist-info/top_level.txt,sha256=EgKJB-7xcrAPeqTRF2laD_Np2gNGYkJkd4OyXqpJphA,11
338
+ atomicshop-3.3.6.dist-info/RECORD,,
@@ -1,82 +0,0 @@
1
- import sys
2
- import subprocess
3
- import tempfile
4
-
5
- from atomicshop.print_api import print_api
6
- from atomicshop.wrappers import githubw
7
- from atomicshop.permissions import permissions
8
- from atomicshop.wrappers.nodejsw import install_nodejs_windows
9
-
10
-
11
- WINDOWS_TESSERACT_DEFAULT_INSTALLATION_DIRECTORY: str = r"C:\Program Files\Tesseract-OCR"
12
-
13
-
14
- def main():
15
- if not permissions.is_admin():
16
- print_api("Please run this script as an Administrator.", color="red")
17
- return 1
18
-
19
- if not install_nodejs_windows.is_nodejs_installed():
20
- install_nodejs_windows.install_nodejs_windows()
21
- install_nodejs_windows.add_nodejs_to_path()
22
- if not install_nodejs_windows.is_nodejs_installed():
23
- print_api("Node.js installation failed.", color="red")
24
- return 1
25
-
26
- print_api("PIP Installing Robocorp.", color="blue")
27
- subprocess.check_call(["pip", "install", "--upgrade", "rpaframework"])
28
-
29
- print_api("PIP Installing Robocorp-Browser.", color="blue")
30
- subprocess.check_call(["pip", "install", "--upgrade", "robotframework-browser"])
31
-
32
- print_api("PIP Installing Robocorp-Recognition.", color="blue")
33
- subprocess.check_call(["pip", "install", "--upgrade", "rpaframework-recognition"])
34
-
35
- print_api("PIP Installing pynput.", color="blue")
36
- subprocess.check_call(["pip", "install", "--upgrade", "pynput"])
37
-
38
- print_api("Installing Playwright browsers.", color="blue")
39
- subprocess.check_call(["playwright", "install"])
40
-
41
- print_api("Initializing Robocorp Browser.", color="blue")
42
- subprocess.check_call(["rfbrowser", "init"])
43
-
44
- print_api("Installing Additional modules.", color="blue")
45
- subprocess.check_call(["pip", "install", "--upgrade", "matplotlib", "imagehash"])
46
-
47
- print_api("Installing Tesseract OCR.", color="blue")
48
- github_wrapper = githubw.GitHubWrapper(
49
- user_name="tesseract-ocr",
50
- repo_name="tesseract",
51
- branch="main")
52
- github_wrapper.build_links_from_user_and_repo()
53
- temp_file_path: str = tempfile.gettempdir()
54
- tesseract_installer = github_wrapper.download_latest_release(
55
- target_directory=temp_file_path,
56
- string_pattern="*tesseract*exe")
57
-
58
- # The Admin needed to install Tesseract.
59
- subprocess.check_call([tesseract_installer, "/S"])
60
-
61
- # Add Tesseract to the PATH.
62
- subprocess.check_call(["setx", "PATH", f"%PATH%;{WINDOWS_TESSERACT_DEFAULT_INSTALLATION_DIRECTORY}"])
63
-
64
- # Patch robocorp: Remove mouse to the center of the screen on control command.
65
- # Import the library to find its path.
66
- print_api("Patching: .\RPA\Windows\keywords\window.py", color="blue")
67
- import RPA.Windows.keywords.window as window
68
- window_file_path = window.__file__
69
-
70
- # Patch the file.
71
- with open(window_file_path, "r") as file:
72
- file_content = file.read()
73
- file_content = file_content.replace(
74
- "window.item.MoveCursorToMyCenter(simulateMove=self.ctx.simulate_move)",
75
- "# window.item.MoveCursorToMyCenter(simulateMove=self.ctx.simulate_move) # Patched to remove center placement during foreground window control."
76
- )
77
- with open(window_file_path, "w") as file:
78
- file.write(file_content)
79
-
80
-
81
- if __name__ == '__main__':
82
- sys.exit(main())