hexif-pyutils 1.0.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.
- hexif_pyutils-1.0.0/PKG-INFO +112 -0
- hexif_pyutils-1.0.0/README.md +99 -0
- hexif_pyutils-1.0.0/hexif_pyutils.egg-info/PKG-INFO +112 -0
- hexif_pyutils-1.0.0/hexif_pyutils.egg-info/SOURCES.txt +13 -0
- hexif_pyutils-1.0.0/hexif_pyutils.egg-info/dependency_links.txt +1 -0
- hexif_pyutils-1.0.0/hexif_pyutils.egg-info/top_level.txt +1 -0
- hexif_pyutils-1.0.0/pyproject.toml +29 -0
- hexif_pyutils-1.0.0/setup.cfg +4 -0
- hexif_pyutils-1.0.0/utils/__init__.py +3 -0
- hexif_pyutils-1.0.0/utils/file/__init__.py +77 -0
- hexif_pyutils-1.0.0/utils/file/json.py +57 -0
- hexif_pyutils-1.0.0/utils/logger.py +78 -0
- hexif_pyutils-1.0.0/utils/system/__init__.py +2 -0
- hexif_pyutils-1.0.0/utils/system/security.py +31 -0
- hexif_pyutils-1.0.0/utils/system/shell.py +20 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: hexif-pyutils
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Super simple python utility library
|
|
5
|
+
Author: HeXif
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/xHeXifx/hexif-pyutils
|
|
8
|
+
Project-URL: Repository, https://github.com/xHeXifx/hexif-pyutils
|
|
9
|
+
Project-URL: Issues, https://github.com/xHeXifx/hexif-pyutils/issues
|
|
10
|
+
Keywords: utilties,utils,python,helpers
|
|
11
|
+
Requires-Python: >=3.9
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
|
|
14
|
+
# hexif-pyutils
|
|
15
|
+
|
|
16
|
+
Super simple Python utilities.
|
|
17
|
+
|
|
18
|
+
This was mainly put on PyPi so i can install it without cloning it off gitea and then pip installing it off the local path.
|
|
19
|
+
|
|
20
|
+
## Install
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
pip install hexif-pyutils
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Install (TouchID Helper MacOS)
|
|
27
|
+
|
|
28
|
+
(If not cloned clone)
|
|
29
|
+
```zsh
|
|
30
|
+
git clone https://github.com/xHeXifx/hexif-pyutils
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
```zsh
|
|
34
|
+
cd {repo}/macOS/touchid-executable/touchid-helper
|
|
35
|
+
swift build -c release
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Find the executable, will be somewhere in ./build and named 'touchid'
|
|
39
|
+
```zsh
|
|
40
|
+
cp {executable location} /usr/local/bin/touchid
|
|
41
|
+
sudo chmod +x /usr/local/bin/touchid
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Optional test
|
|
45
|
+
```zsh
|
|
46
|
+
/usr/local/bin/touchid "perform a test"
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Usage
|
|
50
|
+
|
|
51
|
+
### Logger
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
from utils.logger import Logger
|
|
55
|
+
|
|
56
|
+
log = Logger("app", log_file="app.log")
|
|
57
|
+
log.info("Hello")
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
What it does: simple logging wrapper with console and file output.
|
|
61
|
+
|
|
62
|
+
### File helpers
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
from utils.file import read, write, get, touch
|
|
66
|
+
|
|
67
|
+
write("hello", "test.txt")
|
|
68
|
+
print(read("test.txt"))
|
|
69
|
+
print(get("test.txt").name)
|
|
70
|
+
touch("new.txt")
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
What it does: basic file reading/writing, file metadata lookup, and creating empty files.
|
|
74
|
+
|
|
75
|
+
### JSON
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
from utils.file.json import read, write
|
|
79
|
+
|
|
80
|
+
write({"name": "hexif"}, "data.json")
|
|
81
|
+
data = read("data.json")
|
|
82
|
+
print(data)
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
What it does: reads and writes JSON files quickly.
|
|
86
|
+
|
|
87
|
+
### Shell
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
from utils.system.shell import run
|
|
91
|
+
|
|
92
|
+
result = run("echo hello", capture_output=True, text=True)
|
|
93
|
+
print(result.stdout)
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
What it does: runs shell commands using Python subprocess.
|
|
97
|
+
|
|
98
|
+
### Touch ID
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
from utils.system.security import askForTouchID
|
|
102
|
+
|
|
103
|
+
allowed = askForTouchID("confirm action")
|
|
104
|
+
print(allowed)
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
What it does: checks for the macOS Touch ID helper and asks for confirmation.
|
|
108
|
+
|
|
109
|
+
## Credits
|
|
110
|
+
|
|
111
|
+
- https://hexif.vercel.app
|
|
112
|
+
- https://github.com/xHeXifx
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# hexif-pyutils
|
|
2
|
+
|
|
3
|
+
Super simple Python utilities.
|
|
4
|
+
|
|
5
|
+
This was mainly put on PyPi so i can install it without cloning it off gitea and then pip installing it off the local path.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install hexif-pyutils
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Install (TouchID Helper MacOS)
|
|
14
|
+
|
|
15
|
+
(If not cloned clone)
|
|
16
|
+
```zsh
|
|
17
|
+
git clone https://github.com/xHeXifx/hexif-pyutils
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
```zsh
|
|
21
|
+
cd {repo}/macOS/touchid-executable/touchid-helper
|
|
22
|
+
swift build -c release
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Find the executable, will be somewhere in ./build and named 'touchid'
|
|
26
|
+
```zsh
|
|
27
|
+
cp {executable location} /usr/local/bin/touchid
|
|
28
|
+
sudo chmod +x /usr/local/bin/touchid
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Optional test
|
|
32
|
+
```zsh
|
|
33
|
+
/usr/local/bin/touchid "perform a test"
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Usage
|
|
37
|
+
|
|
38
|
+
### Logger
|
|
39
|
+
|
|
40
|
+
```python
|
|
41
|
+
from utils.logger import Logger
|
|
42
|
+
|
|
43
|
+
log = Logger("app", log_file="app.log")
|
|
44
|
+
log.info("Hello")
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
What it does: simple logging wrapper with console and file output.
|
|
48
|
+
|
|
49
|
+
### File helpers
|
|
50
|
+
|
|
51
|
+
```python
|
|
52
|
+
from utils.file import read, write, get, touch
|
|
53
|
+
|
|
54
|
+
write("hello", "test.txt")
|
|
55
|
+
print(read("test.txt"))
|
|
56
|
+
print(get("test.txt").name)
|
|
57
|
+
touch("new.txt")
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
What it does: basic file reading/writing, file metadata lookup, and creating empty files.
|
|
61
|
+
|
|
62
|
+
### JSON
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
from utils.file.json import read, write
|
|
66
|
+
|
|
67
|
+
write({"name": "hexif"}, "data.json")
|
|
68
|
+
data = read("data.json")
|
|
69
|
+
print(data)
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
What it does: reads and writes JSON files quickly.
|
|
73
|
+
|
|
74
|
+
### Shell
|
|
75
|
+
|
|
76
|
+
```python
|
|
77
|
+
from utils.system.shell import run
|
|
78
|
+
|
|
79
|
+
result = run("echo hello", capture_output=True, text=True)
|
|
80
|
+
print(result.stdout)
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
What it does: runs shell commands using Python subprocess.
|
|
84
|
+
|
|
85
|
+
### Touch ID
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
from utils.system.security import askForTouchID
|
|
89
|
+
|
|
90
|
+
allowed = askForTouchID("confirm action")
|
|
91
|
+
print(allowed)
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
What it does: checks for the macOS Touch ID helper and asks for confirmation.
|
|
95
|
+
|
|
96
|
+
## Credits
|
|
97
|
+
|
|
98
|
+
- https://hexif.vercel.app
|
|
99
|
+
- https://github.com/xHeXifx
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: hexif-pyutils
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Super simple python utility library
|
|
5
|
+
Author: HeXif
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/xHeXifx/hexif-pyutils
|
|
8
|
+
Project-URL: Repository, https://github.com/xHeXifx/hexif-pyutils
|
|
9
|
+
Project-URL: Issues, https://github.com/xHeXifx/hexif-pyutils/issues
|
|
10
|
+
Keywords: utilties,utils,python,helpers
|
|
11
|
+
Requires-Python: >=3.9
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
|
|
14
|
+
# hexif-pyutils
|
|
15
|
+
|
|
16
|
+
Super simple Python utilities.
|
|
17
|
+
|
|
18
|
+
This was mainly put on PyPi so i can install it without cloning it off gitea and then pip installing it off the local path.
|
|
19
|
+
|
|
20
|
+
## Install
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
pip install hexif-pyutils
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Install (TouchID Helper MacOS)
|
|
27
|
+
|
|
28
|
+
(If not cloned clone)
|
|
29
|
+
```zsh
|
|
30
|
+
git clone https://github.com/xHeXifx/hexif-pyutils
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
```zsh
|
|
34
|
+
cd {repo}/macOS/touchid-executable/touchid-helper
|
|
35
|
+
swift build -c release
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Find the executable, will be somewhere in ./build and named 'touchid'
|
|
39
|
+
```zsh
|
|
40
|
+
cp {executable location} /usr/local/bin/touchid
|
|
41
|
+
sudo chmod +x /usr/local/bin/touchid
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Optional test
|
|
45
|
+
```zsh
|
|
46
|
+
/usr/local/bin/touchid "perform a test"
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Usage
|
|
50
|
+
|
|
51
|
+
### Logger
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
from utils.logger import Logger
|
|
55
|
+
|
|
56
|
+
log = Logger("app", log_file="app.log")
|
|
57
|
+
log.info("Hello")
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
What it does: simple logging wrapper with console and file output.
|
|
61
|
+
|
|
62
|
+
### File helpers
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
from utils.file import read, write, get, touch
|
|
66
|
+
|
|
67
|
+
write("hello", "test.txt")
|
|
68
|
+
print(read("test.txt"))
|
|
69
|
+
print(get("test.txt").name)
|
|
70
|
+
touch("new.txt")
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
What it does: basic file reading/writing, file metadata lookup, and creating empty files.
|
|
74
|
+
|
|
75
|
+
### JSON
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
from utils.file.json import read, write
|
|
79
|
+
|
|
80
|
+
write({"name": "hexif"}, "data.json")
|
|
81
|
+
data = read("data.json")
|
|
82
|
+
print(data)
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
What it does: reads and writes JSON files quickly.
|
|
86
|
+
|
|
87
|
+
### Shell
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
from utils.system.shell import run
|
|
91
|
+
|
|
92
|
+
result = run("echo hello", capture_output=True, text=True)
|
|
93
|
+
print(result.stdout)
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
What it does: runs shell commands using Python subprocess.
|
|
97
|
+
|
|
98
|
+
### Touch ID
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
from utils.system.security import askForTouchID
|
|
102
|
+
|
|
103
|
+
allowed = askForTouchID("confirm action")
|
|
104
|
+
print(allowed)
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
What it does: checks for the macOS Touch ID helper and asks for confirmation.
|
|
108
|
+
|
|
109
|
+
## Credits
|
|
110
|
+
|
|
111
|
+
- https://hexif.vercel.app
|
|
112
|
+
- https://github.com/xHeXifx
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
hexif_pyutils.egg-info/PKG-INFO
|
|
4
|
+
hexif_pyutils.egg-info/SOURCES.txt
|
|
5
|
+
hexif_pyutils.egg-info/dependency_links.txt
|
|
6
|
+
hexif_pyutils.egg-info/top_level.txt
|
|
7
|
+
utils/__init__.py
|
|
8
|
+
utils/logger.py
|
|
9
|
+
utils/file/__init__.py
|
|
10
|
+
utils/file/json.py
|
|
11
|
+
utils/system/__init__.py
|
|
12
|
+
utils/system/security.py
|
|
13
|
+
utils/system/shell.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
utils
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "hexif-pyutils"
|
|
7
|
+
version = "1.0.0"
|
|
8
|
+
description = "Super simple python utility library"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
|
|
12
|
+
authors = [{name = "HeXif"}]
|
|
13
|
+
|
|
14
|
+
license = "MIT"
|
|
15
|
+
|
|
16
|
+
keywords = [
|
|
17
|
+
"utilties",
|
|
18
|
+
"utils",
|
|
19
|
+
"python",
|
|
20
|
+
"helpers"
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
[project.urls]
|
|
24
|
+
Homepage = "https://github.com/xHeXifx/hexif-pyutils"
|
|
25
|
+
Repository = "https://github.com/xHeXifx/hexif-pyutils"
|
|
26
|
+
Issues = "https://github.com/xHeXifx/hexif-pyutils/issues"
|
|
27
|
+
|
|
28
|
+
[tool.setuptools.packages.find]
|
|
29
|
+
include = ["utils*"]
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
from ..file import json
|
|
2
|
+
|
|
3
|
+
from pathlib import Path as _Path
|
|
4
|
+
from os.path import isfile as _isfile
|
|
5
|
+
from os.path import exists as _exists
|
|
6
|
+
from typing import Any as _Any
|
|
7
|
+
|
|
8
|
+
class File:
|
|
9
|
+
def __init__(self, filename: str|_Path):
|
|
10
|
+
if not isinstance(filename, _Path):
|
|
11
|
+
filename = _Path(filename)
|
|
12
|
+
self.path = filename
|
|
13
|
+
self.exists = self.path.exists()
|
|
14
|
+
|
|
15
|
+
self.is_file = self.path.is_file()
|
|
16
|
+
self.is_dir = self.path.is_dir()
|
|
17
|
+
self.is_symlink = self.path.is_symlink()
|
|
18
|
+
|
|
19
|
+
self.name = self.path.name
|
|
20
|
+
self.stem = self.path.stem
|
|
21
|
+
self.extension = self.path.suffix
|
|
22
|
+
self.parent = self.path.parent
|
|
23
|
+
self.absolute = self.path.absolute()
|
|
24
|
+
self.resolved = self.path.resolve()
|
|
25
|
+
|
|
26
|
+
self.size_bytes = self.path.stat().st_size
|
|
27
|
+
self.size_kb = self.size_bytes / 1024
|
|
28
|
+
self.size_mb = self.size_bytes / 1024**2
|
|
29
|
+
self.size_gb = self.size_bytes / 1024**3
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def read(filename: str|_Path) -> str|None:
|
|
33
|
+
"""Read contents of a file"""
|
|
34
|
+
try:
|
|
35
|
+
if _isfile(filename):
|
|
36
|
+
with open(filename, 'r') as f:
|
|
37
|
+
return f.read()
|
|
38
|
+
else:
|
|
39
|
+
raise FileNotFoundError(f"File '{filename}' does not exist.")
|
|
40
|
+
except Exception as e:
|
|
41
|
+
raise Exception(f"Failed to read file {filename}") from e
|
|
42
|
+
|
|
43
|
+
def write(data: _Any, filename: str|_Path) -> bool|None:
|
|
44
|
+
"""Opens file as 'w' and writes data
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
data: Information to write
|
|
48
|
+
filename: File to write to
|
|
49
|
+
|
|
50
|
+
Returns:
|
|
51
|
+
bool (True): If completed successfully
|
|
52
|
+
None: If fails and raises Exception
|
|
53
|
+
"""
|
|
54
|
+
try:
|
|
55
|
+
with open(filename, 'w') as f:
|
|
56
|
+
f.write(data)
|
|
57
|
+
return True
|
|
58
|
+
except Exception as e:
|
|
59
|
+
raise Exception(f"Failed to write to file {filename}") from e
|
|
60
|
+
|
|
61
|
+
def get(file: str|_Path) -> File|None:
|
|
62
|
+
"""Get information on a file
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
File: If file is found
|
|
66
|
+
None: If file is not found
|
|
67
|
+
"""
|
|
68
|
+
if _exists(file):
|
|
69
|
+
return File(file)
|
|
70
|
+
else:
|
|
71
|
+
raise FileNotFoundError()
|
|
72
|
+
|
|
73
|
+
def touch(file: str|_Path) -> None:
|
|
74
|
+
"""Touch (create) a empty file"""
|
|
75
|
+
if _exists(file):
|
|
76
|
+
return None
|
|
77
|
+
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
import os
|
|
4
|
+
|
|
5
|
+
def read(filename: str|Path) -> dict|list|None:
|
|
6
|
+
"""Read file with open 'r' and returns json.load()"""
|
|
7
|
+
try:
|
|
8
|
+
if os.path.isfile(filename):
|
|
9
|
+
with open(filename, 'r') as f:
|
|
10
|
+
return json.load(f)
|
|
11
|
+
else:
|
|
12
|
+
raise FileNotFoundError(f"File '{filename}' does not exist.")
|
|
13
|
+
except Exception as e:
|
|
14
|
+
raise Exception(f"Failed to read file {filename}") from e
|
|
15
|
+
|
|
16
|
+
def write(data: dict|list, filename: str|Path, indent=4) -> bool|None:
|
|
17
|
+
"""Write dict/list data with 'f' to json file
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
data: JSON data to write
|
|
21
|
+
filename: File to write to
|
|
22
|
+
indent: Indentation to use in the file
|
|
23
|
+
|
|
24
|
+
Returns:
|
|
25
|
+
bool (True): If operation completes successfully
|
|
26
|
+
None: If operation fails and raises Exception
|
|
27
|
+
"""
|
|
28
|
+
try:
|
|
29
|
+
with open(filename, 'w') as f:
|
|
30
|
+
json.dump(data, f, indent=indent)
|
|
31
|
+
return True
|
|
32
|
+
except Exception as e:
|
|
33
|
+
raise Exception(f"Failed to write to file {filename}") from e
|
|
34
|
+
|
|
35
|
+
def extract_dict_obj(text: str) -> dict | None:
|
|
36
|
+
"""Finds and returns a dict from a string
|
|
37
|
+
Args:
|
|
38
|
+
text (str): The text you wish to extract object from
|
|
39
|
+
|
|
40
|
+
Returns:
|
|
41
|
+
dict: If object was extracted
|
|
42
|
+
None: If no object found
|
|
43
|
+
"""
|
|
44
|
+
text = text.strip()
|
|
45
|
+
try:
|
|
46
|
+
obj = json.loads(text)
|
|
47
|
+
return obj if isinstance(obj, dict) else None
|
|
48
|
+
except Exception:
|
|
49
|
+
pass
|
|
50
|
+
start, end = text.find("{"), text.rfind("}")
|
|
51
|
+
if start == -1 or end == -1 or end <= start:
|
|
52
|
+
return None
|
|
53
|
+
try:
|
|
54
|
+
obj = json.loads(text[start:end + 1])
|
|
55
|
+
return obj if isinstance(obj, dict) else None
|
|
56
|
+
except Exception:
|
|
57
|
+
return None
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import logging as _logging
|
|
2
|
+
from pathlib import Path as _Path
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
import logging as _logging
|
|
6
|
+
from pathlib import Path as _Path
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Logger:
|
|
10
|
+
"""Wrapper around Python's logging.Logger."""
|
|
11
|
+
|
|
12
|
+
def __init__(
|
|
13
|
+
self,
|
|
14
|
+
name: str | None = None,
|
|
15
|
+
log_file: str | _Path | None = None,
|
|
16
|
+
level: int = _logging.INFO,
|
|
17
|
+
console: bool = True,
|
|
18
|
+
):
|
|
19
|
+
self.logger = _logging.getLogger(name)
|
|
20
|
+
self.logger.setLevel(level)
|
|
21
|
+
|
|
22
|
+
if not self.logger.handlers:
|
|
23
|
+
formatter = _logging.Formatter(
|
|
24
|
+
"%(asctime)s [%(levelname)s] %(name)s: %(message)s"
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
if console:
|
|
28
|
+
console_handler = _logging.StreamHandler()
|
|
29
|
+
console_handler.setFormatter(formatter)
|
|
30
|
+
self.logger.addHandler(console_handler)
|
|
31
|
+
|
|
32
|
+
if log_file is not None:
|
|
33
|
+
file_handler = _logging.FileHandler(
|
|
34
|
+
log_file,
|
|
35
|
+
encoding="utf-8"
|
|
36
|
+
)
|
|
37
|
+
file_handler.setFormatter(formatter)
|
|
38
|
+
self.logger.addHandler(file_handler)
|
|
39
|
+
|
|
40
|
+
def debug(self, msg, *args, **kwargs):
|
|
41
|
+
self.logger.debug(msg, *args, **kwargs)
|
|
42
|
+
|
|
43
|
+
def info(self, msg, *args, **kwargs):
|
|
44
|
+
self.logger.info(msg, *args, **kwargs)
|
|
45
|
+
|
|
46
|
+
def warning(self, msg, *args, **kwargs):
|
|
47
|
+
self.logger.warning(msg, *args, **kwargs)
|
|
48
|
+
|
|
49
|
+
def error(self, msg, *args, **kwargs):
|
|
50
|
+
self.logger.error(msg, *args, **kwargs)
|
|
51
|
+
|
|
52
|
+
def critical(self, msg, *args, **kwargs):
|
|
53
|
+
self.logger.critical(msg, *args, **kwargs)
|
|
54
|
+
|
|
55
|
+
def exception(self, msg, *args, **kwargs):
|
|
56
|
+
self.logger.exception(msg, *args, **kwargs)
|
|
57
|
+
|
|
58
|
+
def log(self, level, msg, *args, **kwargs):
|
|
59
|
+
self.logger.log(level, msg, *args, **kwargs)
|
|
60
|
+
|
|
61
|
+
def setLevel(self, level):
|
|
62
|
+
self.logger.setLevel(level)
|
|
63
|
+
|
|
64
|
+
def addHandler(self, handler):
|
|
65
|
+
self.logger.addHandler(handler)
|
|
66
|
+
|
|
67
|
+
def removeHandler(self, handler):
|
|
68
|
+
self.logger.removeHandler(handler)
|
|
69
|
+
|
|
70
|
+
def hasHandlers(self):
|
|
71
|
+
return self.logger.hasHandlers()
|
|
72
|
+
|
|
73
|
+
def isEnabledFor(self, level):
|
|
74
|
+
return self.logger.isEnabledFor(level)
|
|
75
|
+
|
|
76
|
+
def _appendToLog(content: str, log: Logger):
|
|
77
|
+
with open(log.logFile, 'a') as f:
|
|
78
|
+
f.write(content + "\n")
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import subprocess
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
class TouchIDError(Exception):
|
|
5
|
+
pass
|
|
6
|
+
|
|
7
|
+
def ensureTouchID() -> bool:
|
|
8
|
+
"""Checks if macos touchid executable exists"""
|
|
9
|
+
exePath = Path('/usr/local/bin/touchid')
|
|
10
|
+
return exePath.exists()
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def askForTouchID(reason: str = "confirm a action") -> bool:
|
|
14
|
+
if not ensureTouchID():
|
|
15
|
+
raise TouchIDError("touchid executable is not installed")
|
|
16
|
+
result = subprocess.run(
|
|
17
|
+
["touchid", reason],
|
|
18
|
+
stdout=subprocess.PIPE,
|
|
19
|
+
stderr=subprocess.PIPE,
|
|
20
|
+
text=True,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
if result.returncode == 0:
|
|
24
|
+
return True
|
|
25
|
+
if result.returncode == 1:
|
|
26
|
+
return False
|
|
27
|
+
|
|
28
|
+
if result.returncode == 2:
|
|
29
|
+
raise TouchIDError(
|
|
30
|
+
result.stderr.strip() or "Touch ID is unavailable"
|
|
31
|
+
)
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import subprocess as _sbp
|
|
2
|
+
|
|
3
|
+
def run(command: str, **kwargs) -> _sbp.CompletedProcess | None:
|
|
4
|
+
"""Run a command with subprocess.
|
|
5
|
+
|
|
6
|
+
Args:
|
|
7
|
+
command: Command to execute as a string.
|
|
8
|
+
**kwargs: Additional arguments passed to subprocess.run().
|
|
9
|
+
|
|
10
|
+
Returns:
|
|
11
|
+
The command's stdout if capture_output=True, otherwise None.
|
|
12
|
+
|
|
13
|
+
Raises:
|
|
14
|
+
RuntimeError: If the command returns a non-zero exit code.
|
|
15
|
+
subprocess.CalledProcessError: If check=True and the command fails.
|
|
16
|
+
"""
|
|
17
|
+
return _sbp.run(
|
|
18
|
+
command.split(),
|
|
19
|
+
**kwargs
|
|
20
|
+
)
|