sferriol-python 0.5.0__tar.gz → 0.6.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.
Files changed (20) hide show
  1. {sferriol_python-0.5.0 → sferriol_python-0.6.0}/PKG-INFO +1 -1
  2. {sferriol_python-0.5.0 → sferriol_python-0.6.0}/sferriol/python/__init__.py +3 -0
  3. sferriol_python-0.6.0/sferriol/python/_asyncio.py +13 -0
  4. {sferriol_python-0.5.0 → sferriol_python-0.6.0}/sferriol/python/env.py +2 -3
  5. sferriol_python-0.6.0/sferriol/python/net.py +128 -0
  6. {sferriol_python-0.5.0 → sferriol_python-0.6.0}/sferriol_python.egg-info/PKG-INFO +1 -1
  7. {sferriol_python-0.5.0 → sferriol_python-0.6.0}/sferriol_python.egg-info/SOURCES.txt +1 -0
  8. sferriol_python-0.5.0/sferriol/python/net.py +0 -24
  9. {sferriol_python-0.5.0 → sferriol_python-0.6.0}/LICENSE +0 -0
  10. {sferriol_python-0.5.0 → sferriol_python-0.6.0}/README.md +0 -0
  11. {sferriol_python-0.5.0 → sferriol_python-0.6.0}/pyproject.toml +0 -0
  12. {sferriol_python-0.5.0 → sferriol_python-0.6.0}/setup.cfg +0 -0
  13. {sferriol_python-0.5.0 → sferriol_python-0.6.0}/setup.py +0 -0
  14. {sferriol_python-0.5.0 → sferriol_python-0.6.0}/sferriol/python/dictionary/__init__.py +0 -0
  15. {sferriol_python-0.5.0 → sferriol_python-0.6.0}/sferriol/python/json.py +0 -0
  16. {sferriol_python-0.5.0 → sferriol_python-0.6.0}/sferriol/python/object.py +0 -0
  17. {sferriol_python-0.5.0 → sferriol_python-0.6.0}/sferriol/python/os.py +0 -0
  18. {sferriol_python-0.5.0 → sferriol_python-0.6.0}/sferriol_python.egg-info/dependency_links.txt +0 -0
  19. {sferriol_python-0.5.0 → sferriol_python-0.6.0}/sferriol_python.egg-info/requires.txt +0 -0
  20. {sferriol_python-0.5.0 → sferriol_python-0.6.0}/sferriol_python.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: sferriol-python
3
- Version: 0.5.0
3
+ Version: 0.6.0
4
4
  Summary: python utilities
5
5
  Home-page: https://gitlab.in2p3.fr/sferriol-ip2i/sferriol-python
6
6
  Author: Sylvain Ferriol
@@ -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))
@@ -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 default['env_file'] or in OS_ENV_PREFIX__ENV_FILE os env. variable
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,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: sferriol-python
3
- Version: 0.5.0
3
+ Version: 0.6.0
4
4
  Summary: python utilities
5
5
  Home-page: https://gitlab.in2p3.fr/sferriol-ip2i/sferriol-python
6
6
  Author: Sylvain Ferriol
@@ -4,6 +4,7 @@ pyproject.toml
4
4
  setup.cfg
5
5
  setup.py
6
6
  sferriol/python/__init__.py
7
+ sferriol/python/_asyncio.py
7
8
  sferriol/python/env.py
8
9
  sferriol/python/json.py
9
10
  sferriol/python/net.py
@@ -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