Module control.helpers
Expand source code Browse git
import sys
from subprocess import run as run_cmd, CalledProcessError
from control.files import unexpanduser as ux
def ucFirst(x):
if not x:
return ""
return x[0].upper() + x[1:]
def prettify(x):
return " ".join(ucFirst(w) for w in x.split("_"))
def genViewerSelector(
allViewers,
chosenViewer,
chosenVersion,
origViewer,
origVersion,
fileBase,
):
html = []
for viewer, vwDefault, versions in allViewers:
viewerRep = f"<b>{viewer}</b>" if vwDefault else viewer
viewerRep = f"<i>{viewerRep}</i>" if viewer == origViewer else viewerRep
html.append(f"""<details><summary>{viewerRep}</summary>""")
for version, vvDefault in versions:
versionRep = f"<b>{version}</b>" if vwDefault and vvDefault else version
versionRep = (
f"<i>{versionRep}</i>"
if viewer == origViewer and version == origVersion
else versionRep
)
entry = (
f"""<span>{versionRep}</span>"""
if viewer == chosenViewer and version == chosenVersion
else (
f"""<a href="/{fileBase}-{viewer}-{version}.html">"""
f"""{versionRep}</a>"""
)
)
html.append(f"<div>{entry}</div>")
html.append("</details>")
return "\n".join(html)
def console(*msg, error=False, newline=True):
msg = " ".join(m if type(m) is str else repr(m) for m in msg)
msg = "" if not msg else ux(msg)
msg = msg[1:] if msg.startswith("\n") else msg
msg = msg[0:-1] if msg.endswith("\n") else msg
target = sys.stderr if error else sys.stdout
nl = "\n" if newline else ""
target.write(f"{msg}{nl}")
target.flush()
def run(cmdline, workDir=None):
"""Runs a shell command and returns all relevant info.
The function runs a command-line in a shell, and returns
whether the command was successful, and also what the output was, separately for
standard error and standard output.
Parameters
----------
cmdline: string
The command-line to execute.
workDir: string, optional None
The working directory where the command should be executed.
If `None` the current directory is used.
"""
try:
result = run_cmd(
cmdline,
shell=True,
cwd=workDir,
check=True,
capture_output=True,
)
stdOut = result.stdout.decode("utf8").strip()
stdErr = result.stderr.decode("utf8").strip()
good = True
except CalledProcessError as e:
stdOut = e.stdout.decode("utf8").strip()
stdErr = e.stderr.decode("utf8").strip()
good = False
return (good, stdOut, stdErr)
def htmlEsc(val):
"""Escape certain HTML characters by HTML entities.
To prevent them to be interpreted as HTML
in cases where you need them literally.
Parameters
----------
val: string
The input value
"""
return (
""
if val is None
else str(val)
.replace("&", "&")
.replace("<", "<")
.replace(">", ">")
.replace('"', """)
.replace("'", "'")
)
def htmlUnEsc(val):
"""Unescape certain HTML entities by their character values.
Parameters
----------
val: string
The input value
"""
return (
""
if val is None
else str(val)
.replace("<", "<")
.replace(">", ">")
.replace(""", '"')
.replace("'", "'")
.replace("&", "&")
)
ISSUE_KEYS = {"url", "urls", "uri", "uris"}
def hEmpty(x):
return (
"<i>no value</i>"
if x is None
else """<code>0</code>"""
if x == 0
else """<code>''</code>"""
if x == ""
else f"""<code>{str(x)}</code>"""
)
def hScalar(x, issues={}, isIssueKey=False):
if type(x) is str:
x = htmlEsc(x)
if "\n" in x:
x = x.replace("\n", "<br>")
cls = issues[x] if isIssueKey and x in issues else ""
xRep = f"""<code class="{cls}">{x}</code>"""
return (len(x) < 60 if type(x) is str else True, xRep, cls)
def hScalar0(x, tight=True, issues={}, isIssueKey=False):
tpv = type(x)
if tpv is dict:
(k, v) = list(x.items())[0]
label = f"<b>{k}</b>"
cls = ""
else:
v = list(x)[0]
label = ""
cls = issues[v] if isIssueKey and v in issues else ""
(simple, vRep, clsDeep) = hData(v, issues=issues, isIssueKey=False)
html = (
(
f"{{<b>{k}</b>: {vRep}}}"
if tpv is dict
else f"""[<span class="{cls}">{vRep}</span>]"""
if tpv is list
else f"""(<span class="{cls}">{vRep}</span>)"""
if tpv is tuple
else f"""{{<span class="{cls}">{vRep}</span>}}"""
)
if simple
else (
f"""<li><details open>
<summary>{label}:</summary>
<span class="{cls}">{vRep}</span>
</details></li>"""
if tight
else f"""<li>{label}: {vRep}</li>"""
)
)
return (simple, html, cls)
def hList(x, outer=False, tight=True, issues={}, isIssueKey=False):
elem = f"{'o' if outer else 'u'}l"
html = []
html.append(f"<{elem}>")
outerCls = ""
for i, v in enumerate(x):
(simple, vRep, cls) = hData(v, issues=issues, isIssueKey=isIssueKey)
if (
outerCls == ""
and cls == "warning"
or outerCls != "error"
and cls == "error"
):
outerCls = cls
if simple:
html.append(f"""<li>{vRep}</li>""")
else:
if type(v) is dict:
idStr = f"""(#{v["id"]})""" if "id" in v else ""
nameStr = f"""({v["name"]})""" if "name" in v else ""
titleStr = ""
if "titles" in v:
titles = v["titles"]
if type(titles) is dict:
titleStr = (
titles["EN"]
if "EN" in titles
else ""
if len(titles) == 0
else titles[sorted(titles.keys())[0]]
)
if titleStr == "":
titleStr = "??"
head = " ".join(x for x in (idStr, nameStr, titleStr) if x != "")
else:
head = f"{i + 1}"
html.append(
(
f"""<li><details><summary class="{cls}">{head}:</summary>"""
f"""{vRep}</details></li>"""
)
if tight
else f"""<li class="{cls}">{head}: {vRep}</li>"""
)
html.append(f"</{elem}>")
return ("".join(html), outerCls)
def hDict(x, outer=False, tight=True, issues={}):
html = []
elem = f"{'o' if outer else 'u'}l"
html.append(f"<{elem}>")
outerCls = ""
for k, v in sorted(x.items(), key=lambda y: str(y)):
(simple, vRep, cls) = hData(
v, tight=tight, issues=issues, isIssueKey=k in ISSUE_KEYS
)
if (
outerCls == ""
and cls == "warning"
or outerCls != "error"
and cls == "error"
):
outerCls = cls
if simple:
html.append(f"""<li><b class="{cls}">{k}</b>: {vRep}</li>""")
else:
html.append(
(
f"""<li><details><summary><b class="{cls}">{k}</b>:</summary>"""
f"""{vRep}</details></li>"""
)
if tight
else f"""<li><b class="{cls}">{k}</b>: {vRep}</li>"""
)
html.append(f"</{elem}>")
return ("".join(html), outerCls)
def hData(x, tight=True, issues={}, isIssueKey=False):
if not x:
return (True, hEmpty(x), "")
tpv = type(x)
if tpv is str or tpv is float or tpv is int or tpv is bool:
return hScalar(x, issues=issues, isIssueKey=isIssueKey)
if tpv is list or tpv is tuple or tpv is set or tpv is dict:
return (
(True, hEmpty(x), "")
if len(x) == 0
else hScalar0(x, tight=tight, issues=issues, isIssueKey=isIssueKey)
if len(x) == 1 and tpv is not dict
else (False, *hDict(x, tight=tight, issues=issues))
if tpv is dict
else (False, *hList(x, tight=tight, issues=issues, isIssueKey=isIssueKey))
)
return hScalar(x, issues=issues, isIssueKey=isIssueKey)
def showDict(title, data, *keys, tight=True, issues={}):
"""Shows selected keys of a dictionary in a pretty way.
Parameters
----------
keys: iterable of string
For each key passed to this function, the information for that key
will be displayed. If no keys are passed, all keys will be displayed.
tight: boolean, optional True
Whether to use the details element to compactify the representation.
Returns
-------
displayed HTML
An expandable list of the key-value pair for the requested keys.
"""
keys = set(keys)
(html, cls) = hDict(
{k: v for (k, v) in data.items() if not keys or k in keys},
outer=True,
tight=tight,
issues=issues,
)
openRep = "open" if keys else ""
html = (
(
f"""<details {openRep}><summary class="{cls}">{title}</summary>"""
f"""{html}</details>"""
)
if tight
else f"""<div class="{cls}">{title}</div><div>{html}</div>"""
)
return html
Functions
def console(*msg, error=False, newline=True)
-
Expand source code Browse git
def console(*msg, error=False, newline=True): msg = " ".join(m if type(m) is str else repr(m) for m in msg) msg = "" if not msg else ux(msg) msg = msg[1:] if msg.startswith("\n") else msg msg = msg[0:-1] if msg.endswith("\n") else msg target = sys.stderr if error else sys.stdout nl = "\n" if newline else "" target.write(f"{msg}{nl}") target.flush()
def genViewerSelector(allViewers, chosenViewer, chosenVersion, origViewer, origVersion, fileBase)
-
Expand source code Browse git
def genViewerSelector( allViewers, chosenViewer, chosenVersion, origViewer, origVersion, fileBase, ): html = [] for viewer, vwDefault, versions in allViewers: viewerRep = f"<b>{viewer}</b>" if vwDefault else viewer viewerRep = f"<i>{viewerRep}</i>" if viewer == origViewer else viewerRep html.append(f"""<details><summary>{viewerRep}</summary>""") for version, vvDefault in versions: versionRep = f"<b>{version}</b>" if vwDefault and vvDefault else version versionRep = ( f"<i>{versionRep}</i>" if viewer == origViewer and version == origVersion else versionRep ) entry = ( f"""<span>{versionRep}</span>""" if viewer == chosenViewer and version == chosenVersion else ( f"""<a href="/{fileBase}-{viewer}-{version}.html">""" f"""{versionRep}</a>""" ) ) html.append(f"<div>{entry}</div>") html.append("</details>") return "\n".join(html)
def hData(x, tight=True, issues={}, isIssueKey=False)
-
Expand source code Browse git
def hData(x, tight=True, issues={}, isIssueKey=False): if not x: return (True, hEmpty(x), "") tpv = type(x) if tpv is str or tpv is float or tpv is int or tpv is bool: return hScalar(x, issues=issues, isIssueKey=isIssueKey) if tpv is list or tpv is tuple or tpv is set or tpv is dict: return ( (True, hEmpty(x), "") if len(x) == 0 else hScalar0(x, tight=tight, issues=issues, isIssueKey=isIssueKey) if len(x) == 1 and tpv is not dict else (False, *hDict(x, tight=tight, issues=issues)) if tpv is dict else (False, *hList(x, tight=tight, issues=issues, isIssueKey=isIssueKey)) ) return hScalar(x, issues=issues, isIssueKey=isIssueKey)
def hDict(x, outer=False, tight=True, issues={})
-
Expand source code Browse git
def hDict(x, outer=False, tight=True, issues={}): html = [] elem = f"{'o' if outer else 'u'}l" html.append(f"<{elem}>") outerCls = "" for k, v in sorted(x.items(), key=lambda y: str(y)): (simple, vRep, cls) = hData( v, tight=tight, issues=issues, isIssueKey=k in ISSUE_KEYS ) if ( outerCls == "" and cls == "warning" or outerCls != "error" and cls == "error" ): outerCls = cls if simple: html.append(f"""<li><b class="{cls}">{k}</b>: {vRep}</li>""") else: html.append( ( f"""<li><details><summary><b class="{cls}">{k}</b>:</summary>""" f"""{vRep}</details></li>""" ) if tight else f"""<li><b class="{cls}">{k}</b>: {vRep}</li>""" ) html.append(f"</{elem}>") return ("".join(html), outerCls)
def hEmpty(x)
-
Expand source code Browse git
def hEmpty(x): return ( "<i>no value</i>" if x is None else """<code>0</code>""" if x == 0 else """<code>''</code>""" if x == "" else f"""<code>{str(x)}</code>""" )
def hList(x, outer=False, tight=True, issues={}, isIssueKey=False)
-
Expand source code Browse git
def hList(x, outer=False, tight=True, issues={}, isIssueKey=False): elem = f"{'o' if outer else 'u'}l" html = [] html.append(f"<{elem}>") outerCls = "" for i, v in enumerate(x): (simple, vRep, cls) = hData(v, issues=issues, isIssueKey=isIssueKey) if ( outerCls == "" and cls == "warning" or outerCls != "error" and cls == "error" ): outerCls = cls if simple: html.append(f"""<li>{vRep}</li>""") else: if type(v) is dict: idStr = f"""(#{v["id"]})""" if "id" in v else "" nameStr = f"""({v["name"]})""" if "name" in v else "" titleStr = "" if "titles" in v: titles = v["titles"] if type(titles) is dict: titleStr = ( titles["EN"] if "EN" in titles else "" if len(titles) == 0 else titles[sorted(titles.keys())[0]] ) if titleStr == "": titleStr = "??" head = " ".join(x for x in (idStr, nameStr, titleStr) if x != "") else: head = f"{i + 1}" html.append( ( f"""<li><details><summary class="{cls}">{head}:</summary>""" f"""{vRep}</details></li>""" ) if tight else f"""<li class="{cls}">{head}: {vRep}</li>""" ) html.append(f"</{elem}>") return ("".join(html), outerCls)
def hScalar(x, issues={}, isIssueKey=False)
-
Expand source code Browse git
def hScalar(x, issues={}, isIssueKey=False): if type(x) is str: x = htmlEsc(x) if "\n" in x: x = x.replace("\n", "<br>") cls = issues[x] if isIssueKey and x in issues else "" xRep = f"""<code class="{cls}">{x}</code>""" return (len(x) < 60 if type(x) is str else True, xRep, cls)
def hScalar0(x, tight=True, issues={}, isIssueKey=False)
-
Expand source code Browse git
def hScalar0(x, tight=True, issues={}, isIssueKey=False): tpv = type(x) if tpv is dict: (k, v) = list(x.items())[0] label = f"<b>{k}</b>" cls = "" else: v = list(x)[0] label = "" cls = issues[v] if isIssueKey and v in issues else "" (simple, vRep, clsDeep) = hData(v, issues=issues, isIssueKey=False) html = ( ( f"{{<b>{k}</b>: {vRep}}}" if tpv is dict else f"""[<span class="{cls}">{vRep}</span>]""" if tpv is list else f"""(<span class="{cls}">{vRep}</span>)""" if tpv is tuple else f"""{{<span class="{cls}">{vRep}</span>}}""" ) if simple else ( f"""<li><details open> <summary>{label}:</summary> <span class="{cls}">{vRep}</span> </details></li>""" if tight else f"""<li>{label}: {vRep}</li>""" ) ) return (simple, html, cls)
def htmlEsc(val)
-
Escape certain HTML characters by HTML entities.
To prevent them to be interpreted as HTML in cases where you need them literally.
Parameters
val
:string
- The input value
Expand source code Browse git
def htmlEsc(val): """Escape certain HTML characters by HTML entities. To prevent them to be interpreted as HTML in cases where you need them literally. Parameters ---------- val: string The input value """ return ( "" if val is None else str(val) .replace("&", "&") .replace("<", "<") .replace(">", ">") .replace('"', """) .replace("'", "'") )
def htmlUnEsc(val)
-
Unescape certain HTML entities by their character values.
Parameters
val
:string
- The input value
Expand source code Browse git
def htmlUnEsc(val): """Unescape certain HTML entities by their character values. Parameters ---------- val: string The input value """ return ( "" if val is None else str(val) .replace("<", "<") .replace(">", ">") .replace(""", '"') .replace("'", "'") .replace("&", "&") )
def prettify(x)
-
Expand source code Browse git
def prettify(x): return " ".join(ucFirst(w) for w in x.split("_"))
def run(cmdline, workDir=None)
-
Runs a shell command and returns all relevant info.
The function runs a command-line in a shell, and returns whether the command was successful, and also what the output was, separately for standard error and standard output.
Parameters
cmdline
:string
- The command-line to execute.
workDir
:string
, optionalNone
- The working directory where the command should be executed.
If
None
the current directory is used.
Expand source code Browse git
def run(cmdline, workDir=None): """Runs a shell command and returns all relevant info. The function runs a command-line in a shell, and returns whether the command was successful, and also what the output was, separately for standard error and standard output. Parameters ---------- cmdline: string The command-line to execute. workDir: string, optional None The working directory where the command should be executed. If `None` the current directory is used. """ try: result = run_cmd( cmdline, shell=True, cwd=workDir, check=True, capture_output=True, ) stdOut = result.stdout.decode("utf8").strip() stdErr = result.stderr.decode("utf8").strip() good = True except CalledProcessError as e: stdOut = e.stdout.decode("utf8").strip() stdErr = e.stderr.decode("utf8").strip() good = False return (good, stdOut, stdErr)
def showDict(title, data, *keys, tight=True, issues={})
-
Shows selected keys of a dictionary in a pretty way.
Parameters
keys
:iterable
ofstring
- For each key passed to this function, the information for that key will be displayed. If no keys are passed, all keys will be displayed.
tight
:boolean
, optionalTrue
- Whether to use the details element to compactify the representation.
Returns
displayed HTML
- An expandable list of the key-value pair for the requested keys.
Expand source code Browse git
def showDict(title, data, *keys, tight=True, issues={}): """Shows selected keys of a dictionary in a pretty way. Parameters ---------- keys: iterable of string For each key passed to this function, the information for that key will be displayed. If no keys are passed, all keys will be displayed. tight: boolean, optional True Whether to use the details element to compactify the representation. Returns ------- displayed HTML An expandable list of the key-value pair for the requested keys. """ keys = set(keys) (html, cls) = hDict( {k: v for (k, v) in data.items() if not keys or k in keys}, outer=True, tight=tight, issues=issues, ) openRep = "open" if keys else "" html = ( ( f"""<details {openRep}><summary class="{cls}">{title}</summary>""" f"""{html}</details>""" ) if tight else f"""<div class="{cls}">{title}</div><div>{html}</div>""" ) return html
def ucFirst(x)
-
Expand source code Browse git
def ucFirst(x): if not x: return "" return x[0].upper() + x[1:]