sferriol-python 0.4.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.4.1/LICENSE +24 -0
- sferriol-python-0.4.1/PKG-INFO +26 -0
- sferriol-python-0.4.1/README.md +13 -0
- sferriol-python-0.4.1/pyproject.toml +10 -0
- sferriol-python-0.4.1/setup.cfg +24 -0
- sferriol-python-0.4.1/setup.py +13 -0
- sferriol-python-0.4.1/sferriol/python/__init__.py +57 -0
- sferriol-python-0.4.1/sferriol/python/dictionary/__init__.py +82 -0
- sferriol-python-0.4.1/sferriol/python/json.py +16 -0
- sferriol-python-0.4.1/sferriol/python/net.py +24 -0
- sferriol-python-0.4.1/sferriol/python/object.py +55 -0
- sferriol-python-0.4.1/sferriol/python/os.py +11 -0
- sferriol-python-0.4.1/sferriol_python.egg-info/PKG-INFO +26 -0
- sferriol-python-0.4.1/sferriol_python.egg-info/SOURCES.txt +15 -0
- sferriol-python-0.4.1/sferriol_python.egg-info/dependency_links.txt +1 -0
- sferriol-python-0.4.1/sferriol_python.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
This is free and unencumbered software released into the public domain.
|
|
2
|
+
|
|
3
|
+
Anyone is free to copy, modify, publish, use, compile, sell, or
|
|
4
|
+
distribute this software, either in source code form or as a compiled
|
|
5
|
+
binary, for any purpose, commercial or non-commercial, and by any
|
|
6
|
+
means.
|
|
7
|
+
|
|
8
|
+
In jurisdictions that recognize copyright laws, the author or authors
|
|
9
|
+
of this software dedicate any and all copyright interest in the
|
|
10
|
+
software to the public domain. We make this dedication for the benefit
|
|
11
|
+
of the public at large and to the detriment of our heirs and
|
|
12
|
+
successors. We intend this dedication to be an overt act of
|
|
13
|
+
relinquishment in perpetuity of all present and future rights to this
|
|
14
|
+
software under copyright law.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
19
|
+
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
20
|
+
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
21
|
+
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
22
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
|
23
|
+
|
|
24
|
+
For more information, please refer to <https://unlicense.org>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: sferriol-python
|
|
3
|
+
Version: 0.4.1
|
|
4
|
+
Summary: python utilities
|
|
5
|
+
Home-page: https://gitlab.in2p3.fr/sferriol-ip2i/sferriol-python
|
|
6
|
+
Author: Sylvain Ferriol
|
|
7
|
+
Author-email: s.ferriol@ipnl.in2p3.fr
|
|
8
|
+
Classifier: License :: OSI Approved :: The Unlicense (Unlicense)
|
|
9
|
+
Classifier: Operating System :: OS Independent
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
|
|
14
|
+
# sferriol-python
|
|
15
|
+
|
|
16
|
+
sferriol-python is a set of useful python libraries.
|
|
17
|
+
|
|
18
|
+
Clone the project
|
|
19
|
+
|
|
20
|
+
git clone git@gitlab.in2p3.fr:sferriol-ip2i/sferriol-python.git
|
|
21
|
+
|
|
22
|
+
Install it in your environment
|
|
23
|
+
|
|
24
|
+
python -m pip install .
|
|
25
|
+
|
|
26
|
+
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = [ "setuptools>=41", "wheel", "setuptools-git-versioning>=2.0,<3", ]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[tool.setuptools-git-versioning]
|
|
6
|
+
enabled = true
|
|
7
|
+
version_file = "VERSION"
|
|
8
|
+
count_commits_from_version_file = true
|
|
9
|
+
dev_template = "{tag}+{branch}{ccount}.git.{sha}"
|
|
10
|
+
dirty_template = "{tag}+{branch}{ccount}.git.{sha}.dirty"
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
[metadata]
|
|
2
|
+
author = Sylvain Ferriol
|
|
3
|
+
author_email = s.ferriol@ipnl.in2p3.fr
|
|
4
|
+
classifiers =
|
|
5
|
+
License :: OSI Approved :: The Unlicense (Unlicense)
|
|
6
|
+
Operating System :: OS Independent
|
|
7
|
+
Programming Language :: Python :: 3
|
|
8
|
+
description = python utilities
|
|
9
|
+
long_description = file: README.md
|
|
10
|
+
long_description_content_type = text/markdown
|
|
11
|
+
name = sferriol-python
|
|
12
|
+
url = https://gitlab.in2p3.fr/sferriol-ip2i/sferriol-python
|
|
13
|
+
|
|
14
|
+
[options]
|
|
15
|
+
packages = find_namespace:
|
|
16
|
+
|
|
17
|
+
[options.packages.find]
|
|
18
|
+
exclude = *.test
|
|
19
|
+
include = sferriol.*
|
|
20
|
+
|
|
21
|
+
[egg_info]
|
|
22
|
+
tag_build =
|
|
23
|
+
tag_date = 0
|
|
24
|
+
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import importlib.util
|
|
2
|
+
import pathlib
|
|
3
|
+
import time
|
|
4
|
+
import types
|
|
5
|
+
from typing import Any, Callable
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def load_module_from_file(fpath):
|
|
9
|
+
"""
|
|
10
|
+
Load a module from a python file.
|
|
11
|
+
The module name is the file name without file extension.
|
|
12
|
+
"""
|
|
13
|
+
name = module_name_from_file(fpath)
|
|
14
|
+
spec = importlib.util.spec_from_file_location(name, fpath)
|
|
15
|
+
module = importlib.util.module_from_spec(spec)
|
|
16
|
+
spec.loader.exec_module(module)
|
|
17
|
+
return module
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def loop_until(fct: Callable, ret: Any, every: float, timeout: float | int):
|
|
21
|
+
"""Loops the execution of the function until it returns ret parameter
|
|
22
|
+
|
|
23
|
+
It raises TimeoutError if the expected value is not returned by the function
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
fct: Function to be called
|
|
27
|
+
ret: The expected return value
|
|
28
|
+
every: Number of seconds to wait at the end of each loop
|
|
29
|
+
timeout: Timeout duration
|
|
30
|
+
"""
|
|
31
|
+
start_time = time.perf_counter()
|
|
32
|
+
while True:
|
|
33
|
+
if fct() == ret:
|
|
34
|
+
return
|
|
35
|
+
time.sleep(every)
|
|
36
|
+
if time.perf_counter() - start_time >= timeout:
|
|
37
|
+
raise TimeoutError()
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def method(obj):
|
|
41
|
+
"""
|
|
42
|
+
Decorator used to define a function as a new method of the object obj.
|
|
43
|
+
The method name is the function name.
|
|
44
|
+
"""
|
|
45
|
+
def _(func):
|
|
46
|
+
name = func.__name__
|
|
47
|
+
setattr(obj, name, types.MethodType(func, obj))
|
|
48
|
+
return getattr(obj, name)
|
|
49
|
+
|
|
50
|
+
return _
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def module_name_from_file(fpath):
|
|
54
|
+
"""
|
|
55
|
+
Return The module name of the associated python file.
|
|
56
|
+
"""
|
|
57
|
+
return pathlib.Path(fpath).stem
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
#
|
|
4
|
+
# Copyright 2020 sferriol <sferriol@ipnl.in2p3.fr>
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class adict(dict):
|
|
8
|
+
"""Attribute dictionary
|
|
9
|
+
"""
|
|
10
|
+
def __delattr__(self, name):
|
|
11
|
+
self.__delitem__(name)
|
|
12
|
+
|
|
13
|
+
def __getattr__(self, name):
|
|
14
|
+
try:
|
|
15
|
+
ret = getattr(adict, name)
|
|
16
|
+
except AttributeError as e:
|
|
17
|
+
try:
|
|
18
|
+
ret = self.__getitem__(name)
|
|
19
|
+
except KeyError:
|
|
20
|
+
# if nothing is found, raise AttributeError instead of KeyError
|
|
21
|
+
raise e
|
|
22
|
+
return ret
|
|
23
|
+
|
|
24
|
+
def __setattr__(self, name, value):
|
|
25
|
+
self.__setitem__(name, value)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def as_adict(elt):
|
|
29
|
+
return dict_to_adict(elt)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class cdict(adict):
|
|
33
|
+
"""Config dictionary.
|
|
34
|
+
c = cdict()
|
|
35
|
+
c['a.b'] = 2 # is equivalent to c['a'] = {'b':2}
|
|
36
|
+
assert c['a.b'] == c['a']['b']
|
|
37
|
+
assert c['a.b'] == c.a.b
|
|
38
|
+
"""
|
|
39
|
+
def __getitem__(self, key):
|
|
40
|
+
di = self
|
|
41
|
+
l = key.split('.')
|
|
42
|
+
for k in l[:-1]:
|
|
43
|
+
di = di[k]
|
|
44
|
+
return adict.__getitem__(di, l[-1])
|
|
45
|
+
|
|
46
|
+
def __setitem__(self, key, value):
|
|
47
|
+
di = self
|
|
48
|
+
l = key.split('.')
|
|
49
|
+
for k in l[:-1]:
|
|
50
|
+
di.setdefault(k, adict())
|
|
51
|
+
di = di[k]
|
|
52
|
+
adict.__setitem__(di, l[-1], value)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def dict_merge(di_1, di_2):
|
|
56
|
+
def _dict(di_1, di_2):
|
|
57
|
+
for key, value in di_2.items():
|
|
58
|
+
if isinstance(value, dict):
|
|
59
|
+
if key not in di_1:
|
|
60
|
+
di_1[key] = {}
|
|
61
|
+
_dict(di_1[key], di_2[key])
|
|
62
|
+
else:
|
|
63
|
+
di_1[key] = value
|
|
64
|
+
|
|
65
|
+
_dict(di_1, di_2)
|
|
66
|
+
return di_1
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def dict_to_adict(di):
|
|
70
|
+
# build an adict from a dictionary
|
|
71
|
+
# and all sub dictionary will be trannform in Attribute_Dict too
|
|
72
|
+
def _di2adi(elt):
|
|
73
|
+
if isinstance(elt, list):
|
|
74
|
+
return [_di2adi(e) for e in elt]
|
|
75
|
+
if isinstance(elt, dict):
|
|
76
|
+
adi = adict()
|
|
77
|
+
for k, v in elt.items():
|
|
78
|
+
adi[k] = _di2adi(v)
|
|
79
|
+
return adi
|
|
80
|
+
return elt
|
|
81
|
+
|
|
82
|
+
return _di2adi(di)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# Copyright 2023 sferriol <s.ferriol@ip2i.in2p3.fr>
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import tempfile
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def dump_temporary(obj, prefix=None, dir=None):
|
|
10
|
+
"""
|
|
11
|
+
Serialize obj as a JSON formatted stream to a temporary file and returns its file path. The file is created securely, using the same rules as mkstemp(). The user is responsible for deleting the temporary file when done with it.
|
|
12
|
+
"""
|
|
13
|
+
_, fpath = tempfile.mkstemp(prefix=prefix, suffix='.json', dir=dir)
|
|
14
|
+
with open(fpath, 'w') as f:
|
|
15
|
+
json.dump(obj, f)
|
|
16
|
+
return fpath
|
|
@@ -0,0 +1,24 @@
|
|
|
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
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
import types
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class Attribute:
|
|
6
|
+
def __init__(self, ns):
|
|
7
|
+
self.__sf__ns__ = ns
|
|
8
|
+
|
|
9
|
+
def __call__(self, fct):
|
|
10
|
+
setattr(self, fct.__name__, fct)
|
|
11
|
+
|
|
12
|
+
def __setattr__(self, name, value):
|
|
13
|
+
if hasattr(self, '__sf__ns__'):
|
|
14
|
+
ns = self.__sf__ns__
|
|
15
|
+
ns.__sf__obj_attributes__[name] = value
|
|
16
|
+
setattr(ns, name, value)
|
|
17
|
+
else:
|
|
18
|
+
object.__setattr__(self, name, value)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def attribute(ns):
|
|
22
|
+
return Attribute(ns)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class Object:
|
|
26
|
+
def __init__(self):
|
|
27
|
+
self.__sf__namespaces = dict()
|
|
28
|
+
|
|
29
|
+
def __set_ns__(self, ns):
|
|
30
|
+
for name, value in ns.__sf__obj_attributes__.items():
|
|
31
|
+
if callable(value):
|
|
32
|
+
value = types.MethodType(value, self)
|
|
33
|
+
setattr(self, name, value)
|
|
34
|
+
self.__sf__namespaces[ns.__sf__name__] = ns
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class Namespace:
|
|
38
|
+
def __init__(self, name):
|
|
39
|
+
self.__sf__name__ = name
|
|
40
|
+
self.__sf__obj_attributes__ = dict()
|
|
41
|
+
|
|
42
|
+
def __call__(self, obj=None):
|
|
43
|
+
if obj is None:
|
|
44
|
+
obj = Object()
|
|
45
|
+
obj.__set_ns__(self)
|
|
46
|
+
return obj
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def namespace():
|
|
50
|
+
def wrapper(fct):
|
|
51
|
+
ns = Namespace(fct.__name__)
|
|
52
|
+
fct(ns)
|
|
53
|
+
return ns
|
|
54
|
+
|
|
55
|
+
return wrapper
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: sferriol-python
|
|
3
|
+
Version: 0.4.1
|
|
4
|
+
Summary: python utilities
|
|
5
|
+
Home-page: https://gitlab.in2p3.fr/sferriol-ip2i/sferriol-python
|
|
6
|
+
Author: Sylvain Ferriol
|
|
7
|
+
Author-email: s.ferriol@ipnl.in2p3.fr
|
|
8
|
+
Classifier: License :: OSI Approved :: The Unlicense (Unlicense)
|
|
9
|
+
Classifier: Operating System :: OS Independent
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
|
|
14
|
+
# sferriol-python
|
|
15
|
+
|
|
16
|
+
sferriol-python is a set of useful python libraries.
|
|
17
|
+
|
|
18
|
+
Clone the project
|
|
19
|
+
|
|
20
|
+
git clone git@gitlab.in2p3.fr:sferriol-ip2i/sferriol-python.git
|
|
21
|
+
|
|
22
|
+
Install it in your environment
|
|
23
|
+
|
|
24
|
+
python -m pip install .
|
|
25
|
+
|
|
26
|
+
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
setup.cfg
|
|
5
|
+
setup.py
|
|
6
|
+
sferriol/python/__init__.py
|
|
7
|
+
sferriol/python/json.py
|
|
8
|
+
sferriol/python/net.py
|
|
9
|
+
sferriol/python/object.py
|
|
10
|
+
sferriol/python/os.py
|
|
11
|
+
sferriol/python/dictionary/__init__.py
|
|
12
|
+
sferriol_python.egg-info/PKG-INFO
|
|
13
|
+
sferriol_python.egg-info/SOURCES.txt
|
|
14
|
+
sferriol_python.egg-info/dependency_links.txt
|
|
15
|
+
sferriol_python.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
sferriol
|