stouputils 1.2.18__tar.gz → 1.2.20__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 (25) hide show
  1. {stouputils-1.2.18 → stouputils-1.2.20}/PKG-INFO +1 -1
  2. {stouputils-1.2.18 → stouputils-1.2.20}/pyproject.toml +1 -1
  3. {stouputils-1.2.18 → stouputils-1.2.20}/stouputils/ctx.py +1 -49
  4. {stouputils-1.2.18 → stouputils-1.2.20}/stouputils/parallel.py +4 -4
  5. {stouputils-1.2.18 → stouputils-1.2.20}/stouputils/print.py +67 -1
  6. {stouputils-1.2.18 → stouputils-1.2.20}/.gitignore +0 -0
  7. {stouputils-1.2.18 → stouputils-1.2.20}/LICENSE +0 -0
  8. {stouputils-1.2.18 → stouputils-1.2.20}/README.md +0 -0
  9. {stouputils-1.2.18 → stouputils-1.2.20}/stouputils/__init__.py +0 -0
  10. {stouputils-1.2.18 → stouputils-1.2.20}/stouputils/all_doctests.py +0 -0
  11. {stouputils-1.2.18 → stouputils-1.2.20}/stouputils/applications/__init__.py +0 -0
  12. {stouputils-1.2.18 → stouputils-1.2.20}/stouputils/applications/automatic_docs.py +0 -0
  13. {stouputils-1.2.18 → stouputils-1.2.20}/stouputils/archive.py +0 -0
  14. {stouputils-1.2.18 → stouputils-1.2.20}/stouputils/backup.py +0 -0
  15. {stouputils-1.2.18 → stouputils-1.2.20}/stouputils/collections.py +0 -0
  16. {stouputils-1.2.18 → stouputils-1.2.20}/stouputils/continuous_delivery/__init__.py +0 -0
  17. {stouputils-1.2.18 → stouputils-1.2.20}/stouputils/continuous_delivery/cd_utils.py +0 -0
  18. {stouputils-1.2.18 → stouputils-1.2.20}/stouputils/continuous_delivery/github.py +0 -0
  19. {stouputils-1.2.18 → stouputils-1.2.20}/stouputils/continuous_delivery/pypi.py +0 -0
  20. {stouputils-1.2.18 → stouputils-1.2.20}/stouputils/continuous_delivery/pyproject.py +0 -0
  21. {stouputils-1.2.18 → stouputils-1.2.20}/stouputils/decorators.py +0 -0
  22. {stouputils-1.2.18 → stouputils-1.2.20}/stouputils/dont_look/zip_file_override.py +0 -0
  23. {stouputils-1.2.18 → stouputils-1.2.20}/stouputils/image.py +0 -0
  24. {stouputils-1.2.18 → stouputils-1.2.20}/stouputils/io.py +0 -0
  25. {stouputils-1.2.18 → stouputils-1.2.20}/stouputils/py.typed +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: stouputils
3
- Version: 1.2.18
3
+ Version: 1.2.20
4
4
  Summary: Stouputils is a collection of utility modules designed to simplify and enhance the development process. It includes a range of tools for tasks such as execution of doctests, display utilities, decorators, as well as context managers, and many more.
5
5
  Project-URL: Homepage, https://github.com/Stoupy51/stouputils
6
6
  Project-URL: Issues, https://github.com/Stoupy51/stouputils/issues
@@ -5,7 +5,7 @@ build-backend = "hatchling.build"
5
5
 
6
6
  [project]
7
7
  name = "stouputils"
8
- version = "1.2.18"
8
+ version = "1.2.20"
9
9
  description = "Stouputils is a collection of utility modules designed to simplify and enhance the development process. It includes a range of tools for tasks such as execution of doctests, display utilities, decorators, as well as context managers, and many more."
10
10
  readme = "README.md"
11
11
  requires-python = ">=3.10"
@@ -12,7 +12,7 @@ This module provides context managers for temporarily silencing output.
12
12
  import os
13
13
  import sys
14
14
  from typing import IO, TextIO, Callable, Any
15
- from .print import remove_colors
15
+ from .print import TeeMultiOutput
16
16
  from .io import super_open
17
17
 
18
18
 
@@ -55,54 +55,6 @@ class Muffle:
55
55
  sys.stderr = self.original_stderr
56
56
 
57
57
 
58
- # TeeMultiOutput class to duplicate output to multiple file-like objects
59
- class TeeMultiOutput(object):
60
- """ File-like object that duplicates output to multiple file objects.
61
-
62
- Args:
63
- *files (IO[Any]): One or more file-like objects that have write and flush methods
64
- strip_colors (bool): Whether to strip ANSI color codes from output sent to non-stdout/stderr files
65
-
66
- Examples:
67
- >>> f = open("logfile.txt", "w")
68
- >>> original_stdout = sys.stdout
69
- >>> sys.stdout = TeeMultiOutput(sys.stdout, f)
70
- >>> print("Hello World") # Output goes to both console and file
71
- >>> sys.stdout = original_stdout
72
- >>> f.close()
73
- """
74
- def __init__(self, *files: IO[Any], strip_colors: bool = True) -> None:
75
- self.files: tuple[IO[Any], ...] = files
76
- """ File-like objects to write to """
77
- self.strip_colors: bool = strip_colors
78
- """ Whether to strip ANSI color codes from output sent to non-stdout/stderr files """
79
-
80
- def write(self, obj: str) -> None:
81
- """ Write the object to all files.
82
-
83
- Args:
84
- obj (str): String to write
85
- """
86
- for f in self.files:
87
- # Strip colors for files that are not stdout or stderr
88
- if self.strip_colors and f not in (sys.stdout, sys.stderr):
89
- f.write(remove_colors(obj))
90
- else:
91
- f.write(obj)
92
-
93
- def flush(self) -> None:
94
- """ Flush all files. """
95
- for f in self.files:
96
- f.flush()
97
-
98
- # Add other methods that might be expected from a file-like object
99
- def isatty(self) -> bool:
100
- """ Return whether the first file is connected to a tty-like device. """
101
- return hasattr(self.files[0], 'isatty') and self.files[0].isatty()
102
-
103
- def fileno(self) -> int:
104
- """ Return the file descriptor of the first file. """
105
- return self.files[0].fileno()
106
58
 
107
59
  # Context manager to log to a file
108
60
  class LogToFile:
@@ -123,7 +123,7 @@ def multiprocessing(func: Callable[[T], R], args: list[T], use_starmap: bool = F
123
123
  # Do multiprocessing only if there is more than 1 argument and more than 1 CPU
124
124
  if max_workers > 1 and len(args) > 1:
125
125
  if verbose > 0:
126
- return list(process_map(func, args, max_workers=max_workers, chunksize=chunksize, desc=desc, bar_format=BAR_FORMAT)) # type: ignore
126
+ return list(process_map(func, args, max_workers=max_workers, chunksize=chunksize, desc=desc, bar_format=BAR_FORMAT, ascii=False)) # type: ignore
127
127
  else:
128
128
  with Pool(max_workers) as pool:
129
129
  return list(pool.map(func, args, chunksize=chunksize)) # type: ignore
@@ -131,7 +131,7 @@ def multiprocessing(func: Callable[[T], R], args: list[T], use_starmap: bool = F
131
131
  # Single process execution
132
132
  else:
133
133
  if verbose > 0:
134
- return [func(arg) for arg in tqdm(args, total=len(args), desc=desc, bar_format=BAR_FORMAT)]
134
+ return [func(arg) for arg in tqdm(args, total=len(args), desc=desc, bar_format=BAR_FORMAT, ascii=False)]
135
135
  else:
136
136
  return [func(arg) for arg in args]
137
137
 
@@ -176,7 +176,7 @@ def multithreading(func: Callable[[T], R], args: list[T], use_starmap: bool = Fa
176
176
  if max_workers > 1 and len(args) > 1:
177
177
  if verbose > 0:
178
178
  with ThreadPoolExecutor(max_workers) as executor:
179
- return list(tqdm(executor.map(func, args), total=len(args), desc=desc, bar_format=BAR_FORMAT))
179
+ return list(tqdm(executor.map(func, args), total=len(args), desc=desc, bar_format=BAR_FORMAT, ascii=False))
180
180
  else:
181
181
  with ThreadPoolExecutor(max_workers) as executor:
182
182
  return list(executor.map(func, args))
@@ -184,7 +184,7 @@ def multithreading(func: Callable[[T], R], args: list[T], use_starmap: bool = Fa
184
184
  # Single process execution
185
185
  else:
186
186
  if verbose > 0:
187
- return [func(arg) for arg in tqdm(args, total=len(args), desc=desc, bar_format=BAR_FORMAT)]
187
+ return [func(arg) for arg in tqdm(args, total=len(args), desc=desc, bar_format=BAR_FORMAT, ascii=False)]
188
188
  else:
189
189
  return [func(arg) for arg in args]
190
190
 
@@ -10,7 +10,7 @@ If a message is printed multiple times, it will be displayed as "(xN) message" w
10
10
  # Imports
11
11
  import sys
12
12
  import time
13
- from typing import Callable, TextIO, Any
13
+ from typing import Callable, IO, TextIO, Any
14
14
 
15
15
  # Colors constants
16
16
  RESET: str = "\033[0m"
@@ -224,7 +224,73 @@ def breakpoint(*values: Any, print_function: Callable[..., None] = warning, **pr
224
224
  sys.exit(1)
225
225
 
226
226
 
227
+ # TeeMultiOutput class to duplicate output to multiple file-like objects
228
+ class TeeMultiOutput(object):
229
+ """ File-like object that duplicates output to multiple file objects.
227
230
 
231
+ Args:
232
+ *files (IO[Any]): One or more file-like objects that have write and flush methods
233
+ strip_colors (bool): Whether to strip ANSI color codes from output sent to non-stdout/stderr files
234
+ force_tty (bool): Whether to force reporting as a TTY device (helps with tqdm)
235
+ ascii_only (bool): Whether to replace non-ASCII characters with their ASCII equivalents for non-stdout/stderr files
236
+
237
+ Examples:
238
+ >>> f = open("logfile.txt", "w")
239
+ >>> original_stdout = sys.stdout
240
+ >>> sys.stdout = TeeMultiOutput(sys.stdout, f)
241
+ >>> print("Hello World") # Output goes to both console and file
242
+ >>> sys.stdout = original_stdout
243
+ >>> f.close()
244
+ """
245
+ def __init__(self, *files: IO[Any], strip_colors: bool = True, ascii_only: bool = True) -> None:
246
+ self.files: tuple[IO[Any], ...] = files
247
+ """ File-like objects to write to """
248
+ self.strip_colors: bool = strip_colors
249
+ """ Whether to strip ANSI color codes from output sent to non-stdout/stderr files """
250
+ self.ascii_only: bool = ascii_only
251
+ """ Whether to replace non-ASCII characters with their ASCII equivalents for non-stdout/stderr files """
252
+
253
+ def write(self, obj: str) -> None:
254
+ """ Write the object to all files while stripping colors if needed.
255
+
256
+ Args:
257
+ obj (str): String to write
258
+ """
259
+ for i, f in enumerate(self.files):
260
+ try:
261
+ content = obj
262
+ if i != 0:
263
+ # First file (i = 0) (often stdout/stderr) gets the original content
264
+ # Other files (i != 0) get processed content
265
+
266
+ # Strip colors if needed
267
+ if self.strip_colors:
268
+ content = remove_colors(content)
269
+
270
+ # Replace Unicode block characters with ASCII equivalents
271
+ # Replace other problematic Unicode characters as needed
272
+ if self.ascii_only:
273
+ content = content.replace('█', '#')
274
+ content = ''.join(c if ord(c) < 128 else '?' for c in content)
275
+
276
+ # Write content to file
277
+ f.write(content)
278
+
279
+ except Exception:
280
+ pass
281
+
282
+ def flush(self) -> None:
283
+ """ Flush all files. """
284
+ for f in self.files:
285
+ if hasattr(f, 'flush'):
286
+ try:
287
+ f.flush()
288
+ except Exception:
289
+ pass
290
+
291
+ def fileno(self) -> int:
292
+ """ Return the file descriptor of the first file. """
293
+ return self.files[0].fileno() if hasattr(self.files[0], "fileno") else 0
228
294
 
229
295
 
230
296
 
File without changes
File without changes
File without changes