Source code for pynxxas.io.utils
import io
from math import log10
from charset_normalizer import from_bytes
MAX_FILESIZE = 100 * 1024 * 1024 # 100 Mb limit
COMMENTCHARS = "#;%*!$"
VALID_CHARS1 = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_"
BAD_FILECHARS = ";~,`!%$@$&^?*#:\"/|'\\\t\r\n (){}[]<>"
GOOD_FILECHARS = "_" * len(BAD_FILECHARS)
BAD_VARSCHARS = BAD_FILECHARS + "=+-."
GOOD_VARSCHARS = "_" * len(BAD_VARSCHARS)
TRANS_FILE = str.maketrans(BAD_FILECHARS, GOOD_FILECHARS)
TRANS_VARS = str.maketrans(BAD_VARSCHARS, GOOD_VARSCHARS)
[docs]
def fix_varname(s):
"""fix string to be a a good Python variable/attribute name."""
t = str(s).translate(TRANS_VARS)
if len(t) < 1:
t = "_var_"
if t[0] not in VALID_CHARS1:
t = "_%s" % t
while t.endswith("_"):
t = t[:-1]
return t
[docs]
def read_textfile(filename, size=None):
"""read text from a file as string
Argument
--------
filename (str or file): name of file to read or file-like object
size (int or None): number of bytes to read
Returns
-------
text of file as string.
Notes
------
1. the encoding is detected with charset_normalizer.from_bytes
which is then used to decode bytes read from file.
2. line endings are normalized to be '\n', so that
splitting on '\n' will give a list of lines.
3. if filename is given, it can be a gzip-compressed file
"""
text = ""
def decode(bytedata):
return str(from_bytes(bytedata).best())
if isinstance(filename, io.IOBase):
text = filename.read(size)
if filename.mode == "rb":
text = decode(text)
else:
with open(filename, "rb") as fh:
text = decode(fh.read(size))
return text.replace("\r\n", "\n").replace("\r", "\n")
[docs]
def gformat(val, length=11):
"""Format a number with '%g'-like format.
Except that:
a) the length of the output string will be of the requested length.
b) positive numbers will have a leading blank.
b) the precision will be as high as possible.
c) trailing zeros will not be trimmed.
The precision will typically be ``length-7``.
Parameters
----------
val : float
Value to be formatted.
length : int, optional
Length of output string (default is 11).
Returns
-------
str
String of specified length.
Notes
------
Positive values will have leading blank.
"""
if val is None or isinstance(val, bool):
return f"{repr(val):>{length}s}"
try:
expon = int(log10(abs(val)))
except (OverflowError, ValueError):
expon = 0
length = max(length, 7)
form = "e"
prec = length - 7
ab_expon = abs(expon)
if ab_expon > 99:
prec -= 1
elif (
(expon >= 0 and expon < (prec + 4))
or (expon <= -1 and -expon < (prec - 2))
or (expon <= -1 and prec < 5 and abs(expon) < 3)
):
form = "f"
prec += 4
if expon > 0:
prec -= expon
def fmt(val, length, prec, form):
out = f"{val:{length}.{prec}{form}}"
if form == "e" and "e+0" in out or "e-0" in out:
out = f"{val:{length+1}.{prec+1}{form}}"
out = out.replace("e-0", "e-").replace("e+0", "e+")
return out
prec += 1
out = "_" * (length + 2)
while len(out) > length:
prec -= 1
out = fmt(val, length, prec, form)
if "_" in out:
out = fmt(val, length, prec, form)
while len(out) < length:
prec += 1
out = fmt(val, length, prec, form)
return out
[docs]
def test_gformat():
for x in range(-10, 12):
for a in [0.2124312134, 0.54364253, 0.812312, 0.96341312124, 1.028456789]:
v = a * (10 ** (x))
for len in (14, 13, 12, 11, 10, 9, 8):
print(gformat(v, length=len))