sferriol-python 0.4.1__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.4.1 → sferriol_python-0.6.0}/PKG-INFO +4 -1
  2. {sferriol-python-0.4.1 → sferriol_python-0.6.0}/setup.cfg +5 -0
  3. {sferriol-python-0.4.1 → sferriol_python-0.6.0}/sferriol/python/__init__.py +3 -0
  4. sferriol_python-0.6.0/sferriol/python/_asyncio.py +13 -0
  5. sferriol_python-0.6.0/sferriol/python/env.py +27 -0
  6. sferriol_python-0.6.0/sferriol/python/net.py +128 -0
  7. {sferriol-python-0.4.1 → sferriol_python-0.6.0}/sferriol_python.egg-info/PKG-INFO +4 -1
  8. {sferriol-python-0.4.1 → sferriol_python-0.6.0}/sferriol_python.egg-info/SOURCES.txt +3 -0
  9. sferriol_python-0.6.0/sferriol_python.egg-info/requires.txt +4 -0
  10. sferriol-python-0.4.1/sferriol/python/net.py +0 -24
  11. {sferriol-python-0.4.1 → sferriol_python-0.6.0}/LICENSE +0 -0
  12. {sferriol-python-0.4.1 → sferriol_python-0.6.0}/README.md +0 -0
  13. {sferriol-python-0.4.1 → sferriol_python-0.6.0}/pyproject.toml +0 -0
  14. {sferriol-python-0.4.1 → sferriol_python-0.6.0}/setup.py +0 -0
  15. {sferriol-python-0.4.1 → sferriol_python-0.6.0}/sferriol/python/dictionary/__init__.py +0 -0
  16. {sferriol-python-0.4.1 → sferriol_python-0.6.0}/sferriol/python/json.py +0 -0
  17. {sferriol-python-0.4.1 → sferriol_python-0.6.0}/sferriol/python/object.py +0 -0
  18. {sferriol-python-0.4.1 → sferriol_python-0.6.0}/sferriol/python/os.py +0 -0
  19. {sferriol-python-0.4.1 → sferriol_python-0.6.0}/sferriol_python.egg-info/dependency_links.txt +0 -0
  20. {sferriol-python-0.4.1 → 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.4.1
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
@@ -10,6 +10,9 @@ Classifier: Operating System :: OS Independent
10
10
  Classifier: Programming Language :: Python :: 3
11
11
  Description-Content-Type: text/markdown
12
12
  License-File: LICENSE
13
+ Provides-Extra: dev
14
+ Requires-Dist: click; extra == "dev"
15
+ Requires-Dist: yapf; extra == "dev"
13
16
 
14
17
  # sferriol-python
15
18
 
@@ -18,6 +18,11 @@ packages = find_namespace:
18
18
  exclude = *.test
19
19
  include = sferriol.*
20
20
 
21
+ [options.extras_require]
22
+ dev =
23
+ click
24
+ yapf
25
+
21
26
  [egg_info]
22
27
  tag_build =
23
28
  tag_date = 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))
@@ -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()
@@ -0,0 +1,27 @@
1
+ import os
2
+ import tomllib
3
+
4
+
5
+ def load(default=None, env_file=None, os_env_prefix=None):
6
+ """
7
+ Return env dictionary loaded from, in order:
8
+ 1. a default dictionary
9
+ 2. a toml file where path is, in order, in env_file or in OS_ENV_PREFIX__ENV_FILE os env. variable
10
+ 3. os env. variables OS_ENV_PREFIX__K where K is each key in previous dictionary in uppercase
11
+ """
12
+ di = default.copy() if default else dict()
13
+ os_env_prefix = os_env_prefix.upper() + '__' if os_env_prefix else None
14
+
15
+ # from the env file
16
+ if os_env_prefix:
17
+ env_file = os.getenv(os_env_prefix + 'ENV_FILE', env_file)
18
+ if env_file is not None:
19
+ with open(env_file, "rb") as f:
20
+ di.update(tomllib.load(f))
21
+
22
+ # from os env variables
23
+ if os_env_prefix:
24
+ for k in di.keys():
25
+ di[k] = os.getenv(os_env_prefix + str(k).upper(), di[k])
26
+
27
+ return di
@@ -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.4.1
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
@@ -10,6 +10,9 @@ Classifier: Operating System :: OS Independent
10
10
  Classifier: Programming Language :: Python :: 3
11
11
  Description-Content-Type: text/markdown
12
12
  License-File: LICENSE
13
+ Provides-Extra: dev
14
+ Requires-Dist: click; extra == "dev"
15
+ Requires-Dist: yapf; extra == "dev"
13
16
 
14
17
  # sferriol-python
15
18
 
@@ -4,6 +4,8 @@ pyproject.toml
4
4
  setup.cfg
5
5
  setup.py
6
6
  sferriol/python/__init__.py
7
+ sferriol/python/_asyncio.py
8
+ sferriol/python/env.py
7
9
  sferriol/python/json.py
8
10
  sferriol/python/net.py
9
11
  sferriol/python/object.py
@@ -12,4 +14,5 @@ sferriol/python/dictionary/__init__.py
12
14
  sferriol_python.egg-info/PKG-INFO
13
15
  sferriol_python.egg-info/SOURCES.txt
14
16
  sferriol_python.egg-info/dependency_links.txt
17
+ sferriol_python.egg-info/requires.txt
15
18
  sferriol_python.egg-info/top_level.txt
@@ -0,0 +1,4 @@
1
+
2
+ [dev]
3
+ click
4
+ yapf
@@ -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