mirror of
https://github.com/wassname/greater_tables_project.git
synced 2026-06-27 16:15:38 +08:00
5.0.0.beta renamed gtXX to XX; added auto SCM
This commit is contained in:
@@ -8,6 +8,7 @@ Versions
|
||||
* Introduced gtutilities to pull out text width estimation, cleaning and escaping, etc.
|
||||
* Delete rich table output format?
|
||||
* Moved logging setup to separate file, called from cli but optional for use in other situation. GPT recommended approach.
|
||||
* Removed ``gt`` prefix from module file names, except logging.
|
||||
|
||||
.. * test cases
|
||||
* tex and or html in data, index, columns, escaped/unescaped
|
||||
|
||||
@@ -2,9 +2,9 @@ __version__ = '5.0.0'
|
||||
__project__ = 'greater_tables'
|
||||
__author__ = 'Stephen J Mildenhall'
|
||||
|
||||
from . gtcore import GT
|
||||
from . gtfabrications import Fabricator
|
||||
from . gtetcher import Etcher
|
||||
from . core import GT
|
||||
from . fabrications import Fabricator
|
||||
from . etcher import Etcher
|
||||
|
||||
# from . gtbreaks import Breakability
|
||||
|
||||
|
||||
@@ -10,8 +10,8 @@ from . gtlogging import setup_logging
|
||||
|
||||
setup_logging() # <-- must come before using your package
|
||||
|
||||
from .gtconfig import Configurator, write_template
|
||||
from .gtcore import GT
|
||||
from . config import Configurator, write_template
|
||||
from . core import GT
|
||||
|
||||
|
||||
@click.group()
|
||||
|
||||
@@ -10,7 +10,6 @@ Also includes functions for writing editable config templates and loading from Y
|
||||
|
||||
from pathlib import Path
|
||||
from typing import Optional, Union, Literal, Callable, Any
|
||||
import yaml
|
||||
|
||||
from pydantic import BaseModel, Field, ValidationError, ConfigDict
|
||||
import yaml
|
||||
@@ -29,7 +28,7 @@ class Configurator(BaseModel):
|
||||
|
||||
:Usage:
|
||||
|
||||
>>> from greater_tables.gtconfig import Configurator
|
||||
>>> from greater_tables.config import Configurator
|
||||
>>> cfg = Configurator(font_size="1.2em", caption_align="left")
|
||||
|
||||
:see also: ``GTConfig`` for loading from YAML with overrides.
|
||||
@@ -134,14 +133,17 @@ class Configurator(BaseModel):
|
||||
header_alignment: Literal["few", "center"] = Field(
|
||||
default='few', description="NYI!! TOOD Alignment of header cells, few=follow column, center=center." )
|
||||
|
||||
max_table_width: int = Field(
|
||||
200, description="Maximum table width for markdown/text output mode"
|
||||
table_font_pt_size: float = Field(
|
||||
default=11, description="Font size for table text in points, 12 points/inch; 85 char/6.5 inch page"
|
||||
)
|
||||
max_table_inch_width: float = Field(
|
||||
8.0, description="Maximum/target table width in inches"
|
||||
)
|
||||
table_width_mode: Literal["explicit", "natural", "breakable", "minimum"] = Field(
|
||||
"explicit",
|
||||
description=(
|
||||
"Mode for determining table width. "
|
||||
"'explicit': fixed width using max_table_width; "
|
||||
"'explicit': fixed width using max_table_width_em; "
|
||||
"'natural': each cell fits its full content; "
|
||||
"'breakable': wrap breakable strings; "
|
||||
"'minimum': also wraps dates or float-like cells"
|
||||
@@ -30,11 +30,11 @@ from pydantic import ValidationError
|
||||
from rich import box
|
||||
from IPython.display import display, SVG
|
||||
|
||||
from . gtenums import Breakability
|
||||
from . gtconfig import Configurator
|
||||
from . gthasher import df_short_hash
|
||||
from . gtetcher import Etcher
|
||||
from . gtutilities import *
|
||||
from . enums import Breakability
|
||||
from . config import Configurator
|
||||
from . hasher import df_short_hash
|
||||
from . etcher import Etcher
|
||||
from . utilities import *
|
||||
|
||||
# turn off this fuck-fest
|
||||
pd.set_option('future.no_silent_downcasting', True)
|
||||
@@ -181,7 +181,7 @@ class GT(object):
|
||||
:param str_table_fmt: table border format used for string output
|
||||
(markdown), default mixed_grid DEPRECATED??
|
||||
:param config.table_width_mode:
|
||||
'explicit': set using config.max_table_width
|
||||
'explicit': set using config.max_table_width_em
|
||||
'natural': each cell on one line (can be very wide with long strings)
|
||||
'breakable': wrap breakable cells (text strings) at word boundaries
|
||||
to fit longest word
|
||||
@@ -190,9 +190,9 @@ class GT(object):
|
||||
used to balance header columns.
|
||||
:param config.table_width_header_relax: extra spaces allowed per column heading
|
||||
to facilitate better column header wrapping.
|
||||
:param config.max_table_width: max table width used for markdown string output,
|
||||
:param config.max_table_width_em: max table width used for markdown string output,
|
||||
default 200; width is never less than minimum width. Padding (3 chars
|
||||
per row plus 1) consumed out of config.max_table_width in string output mode.
|
||||
per row plus 1) consumed out of config.max_table_width_em in string output mode.
|
||||
:param config.debug: if True, add id to caption and use colored lines in table,
|
||||
default False.
|
||||
"""
|
||||
@@ -290,17 +290,7 @@ class GT(object):
|
||||
# get rid of column names
|
||||
# self.df.columns.names = [None] * self.df.columns.nlevels
|
||||
self.df_id = df_short_hash(self.df)
|
||||
# TODO: update / change
|
||||
# self.str_table_fmt = str_table_fmt
|
||||
# TODO: implement
|
||||
# self.table_width_mode = config.table_width_mode.lower()
|
||||
# if config.table_width_mode not in ('explicit', 'natural', 'breakable', 'minimum'):
|
||||
# raise ValueError(f'Inadmissible options {config.table_width_mode} for config.table_width_mode.')
|
||||
# self.table_width_mode = table_width_mode
|
||||
# self.table_width_header_adjust = table_width_header_adjust
|
||||
# self.table_width_header_relax = table_width_header_relax
|
||||
# self.max_table_width = max_table_width
|
||||
# self.debug = debug
|
||||
|
||||
if self.caption != '' and self.config.debug:
|
||||
self.caption += f' (id: {self.df_id})'
|
||||
# self.max_str_length = max_str_length
|
||||
@@ -520,34 +510,6 @@ class GT(object):
|
||||
raise ValueError(
|
||||
'formatters must be dict of callables or ints or format strings {x:...}')
|
||||
|
||||
# store defaults
|
||||
# self.default_integer_str = default_integer_str
|
||||
# VERY rarely used; for floats in cols that are not floats
|
||||
# self.default_float_str = default_float_str
|
||||
# self.default_date_str = default_date_str.replace(
|
||||
# '{x:', '').replace('}', '')
|
||||
# self.default_ratio_str = default_ratio_str
|
||||
# self.pef_precision = pef_precision
|
||||
# self.pef_lower = pef_lower
|
||||
# self.pef_upper = pef_upper
|
||||
self._pef = None
|
||||
# self.table_float_format = table_float_format
|
||||
# self.default_float_formatter = None
|
||||
# self.hrule_widths = hrule_widths or (0, 0, 0)
|
||||
# if not isinstance(self.config.hrule_widths, (list, tuple)):
|
||||
# self.config.hrule_widths = (self.config.hrule_widths,)
|
||||
# self.vrule_widths = vrule_widths or (0, 0, 0)
|
||||
# if not isinstance(self.config.hrule_widths, (list, tuple)):
|
||||
# self.config.hrule_widths = (self.config.hrule_widths, )
|
||||
# self.table_hrule_width = table_hrule_width
|
||||
# self.table_vrule_width = table_vrule_width
|
||||
# self.font_body = font_body
|
||||
# self.font_head = font_head
|
||||
# self.font_caption = font_caption
|
||||
# self.tikz_scale = tikz_scale
|
||||
# self.font_bold_index = font_bold_index
|
||||
# self.caption_align = caption_align
|
||||
# self.sparsify_columns = sparsify_columns
|
||||
if tabs is None:
|
||||
self.tabs = None
|
||||
elif isinstance(tabs, (int, float)):
|
||||
@@ -582,6 +544,8 @@ class GT(object):
|
||||
|
||||
# because of the problem of non-unique indexes use a list and
|
||||
# not a dict to pass the formatters to to_html
|
||||
self.max_table_width_em = self.config.max_table_inch_width * 72 / self.config.table_font_pt_size
|
||||
self._pef = None
|
||||
self._df_formatters = None
|
||||
self.df_style = ''
|
||||
self.df_html = ''
|
||||
@@ -968,9 +932,17 @@ class GT(object):
|
||||
h = self.html_knowledge_df.recommended.sum()
|
||||
tikz = self.tex_knowledge_df['tikz_colw'].sum()
|
||||
tex = self.tex_knowledge_df['scaled_tabs'].sum()
|
||||
mtw = self.config.max_table_width
|
||||
cols = self.df.shape[1]
|
||||
df = pd.Series({
|
||||
mtw = self.max_table_width_em
|
||||
bit = pd.DataFrame({
|
||||
'text natural': self.text_knowledge_df.natural_width,
|
||||
'text minimum': self.text_knowledge_df.minimum_width,
|
||||
'text header tweak': self.text_knowledge_df.header_tweak,
|
||||
'text recommended': self.text_knowledge_df.recommended,
|
||||
'html recommended': self.html_knowledge_df.recommended,
|
||||
'tex recommended': self.tex_knowledge_df['scaled_tabs'],
|
||||
'tikz recommended': self.tex_knowledge_df['tikz_colw'],
|
||||
}).fillna(0)
|
||||
ser = pd.Series({
|
||||
'text natural': natural,
|
||||
'text minimum': minimum,
|
||||
'text header tweak': ht,
|
||||
@@ -978,13 +950,13 @@ class GT(object):
|
||||
'html recommended': h,
|
||||
'tex recommended': tex,
|
||||
'tikz recommended': tikz,
|
||||
'requested': mtw,
|
||||
'width mode' : self.config.table_width_mode,
|
||||
'header relax': self.config.table_width_header_adjust,
|
||||
'header chars': self.config.table_width_header_relax,
|
||||
}).to_frame('value')
|
||||
df.index.name = 'metric'
|
||||
return df
|
||||
})
|
||||
bit.loc['total', :] = ser
|
||||
print(f"requested width = {mtw}\n"
|
||||
f"width mode = {self.config.table_width_mode}\n"
|
||||
f"header relax = {self.config.table_width_header_adjust}\n"
|
||||
f"header chars = {self.config.table_width_header_relax}")
|
||||
return bit
|
||||
|
||||
def estimate_column_widths_by_mode(self, mode):
|
||||
"""
|
||||
@@ -1074,9 +1046,9 @@ class GT(object):
|
||||
PADDING = 2 # per column TODO enhance
|
||||
if self.config.table_width_mode == 'explicit':
|
||||
# target width INCLUDES padding and column marks |
|
||||
target_width = self.config.max_table_width - \
|
||||
(PADDING + 1) * n_col - 1
|
||||
logger.info(f'Col padding effect {self.config.max_table_width=}'
|
||||
target_width = self.max_table_width_em - \
|
||||
(PADDING + 1) * n_col - 1
|
||||
logger.info(f'Col padding effect {self.max_table_width_em=}'
|
||||
f' ==> {target_width=}')
|
||||
elif self.config.table_width_mode == 'natural':
|
||||
target_width = natural + (PADDING + 1) * n_col + 1
|
||||
@@ -1177,9 +1149,14 @@ class GT(object):
|
||||
target_width,
|
||||
ans['recommended'].sum() - target_width
|
||||
)
|
||||
else:
|
||||
# avoid a failure blow
|
||||
ans['raw_recommended'] = np.nan
|
||||
ans['header_tweak'] = np.nan
|
||||
ans['natural_w_header'] = np.nan
|
||||
else:
|
||||
# for html and tex modes: adapts from old estimate_column_widths
|
||||
target_width = self.config.max_table_width
|
||||
target_width = self.max_table_width_em
|
||||
nc_index = self.nindex
|
||||
|
||||
# without tex adjustment
|
||||
@@ -12,7 +12,7 @@ from pathlib import Path
|
||||
from subprocess import run, Popen, PIPE
|
||||
from IPython.display import SVG, display
|
||||
|
||||
from .gthasher import txt_short_hash
|
||||
from . hasher import txt_short_hash
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -9,10 +9,11 @@ import re
|
||||
from textwrap import wrap
|
||||
|
||||
import pandas as pd
|
||||
from pybtex.textutils import width
|
||||
from rich import box
|
||||
from rich.table import Table
|
||||
|
||||
from . gtformats import GT_Format, TableFormat, Line, DataRow
|
||||
from . formats import GT_Format, TableFormat, Line, DataRow
|
||||
|
||||
|
||||
__all__ = ['MD2DF', 'Escaping', 'TextLength',
|
||||
@@ -221,6 +222,88 @@ class TextLength:
|
||||
"?": 0.6,
|
||||
" ": 0.4,
|
||||
}
|
||||
width_table = {
|
||||
"a": 0.444,
|
||||
"b": 0.5,
|
||||
"c": 0.444,
|
||||
"d": 0.5,
|
||||
"e": 0.444,
|
||||
"f": 0.333,
|
||||
"g": 0.5,
|
||||
"h": 0.5,
|
||||
"i": 0.278,
|
||||
"j": 0.278,
|
||||
"k": 0.5,
|
||||
"l": 0.278,
|
||||
"m": 0.778,
|
||||
"n": 0.5,
|
||||
"o": 0.5,
|
||||
"p": 0.5,
|
||||
"q": 0.5,
|
||||
"r": 0.333,
|
||||
"s": 0.389,
|
||||
"t": 0.278,
|
||||
"u": 0.5,
|
||||
"v": 0.5,
|
||||
"w": 0.722,
|
||||
"x": 0.5,
|
||||
"y": 0.5,
|
||||
"z": 0.444,
|
||||
"A": 0.722,
|
||||
"B": 0.667,
|
||||
"C": 0.667,
|
||||
"D": 0.722,
|
||||
"E": 0.611,
|
||||
"F": 0.556,
|
||||
"G": 0.722,
|
||||
"H": 0.722,
|
||||
"I": 0.333,
|
||||
"J": 0.389,
|
||||
"K": 0.722,
|
||||
"L": 0.611,
|
||||
"M": 0.889,
|
||||
"N": 0.722,
|
||||
"O": 0.722,
|
||||
"P": 0.556,
|
||||
"Q": 0.722,
|
||||
"R": 0.667,
|
||||
"S": 0.556,
|
||||
"T": 0.611,
|
||||
"U": 0.722,
|
||||
"V": 0.722,
|
||||
"W": 0.944,
|
||||
"X": 0.722,
|
||||
"Y": 0.722,
|
||||
"Z": 0.611,
|
||||
"0": 0.5,
|
||||
"1": 0.5,
|
||||
"2": 0.5,
|
||||
"3": 0.5,
|
||||
"4": 0.5,
|
||||
"5": 0.5,
|
||||
"6": 0.5,
|
||||
"7": 0.5,
|
||||
"8": 0.5,
|
||||
"9": 0.5,
|
||||
".": 0.25,
|
||||
",": 0.25,
|
||||
":": 0.278,
|
||||
";": 0.278,
|
||||
"(": 0.333,
|
||||
")": 0.333,
|
||||
"[": 0.333,
|
||||
"]": 0.333,
|
||||
"’": 0.333,
|
||||
'"': 0.444,
|
||||
"!": 0.333,
|
||||
"?": 0.444,
|
||||
" ": 0.25,
|
||||
"|": 0.2,
|
||||
"‘": 0.333,
|
||||
"{": 0.48,
|
||||
"}": 0.48,
|
||||
"-": 0.333,
|
||||
}
|
||||
char_width = {c: w for chars, w in width_table.items() for c in chars}
|
||||
return char_width.get(c, 0.6)
|
||||
|
||||
+10
-1
@@ -1,5 +1,9 @@
|
||||
[build-system]
|
||||
requires = ["setuptools", "build"]
|
||||
requires = [
|
||||
"setuptools",
|
||||
"build",
|
||||
"setuptools_scm[toml]>=7.0"
|
||||
]
|
||||
build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
@@ -27,6 +31,11 @@ classifiers = [
|
||||
"Topic :: Office/Business"
|
||||
]
|
||||
|
||||
[tool.setuptools_scm]
|
||||
write_to = "greater_tables/_version.py"
|
||||
version_scheme = "post-release"
|
||||
local_scheme = "no-local-version"
|
||||
|
||||
[tool.setuptools.packages.find]
|
||||
include = ["greater_tables", "greater_tables.data"]
|
||||
exclude = ["img", "tests", "docs"]
|
||||
|
||||
Reference in New Issue
Block a user