python_arango_ogm.utils.md_util

  1import base64
  2from enum import Enum
  3import json
  4import textwrap
  5
  6from IPython.display import display, display_svg, HTML, Markdown, Latex, SVG
  7from pygments import highlight
  8from pygments.lexers import get_lexer_by_name
  9from pygments.formatters import HtmlFormatter
 10from jupyterlab_pygments import JupyterStyle
 11# import qgrid
 12
 13from .str_util import squish_text
 14
 15PrettyFormats = Enum('PrettyFormats', 'json python')
 16
 17COL_SEP = ' | '
 18NEWLINE = "\r\n"
 19CR = "\n"
 20INDENT = '  '
 21
 22PAD = "style='margin: 4em; padding 1em; vertical-align:top;'"
 23CELL_HTML = f"<td {PAD}>%s</td>"
 24ROW_HTML = f"<tr {PAD}>%s</tr>"
 25TABLE_HTML = f"<table {PAD}>%s</table>"
 26MIN_VISIBLE_ROWS = 8
 27
 28BG_HEADER = '#202B30'
 29FG_HEADER = '#BBBBBB'
 30
 31BG_ROW = '#455A64'
 32FG_ROW = '#BBBBBB'
 33
 34BG_ROWODD = '#769BAE'
 35FG_ROWODD = '#222222'
 36
 37QGRID_CSS = f"""
 38<style>
 39  .q-grid {{
 40    background-color: {BG_HEADER};
 41    height: auto;
 42    width: auto;
 43    max-height: 600px;
 44  }}
 45  .q-grid .slick-header, .q-grid .slick-header-columns {{
 46    background-color: {BG_HEADER};
 47  }}
 48  .q-grid .slick-header-column {{
 49    background-color: {BG_HEADER};
 50    color: {FG_HEADER};
 51    border-color: {FG_HEADER};
 52  }}
 53  .q-grid .slick-row.odd {{
 54    background-color: {BG_ROWODD};
 55    color: {FG_ROWODD};
 56    border-color: {FG_ROWODD};
 57  }}
 58  .q-grid .slick-row.even {{
 59    background-color: {BG_ROW};
 60    color: {FG_ROW};
 61    border-color: {FG_ROW};
 62  }}
 63  .q-grid .slick-resizable-handle {{
 64    background-color: {BG_ROW};
 65    border-left-color: {BG_ROWODD};
 66    border-right-color: {BG_ROWODD};
 67    border-left-width: 1px;
 68    border-right-width: 1px;
 69  }}
 70</style>
 71"""
 72
 73def display_obj(obj):
 74  display(obj)
 75
 76def display_html(html):
 77  display_obj(HTML(html))
 78
 79def render_svg(data, b64=True):
 80  svg_data = str(base64.b64encode(data)) if b64 else data
 81  # b64 = str(base64.b64encode(svg).decode('utf-8'))
 82  display_obj(SVG(svg_data))  # , raw=raw)
 83
 84def init_df_grid_style():
 85  display_obj(HTML(QGRID_CSS))
 86
 87def md(md_text, render=True):
 88  markdown = Markdown(str(md_text))
 89  return display_obj(markdown) if render else markdown
 90
 91def md_code(md_code: any, syntax: str = '', escape=True, render=True, squish=False, simple=True):
 92  md_txt = escape_md(md_code) if escape else str(md_code)
 93  code_text = squish_text(md_txt) if squish else md_txt
 94  code_text = textwrap.indent(code_text, INDENT)
 95  if simple:
 96    return md(f"`{code_text}`{NEWLINE}", render=render)
 97  else:
 98    return md(f"```{syntax}{NEWLINE}{code_text}{NEWLINE}```", render=render)
 99
100def md_table(cols, vals, header=True):
101  md(table_md(cols, vals, header=header))
102
103def md_list(rows, render=True, bullet='*', header=None):
104  bullets = [f"{bullet} {row}" for row in rows]
105  md_bullets = CR.join(bullets)
106  markdown = f"{header}{CR}{md_bullets}" if header else md_bullets
107  md(markdown, render=render)
108
109# Usage: horizontally('foo', 'bar', '`baz`')
110def horizontally(*items):
111  cells_html = ''.join([(CELL_HTML % item) for item in items])
112  md(TABLE_HTML % (ROW_HTML % cells_html))
113
114def vertically(*items):
115  rows_html = ''.join([(ROW_HTML % (CELL_HTML % item)) for item in items])
116  md(TABLE_HTML % (rows_html))
117
118# Add escape characters to string to avoid marking down:
119def escape_md(obj):
120  md = str(obj)
121  return md.replace('_', "\\_")
122
123def table_header_md(cols):
124  col_names = cols.values() if hasattr(cols, 'values') else cols
125  col_captions = [f"<th>{(col.title())}</th>" for col in col_names]
126  # md_cols = "<tr>%s</tr>" % COL_SEP.join(col_captions)
127  # md_sep = "| :--- " * len(col_names) + '|'
128  return "<tr>%s</tr>" % ''.join(col_captions)  # f"{md_cols}{NEWLINE}{md_sep}"
129
130def table_body_md(cols, vals):
131  md_rows = []
132  col_names = cols.keys() if hasattr(cols, 'keys') else cols
133  for row in vals:
134    row_vals = [f"<td>{str(row[col])}</td>" for col in col_names]
135    md_row = ''.join(row_vals)
136    md_rows.append("<tr>%s</tr>" % md_row)
137
138  return NEWLINE.join(md_rows)
139
140def table_md(cols, vals, caption=None, header=True):
141  md_rows = ['<table>']
142
143  # if caption: md_rows.append(f"### {caption}")
144  if header:
145    md_rows.append(table_header_md(cols))
146
147  md_rows.append(table_body_md(cols, vals))
148  md_rows.append('</table>')
149  return NEWLINE.join(md_rows)
150
151def pretty_json(json, markdown=True):
152  return pretty(json, markdown=markdown, format=PrettyFormats.json)
153
154def pretty(code, markdown=True, format=PrettyFormats.python, render=True):
155  code_str = json.dumps(code, indent=2) if format == PrettyFormats.json else str(code)
156  formatter = HtmlFormatter(style=JupyterStyle)
157  # lexer = PythonLexer if format==PrettyFormats.PYTHON else JsonLexer
158  lexer = get_lexer_by_name("json", stripall=False)
159  html = highlight(code_str, lexer, formatter)
160  css = formatter.get_style_defs('.highlight')
161  html = f'<style>{css}</style><div class="highlight">{html}</div>'
162  return display_html(html) if markdown else html
163
164# def md_dataframe(df, heading=None, include_index: bool = False, render: bool = True, sortable: bool = False, filterable: bool = False, allrows: bool = False, plain: bool = False):
165#
166#   if plain:
167#     html = df.to_html(index=False)
168#     if render:
169#       return(HTML(html))
170#     else:
171#       return html
172#   else:
173#     min_rows = len(df.index_name) + 2 if allrows else min(MIN_VISIBLE_ROWS, len(df.index_name) + 1)
174#     widget = qgrid.show_grid(df, show_toolbar=False, grid_options=dict(
175#         forceFitColumns=False,
176#         syncColumnCellResize=True,
177#         fullWidthRows=False,
178#         minVisibleRows=min_rows,
179#         sortable=sortable,
180#         filterable=filterable,
181#     ))
182#
183#     header = f"## {heading}" if heading else None
184#     if render:
185#       if header:
186#         md(header, render=render)
187#       return(widget)
188#     else:
189#       return widget
class PrettyFormats(enum.Enum):

Create a collection of name/value pairs.

Example enumeration:

>>> class Color(Enum):
...     RED = 1
...     BLUE = 2
...     GREEN = 3

Access them by:

  • attribute access:

    >>> Color.RED
    <Color.RED: 1>
    
  • value lookup:

    >>> Color(1)
    <Color.RED: 1>
    
  • name lookup:

    >>> Color['RED']
    <Color.RED: 1>
    

Enumerations can be iterated over, and know how many members they have:

>>> len(Color)
3
>>> list(Color)
[<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>]

Methods can be added to enumerations, and members can have their own attributes -- see the documentation for details.

json = <PrettyFormats.json: 1>
python = <PrettyFormats.python: 2>
Inherited Members
enum.Enum
name
value
COL_SEP = ' | '
NEWLINE = '\r\n'
CR = '\n'
INDENT = ' '
PAD = "style='margin: 4em; padding 1em; vertical-align:top;'"
CELL_HTML = "<td style='margin: 4em; padding 1em; vertical-align:top;'>%s</td>"
ROW_HTML = "<tr style='margin: 4em; padding 1em; vertical-align:top;'>%s</tr>"
TABLE_HTML = "<table style='margin: 4em; padding 1em; vertical-align:top;'>%s</table>"
MIN_VISIBLE_ROWS = 8
BG_HEADER = '#202B30'
FG_HEADER = '#BBBBBB'
BG_ROW = '#455A64'
FG_ROW = '#BBBBBB'
BG_ROWODD = '#769BAE'
FG_ROWODD = '#222222'
QGRID_CSS = '\n<style>\n .q-grid {\n background-color: #202B30;\n height: auto;\n width: auto;\n max-height: 600px;\n }\n .q-grid .slick-header, .q-grid .slick-header-columns {\n background-color: #202B30;\n }\n .q-grid .slick-header-column {\n background-color: #202B30;\n color: #BBBBBB;\n border-color: #BBBBBB;\n }\n .q-grid .slick-row.odd {\n background-color: #769BAE;\n color: #222222;\n border-color: #222222;\n }\n .q-grid .slick-row.even {\n background-color: #455A64;\n color: #BBBBBB;\n border-color: #BBBBBB;\n }\n .q-grid .slick-resizable-handle {\n background-color: #455A64;\n border-left-color: #769BAE;\n border-right-color: #769BAE;\n border-left-width: 1px;\n border-right-width: 1px;\n }\n</style>\n'
def display_obj(obj):
74def display_obj(obj):
75  display(obj)
def display_html(html):
77def display_html(html):
78  display_obj(HTML(html))
def render_svg(data, b64=True):
80def render_svg(data, b64=True):
81  svg_data = str(base64.b64encode(data)) if b64 else data
82  # b64 = str(base64.b64encode(svg).decode('utf-8'))
83  display_obj(SVG(svg_data))  # , raw=raw)
def init_df_grid_style():
85def init_df_grid_style():
86  display_obj(HTML(QGRID_CSS))
def md(md_text, render=True):
88def md(md_text, render=True):
89  markdown = Markdown(str(md_text))
90  return display_obj(markdown) if render else markdown
def md_code( md_code: <built-in function any>, syntax: str = '', escape=True, render=True, squish=False, simple=True):
92def md_code(md_code: any, syntax: str = '', escape=True, render=True, squish=False, simple=True):
93  md_txt = escape_md(md_code) if escape else str(md_code)
94  code_text = squish_text(md_txt) if squish else md_txt
95  code_text = textwrap.indent(code_text, INDENT)
96  if simple:
97    return md(f"`{code_text}`{NEWLINE}", render=render)
98  else:
99    return md(f"```{syntax}{NEWLINE}{code_text}{NEWLINE}```", render=render)
def md_table(cols, vals, header=True):
101def md_table(cols, vals, header=True):
102  md(table_md(cols, vals, header=header))
def md_list(rows, render=True, bullet='*', header=None):
104def md_list(rows, render=True, bullet='*', header=None):
105  bullets = [f"{bullet} {row}" for row in rows]
106  md_bullets = CR.join(bullets)
107  markdown = f"{header}{CR}{md_bullets}" if header else md_bullets
108  md(markdown, render=render)
def horizontally(*items):
111def horizontally(*items):
112  cells_html = ''.join([(CELL_HTML % item) for item in items])
113  md(TABLE_HTML % (ROW_HTML % cells_html))
def vertically(*items):
115def vertically(*items):
116  rows_html = ''.join([(ROW_HTML % (CELL_HTML % item)) for item in items])
117  md(TABLE_HTML % (rows_html))
def escape_md(obj):
120def escape_md(obj):
121  md = str(obj)
122  return md.replace('_', "\\_")
def table_header_md(cols):
124def table_header_md(cols):
125  col_names = cols.values() if hasattr(cols, 'values') else cols
126  col_captions = [f"<th>{(col.title())}</th>" for col in col_names]
127  # md_cols = "<tr>%s</tr>" % COL_SEP.join(col_captions)
128  # md_sep = "| :--- " * len(col_names) + '|'
129  return "<tr>%s</tr>" % ''.join(col_captions)  # f"{md_cols}{NEWLINE}{md_sep}"
def table_body_md(cols, vals):
131def table_body_md(cols, vals):
132  md_rows = []
133  col_names = cols.keys() if hasattr(cols, 'keys') else cols
134  for row in vals:
135    row_vals = [f"<td>{str(row[col])}</td>" for col in col_names]
136    md_row = ''.join(row_vals)
137    md_rows.append("<tr>%s</tr>" % md_row)
138
139  return NEWLINE.join(md_rows)
def table_md(cols, vals, caption=None, header=True):
141def table_md(cols, vals, caption=None, header=True):
142  md_rows = ['<table>']
143
144  # if caption: md_rows.append(f"### {caption}")
145  if header:
146    md_rows.append(table_header_md(cols))
147
148  md_rows.append(table_body_md(cols, vals))
149  md_rows.append('</table>')
150  return NEWLINE.join(md_rows)
def pretty_json(json, markdown=True):
152def pretty_json(json, markdown=True):
153  return pretty(json, markdown=markdown, format=PrettyFormats.json)
def pretty(code, markdown=True, format=<PrettyFormats.python: 2>, render=True):
155def pretty(code, markdown=True, format=PrettyFormats.python, render=True):
156  code_str = json.dumps(code, indent=2) if format == PrettyFormats.json else str(code)
157  formatter = HtmlFormatter(style=JupyterStyle)
158  # lexer = PythonLexer if format==PrettyFormats.PYTHON else JsonLexer
159  lexer = get_lexer_by_name("json", stripall=False)
160  html = highlight(code_str, lexer, formatter)
161  css = formatter.get_style_defs('.highlight')
162  html = f'<style>{css}</style><div class="highlight">{html}</div>'
163  return display_html(html) if markdown else html