sferriol-python 0.5.0__tar.gz → 0.7.1__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.
- {sferriol_python-0.5.0 → sferriol_python-0.7.1}/PKG-INFO +1 -1
- {sferriol_python-0.5.0 → sferriol_python-0.7.1}/sferriol/python/__init__.py +12 -0
- sferriol_python-0.7.1/sferriol/python/_asyncio.py +13 -0
- {sferriol_python-0.5.0 → sferriol_python-0.7.1}/sferriol/python/env.py +2 -3
- sferriol_python-0.7.1/sferriol/python/net.py +128 -0
- {sferriol_python-0.5.0 → sferriol_python-0.7.1}/sferriol_python.egg-info/PKG-INFO +1 -1
- {sferriol_python-0.5.0 → sferriol_python-0.7.1}/sferriol_python.egg-info/SOURCES.txt +1 -0
- sferriol_python-0.5.0/sferriol/python/net.py +0 -24
- {sferriol_python-0.5.0 → sferriol_python-0.7.1}/LICENSE +0 -0
- {sferriol_python-0.5.0 → sferriol_python-0.7.1}/README.md +0 -0
- {sferriol_python-0.5.0 → sferriol_python-0.7.1}/pyproject.toml +0 -0
- {sferriol_python-0.5.0 → sferriol_python-0.7.1}/setup.cfg +0 -0
- {sferriol_python-0.5.0 → sferriol_python-0.7.1}/setup.py +0 -0
- {sferriol_python-0.5.0 → sferriol_python-0.7.1}/sferriol/python/dictionary/__init__.py +0 -0
- {sferriol_python-0.5.0 → sferriol_python-0.7.1}/sferriol/python/json.py +0 -0
- {sferriol_python-0.5.0 → sferriol_python-0.7.1}/sferriol/python/object.py +0 -0
- {sferriol_python-0.5.0 → sferriol_python-0.7.1}/sferriol/python/os.py +0 -0
- {sferriol_python-0.5.0 → sferriol_python-0.7.1}/sferriol_python.egg-info/dependency_links.txt +0 -0
- {sferriol_python-0.5.0 → sferriol_python-0.7.1}/sferriol_python.egg-info/requires.txt +0 -0
- {sferriol_python-0.5.0 → sferriol_python-0.7.1}/sferriol_python.egg-info/top_level.txt +0 -0
|
@@ -4,6 +4,8 @@ import time
|
|
|
4
4
|
import types
|
|
5
5
|
from typing import Any, Callable
|
|
6
6
|
|
|
7
|
+
import _asyncio as asyncio
|
|
8
|
+
|
|
7
9
|
|
|
8
10
|
def load_module_from_file(fpath):
|
|
9
11
|
"""
|
|
@@ -42,6 +44,7 @@ def method(obj):
|
|
|
42
44
|
Decorator used to define a function as a new method of the object obj.
|
|
43
45
|
The method name is the function name.
|
|
44
46
|
"""
|
|
47
|
+
|
|
45
48
|
def _(func):
|
|
46
49
|
name = func.__name__
|
|
47
50
|
setattr(obj, name, types.MethodType(func, obj))
|
|
@@ -55,3 +58,12 @@ def module_name_from_file(fpath):
|
|
|
55
58
|
Return The module name of the associated python file.
|
|
56
59
|
"""
|
|
57
60
|
return pathlib.Path(fpath).stem
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def update_methods(obj, functions):
|
|
64
|
+
"""
|
|
65
|
+
Update object methods by bounding new functions to instance obj
|
|
66
|
+
"""
|
|
67
|
+
for func in functions:
|
|
68
|
+
name = func.__name__
|
|
69
|
+
setattr(obj, name, types.MethodType(func, obj))
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
async def run_shell_cmd(cmd: str) -> (int, str, str):
|
|
5
|
+
"""Execute shell command
|
|
6
|
+
|
|
7
|
+
Returns:
|
|
8
|
+
Tuple (returned code, stdout, stderr)
|
|
9
|
+
"""
|
|
10
|
+
proc = await asyncio.create_subprocess_shell(
|
|
11
|
+
cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE)
|
|
12
|
+
stdout, stderr = await proc.communicate()
|
|
13
|
+
return proc.returncode, stdout.decode().strip(), stderr.decode().strip()
|
|
@@ -2,18 +2,17 @@ import os
|
|
|
2
2
|
import tomllib
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
def load(default=None, os_env_prefix=None):
|
|
5
|
+
def load(default=None, env_file=None, os_env_prefix=None):
|
|
6
6
|
"""
|
|
7
7
|
Return env dictionary loaded from, in order:
|
|
8
8
|
1. a default dictionary
|
|
9
|
-
2. a toml file where path is, in order, in
|
|
9
|
+
2. a toml file where path is, in order, in env_file or in OS_ENV_PREFIX__ENV_FILE os env. variable
|
|
10
10
|
3. os env. variables OS_ENV_PREFIX__K where K is each key in previous dictionary in uppercase
|
|
11
11
|
"""
|
|
12
12
|
di = default.copy() if default else dict()
|
|
13
13
|
os_env_prefix = os_env_prefix.upper() + '__' if os_env_prefix else None
|
|
14
14
|
|
|
15
15
|
# from the env file
|
|
16
|
-
env_file = di.get('env_file', None)
|
|
17
16
|
if os_env_prefix:
|
|
18
17
|
env_file = os.getenv(os_env_prefix + 'ENV_FILE', env_file)
|
|
19
18
|
if env_file is not None:
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# Copyright 2023 sferriol <s.ferriol@ip2i.in2p3.fr>
|
|
4
|
+
"""Network utilities"""
|
|
5
|
+
import fcntl
|
|
6
|
+
import socket
|
|
7
|
+
import struct
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def are_in_same_network(ip_addr1: str, ip_addr2: str,
|
|
11
|
+
netmask_addr: str) -> bool:
|
|
12
|
+
"""Returns True if two addresses are in the same network specified by its netmask
|
|
13
|
+
|
|
14
|
+
Examples:
|
|
15
|
+
>>> are_in_same_network('1.2.3.4', '1.2.3.5', '255.255.255.0')
|
|
16
|
+
True
|
|
17
|
+
"""
|
|
18
|
+
a1 = socket.inet_aton(ip_addr1)
|
|
19
|
+
a2 = socket.inet_aton(ip_addr2)
|
|
20
|
+
n = socket.inet_aton(netmask_addr)
|
|
21
|
+
return all([a1[i] & n[i] == a2[i] & n[i] for i in range(4)])
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def get_interface_ip_address(if_str: str) -> str:
|
|
25
|
+
"""Returns the ip address of the interface
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
if_str name of the interface or ip address of its network
|
|
29
|
+
|
|
30
|
+
Examples:
|
|
31
|
+
>>> get_interface_ip_address('lo')
|
|
32
|
+
'127.0.0.1'
|
|
33
|
+
"""
|
|
34
|
+
if_name = get_interface_name(if_str) if is_ipv4_address(if_str) else if_str
|
|
35
|
+
if if_name in list_interfaces():
|
|
36
|
+
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
|
37
|
+
return socket.inet_ntoa(
|
|
38
|
+
fcntl.ioctl(s.fileno(), 0x8915,
|
|
39
|
+
struct.pack('256s', bytes(if_name[:15],
|
|
40
|
+
'utf-8')))[20:24])
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def get_interface_name(ip_addr: str) -> str:
|
|
44
|
+
"""Returns the interface name
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
ip_addr ip address of interface network
|
|
48
|
+
|
|
49
|
+
Examples:
|
|
50
|
+
>>> get_interface_name('127.0.0.1')
|
|
51
|
+
'lo'
|
|
52
|
+
"""
|
|
53
|
+
interfaces = list_interfaces()
|
|
54
|
+
ret = None
|
|
55
|
+
for if_name in interfaces:
|
|
56
|
+
try:
|
|
57
|
+
if_addr = get_interface_ip_address(if_name)
|
|
58
|
+
netmask_addr = get_netmask_address(if_name)
|
|
59
|
+
except OSError:
|
|
60
|
+
continue
|
|
61
|
+
else:
|
|
62
|
+
if are_in_same_network(ip_addr, if_addr, netmask_addr):
|
|
63
|
+
ret = if_name
|
|
64
|
+
break
|
|
65
|
+
return ret
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def get_netmask_address(if_name: str) -> str:
|
|
69
|
+
"""Returns the netmask of an interface
|
|
70
|
+
|
|
71
|
+
Examples:
|
|
72
|
+
>>> get_netmask_address('lo')
|
|
73
|
+
'255.0.0.0'
|
|
74
|
+
"""
|
|
75
|
+
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
|
76
|
+
return socket.inet_ntoa(
|
|
77
|
+
fcntl.ioctl(s.fileno(), 0x891b,
|
|
78
|
+
struct.pack('256s', bytes(if_name[:15], 'utf-8')))[20:24])
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def is_interface_connected(if_name: str) -> bool:
|
|
82
|
+
"""Returns if interface has a carrier up status
|
|
83
|
+
|
|
84
|
+
Examples:
|
|
85
|
+
>>> is_interface_connected('lo')
|
|
86
|
+
True
|
|
87
|
+
"""
|
|
88
|
+
file = f'/sys/class/net/{if_name}/carrier'
|
|
89
|
+
with open(file) as f:
|
|
90
|
+
return int(f.read().strip()) == 1
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def is_ipv4_address(ip_addr: str) -> bool:
|
|
94
|
+
"""Returns if the addr has en IPV4 format
|
|
95
|
+
|
|
96
|
+
Examples:
|
|
97
|
+
>>> is_ipv4_address('1.2.3.4')
|
|
98
|
+
True
|
|
99
|
+
>>> is_ipv4_address('toto')
|
|
100
|
+
False
|
|
101
|
+
|
|
102
|
+
"""
|
|
103
|
+
nbrs = ip_addr.strip().split('.')
|
|
104
|
+
return len(nbrs) == 4 and all([n.isdigit() for n in nbrs])
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def is_port_in_use(port: int) -> bool:
|
|
108
|
+
"""Test if the port is already used"""
|
|
109
|
+
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
|
110
|
+
return s.connect_ex(('localhost', port)) == 0
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def list_interfaces() -> tuple[str, ...]:
|
|
114
|
+
"""Returns all network interfaces available"""
|
|
115
|
+
return (k[1] for k in socket.if_nameindex())
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def unused_port() -> int:
|
|
119
|
+
"""Return an unsued port
|
|
120
|
+
|
|
121
|
+
Returns:
|
|
122
|
+
Port value
|
|
123
|
+
"""
|
|
124
|
+
sock = socket.socket()
|
|
125
|
+
sock.bind(('127.0.0.1', 0))
|
|
126
|
+
_, port = sock.getsockname()
|
|
127
|
+
sock.close()
|
|
128
|
+
return port
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
#
|
|
3
|
-
# Copyright 2023 sferriol <s.ferriol@ip2i.in2p3.fr>
|
|
4
|
-
"""Network utilities"""
|
|
5
|
-
import socket
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
def is_port_in_use(port: int) -> bool:
|
|
9
|
-
"""Test if the port is already used"""
|
|
10
|
-
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
|
11
|
-
return s.connect_ex(('localhost', port)) == 0
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
def unused_port() -> int:
|
|
15
|
-
"""Return an unsued port
|
|
16
|
-
|
|
17
|
-
Returns:
|
|
18
|
-
Port value
|
|
19
|
-
"""
|
|
20
|
-
sock = socket.socket()
|
|
21
|
-
sock.bind(('127.0.0.1', 0))
|
|
22
|
-
_, port = sock.getsockname()
|
|
23
|
-
sock.close()
|
|
24
|
-
return port
|
|
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
|
{sferriol_python-0.5.0 → sferriol_python-0.7.1}/sferriol_python.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|