replbase 0.0.23__tar.gz → 0.0.25__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.
- {replbase-0.0.23 → replbase-0.0.25}/PKG-INFO +2 -1
- {replbase-0.0.23 → replbase-0.0.25}/pyproject.toml +2 -1
- {replbase-0.0.23 → replbase-0.0.25}/replbase/repl_base.py +149 -1
- {replbase-0.0.23 → replbase-0.0.25}/LICENSE +0 -0
- {replbase-0.0.23 → replbase-0.0.25}/README.md +0 -0
- {replbase-0.0.23 → replbase-0.0.25}/replbase/__init__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: replbase
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.25
|
|
4
4
|
Summary: "Combination of other REPL tools into a reusable class that generates a REPL"
|
|
5
5
|
License: MIT
|
|
6
6
|
Author: Joseph Bochinski
|
|
@@ -12,6 +12,7 @@ Classifier: Programming Language :: Python :: 3.12
|
|
|
12
12
|
Requires-Dist: prompt-toolkit (>=3.0.48,<4.0.0)
|
|
13
13
|
Requires-Dist: ptpython (>=3.0.29,<4.0.0)
|
|
14
14
|
Requires-Dist: rich (>=13.9.4,<14.0.0)
|
|
15
|
+
Requires-Dist: tabulate (>=0.9.0,<0.10.0)
|
|
15
16
|
Description-Content-Type: text/markdown
|
|
16
17
|
|
|
17
18
|
# replbase
|
|
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
|
|
|
4
4
|
|
|
5
5
|
[tool.poetry]
|
|
6
6
|
name = "replbase"
|
|
7
|
-
version = "0.0.
|
|
7
|
+
version = "0.0.25"
|
|
8
8
|
description = "\"Combination of other REPL tools into a reusable class that generates a REPL\""
|
|
9
9
|
authors = [ "Joseph Bochinski <stirgejr@gmail.com>",]
|
|
10
10
|
license = "MIT"
|
|
@@ -15,3 +15,4 @@ python = "^3.12"
|
|
|
15
15
|
prompt-toolkit = "^3.0.48"
|
|
16
16
|
ptpython = "^3.0.29"
|
|
17
17
|
rich = "^13.9.4"
|
|
18
|
+
tabulate = "^0.9.0"
|
|
@@ -15,9 +15,14 @@
|
|
|
15
15
|
from __future__ import annotations
|
|
16
16
|
|
|
17
17
|
import argparse
|
|
18
|
+
import grp
|
|
19
|
+
import math
|
|
18
20
|
import os
|
|
21
|
+
import pwd
|
|
19
22
|
import re
|
|
20
23
|
import shlex
|
|
24
|
+
import stat
|
|
25
|
+
import time
|
|
21
26
|
|
|
22
27
|
from dataclasses import dataclass, field
|
|
23
28
|
from typing import Any, Callable, Literal
|
|
@@ -32,6 +37,7 @@ from prompt_toolkit.styles import Style
|
|
|
32
37
|
from ptpython.repl import embed
|
|
33
38
|
from rich.console import Console
|
|
34
39
|
from rich.theme import Theme
|
|
40
|
+
from tabulate import tabulate
|
|
35
41
|
|
|
36
42
|
# endregion Imports
|
|
37
43
|
|
|
@@ -49,6 +55,77 @@ def is_num_str(val: str) -> bool:
|
|
|
49
55
|
return bool(re.match(r"^-?\d+(\.\d+)?$", val))
|
|
50
56
|
|
|
51
57
|
|
|
58
|
+
def ls_liah(path: str = "."):
|
|
59
|
+
"""Print output similar to using `ls -liah` in the terminal"""
|
|
60
|
+
|
|
61
|
+
files = os.listdir(path)
|
|
62
|
+
files_info = []
|
|
63
|
+
|
|
64
|
+
for file_name in files:
|
|
65
|
+
# Get the full path
|
|
66
|
+
full_path = os.path.join(path, file_name)
|
|
67
|
+
|
|
68
|
+
# Get file stats
|
|
69
|
+
file_stat = os.lstat(full_path)
|
|
70
|
+
|
|
71
|
+
# Get permissions
|
|
72
|
+
permissions = stat.filemode(file_stat.st_mode)
|
|
73
|
+
|
|
74
|
+
# Get number of hard links
|
|
75
|
+
hard_links = file_stat.st_nlink
|
|
76
|
+
|
|
77
|
+
# Get UID and GID, convert to names
|
|
78
|
+
uid_name = pwd.getpwuid(file_stat.st_uid).pw_name
|
|
79
|
+
gid_name = grp.getgrgid(file_stat.st_gid).gr_name
|
|
80
|
+
|
|
81
|
+
# Get file size
|
|
82
|
+
size = file_stat.st_size
|
|
83
|
+
|
|
84
|
+
# Convert size to human-readable form
|
|
85
|
+
size_human = convert_size(size)
|
|
86
|
+
|
|
87
|
+
# Get last modification time
|
|
88
|
+
mtime = time.strftime("%Y-%m-%d %H:%M", time.localtime(file_stat.st_mtime))
|
|
89
|
+
|
|
90
|
+
# Append the information
|
|
91
|
+
files_info.append(
|
|
92
|
+
[
|
|
93
|
+
file_stat.st_ino,
|
|
94
|
+
permissions,
|
|
95
|
+
hard_links,
|
|
96
|
+
uid_name,
|
|
97
|
+
gid_name,
|
|
98
|
+
size_human,
|
|
99
|
+
mtime,
|
|
100
|
+
file_name,
|
|
101
|
+
]
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
# Print in tabular format
|
|
105
|
+
headers = [
|
|
106
|
+
"Inode",
|
|
107
|
+
"Permissions",
|
|
108
|
+
"Links",
|
|
109
|
+
"UID",
|
|
110
|
+
"GID",
|
|
111
|
+
"Size",
|
|
112
|
+
"Last Modified",
|
|
113
|
+
"Name",
|
|
114
|
+
]
|
|
115
|
+
print(tabulate(files_info, headers=headers, tablefmt="plain"))
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def convert_size(size_bytes):
|
|
119
|
+
"""Convert a size in bytes to a human-readable string."""
|
|
120
|
+
if size_bytes == 0:
|
|
121
|
+
return "0B"
|
|
122
|
+
size_name = ("B", "K", "M", "G", "T", "P", "E", "Z", "Y")
|
|
123
|
+
i = int(math.floor(math.log(size_bytes, 1024)))
|
|
124
|
+
p = math.pow(1024, i)
|
|
125
|
+
s = round(size_bytes / p, 2)
|
|
126
|
+
return f"{s}{size_name[i]}"
|
|
127
|
+
|
|
128
|
+
|
|
52
129
|
@dataclass
|
|
53
130
|
class ReplTheme(Theme):
|
|
54
131
|
title: str = "bold cyan"
|
|
@@ -252,7 +329,8 @@ class ReplBase:
|
|
|
252
329
|
|
|
253
330
|
def input_prefer_int(self, *args) -> int | str:
|
|
254
331
|
"""Parse input as int if possible, otherwise return the string"""
|
|
255
|
-
|
|
332
|
+
if not args:
|
|
333
|
+
return 0
|
|
256
334
|
user_input = self.input(*args).strip().split(".")[0].strip()
|
|
257
335
|
if is_num_str(user_input):
|
|
258
336
|
return int(user_input)
|
|
@@ -331,6 +409,76 @@ class ReplBase:
|
|
|
331
409
|
self.commands[cmd_name] = new_cmd
|
|
332
410
|
return new_cmd
|
|
333
411
|
|
|
412
|
+
def setup_cmds(self, *cmd_names: list[str]) -> None:
|
|
413
|
+
"""Automatically configure commands based on the provided names
|
|
414
|
+
The ReplCommand objects are populated based on function meta
|
|
415
|
+
data retrieved from the provided function names
|
|
416
|
+
Args:
|
|
417
|
+
cmd_names (list[str]): List of class methods to convert to REPL commands
|
|
418
|
+
"""
|
|
419
|
+
|
|
420
|
+
funcs: list[Callable] = [
|
|
421
|
+
getattr(self, name)
|
|
422
|
+
for name in cmd_names
|
|
423
|
+
if hasattr(self, name) and callable(getattr(self, name))
|
|
424
|
+
]
|
|
425
|
+
|
|
426
|
+
for func in funcs:
|
|
427
|
+
help_text = func.__doc__
|
|
428
|
+
name = func.__name__
|
|
429
|
+
self.add_command(name, func, help_txt=help_text)
|
|
430
|
+
|
|
431
|
+
def warn(self, msg: str) -> None:
|
|
432
|
+
"""Print a message to the REPL preformatted as a warning"""
|
|
433
|
+
|
|
434
|
+
self.print(f"[warn]{msg}[/warn]")
|
|
435
|
+
|
|
436
|
+
def pretty_print(self, obj: Any) -> None:
|
|
437
|
+
pretty.pprint(obj)
|
|
438
|
+
|
|
439
|
+
def pwd(self) -> str:
|
|
440
|
+
"""Print out the current path location
|
|
441
|
+
|
|
442
|
+
Returns:
|
|
443
|
+
str: The current path
|
|
444
|
+
"""
|
|
445
|
+
|
|
446
|
+
self.print(f"Current location: {os.getcwd()}")
|
|
447
|
+
return os.getcwd()
|
|
448
|
+
|
|
449
|
+
def cd(self, path: str = "..") -> str:
|
|
450
|
+
"""Move the terminal to a new path location
|
|
451
|
+
|
|
452
|
+
Args:
|
|
453
|
+
path (str, optional): Path to move to. Defaults to "..".
|
|
454
|
+
|
|
455
|
+
Returns:
|
|
456
|
+
str: The new location
|
|
457
|
+
"""
|
|
458
|
+
|
|
459
|
+
try:
|
|
460
|
+
os.chdir(path)
|
|
461
|
+
except FileNotFoundError:
|
|
462
|
+
self.warn(
|
|
463
|
+
f"Path: {path} does not exist, remaining in current directory"
|
|
464
|
+
)
|
|
465
|
+
new_pwd = os.getcwd()
|
|
466
|
+
self.print(f"New dir: {new_pwd}")
|
|
467
|
+
return new_pwd
|
|
468
|
+
|
|
469
|
+
def ls(self, path: str = ".") -> list[str]:
|
|
470
|
+
"""List metadata about the files/directories at the given path
|
|
471
|
+
|
|
472
|
+
Args:
|
|
473
|
+
path (str, optional): Path to list. Defaults to ".".
|
|
474
|
+
|
|
475
|
+
Returns:
|
|
476
|
+
list[str]: List of file and directory names at the location
|
|
477
|
+
"""
|
|
478
|
+
|
|
479
|
+
ls_liah(path)
|
|
480
|
+
return os.listdir(path)
|
|
481
|
+
|
|
334
482
|
def interactive(self, *args, **kwargs) -> None:
|
|
335
483
|
"""Starts an interactive session from within the class"""
|
|
336
484
|
if kwargs:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|