Skip to main content

An ASCII plain text table renderer.

Project description

def table_string(table_columns: List[dict], table_dict: List[dict], header: bool=True, footer: bool=True) -> str:

    # analyse table_dict for lengths?
    table_width = 1
    return_string = ""
    for table_column in table_columns:
        table_width += table_column["width"] + 1

    if header:
        # return_string += f"{'=' * table_width}\n"
        for i, table_column in enumerate(table_columns):
            if i == 0:
                return_string += f"  {table_column['name']}{' ' * (table_column['width'] - len(table_column['name']) - 1)}"
        return_string += "|\n"
        for table_column in table_columns:
            return_string += f"┼{'-' * table_column['width']}"
        return_string += "|\n"
        for table_column in table_columns:
            return_string += f"|{' ' * table_column['width']}"
        return_string += "|\n"
        for table_column in table_columns:
            return_string += f"|{' ' * table_column['width']}"
        return_string += "|\n"
        for table_column in table_columns:
            return_string += f"|{' ' * table_column['width']}"
        return_string += "|\n"

    # return_string += f"{'=' * table_width}\n"




    for table_row in table_dict:
        for table_cell in table_row.items():
            pass

    return return_string


test_columns = [
    {
        "width": 40,
        "name": "Projects"
    },
    {
        "width": 20,
        "name": "Epochs"
    },
    {
        "width": 20,
        "name": "Collections"
    },
]

print(table_string(test_columns, test_columns))

"""

┏━━━━━━━━┳━━━━━━━┓
┃ item   ┃   qty ┃
┣━━━━━━━━╋━━━━━━━┫
┃ spam   ┃    42 ┃
┣━━━━━━━━╋━━━━━━━┫
┃ eggs   ┃   451 ┃
┣━━━━━━━━╋━━━━━━━┫
┃ bacon  ┃     0 ┃
┗━━━━━━━━┻━━━━━━━┛

╔════════════════╗
║ item   ┃   qty ║
╠════════════════╣
║ spam   ┃    42 ║
║━━━━━━━━╋━━━━━━━║
║ eggs   ┃   451 ║
║━━━━━━━━╋━━━━━━━║
║ bacon  ┃     0 ║
╚════════════════╝

╔════════════════╗
║ item   ┃   qty ║
╠════════════════╣
║ spam   ┃    42 ║
╠════════════════╣
║ eggs   ┃   451 ║
╠════════════════╣
║ bacon  ┃     0 ║
╚════════════════╝

┏━━━━━━━━┯━━━━━━━┓
┃ item   │   qty ┃
┠────────┼───────┨
┃ spam   │    42 ┃
┠────────┼───────┨
┃ eggs   │   451 ┃
┠────────┼───────┨
┃ bacon  │     0 ┃
┗━━━━━━━━┷━━━━━━━┛

┏━━━━━━━━┳━━━━━━━┓
┃ item   ┃   qty ┃
┣━━━━━━━━╇━━━━━━━┫
┃ spam   │    42 ┃
┠────────┼───────┨
┃ eggs   │   451 ┃
┠────────┼───────┨
┃ bacon  │     0 ┃
┗━━━━━━━━┷━━━━━━━┛


    ╔════════════════════════════════════════════╤═════╤═════╤═════╤═════╗
    ║ asdasdasd                        asdasdasd │ asd │ asd │ asd │ sdf ║
    ╠════════════════════════════════════════════╪═════╪═════╪═════╪═════╣
    ║ asd                                        │ asd │ asd │ asd │ sdf ║
    ╟────────────────────────────────────────────┼─────┼─────┼─────┼─────╢
    ║ sdf                                        │ sdf │ sdf │ sdf │ sdf ║
    ╟────────────────────────────────────────────┼─────┼─────┼─────┼─────╢
    ║ sdf                                        │ sdf │ sdf │ sdf │ sdf ║
    ╚════════════════════════════════════════════╧═════╧═════╧═════╧═════╝


╔════════════════════════════════════════════════════════════════════╗
║ PROJECT: Some Project                                              ║
╟────────────────────────────────────────────────────────────────────╢
║ And here is the project descript, whatever it might be. It might   ║
║ even be several lines.                                             ║
╠════════════════════════════════════════════╤═════╤═════╤═════╤═════╣
║ EPOCHS                                     │ asd │ asd │ asd │ sdf ║
╠════════════════════════════════════════════╪═════╪═════╪═════╪═════╣
║ asd                                        │ asd │ asd │ asd │ sdf ║
╟────────────────────────────────────────────┼─────┼─────┼─────┼─────╢
║ sdf                                        │ sdf │ sdf │ sdf │ sdf ║
╟────────────────────────────────────────────┼─────┼─────┼─────┼─────╢
║ sdf                                        │ sdf │ sdf │ sdf │ sdf ║
╚════════════════════════════════════════════╧═════╧═════╧═════╧═════╝


╔════════════════════════════════════════════════════════════════════╗
║ PROJECT: Some Project                                              ║
╟────────────────────────────────────────────────────────────────────╢
║ And here is the project descript, whatever it might be. It might   ║
║ even be several lines.                                             ║
╠════════════════════════════════════════════╤═════╤═════╤═════╤═════╣
║                   EPOCHS                   │ asd │ asd │ asd │ sdf ║
╠════════════════════════════════════════════╪═════╪═════╪═════╪═════╣
║ asd                                        │ asd │ asd │ asd │ sdf ║
╟────────────────────────────────────────────┼─────┼─────┼─────┼─────╢
║ sdf                                        │ sdf │ sdf │ sdf │ sdf ║
╟────────────────────────────────────────────┼─────┼─────┼─────┼─────╢
║ sdf                                        │ sdf │ sdf │ sdf │ sdf ║
╚════════════════════════════════════════════╧═════╧═════╧═════╧═════╝




╔════════════════════════════════════════════════════════════════════╗
║ PROJECT: Some Project                                              ║
╟────────────────────────────────────────────────────────────────────╢
║ And here is the project descript, whatever it might be.            ║
╠════════════════════════════════════════════╤═════╤═════╤═════╤═════╣
║ EPOCHS                                     │ asd │ asd │ asd │ sdf ║
╠════════════════════════════════════════════╪═════╪═════╪═════╪═════╣
║ Getting started                            │ asd │ asd │ asd │ sdf ║
╟────────────────────────────────────────────┼─────┼─────┼─────┼─────╢
║ Moving forward                             │ sdf │ sdf │ sdf │ sdf ║
╟────────────────────────────────────────────┼─────┼─────┼─────┼─────╢
║ Cleaning up                                │ sdf │ sdf │ sdf │ sdf ║
╚════════════════════════════════════════════╧═════╧═════╧═════╧═════╝




















╔════════════════════════════════════════════╤═══════╤═══════╤═══════╤════════╗
║ asdasdasd                                  │ asd   │ asd   │ asd   │ asd    ║
╟────────────────────────────────────────────┼───────┼───────┼───────┼────────╢
║ asd                                        │ asd   │ asd   │ asd   │ asd    ║
║ sdf                                        │ asd   │ asd   │ asd   │ asd    ║
║ sdf                                        │ asd   │ asd   │ asd   │ asd    ║
╚════════════════════════════════════════════╧═══════╧═══════╧═══════╧════════╝


┌────────────────────────────────────────────┬─────┬─────┬─────┬─────┐
│ asdasdasd                                  │ asd │ asd │ asd │ sdf │
├────────────────────────────────────────────┼─────┼─────┼─────┼─────┤
│ asd                                        │ asd │ asd │ asd │ sdf │
│ sdf                                        │ sdf │ sdf │ sdf │ sdf │
│ sdf                                        │ sdf │ sdf │ sdf │ sdf │
└────────────────────────────────────────────┴─────┴─────┴─────┴─────┘




┌────────────────────────────────────────────┬─────┬─────┬─────┬─────┐
│ asdasdasd                        asdasdasd │ asd │ asd │ asd │ sdf │
╞════════════════════════════════════════════╪═════╪═════╪═════╪═════╡
│ asd                                        │ asd │ asd │ asd │ sdf │
│ sdf                                        │ sdf │ sdf │ sdf │ sdf │
│ sdf                                        │ sdf │ sdf │ sdf │ sdf │
└────────────────────────────────────────────┴─────┴─────┴─────┴─────┘














    ╔════════════════════════════════════════════╤═══════════════════════╗
    ║                                            │     SUPER HEADER      ║
    ║ CLIENTS                                    │ ABC │ ABC │ ABC │ ABC ║
    ╠════════════════════════════════════════════╪═════╪═════╪═════╪═════╣
    ║ asd                                        │ asd │ asd │ asd │ sdf ║
    ╟────────────────────────────────────────────┼─────┼─────┼─────┼─────╢
    ║ sdf                                        │ sdf │ sdf │ sdf │ sdf ║
    ╟────────────────────────────────────────────┼─────┼─────┼─────┼─────╢
    ║ sdf                                        │ sdf │ sdf │ sdf │ sdf ║
    ╚════════════════════════════════════════════╧═════╧═════╧═════╧═════╝


    ╔════════════════════════════════════════════╤═══════════════════════╗
    ║                                            │                       ║
    ║                                            │     super header      ║
    ║                                            │                       ║
    ║ asdasdasd                                  │ asd │ asd │ asd │ sdf ║
    ╠════════════════════════════════════════════╪═════╪═════╪═════╪═════╣
    ║ asd                                        │ asd │ asd │ asd │ sdf ║
    ╟────────────────────────────────────────────┼─────┼─────┼─────┼─────╢
    ║ sdf                                        │ sdf │ sdf │ sdf │ sdf ║
    ╟────────────────────────────────────────────┼─────┼─────┼─────┼─────╢
    ║ sdf                                        │ sdf │ sdf │ sdf │ sdf ║
    ╚════════════════════════════════════════════╧═════╧═════╧═════╧═════╝

























"""


"""
│ ┃ ║

─ ━ ═

┌ ┏ ╔ ┍ ┎ ╒ ╓ * 4

├ ┣ ╠ ┠ ┝ ╟ ╞

┤ ┫ ╣ ┨ ┥ ╢ ╡

┼ ╋ ╬ ╂ ┿ ╀ ╁ ╇ ╈ ╫ ╪ 
"""

x = [
    "thin",
    "thick",
    "thin"
    "┿"
]

"""
│ ║

─ ═

┌ ╔ ╒ ╓ * 4

├ ╠ ╟ ╞

┤ ╣ ╢ ╡

┼ ╬ ╫ ╪ 
"""

"""
only thin for inner column... yes!

│ ┃ ║

─ ━ ═

┌ ┏ ╔ ┍ ┎ ╒ ╓     * 4

├ ┣ ╠ ┠ ┝ ╟ ╞ ║ ┃

┤ ┫ ╣ ┨ ┥ ╢ ╡ ║

┼ ┿ ╪ 
"""

"""
only thin for inner column... 
same same outer border...
yes yes!!!

│ ┃ ║

─ ━ ═

┌ ┏ ╔     * 4

├ ┣ ╠ ┠ ┝ ╟ ╞ ║ ┃

┤ ┫ ╣ ┨ ┥ ╢ ╡ ║ ┃

┼ ┿ ╪ 
"""


"""
only thin for inner column... 
same same outer border...
yes yes!!!

(sorted by outer first)

│ ┃ ║

─ ━ ═

┌ ┏ ╔     * 4

├ ┝ ╞ ┠ ┠ ┃ ╟ ║ ╠

┤ ┥ ╡ ┨ ┫ ┃ ╢ ║ ╣

┼ ┿ ╪ 

manageable...
"""

left_side_matrix = {
    "thin": {
        "thin": "├",
        "thick": "┝",
        "double": "╞"
    },
    "thick": {
        "thin": "┠",
        "thick": "┣",
        "double": "┃"
    },
    "double": {
        "thin": "╟",
        "thick": "║",
        "double": "╠"
    }
}

right_side_matrix = {
    "thin": {
        "thin": "┤",
        "thick": "┥",
        "double": "╡"
    },
    "thick": {
        "thin": "┨",
        "thick": "┫",
        "double": "┃"
    },
    "double": {
        "thin": "╢",
        "thick": "║",
        "double": "╣"
    }
}
                # A - is this an outer_border
                    # 1 - determine border type
                    # 2 - populate edge characters (in array [a])
                    # 2 - populate line (in array [b]) with line type
                    # 3 - calculate intersections (in an array of arrays [c])
                    # 5 - populate intersection (in array [b])
                    # 6 - generate string
                # B - is this a line row (should really only be between frames, me thinks...) (maybe each table row is a frame?)
                    # 1 - determine line type
                    # 2 - populate edge characters (in array [a])
                    # 3 - populate line (in array [b]) with line type
                    # 4 - calculate intersections (in an array of arrays [c])
                    # 5 - populate intersection (in array [b])
                    # 6 - generate string
                # C - is this a text line
                    # 1 - populate edge characters (in array [a])
                    # 2 - generate string


                # how much of this should be done above? ie: should the print just have complete frames? just handling the edge character?
                # (more specifically, handling the line rows above?)

                row_index = 0

thought for the future:

the reason for having each frame fully stringify itself and have to_string only handle the lines between frames was an attempt to balance to three considerations:

  • the dividing line can only be drawn when the frames both above and below are known ( so in to_string )
  • the original idea to leave padding and outer borders to to_string and the rest in the ... would be complicated because of the table row lines interacting with outer borders
  • reducing load on the to_string method to ensure smooth printing (perhaps not necessary... perform time tests)

maybe in the future it would be better to treat each row of the table as a frame and have to_string stringify everything

probably this will be less confusing and better unify concerns

new_to_string & new_add_ methods... to perform A/B tests

performance vs clean code...

(thought: perhaps the end of each add_ function could render all above??? could get messy...)

maybe perform speed test in constrained VM/container

finish everything else before doing this... (so not having to go too far back in time in case want to undo later...)

NOTE: currently... the table row lines are generated only once and reused...

one solution would be to define the line types... whether divider or text (so border can be correctly rendered) => too many checks (specific only for table...) in to_string

the trick is that there is so much logic specific to tables... => blank dividers for instance (actually this would not be a problem since this doesn't affect the row divider)

current timings:

  • add_table = 0.119ms
  • to_string = 0.047ms
  • print = 0.014ms
  • row_frame_divider = 0.006ms

  • for 20 row table, row_frame_divider would cost 0.12ms (vs 0.006 currently)
  • for 100 row table, row_frame_divider would cost 0.6ms (vs 0.006 currently)

conclusion: leave as is until a best of both worlds (clean and performant) solution can be found... the performance differences are too great.


Project details


Release history Release notifications | RSS feed

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

tablate-0.0.4.tar.gz (22.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

tablate-0.0.4-py3-none-any.whl (33.1 kB view details)

Uploaded Python 3

File details

Details for the file tablate-0.0.4.tar.gz.

File metadata

  • Download URL: tablate-0.0.4.tar.gz
  • Upload date:
  • Size: 22.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.9.16

File hashes

Hashes for tablate-0.0.4.tar.gz
Algorithm Hash digest
SHA256 178ad77e150b33016d45864bdf963fa820d278ccee19e6be467c0451136c3653
MD5 7cd95876e75c2c7bee5fba4232760939
BLAKE2b-256 293f07e225eb3e997768ac39916870f94a31cabb7ed02389a34be86c1715ecd5

See more details on using hashes here.

File details

Details for the file tablate-0.0.4-py3-none-any.whl.

File metadata

  • Download URL: tablate-0.0.4-py3-none-any.whl
  • Upload date:
  • Size: 33.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.9.16

File hashes

Hashes for tablate-0.0.4-py3-none-any.whl
Algorithm Hash digest
SHA256 faedfd79c8093cea3461ac6e1584c7d042ae08c0c9b35523eb2d2e39f0e5f882
MD5 95b57d26ffde9f0700dd432787320bca
BLAKE2b-256 1bf79626093f52a862f6d2a5e0ad0dd56e35568ed369ddc533b2b099bd980390

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page