Spaces:
Running
Running
Bor Hodošček
commited on
feat: initial working version
Browse files- Dockerfile +21 -0
- README.md +1 -1
- app.py +1247 -0
- development.md +8 -0
- pyproject.toml +12 -0
- uv.lock +600 -0
Dockerfile
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
FROM python:3.12-slim
|
2 |
+
COPY --from=ghcr.io/astral-sh/uv:0.7.13 /uv /bin/uv
|
3 |
+
|
4 |
+
RUN useradd -m -u 1000 user
|
5 |
+
ENV PATH="/home/user/.local/bin:$PATH"
|
6 |
+
ENV UV_SYSTEM_PYTHON=1
|
7 |
+
|
8 |
+
WORKDIR /app
|
9 |
+
|
10 |
+
RUN apt update && apt install -y curl unzip gcc g++
|
11 |
+
RUN mkdir -p /app && chown -R user:user /app
|
12 |
+
|
13 |
+
COPY --chown=user ./pyproject.toml ./uv.lock ./app.py /app
|
14 |
+
|
15 |
+
RUN chmod -R u+w /app
|
16 |
+
|
17 |
+
USER user
|
18 |
+
|
19 |
+
RUN uv sync
|
20 |
+
|
21 |
+
CMD ["uv", "run", "marimo", "run", "app.py", "--no-sandbox", "--include-code", "--host", "0.0.0.0", "--port", "7860"]
|
README.md
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
---
|
2 |
-
title:
|
3 |
emoji: 🐢
|
4 |
colorFrom: pink
|
5 |
colorTo: red
|
|
|
1 |
---
|
2 |
+
title: LLM Text Preprocessing Checker
|
3 |
emoji: 🐢
|
4 |
colorFrom: pink
|
5 |
colorTo: red
|
app.py
ADDED
@@ -0,0 +1,1247 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# /// script
|
2 |
+
# requires-python = ">=3.12"
|
3 |
+
# dependencies = [
|
4 |
+
# "charset-normalizer",
|
5 |
+
# "great-tables",
|
6 |
+
# "marimo",
|
7 |
+
# "pandas",
|
8 |
+
# ]
|
9 |
+
# ///
|
10 |
+
import marimo
|
11 |
+
|
12 |
+
__generated_with = "0.14.6"
|
13 |
+
app = marimo.App(width="full", app_title="LLM Text Preprocessing Checker")
|
14 |
+
|
15 |
+
|
16 |
+
@app.cell
|
17 |
+
def _():
|
18 |
+
import marimo as mo
|
19 |
+
|
20 |
+
return (mo,)
|
21 |
+
|
22 |
+
|
23 |
+
@app.cell
|
24 |
+
def _(mo):
|
25 |
+
mo.md(
|
26 |
+
r"""
|
27 |
+
# LLM Text Preprocessing Checker
|
28 |
+
|
29 |
+
Checks two files and provides the diff output as well as metrics on deleted and inserted characters.
|
30 |
+
Additionaly, provides a breakdown by Unicode character class of deletions and insertions.
|
31 |
+
|
32 |
+
Note that this uses a pure-Python Myers diff algorithm for the comparison and may not be performant for larger diffs.
|
33 |
+
"""
|
34 |
+
)
|
35 |
+
return
|
36 |
+
|
37 |
+
|
38 |
+
@app.cell
|
39 |
+
def _():
|
40 |
+
import unicodedata
|
41 |
+
from typing import List, Dict, Any
|
42 |
+
from dataclasses import dataclass
|
43 |
+
from enum import IntEnum
|
44 |
+
import html as python_html
|
45 |
+
from great_tables import GT, loc, style
|
46 |
+
import pandas as pd
|
47 |
+
|
48 |
+
class Operation(IntEnum):
|
49 |
+
DELETE = 0
|
50 |
+
INSERT = 1
|
51 |
+
EQUAL = 2
|
52 |
+
|
53 |
+
@dataclass(slots=True)
|
54 |
+
class Edit:
|
55 |
+
operation: Operation
|
56 |
+
old_start: int
|
57 |
+
old_end: int
|
58 |
+
new_start: int
|
59 |
+
new_end: int
|
60 |
+
old_text: str = ""
|
61 |
+
new_text: str = ""
|
62 |
+
|
63 |
+
DEL_STYLE = "background-color:#ffcccc;color:#880000;text-decoration:line-through;"
|
64 |
+
INS_STYLE = "background-color:#ccffcc;color:#008800;"
|
65 |
+
EQUAL_STYLE = "color:#666666;"
|
66 |
+
CONTAINER_STYLE = (
|
67 |
+
"font-family: ui-monospace, monospace; "
|
68 |
+
"white-space: pre-wrap; "
|
69 |
+
"line-height: 1.6; "
|
70 |
+
"padding: 20px; "
|
71 |
+
"background-color: #f8f9fa; "
|
72 |
+
"border-radius: 8px; "
|
73 |
+
"border: 1px solid #dee2e6;"
|
74 |
+
)
|
75 |
+
|
76 |
+
def classify_char(char: str) -> str:
|
77 |
+
"""Classify a character using Unicode categories."""
|
78 |
+
if not char:
|
79 |
+
return "empty"
|
80 |
+
|
81 |
+
category = unicodedata.category(char)
|
82 |
+
|
83 |
+
# Map Unicode categories to readable classifications
|
84 |
+
category_map = {
|
85 |
+
"Ll": "lowercase",
|
86 |
+
"Lu": "uppercase",
|
87 |
+
"Lt": "titlecase",
|
88 |
+
"Lm": "modifier_letter",
|
89 |
+
"Lo": "other_letter",
|
90 |
+
"Nd": "decimal_digit",
|
91 |
+
"Nl": "letter_number",
|
92 |
+
"No": "other_number",
|
93 |
+
"Pc": "connector_punctuation",
|
94 |
+
"Pd": "dash_punctuation",
|
95 |
+
"Ps": "open_punctuation",
|
96 |
+
"Pe": "close_punctuation",
|
97 |
+
"Pi": "initial_punctuation",
|
98 |
+
"Pf": "final_punctuation",
|
99 |
+
"Po": "other_punctuation",
|
100 |
+
"Sm": "math_symbol",
|
101 |
+
"Sc": "currency_symbol",
|
102 |
+
"Sk": "modifier_symbol",
|
103 |
+
"So": "other_symbol",
|
104 |
+
"Zs": "space",
|
105 |
+
"Zl": "line_separator",
|
106 |
+
"Zp": "paragraph_separator",
|
107 |
+
"Cc": "control",
|
108 |
+
"Cf": "format",
|
109 |
+
"Co": "private_use",
|
110 |
+
"Cn": "unassigned",
|
111 |
+
}
|
112 |
+
|
113 |
+
# Special handling for CJK
|
114 |
+
if "\u4e00" <= char <= "\u9fff":
|
115 |
+
return "cjk_ideograph"
|
116 |
+
elif "\u3040" <= char <= "\u309f":
|
117 |
+
return "hiragana"
|
118 |
+
elif "\u30a0" <= char <= "\u30ff":
|
119 |
+
return "katakana"
|
120 |
+
elif "\uac00" <= char <= "\ud7af":
|
121 |
+
return "hangul"
|
122 |
+
|
123 |
+
return category_map.get(category, category)
|
124 |
+
|
125 |
+
def _myers_backtrack(trace: List[List[int]], a: str, b: str) -> List[Edit]:
|
126 |
+
"""Back-tracking helper to materialise the edit script."""
|
127 |
+
edits: List[Edit] = []
|
128 |
+
n, m = len(a), len(b)
|
129 |
+
x, y = n, m
|
130 |
+
offset = len(trace[0]) // 2
|
131 |
+
|
132 |
+
# Walk the layers backwards
|
133 |
+
for d in range(len(trace) - 1, 0, -1):
|
134 |
+
v = trace[d]
|
135 |
+
k = x - y
|
136 |
+
idx = k + offset
|
137 |
+
|
138 |
+
# Determine the predecessor k'
|
139 |
+
if k == -d or (k != d and v[idx - 1] < v[idx + 1]):
|
140 |
+
k_prev = k + 1 # came from below (insertion)
|
141 |
+
else:
|
142 |
+
k_prev = k - 1 # came from right (deletion)
|
143 |
+
|
144 |
+
x_prev = trace[d - 1][k_prev + offset]
|
145 |
+
y_prev = x_prev - k_prev
|
146 |
+
|
147 |
+
# Emit the matching "snake"
|
148 |
+
while x > x_prev and y > y_prev:
|
149 |
+
x -= 1
|
150 |
+
y -= 1
|
151 |
+
edits.append(Edit(Operation.EQUAL, x, x + 1, y, y + 1, a[x], b[y]))
|
152 |
+
|
153 |
+
# Emit the single edit (INSERT or DELETE) that led to the snake
|
154 |
+
if x_prev == x: # insertion
|
155 |
+
y -= 1
|
156 |
+
edits.append(Edit(Operation.INSERT, x, x, y, y + 1, "", b[y]))
|
157 |
+
else: # deletion
|
158 |
+
x -= 1
|
159 |
+
edits.append(Edit(Operation.DELETE, x, x + 1, y, y, a[x], ""))
|
160 |
+
|
161 |
+
# Leading snake (d = 0) – everything matched at the start
|
162 |
+
while x > 0 and y > 0:
|
163 |
+
x -= 1
|
164 |
+
y -= 1
|
165 |
+
edits.append(Edit(Operation.EQUAL, x, x + 1, y, y + 1, a[x], b[y]))
|
166 |
+
|
167 |
+
# Any remaining leading insertions / deletions
|
168 |
+
while x > 0:
|
169 |
+
x -= 1
|
170 |
+
edits.append(Edit(Operation.DELETE, x, x + 1, y, y, a[x], ""))
|
171 |
+
while y > 0:
|
172 |
+
y -= 1
|
173 |
+
edits.append(Edit(Operation.INSERT, x, x, y, y + 1, "", b[y]))
|
174 |
+
|
175 |
+
edits.reverse()
|
176 |
+
return edits
|
177 |
+
|
178 |
+
def myers_diff(a: str, b: str) -> List[Edit]:
|
179 |
+
"""
|
180 |
+
Very fast Myers diff (O((N+M)·D) time, O(N+M) memory).
|
181 |
+
|
182 |
+
Returns a list of Edit objects (DELETE / INSERT / EQUAL).
|
183 |
+
"""
|
184 |
+
n, m = len(a), len(b)
|
185 |
+
if n == 0:
|
186 |
+
return [Edit(Operation.INSERT, 0, 0, 0, m, "", b)] if m else []
|
187 |
+
if m == 0:
|
188 |
+
return [Edit(Operation.DELETE, 0, n, 0, 0, a, "")] if n else []
|
189 |
+
|
190 |
+
max_d = n + m
|
191 |
+
offset = max_d # map k ∈ [-max_d .. +max_d] → index
|
192 |
+
v = [0] * (2 * max_d + 1) # current frontier
|
193 |
+
trace = [] # keeps a copy of v for every d
|
194 |
+
|
195 |
+
# Forward phase – build the "trace" that will be backtracked
|
196 |
+
for d in range(max_d + 1):
|
197 |
+
v_next = v[:] # copy *once* per layer
|
198 |
+
for k in range(-d, d + 1, 2):
|
199 |
+
idx = k + offset
|
200 |
+
|
201 |
+
# Choosing the predecessor (insertion vs deletion)
|
202 |
+
if k == -d or (k != d and v[idx - 1] < v[idx + 1]):
|
203 |
+
x = v[idx + 1] # insertion (move down)
|
204 |
+
else:
|
205 |
+
x = v[idx - 1] + 1 # deletion (move right)
|
206 |
+
|
207 |
+
y = x - k
|
208 |
+
|
209 |
+
# Greedy snake – march diagonally while chars match
|
210 |
+
while x < n and y < m and a[x] == b[y]:
|
211 |
+
x += 1
|
212 |
+
y += 1
|
213 |
+
|
214 |
+
v_next[idx] = x
|
215 |
+
|
216 |
+
# Reached the end – stop early
|
217 |
+
if x >= n and y >= m:
|
218 |
+
trace.append(v_next)
|
219 |
+
return _myers_backtrack(trace, a, b)
|
220 |
+
|
221 |
+
trace.append(v_next)
|
222 |
+
v = v_next # reuse buffer
|
223 |
+
|
224 |
+
# Should never get here
|
225 |
+
raise RuntimeError("diff failed")
|
226 |
+
|
227 |
+
def classify_text(text: str) -> Dict[str, int]:
|
228 |
+
"""Count characters by classification."""
|
229 |
+
if not text:
|
230 |
+
return {}
|
231 |
+
|
232 |
+
classifications = {}
|
233 |
+
for char in text:
|
234 |
+
char_class = classify_char(char)
|
235 |
+
classifications[char_class] = classifications.get(char_class, 0) + 1
|
236 |
+
|
237 |
+
return classifications
|
238 |
+
|
239 |
+
def classify_edits(edits: List[Edit]) -> Dict[Operation, Dict[str, int]]:
|
240 |
+
"""
|
241 |
+
Classify edit operations by character class.
|
242 |
+
Returns a nested dictionary: {operation: {char_class: count}}
|
243 |
+
"""
|
244 |
+
# Filter out EQUAL operations to save memory
|
245 |
+
change_edits = [e for e in edits if e.operation != Operation.EQUAL]
|
246 |
+
|
247 |
+
# Group all edits by operation type (not consecutive grouping)
|
248 |
+
edits_by_op = {}
|
249 |
+
for edit in change_edits:
|
250 |
+
if edit.operation not in edits_by_op:
|
251 |
+
edits_by_op[edit.operation] = []
|
252 |
+
edits_by_op[edit.operation].append(edit)
|
253 |
+
|
254 |
+
result = {}
|
255 |
+
for op, edit_list in edits_by_op.items():
|
256 |
+
combined_text = ""
|
257 |
+
if op == Operation.DELETE:
|
258 |
+
combined_text = "".join(e.old_text for e in edit_list)
|
259 |
+
elif op == Operation.INSERT:
|
260 |
+
combined_text = "".join(e.new_text for e in edit_list)
|
261 |
+
|
262 |
+
result[op] = classify_text(combined_text)
|
263 |
+
|
264 |
+
return result
|
265 |
+
|
266 |
+
def calculate_change_metrics(
|
267 |
+
original: str,
|
268 |
+
edits: List[Edit],
|
269 |
+
classifications: Dict[Operation, Dict[str, int]],
|
270 |
+
) -> Dict[str, Any]:
|
271 |
+
"""Calculate detailed change metrics including percentages."""
|
272 |
+
metrics = {
|
273 |
+
"total_original_chars": len(original),
|
274 |
+
"total_deleted_chars": 0,
|
275 |
+
"total_inserted_chars": 0,
|
276 |
+
"deletion_percentage": 0.0,
|
277 |
+
"insertion_percentage": 0.0,
|
278 |
+
"net_change_percentage": 0.0,
|
279 |
+
"char_class_metrics": {},
|
280 |
+
}
|
281 |
+
|
282 |
+
# Calculate total changes
|
283 |
+
for edit in edits:
|
284 |
+
if edit.operation == Operation.DELETE:
|
285 |
+
metrics["total_deleted_chars"] += len(edit.old_text)
|
286 |
+
elif edit.operation == Operation.INSERT:
|
287 |
+
metrics["total_inserted_chars"] += len(edit.new_text)
|
288 |
+
|
289 |
+
# Calculate percentages
|
290 |
+
if metrics["total_original_chars"] > 0:
|
291 |
+
metrics["deletion_percentage"] = (
|
292 |
+
metrics["total_deleted_chars"] / metrics["total_original_chars"]
|
293 |
+
) * 100
|
294 |
+
metrics["insertion_percentage"] = (
|
295 |
+
metrics["total_inserted_chars"] / metrics["total_original_chars"]
|
296 |
+
) * 100
|
297 |
+
net_change = (
|
298 |
+
metrics["total_inserted_chars"] - metrics["total_deleted_chars"]
|
299 |
+
)
|
300 |
+
metrics["net_change_percentage"] = (
|
301 |
+
net_change / metrics["total_original_chars"]
|
302 |
+
) * 100
|
303 |
+
|
304 |
+
# Get character classification of original text
|
305 |
+
original_classifications = classify_text(original)
|
306 |
+
|
307 |
+
# Calculate per-character-class metrics
|
308 |
+
all_char_classes = set()
|
309 |
+
for op_classes in classifications.values():
|
310 |
+
all_char_classes.update(op_classes.keys())
|
311 |
+
all_char_classes.update(original_classifications.keys())
|
312 |
+
|
313 |
+
for char_class in all_char_classes:
|
314 |
+
original_count = original_classifications.get(char_class, 0)
|
315 |
+
deleted_count = classifications.get(Operation.DELETE, {}).get(char_class, 0)
|
316 |
+
inserted_count = classifications.get(Operation.INSERT, {}).get(
|
317 |
+
char_class, 0
|
318 |
+
)
|
319 |
+
|
320 |
+
class_metrics = {
|
321 |
+
"original_count": original_count,
|
322 |
+
"deleted_count": deleted_count,
|
323 |
+
"inserted_count": inserted_count,
|
324 |
+
"deletion_percentage": 0.0,
|
325 |
+
"insertion_percentage": 0.0,
|
326 |
+
}
|
327 |
+
|
328 |
+
if original_count > 0:
|
329 |
+
class_metrics["deletion_percentage"] = (
|
330 |
+
deleted_count / original_count
|
331 |
+
) * 100
|
332 |
+
|
333 |
+
# Insertion percentage relative to original count of this class
|
334 |
+
if original_count > 0:
|
335 |
+
class_metrics["insertion_percentage"] = (
|
336 |
+
inserted_count / original_count
|
337 |
+
) * 100
|
338 |
+
elif inserted_count > 0:
|
339 |
+
# If there were none originally, show as new
|
340 |
+
class_metrics["insertion_percentage"] = float("inf")
|
341 |
+
|
342 |
+
metrics["char_class_metrics"][char_class] = class_metrics
|
343 |
+
|
344 |
+
return metrics
|
345 |
+
|
346 |
+
def escape_html(text: str) -> str:
|
347 |
+
"""Escape HTML and make whitespace visible."""
|
348 |
+
# First escape HTML
|
349 |
+
text = python_html.escape(text)
|
350 |
+
# Make whitespace visible
|
351 |
+
ws_trans = str.maketrans({" ": "·", "\t": "→ ", "\n": "¶\n"})
|
352 |
+
return text.translate(ws_trans)
|
353 |
+
|
354 |
+
def generate_html_diff(
|
355 |
+
edits: List[Edit], show_equal: bool = True, max_equal_length: int = 100
|
356 |
+
) -> str:
|
357 |
+
"""Generate HTML visualization of the diff with performance optimizations."""
|
358 |
+
# Pre-allocate list for better performance
|
359 |
+
html_parts = []
|
360 |
+
|
361 |
+
# Group consecutive edits of the same type to reduce HTML tags
|
362 |
+
grouped_edits = []
|
363 |
+
current_group = []
|
364 |
+
current_op = None
|
365 |
+
|
366 |
+
for edit in edits:
|
367 |
+
if (
|
368 |
+
edit.operation == current_op and len(current_group) < 100
|
369 |
+
): # Batch up to 100
|
370 |
+
current_group.append(edit)
|
371 |
+
else:
|
372 |
+
if current_group:
|
373 |
+
grouped_edits.append((current_op, current_group))
|
374 |
+
current_group = [edit]
|
375 |
+
current_op = edit.operation
|
376 |
+
|
377 |
+
if current_group:
|
378 |
+
grouped_edits.append((current_op, current_group))
|
379 |
+
|
380 |
+
# Process grouped edits
|
381 |
+
for op, group in grouped_edits:
|
382 |
+
if op == Operation.DELETE:
|
383 |
+
combined_text = "".join(e.old_text for e in group)
|
384 |
+
escaped = escape_html(combined_text)
|
385 |
+
html_parts.append(
|
386 |
+
f'<span style="{DEL_STYLE}" title="Deleted">{escaped}</span>'
|
387 |
+
)
|
388 |
+
elif op == Operation.INSERT:
|
389 |
+
combined_text = "".join(e.new_text for e in group)
|
390 |
+
escaped = escape_html(combined_text)
|
391 |
+
html_parts.append(
|
392 |
+
f'<span style="{INS_STYLE}" title="Added">{escaped}</span>'
|
393 |
+
)
|
394 |
+
elif op == Operation.EQUAL and show_equal:
|
395 |
+
combined_text = "".join(e.old_text for e in group)
|
396 |
+
# Truncate very long equal sections
|
397 |
+
if len(combined_text) > max_equal_length:
|
398 |
+
start = escape_html(combined_text[: max_equal_length // 2])
|
399 |
+
end = escape_html(combined_text[-max_equal_length // 2 :])
|
400 |
+
omitted = len(combined_text) - max_equal_length
|
401 |
+
html_parts.append(
|
402 |
+
f'<span style="{EQUAL_STYLE}">{start}'
|
403 |
+
f"<em>...{omitted} chars omitted...</em>"
|
404 |
+
f"{end}</span>"
|
405 |
+
)
|
406 |
+
else:
|
407 |
+
escaped = escape_html(combined_text)
|
408 |
+
html_parts.append(f'<span style="{EQUAL_STYLE}">{escaped}</span>')
|
409 |
+
|
410 |
+
return f'<div style="{CONTAINER_STYLE}">{"".join(html_parts)}</div>'
|
411 |
+
|
412 |
+
def generate_side_by_side_html(edits: List[Edit]) -> str:
|
413 |
+
"""Generate side-by-side HTML diff view."""
|
414 |
+
old_parts = []
|
415 |
+
new_parts = []
|
416 |
+
|
417 |
+
for edit in edits:
|
418 |
+
if edit.operation == Operation.DELETE:
|
419 |
+
escaped = escape_html(edit.old_text)
|
420 |
+
old_parts.append(f'<span style="{DEL_STYLE}">{escaped}</span>')
|
421 |
+
elif edit.operation == Operation.INSERT:
|
422 |
+
escaped = escape_html(edit.new_text)
|
423 |
+
new_parts.append(f'<span style="{INS_STYLE}">{escaped}</span>')
|
424 |
+
elif edit.operation == Operation.EQUAL:
|
425 |
+
escaped = escape_html(edit.old_text)
|
426 |
+
old_parts.append(f"<span>{escaped}</span>")
|
427 |
+
new_parts.append(f"<span>{escaped}</span>")
|
428 |
+
|
429 |
+
return f'''
|
430 |
+
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 20px;">
|
431 |
+
<div>
|
432 |
+
<h4 style="margin: 0 0 10px 0;">Original</h4>
|
433 |
+
<div style="{CONTAINER_STYLE}">{"".join(old_parts)}</div>
|
434 |
+
</div>
|
435 |
+
<div>
|
436 |
+
<h4 style="margin: 0 0 10px 0;">Processed</h4>
|
437 |
+
<div style="{CONTAINER_STYLE}">{"".join(new_parts)}</div>
|
438 |
+
</div>
|
439 |
+
</div>
|
440 |
+
'''
|
441 |
+
|
442 |
+
def generate_html_diff_fast(edits: List[Edit], context_chars: int = 5) -> str:
|
443 |
+
"""
|
444 |
+
Ultra-fast HTML diff generation showing only changes with context.
|
445 |
+
"""
|
446 |
+
html_parts = []
|
447 |
+
|
448 |
+
# Filter to only show changes and surrounding context
|
449 |
+
change_indices = [
|
450 |
+
i for i, e in enumerate(edits) if e.operation != Operation.EQUAL
|
451 |
+
]
|
452 |
+
|
453 |
+
if not change_indices:
|
454 |
+
return '<div style="{CONTAINER_STYLE}">No changes found.</div>'
|
455 |
+
|
456 |
+
# Build ranges to show (change + context)
|
457 |
+
ranges_to_show = []
|
458 |
+
start = max(0, change_indices[0] - context_chars)
|
459 |
+
end = min(len(edits), change_indices[0] + context_chars + 1)
|
460 |
+
|
461 |
+
for idx in change_indices[1:]:
|
462 |
+
if idx - end <= context_chars * 2:
|
463 |
+
# Extend current range
|
464 |
+
end = min(len(edits), idx + context_chars + 1)
|
465 |
+
else:
|
466 |
+
# Save current range and start new one
|
467 |
+
ranges_to_show.append((start, end))
|
468 |
+
start = max(0, idx - context_chars)
|
469 |
+
end = min(len(edits), idx + context_chars + 1)
|
470 |
+
|
471 |
+
ranges_to_show.append((start, end))
|
472 |
+
|
473 |
+
# Generate HTML for ranges
|
474 |
+
for i, (start, end) in enumerate(ranges_to_show):
|
475 |
+
if i > 0:
|
476 |
+
html_parts.append(
|
477 |
+
'<div style="color:#999;text-align:center;margin:10px 0;">...</div>'
|
478 |
+
)
|
479 |
+
|
480 |
+
for j in range(start, end):
|
481 |
+
edit = edits[j]
|
482 |
+
if edit.operation == Operation.DELETE:
|
483 |
+
escaped = escape_html(edit.old_text)
|
484 |
+
html_parts.append(f'<span style="{DEL_STYLE}">{escaped}</span>')
|
485 |
+
elif edit.operation == Operation.INSERT:
|
486 |
+
escaped = escape_html(edit.new_text)
|
487 |
+
html_parts.append(f'<span style="{INS_STYLE}">{escaped}</span>')
|
488 |
+
else: # EQUAL
|
489 |
+
escaped = escape_html(edit.old_text)
|
490 |
+
html_parts.append(f'<span style="{EQUAL_STYLE}">{escaped}</span>')
|
491 |
+
|
492 |
+
return f'<div style="{CONTAINER_STYLE}">{"".join(html_parts)}</div>'
|
493 |
+
|
494 |
+
def generate_side_by_side_html_fast(
|
495 |
+
edits: List[Edit], context_chars: int = 5
|
496 |
+
) -> str:
|
497 |
+
"""
|
498 |
+
Fast side-by-side HTML diff generation showing only changes with context.
|
499 |
+
"""
|
500 |
+
# Filter to only show changes and surrounding context
|
501 |
+
change_indices = [
|
502 |
+
i for i, e in enumerate(edits) if e.operation != Operation.EQUAL
|
503 |
+
]
|
504 |
+
|
505 |
+
if not change_indices:
|
506 |
+
return """
|
507 |
+
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 20px;">
|
508 |
+
<div>
|
509 |
+
<h4 style="margin: 0 0 10px 0;">Original</h4>
|
510 |
+
<div style="{CONTAINER_STYLE}">No changes found.</div>
|
511 |
+
</div>
|
512 |
+
<div>
|
513 |
+
<h4 style="margin: 0 0 10px 0;">Processed</h4>
|
514 |
+
<div style="{CONTAINER_STYLE}">No changes found.</div>
|
515 |
+
</div>
|
516 |
+
</div>
|
517 |
+
"""
|
518 |
+
|
519 |
+
# Build ranges to show (change + context)
|
520 |
+
ranges_to_show = []
|
521 |
+
start = max(0, change_indices[0] - context_chars)
|
522 |
+
end = min(len(edits), change_indices[0] + context_chars + 1)
|
523 |
+
|
524 |
+
for idx in change_indices[1:]:
|
525 |
+
if idx - end <= context_chars * 2:
|
526 |
+
# Extend current range
|
527 |
+
end = min(len(edits), idx + context_chars + 1)
|
528 |
+
else:
|
529 |
+
# Save current range and start new one
|
530 |
+
ranges_to_show.append((start, end))
|
531 |
+
start = max(0, idx - context_chars)
|
532 |
+
end = min(len(edits), idx + context_chars + 1)
|
533 |
+
|
534 |
+
ranges_to_show.append((start, end))
|
535 |
+
|
536 |
+
# Generate HTML for ranges
|
537 |
+
old_parts = []
|
538 |
+
new_parts = []
|
539 |
+
|
540 |
+
for i, (start, end) in enumerate(ranges_to_show):
|
541 |
+
if i > 0:
|
542 |
+
separator = (
|
543 |
+
'<div style="color:#999;text-align:center;margin:10px 0;">...</div>'
|
544 |
+
)
|
545 |
+
old_parts.append(separator)
|
546 |
+
new_parts.append(separator)
|
547 |
+
|
548 |
+
for j in range(start, end):
|
549 |
+
edit = edits[j]
|
550 |
+
if edit.operation == Operation.DELETE:
|
551 |
+
escaped = escape_html(edit.old_text)
|
552 |
+
old_parts.append(f'<span style="{DEL_STYLE}">{escaped}</span>')
|
553 |
+
elif edit.operation == Operation.INSERT:
|
554 |
+
escaped = escape_html(edit.new_text)
|
555 |
+
new_parts.append(f'<span style="{INS_STYLE}">{escaped}</span>')
|
556 |
+
else: # EQUAL
|
557 |
+
escaped = escape_html(edit.old_text)
|
558 |
+
old_parts.append(f'<span style="{EQUAL_STYLE}">{escaped}</span>')
|
559 |
+
new_parts.append(f'<span style="{EQUAL_STYLE}">{escaped}</span>')
|
560 |
+
|
561 |
+
return f'''
|
562 |
+
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 20px;">
|
563 |
+
<div>
|
564 |
+
<h4 style="margin: 0 0 10px 0;">Original</h4>
|
565 |
+
<div style="{CONTAINER_STYLE}">{"".join(old_parts)}</div>
|
566 |
+
</div>
|
567 |
+
<div>
|
568 |
+
<h4 style="margin: 0 0 10px 0;">Processed</h4>
|
569 |
+
<div style="{CONTAINER_STYLE}">{"".join(new_parts)}</div>
|
570 |
+
</div>
|
571 |
+
</div>
|
572 |
+
'''
|
573 |
+
|
574 |
+
def operation_to_past(op: Operation) -> str:
|
575 |
+
if op == Operation.INSERT:
|
576 |
+
return "inserted"
|
577 |
+
else:
|
578 |
+
return str(op) + "d"
|
579 |
+
|
580 |
+
def format_diff_summary(
|
581 |
+
edits: List[Edit],
|
582 |
+
classifications: Dict[Operation, Dict[str, int]],
|
583 |
+
metrics: Dict[str, Any],
|
584 |
+
) -> str:
|
585 |
+
"""Create a human-readable summary of the diff."""
|
586 |
+
lines = ["## Diff Summary\n"]
|
587 |
+
|
588 |
+
# Overall statistics
|
589 |
+
lines.append("### Overall Statistics")
|
590 |
+
lines.append(
|
591 |
+
f"- **Original text**: {metrics['total_original_chars']:,} characters"
|
592 |
+
)
|
593 |
+
|
594 |
+
# Format deletions
|
595 |
+
del_pct = format_percentage(metrics["deletion_percentage"])
|
596 |
+
lines.append(
|
597 |
+
f"- **Deletions**: {metrics['total_deleted_chars']:,} characters ({del_pct})"
|
598 |
+
)
|
599 |
+
|
600 |
+
# Format insertions
|
601 |
+
ins_pct = format_percentage(metrics["insertion_percentage"])
|
602 |
+
lines.append(
|
603 |
+
f"- **Insertions**: {metrics['total_inserted_chars']:,} characters ({ins_pct})"
|
604 |
+
)
|
605 |
+
|
606 |
+
# Format net change
|
607 |
+
net_pct = metrics["net_change_percentage"]
|
608 |
+
if abs(net_pct) < 0.01:
|
609 |
+
net_pct_str = f"{net_pct:+.3f}%"
|
610 |
+
else:
|
611 |
+
net_pct_str = f"{net_pct:+.1f}%"
|
612 |
+
|
613 |
+
lines.append(
|
614 |
+
f"- **Net change**: {net_pct_str} "
|
615 |
+
f"({'increase' if metrics['net_change_percentage'] > 0 else 'decrease' if metrics['net_change_percentage'] < 0 else 'no change'})"
|
616 |
+
)
|
617 |
+
|
618 |
+
# Character classifications
|
619 |
+
if classifications:
|
620 |
+
lines.append("\n### Character Classifications")
|
621 |
+
|
622 |
+
# Show changes by character class
|
623 |
+
for op in [Operation.DELETE, Operation.INSERT]:
|
624 |
+
if op in classifications and classifications[op]:
|
625 |
+
lines.append(f"\n**{operation_to_past(op).title()} Characters:**")
|
626 |
+
for char_class, count in sorted(
|
627 |
+
classifications[op].items(), key=lambda x: -x[1]
|
628 |
+
):
|
629 |
+
lines.append(
|
630 |
+
f"- {char_class.replace('_', ' ').title()}: {count}"
|
631 |
+
)
|
632 |
+
|
633 |
+
# Show percentage changes by character class
|
634 |
+
lines.append("\n### Change Percentages by Character Class")
|
635 |
+
|
636 |
+
# Sort by most changed (highest deletion or insertion percentage)
|
637 |
+
sorted_classes = sorted(
|
638 |
+
metrics["char_class_metrics"].items(),
|
639 |
+
key=lambda x: max(
|
640 |
+
x[1]["deletion_percentage"],
|
641 |
+
0
|
642 |
+
if x[1]["insertion_percentage"] == float("inf")
|
643 |
+
else x[1]["insertion_percentage"],
|
644 |
+
),
|
645 |
+
reverse=True,
|
646 |
+
)
|
647 |
+
|
648 |
+
for char_class, class_metrics in sorted_classes:
|
649 |
+
if (
|
650 |
+
class_metrics["deleted_count"] > 0
|
651 |
+
or class_metrics["inserted_count"] > 0
|
652 |
+
):
|
653 |
+
class_name = char_class.replace("_", " ").title()
|
654 |
+
|
655 |
+
# Format the line
|
656 |
+
line_parts = [f"- **{class_name}**:"]
|
657 |
+
|
658 |
+
if class_metrics["original_count"] > 0:
|
659 |
+
line_parts.append(
|
660 |
+
f"Original: {class_metrics['original_count']}"
|
661 |
+
)
|
662 |
+
|
663 |
+
if class_metrics["deleted_count"] > 0:
|
664 |
+
line_parts.append(
|
665 |
+
f"Deleted: {class_metrics['deleted_count']} "
|
666 |
+
f"({class_metrics['deletion_percentage']:.1f}%)"
|
667 |
+
)
|
668 |
+
|
669 |
+
if class_metrics["inserted_count"] > 0:
|
670 |
+
if class_metrics["insertion_percentage"] == float("inf"):
|
671 |
+
line_parts.append(
|
672 |
+
f"Inserted: {class_metrics['inserted_count']} (new)"
|
673 |
+
)
|
674 |
+
else:
|
675 |
+
line_parts.append(
|
676 |
+
f"Inserted: {class_metrics['inserted_count']} "
|
677 |
+
f"({class_metrics['insertion_percentage']:.1f}%)"
|
678 |
+
)
|
679 |
+
|
680 |
+
lines.append(" | ".join(line_parts))
|
681 |
+
|
682 |
+
return "\n".join(lines)
|
683 |
+
|
684 |
+
def format_percentage(value: float, min_decimals: int = 1) -> str:
|
685 |
+
"""Format percentage with adaptive decimal places."""
|
686 |
+
if value == 0:
|
687 |
+
return "0%"
|
688 |
+
elif value < 0.01:
|
689 |
+
return f"{value:.3f}%" # Show 3 decimals for very small values
|
690 |
+
elif value < 0.1:
|
691 |
+
return f"{value:.2f}%" # Show 2 decimals for small values
|
692 |
+
elif value < 1:
|
693 |
+
return f"{value:.1f}%" # Show 1 decimal for values < 1%
|
694 |
+
else:
|
695 |
+
return f"{value:.0f}%" # No decimals for values >= 1%
|
696 |
+
|
697 |
+
def classify_edits_with_chars(
|
698 |
+
edits: List[Edit],
|
699 |
+
) -> Dict[Operation, Dict[str, Dict[str, int]]]:
|
700 |
+
"""
|
701 |
+
Classify edit operations by character class and track character frequencies.
|
702 |
+
Returns: {operation: {char_class: {char: count}}}
|
703 |
+
"""
|
704 |
+
from collections import defaultdict, Counter
|
705 |
+
|
706 |
+
# Filter out EQUAL operations
|
707 |
+
change_edits = [e for e in edits if e.operation != Operation.EQUAL]
|
708 |
+
|
709 |
+
# Track characters by operation and classification
|
710 |
+
result = defaultdict(lambda: defaultdict(Counter))
|
711 |
+
|
712 |
+
for edit in change_edits:
|
713 |
+
text = (
|
714 |
+
edit.old_text if edit.operation == Operation.DELETE else edit.new_text
|
715 |
+
)
|
716 |
+
|
717 |
+
for char in text:
|
718 |
+
char_class = classify_char(char)
|
719 |
+
result[edit.operation][char_class][char] += 1
|
720 |
+
|
721 |
+
return dict(result)
|
722 |
+
|
723 |
+
def get_top_chars(char_counter: Dict[str, int], n: int = 5) -> str:
|
724 |
+
"""Get top n characters by frequency, formatted for display."""
|
725 |
+
if not char_counter:
|
726 |
+
return "-"
|
727 |
+
|
728 |
+
# Sort by frequency and take top n
|
729 |
+
top_chars = sorted(char_counter.items(), key=lambda x: -x[1])[:n]
|
730 |
+
|
731 |
+
# Format characters for display
|
732 |
+
formatted_chars = []
|
733 |
+
for char, _ in top_chars:
|
734 |
+
if char == " ":
|
735 |
+
formatted_chars.append("·") # Middle dot for space
|
736 |
+
elif char == "\n":
|
737 |
+
formatted_chars.append("¶") # Pilcrow for newline
|
738 |
+
elif char == "\t":
|
739 |
+
formatted_chars.append("→") # Arrow for tab
|
740 |
+
elif ord(char) < 32 or ord(char) == 127:
|
741 |
+
formatted_chars.append(f"\\x{ord(char):02x}") # Hex for control chars
|
742 |
+
else:
|
743 |
+
formatted_chars.append(char)
|
744 |
+
|
745 |
+
return " ".join(formatted_chars)
|
746 |
+
|
747 |
+
def create_summary_tables(
|
748 |
+
edits: List[Edit],
|
749 |
+
classifications: Dict[Operation, Dict[str, int]],
|
750 |
+
metrics: Dict[str, Any],
|
751 |
+
) -> Dict[str, GT]:
|
752 |
+
"""Create great_tables tables for the diff summary."""
|
753 |
+
|
754 |
+
# Get detailed character data
|
755 |
+
detailed_classifications = classify_edits_with_chars(edits)
|
756 |
+
|
757 |
+
# Table 1: Overall Statistics (unchanged)
|
758 |
+
overall_data = pd.DataFrame(
|
759 |
+
{
|
760 |
+
"Metric": [
|
761 |
+
"Original Length",
|
762 |
+
"Characters Deleted",
|
763 |
+
"Characters Inserted",
|
764 |
+
"Net Change",
|
765 |
+
],
|
766 |
+
"Count": [
|
767 |
+
metrics["total_original_chars"],
|
768 |
+
metrics["total_deleted_chars"],
|
769 |
+
metrics["total_inserted_chars"],
|
770 |
+
metrics["total_inserted_chars"] - metrics["total_deleted_chars"],
|
771 |
+
],
|
772 |
+
"Percentage": [
|
773 |
+
"-",
|
774 |
+
format_percentage(metrics["deletion_percentage"]),
|
775 |
+
format_percentage(metrics["insertion_percentage"]),
|
776 |
+
f"{metrics['net_change_percentage']:+.3f}%"
|
777 |
+
if abs(metrics["net_change_percentage"]) < 0.01
|
778 |
+
else f"{metrics['net_change_percentage']:+.1f}%",
|
779 |
+
],
|
780 |
+
}
|
781 |
+
)
|
782 |
+
|
783 |
+
overall_table = (
|
784 |
+
GT(overall_data)
|
785 |
+
.tab_header(
|
786 |
+
title="Text Change Summary",
|
787 |
+
subtitle=f"Total edits: {len([e for e in edits if e.operation != Operation.EQUAL])}",
|
788 |
+
)
|
789 |
+
.fmt_number(columns="Count", decimals=0, use_seps=True)
|
790 |
+
.tab_style(
|
791 |
+
style=[style.fill(color="#f0f0f0"), style.text(weight="bold")],
|
792 |
+
locations=loc.body(rows=[3]),
|
793 |
+
)
|
794 |
+
.cols_align(align="center", columns=["Count", "Percentage"])
|
795 |
+
.opt_stylize(style=1, color="blue")
|
796 |
+
)
|
797 |
+
|
798 |
+
# Table 2: Character Class Changes with top characters
|
799 |
+
char_class_data = []
|
800 |
+
|
801 |
+
# Get all character classes
|
802 |
+
all_classes = set()
|
803 |
+
for op_classes in classifications.values():
|
804 |
+
all_classes.update(op_classes.keys())
|
805 |
+
all_classes.update(metrics["char_class_metrics"].keys())
|
806 |
+
|
807 |
+
# Build rows
|
808 |
+
for char_class in sorted(all_classes):
|
809 |
+
class_metrics = metrics["char_class_metrics"].get(char_class, {})
|
810 |
+
|
811 |
+
# Get top characters for this class
|
812 |
+
del_chars = detailed_classifications.get(Operation.DELETE, {}).get(
|
813 |
+
char_class, {}
|
814 |
+
)
|
815 |
+
ins_chars = detailed_classifications.get(Operation.INSERT, {}).get(
|
816 |
+
char_class, {}
|
817 |
+
)
|
818 |
+
|
819 |
+
row = {
|
820 |
+
"Character Class": char_class.replace("_", " ").title(),
|
821 |
+
"Original": class_metrics.get("original_count", 0),
|
822 |
+
"Deleted": class_metrics.get("deleted_count", 0),
|
823 |
+
"Top Deleted": get_top_chars(del_chars, 5),
|
824 |
+
"Inserted": class_metrics.get("inserted_count", 0),
|
825 |
+
"Top Inserted": get_top_chars(ins_chars, 5),
|
826 |
+
"Del %": format_percentage(class_metrics.get("deletion_percentage", 0))
|
827 |
+
if class_metrics.get("deletion_percentage", 0) > 0
|
828 |
+
else "-",
|
829 |
+
"Ins %": (
|
830 |
+
"new"
|
831 |
+
if class_metrics.get("insertion_percentage", 0) == float("inf")
|
832 |
+
else format_percentage(class_metrics.get("insertion_percentage", 0))
|
833 |
+
if class_metrics.get("insertion_percentage", 0) > 0
|
834 |
+
else "-"
|
835 |
+
),
|
836 |
+
}
|
837 |
+
|
838 |
+
# Only include rows with changes
|
839 |
+
if row["Deleted"] > 0 or row["Inserted"] > 0:
|
840 |
+
char_class_data.append(row)
|
841 |
+
|
842 |
+
if char_class_data:
|
843 |
+
char_class_df = pd.DataFrame(char_class_data)
|
844 |
+
char_class_table = (
|
845 |
+
GT(char_class_df)
|
846 |
+
.tab_header(title="Changes by Character Classification")
|
847 |
+
.fmt_number(
|
848 |
+
columns=["Original", "Deleted", "Inserted"],
|
849 |
+
decimals=0,
|
850 |
+
use_seps=True,
|
851 |
+
)
|
852 |
+
.tab_style(
|
853 |
+
style=style.fill(color="#ffcccc"),
|
854 |
+
locations=loc.body(columns=["Deleted", "Top Deleted"]),
|
855 |
+
)
|
856 |
+
.tab_style(
|
857 |
+
style=style.fill(color="#ccffcc"),
|
858 |
+
locations=loc.body(columns=["Inserted", "Top Inserted"]),
|
859 |
+
)
|
860 |
+
.tab_style(
|
861 |
+
style=style.text(font="monospace"),
|
862 |
+
locations=loc.body(columns=["Top Deleted", "Top Inserted"]),
|
863 |
+
)
|
864 |
+
.cols_align(
|
865 |
+
align="center",
|
866 |
+
columns=["Original", "Deleted", "Inserted", "Del %", "Ins %"],
|
867 |
+
)
|
868 |
+
.cols_align(align="left", columns=["Top Deleted", "Top Inserted"])
|
869 |
+
.tab_spanner(
|
870 |
+
label="Counts", columns=["Original", "Deleted", "Inserted"]
|
871 |
+
)
|
872 |
+
.tab_spanner(
|
873 |
+
label="Characters", columns=["Top Deleted", "Top Inserted"]
|
874 |
+
)
|
875 |
+
.tab_spanner(label="Percentages", columns=["Del %", "Ins %"])
|
876 |
+
.cols_width(
|
877 |
+
{
|
878 |
+
"Character Class": "20%",
|
879 |
+
"Original": "10%",
|
880 |
+
"Deleted": "10%",
|
881 |
+
"Top Deleted": "15%",
|
882 |
+
"Inserted": "10%",
|
883 |
+
"Top Inserted": "15%",
|
884 |
+
"Del %": "10%",
|
885 |
+
"Ins %": "10%",
|
886 |
+
}
|
887 |
+
)
|
888 |
+
.opt_stylize(style=1, color="blue")
|
889 |
+
)
|
890 |
+
else:
|
891 |
+
char_class_table = None
|
892 |
+
|
893 |
+
# Table 3: Compact Combined View (unchanged except for percentage formatting)
|
894 |
+
compact_data = []
|
895 |
+
|
896 |
+
# Add summary row
|
897 |
+
compact_data.append(
|
898 |
+
{
|
899 |
+
"Type": "Total",
|
900 |
+
"Deleted": metrics["total_deleted_chars"],
|
901 |
+
"Inserted": metrics["total_inserted_chars"],
|
902 |
+
"Net": metrics["total_inserted_chars"] - metrics["total_deleted_chars"],
|
903 |
+
"Change": f"{metrics['net_change_percentage']:+.3f}%"
|
904 |
+
if abs(metrics["net_change_percentage"]) < 0.01
|
905 |
+
else f"{metrics['net_change_percentage']:+.0f}%",
|
906 |
+
}
|
907 |
+
)
|
908 |
+
|
909 |
+
# Add top character classes (sorted by total change)
|
910 |
+
class_changes = []
|
911 |
+
for char_class, class_metrics in metrics["char_class_metrics"].items():
|
912 |
+
if (
|
913 |
+
class_metrics["deleted_count"] > 0
|
914 |
+
or class_metrics["inserted_count"] > 0
|
915 |
+
):
|
916 |
+
class_changes.append(
|
917 |
+
{
|
918 |
+
"Type": char_class.replace("_", " ").title(),
|
919 |
+
"Deleted": class_metrics["deleted_count"],
|
920 |
+
"Inserted": class_metrics["inserted_count"],
|
921 |
+
"Net": class_metrics["inserted_count"]
|
922 |
+
- class_metrics["deleted_count"],
|
923 |
+
"Change": class_metrics["deleted_count"]
|
924 |
+
+ class_metrics["inserted_count"],
|
925 |
+
}
|
926 |
+
)
|
927 |
+
|
928 |
+
# Sort by total change and take top 5
|
929 |
+
class_changes.sort(key=lambda x: x["Change"], reverse=True)
|
930 |
+
for item in class_changes[:5]:
|
931 |
+
item["Change"] = f"{item['Net']:+d}" if item["Net"] != 0 else "±0"
|
932 |
+
compact_data.append(item)
|
933 |
+
|
934 |
+
compact_df = pd.DataFrame(compact_data)
|
935 |
+
compact_table = (
|
936 |
+
GT(compact_df)
|
937 |
+
.tab_header(title="Edit Summary - Compact View")
|
938 |
+
.fmt_number(
|
939 |
+
columns=["Deleted", "Inserted", "Net"], decimals=0, use_seps=True
|
940 |
+
)
|
941 |
+
.tab_style(
|
942 |
+
style=[
|
943 |
+
style.fill(color="#e8e8e8"),
|
944 |
+
style.text(weight="bold"),
|
945 |
+
style.borders(sides=["top", "bottom"], color="#666", weight="2px"),
|
946 |
+
],
|
947 |
+
locations=loc.body(rows=[0]),
|
948 |
+
)
|
949 |
+
.tab_style(
|
950 |
+
style=style.text(color="#880000"),
|
951 |
+
locations=loc.body(columns=["Deleted"]),
|
952 |
+
)
|
953 |
+
.tab_style(
|
954 |
+
style=style.text(color="#008800"),
|
955 |
+
locations=loc.body(columns=["Inserted"]),
|
956 |
+
)
|
957 |
+
.cols_align(
|
958 |
+
align="center", columns=["Deleted", "Inserted", "Net", "Change"]
|
959 |
+
)
|
960 |
+
.cols_width(
|
961 |
+
{
|
962 |
+
"Type": "40%",
|
963 |
+
"Deleted": "15%",
|
964 |
+
"Inserted": "15%",
|
965 |
+
"Net": "15%",
|
966 |
+
"Change": "15%",
|
967 |
+
}
|
968 |
+
)
|
969 |
+
.opt_stylize(style=1, color="cyan")
|
970 |
+
)
|
971 |
+
|
972 |
+
return {
|
973 |
+
"overall": overall_table,
|
974 |
+
"char_class": char_class_table,
|
975 |
+
"compact": compact_table,
|
976 |
+
}
|
977 |
+
|
978 |
+
def create_operation_matrix_table(
|
979 |
+
edits: List[Edit], classifications: Dict[Operation, Dict[str, int]]
|
980 |
+
) -> GT:
|
981 |
+
"""Create a matrix view of operations by character class."""
|
982 |
+
|
983 |
+
# Get all character classes
|
984 |
+
all_classes = set()
|
985 |
+
for op_classes in classifications.values():
|
986 |
+
all_classes.update(op_classes.keys())
|
987 |
+
|
988 |
+
# Build matrix data
|
989 |
+
matrix_data = []
|
990 |
+
for char_class in sorted(all_classes):
|
991 |
+
row = {
|
992 |
+
"Character Type": char_class.replace("_", " ").title(),
|
993 |
+
"Deletions": classifications.get(Operation.DELETE, {}).get(
|
994 |
+
char_class, 0
|
995 |
+
),
|
996 |
+
"Insertions": classifications.get(Operation.INSERT, {}).get(
|
997 |
+
char_class, 0
|
998 |
+
),
|
999 |
+
"Balance": (
|
1000 |
+
classifications.get(Operation.INSERT, {}).get(char_class, 0)
|
1001 |
+
- classifications.get(Operation.DELETE, {}).get(char_class, 0)
|
1002 |
+
),
|
1003 |
+
}
|
1004 |
+
matrix_data.append(row)
|
1005 |
+
|
1006 |
+
# Sort by total changes
|
1007 |
+
matrix_data.sort(key=lambda x: x["Deletions"] + x["Insertions"], reverse=True)
|
1008 |
+
|
1009 |
+
# Convert to DataFrame
|
1010 |
+
matrix_df = pd.DataFrame(matrix_data)
|
1011 |
+
|
1012 |
+
# Calculate max values for domains
|
1013 |
+
max_del = max((r["Deletions"] for r in matrix_data), default=1)
|
1014 |
+
max_ins = max((r["Insertions"] for r in matrix_data), default=1)
|
1015 |
+
max_balance = max((abs(r["Balance"]) for r in matrix_data), default=1)
|
1016 |
+
|
1017 |
+
matrix_table = (
|
1018 |
+
GT(matrix_df)
|
1019 |
+
.tab_header(title="Operation Matrix by Character Type")
|
1020 |
+
.fmt_number(columns=["Deletions", "Insertions", "Balance"], decimals=0)
|
1021 |
+
.data_color(
|
1022 |
+
columns=["Deletions"],
|
1023 |
+
palette=["white", "#ffcccc"],
|
1024 |
+
domain=[0, max_del],
|
1025 |
+
)
|
1026 |
+
.data_color(
|
1027 |
+
columns=["Insertions"],
|
1028 |
+
palette=["white", "#ccffcc"],
|
1029 |
+
domain=[0, max_ins],
|
1030 |
+
)
|
1031 |
+
.data_color(
|
1032 |
+
columns=["Balance"],
|
1033 |
+
palette=["#ffcccc", "white", "#ccffcc"],
|
1034 |
+
domain=[-max_balance, max_balance],
|
1035 |
+
)
|
1036 |
+
.cols_align(align="center", columns=["Deletions", "Insertions", "Balance"])
|
1037 |
+
.opt_stylize(style=2, color="gray")
|
1038 |
+
)
|
1039 |
+
|
1040 |
+
return matrix_table
|
1041 |
+
|
1042 |
+
def is_long_diff(edits: List[Edit], original: str) -> bool:
|
1043 |
+
"""Determine if a diff should use fast rendering."""
|
1044 |
+
return len(edits) > 1000 or len(original) > 10000
|
1045 |
+
|
1046 |
+
def analyze_text_changes(
|
1047 |
+
original: str,
|
1048 |
+
processed: str,
|
1049 |
+
) -> Dict[str, Any]:
|
1050 |
+
"""
|
1051 |
+
Main function to analyze changes between two texts.
|
1052 |
+
"""
|
1053 |
+
edits = myers_diff(original, processed)
|
1054 |
+
classifications = classify_edits(edits)
|
1055 |
+
metrics = calculate_change_metrics(original, edits, classifications)
|
1056 |
+
summary = format_diff_summary(edits, classifications, metrics)
|
1057 |
+
|
1058 |
+
result = {
|
1059 |
+
"edits": edits,
|
1060 |
+
"classifications": classifications,
|
1061 |
+
"metrics": metrics,
|
1062 |
+
"summary": summary,
|
1063 |
+
"tables": create_summary_tables(edits, classifications, metrics),
|
1064 |
+
"matrix_table": create_operation_matrix_table(edits, classifications),
|
1065 |
+
}
|
1066 |
+
|
1067 |
+
return result
|
1068 |
+
|
1069 |
+
def render_html_diff(
|
1070 |
+
edits: List[Edit],
|
1071 |
+
original: str,
|
1072 |
+
context_chars: int = 5,
|
1073 |
+
side_by_side: bool = False,
|
1074 |
+
use_fast_html: bool | None = None,
|
1075 |
+
) -> str:
|
1076 |
+
"""
|
1077 |
+
Unified function to render HTML diffs with automatic optimization.
|
1078 |
+
|
1079 |
+
Args:
|
1080 |
+
edits: List of Edit operations
|
1081 |
+
original: Original text (for length checking)
|
1082 |
+
context_chars: Number of context lines to show in fast mode
|
1083 |
+
side_by_side: Whether to use side-by-side view
|
1084 |
+
use_fast_html: Force fast mode (None for auto-detect)
|
1085 |
+
|
1086 |
+
Returns:
|
1087 |
+
HTML string of the diff
|
1088 |
+
"""
|
1089 |
+
if use_fast_html is None:
|
1090 |
+
use_fast_html = is_long_diff(edits, original)
|
1091 |
+
|
1092 |
+
if use_fast_html:
|
1093 |
+
if side_by_side:
|
1094 |
+
return generate_side_by_side_html_fast(
|
1095 |
+
edits, context_chars=context_chars
|
1096 |
+
)
|
1097 |
+
else:
|
1098 |
+
return generate_html_diff_fast(edits, context_chars=context_chars)
|
1099 |
+
else:
|
1100 |
+
if side_by_side:
|
1101 |
+
# For non-fast mode, still use length-based optimization
|
1102 |
+
if len(edits) > 500:
|
1103 |
+
return generate_side_by_side_html_fast(edits, max_length=50000)
|
1104 |
+
else:
|
1105 |
+
return generate_side_by_side_html(edits)
|
1106 |
+
else:
|
1107 |
+
return generate_html_diff(edits, show_equal=True, max_equal_length=200)
|
1108 |
+
|
1109 |
+
return analyze_text_changes, render_html_diff
|
1110 |
+
|
1111 |
+
|
1112 |
+
@app.cell
|
1113 |
+
def _(mo):
|
1114 |
+
o_file_upload = mo.ui.file(label="Original text", kind="area")
|
1115 |
+
p_file_upload = mo.ui.file(label="Preprocessed text", kind="area")
|
1116 |
+
|
1117 |
+
file_stack = mo.hstack([o_file_upload, p_file_upload], widths="equal")
|
1118 |
+
return file_stack, o_file_upload, p_file_upload
|
1119 |
+
|
1120 |
+
|
1121 |
+
@app.cell
|
1122 |
+
def _(mo):
|
1123 |
+
o_textbox = mo.ui.text_area(label="Original text", full_width=True)
|
1124 |
+
p_textbox = mo.ui.text_area(label="Preprocessed text", full_width=True)
|
1125 |
+
|
1126 |
+
text_stack = mo.hstack([o_textbox, p_textbox], widths="equal")
|
1127 |
+
return o_textbox, p_textbox, text_stack
|
1128 |
+
|
1129 |
+
|
1130 |
+
@app.cell
|
1131 |
+
def _(file_stack, mo, text_stack):
|
1132 |
+
mo.ui.tabs({"Text": text_stack, "File": file_stack})
|
1133 |
+
return
|
1134 |
+
|
1135 |
+
|
1136 |
+
@app.function
|
1137 |
+
def check_text_similarity(text1: str, text2: str, threshold: float = 0.6) -> bool:
|
1138 |
+
"""Check if texts are similar enough based on length and character overlap."""
|
1139 |
+
if not text1 or not text2:
|
1140 |
+
return False
|
1141 |
+
return len(set(text1) & set(text2)) / len(
|
1142 |
+
set(text1) | set(text2)
|
1143 |
+
) >= threshold and abs(len(text1) - len(text2)) / max(len(text1), len(text2)) <= (
|
1144 |
+
1 - threshold
|
1145 |
+
)
|
1146 |
+
|
1147 |
+
|
1148 |
+
@app.cell
|
1149 |
+
def _(mo, o_file_upload, o_textbox, p_file_upload, p_textbox):
|
1150 |
+
from charset_normalizer import detect
|
1151 |
+
|
1152 |
+
def detect_encoding(b: bytes) -> str:
|
1153 |
+
result = detect(b)
|
1154 |
+
return result["encoding"]
|
1155 |
+
|
1156 |
+
o_text, p_text = (
|
1157 |
+
"Example text will be used if none provided!",
|
1158 |
+
"Example Text will be used, if none provided.",
|
1159 |
+
)
|
1160 |
+
try:
|
1161 |
+
if o_file_upload.contents():
|
1162 |
+
encoding = detect_encoding(o_file_upload.contents())
|
1163 |
+
try:
|
1164 |
+
o_text = o_file_upload.contents().decode(encoding)
|
1165 |
+
except UnicodeDecodeError:
|
1166 |
+
o_text = o_file_upload.contents().decode("utf-8")
|
1167 |
+
elif o_textbox.value:
|
1168 |
+
o_text = o_textbox.value
|
1169 |
+
|
1170 |
+
if p_file_upload.contents():
|
1171 |
+
encoding = detect_encoding(o_file_upload.contents())
|
1172 |
+
try:
|
1173 |
+
p_text = p_file_upload.contents().decode(encoding)
|
1174 |
+
except UnicodeDecodeError:
|
1175 |
+
p_text = p_file_upload.contents().decode("utf-8")
|
1176 |
+
elif p_textbox.value:
|
1177 |
+
p_text = p_textbox.value
|
1178 |
+
except UnicodeDecodeError:
|
1179 |
+
mo.stop(
|
1180 |
+
True,
|
1181 |
+
mo.md("Error decoding files. Please try UTF-8.").callout(kind="danger"),
|
1182 |
+
)
|
1183 |
+
|
1184 |
+
mo.stop(
|
1185 |
+
not check_text_similarity(o_text, p_text),
|
1186 |
+
mo.md(
|
1187 |
+
f"Texts are too dissimilar! Aborting comparison.\n\n{o_text[:50]}\n\n{p_text[:50]}"
|
1188 |
+
).callout(kind="danger"),
|
1189 |
+
)
|
1190 |
+
return o_text, p_text
|
1191 |
+
|
1192 |
+
|
1193 |
+
@app.cell
|
1194 |
+
def _(analyze_text_changes, o_text, p_text):
|
1195 |
+
results = analyze_text_changes(o_text, p_text)
|
1196 |
+
return (results,)
|
1197 |
+
|
1198 |
+
|
1199 |
+
@app.cell
|
1200 |
+
def _(mo, results):
|
1201 |
+
results_tables = mo.vstack(
|
1202 |
+
[
|
1203 |
+
results["tables"]["overall"],
|
1204 |
+
results["tables"]["char_class"],
|
1205 |
+
results["tables"]["compact"],
|
1206 |
+
]
|
1207 |
+
)
|
1208 |
+
return (results_tables,)
|
1209 |
+
|
1210 |
+
|
1211 |
+
@app.cell
|
1212 |
+
def _(mo, o_text, render_html_diff, results, results_tables):
|
1213 |
+
diff_view = mo.ui.tabs(
|
1214 |
+
{
|
1215 |
+
"Combined diff": mo.Html(
|
1216 |
+
render_html_diff(
|
1217 |
+
results["edits"],
|
1218 |
+
o_text,
|
1219 |
+
)
|
1220 |
+
),
|
1221 |
+
"Side-by-side diff": mo.Html(
|
1222 |
+
render_html_diff(
|
1223 |
+
results["edits"],
|
1224 |
+
o_text,
|
1225 |
+
side_by_side=True,
|
1226 |
+
)
|
1227 |
+
),
|
1228 |
+
}
|
1229 |
+
)
|
1230 |
+
|
1231 |
+
mo.md(f"""
|
1232 |
+
# Results
|
1233 |
+
|
1234 |
+
{results_tables}
|
1235 |
+
|
1236 |
+
{diff_view}
|
1237 |
+
""")
|
1238 |
+
return
|
1239 |
+
|
1240 |
+
|
1241 |
+
@app.cell
|
1242 |
+
def _():
|
1243 |
+
return
|
1244 |
+
|
1245 |
+
|
1246 |
+
if __name__ == "__main__":
|
1247 |
+
app.run()
|
development.md
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Development
|
2 |
+
|
3 |
+
## Testing your Dockerfile locally
|
4 |
+
|
5 |
+
```bash
|
6 |
+
docker build -t marimo-app .
|
7 |
+
docker run -it --rm -p 7860:7860 marimo-app
|
8 |
+
```
|
pyproject.toml
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
[project]
|
2 |
+
name = "llm-text-preprocessing"
|
3 |
+
version = "0.1.0"
|
4 |
+
description = "Add your description here"
|
5 |
+
readme = "README.md"
|
6 |
+
requires-python = ">=3.12"
|
7 |
+
dependencies = [
|
8 |
+
"charset-normalizer>=3.4.2",
|
9 |
+
"great-tables>=0.17.0",
|
10 |
+
"marimo>=0.14.6",
|
11 |
+
"pandas>=2.3.0",
|
12 |
+
]
|
uv.lock
ADDED
@@ -0,0 +1,600 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
version = 1
|
2 |
+
revision = 2
|
3 |
+
requires-python = ">=3.12"
|
4 |
+
|
5 |
+
[[package]]
|
6 |
+
name = "anyio"
|
7 |
+
version = "4.9.0"
|
8 |
+
source = { registry = "https://pypi.org/simple" }
|
9 |
+
dependencies = [
|
10 |
+
{ name = "idna" },
|
11 |
+
{ name = "sniffio" },
|
12 |
+
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
|
13 |
+
]
|
14 |
+
sdist = { url = "https://files.pythonhosted.org/packages/95/7d/4c1bd541d4dffa1b52bd83fb8527089e097a106fc90b467a7313b105f840/anyio-4.9.0.tar.gz", hash = "sha256:673c0c244e15788651a4ff38710fea9675823028a6f08a5eda409e0c9840a028", size = 190949, upload-time = "2025-03-17T00:02:54.77Z" }
|
15 |
+
wheels = [
|
16 |
+
{ url = "https://files.pythonhosted.org/packages/a1/ee/48ca1a7c89ffec8b6a0c5d02b89c305671d5ffd8d3c94acf8b8c408575bb/anyio-4.9.0-py3-none-any.whl", hash = "sha256:9f76d541cad6e36af7beb62e978876f3b41e3e04f2c1fbf0884604c0a9c4d93c", size = 100916, upload-time = "2025-03-17T00:02:52.713Z" },
|
17 |
+
]
|
18 |
+
|
19 |
+
[[package]]
|
20 |
+
name = "babel"
|
21 |
+
version = "2.17.0"
|
22 |
+
source = { registry = "https://pypi.org/simple" }
|
23 |
+
sdist = { url = "https://files.pythonhosted.org/packages/7d/6b/d52e42361e1aa00709585ecc30b3f9684b3ab62530771402248b1b1d6240/babel-2.17.0.tar.gz", hash = "sha256:0c54cffb19f690cdcc52a3b50bcbf71e07a808d1c80d549f2459b9d2cf0afb9d", size = 9951852, upload-time = "2025-02-01T15:17:41.026Z" }
|
24 |
+
wheels = [
|
25 |
+
{ url = "https://files.pythonhosted.org/packages/b7/b8/3fe70c75fe32afc4bb507f75563d39bc5642255d1d94f1f23604725780bf/babel-2.17.0-py3-none-any.whl", hash = "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2", size = 10182537, upload-time = "2025-02-01T15:17:37.39Z" },
|
26 |
+
]
|
27 |
+
|
28 |
+
[[package]]
|
29 |
+
name = "charset-normalizer"
|
30 |
+
version = "3.4.2"
|
31 |
+
source = { registry = "https://pypi.org/simple" }
|
32 |
+
sdist = { url = "https://files.pythonhosted.org/packages/e4/33/89c2ced2b67d1c2a61c19c6751aa8902d46ce3dacb23600a283619f5a12d/charset_normalizer-3.4.2.tar.gz", hash = "sha256:5baececa9ecba31eff645232d59845c07aa030f0c81ee70184a90d35099a0e63", size = 126367, upload-time = "2025-05-02T08:34:42.01Z" }
|
33 |
+
wheels = [
|
34 |
+
{ url = "https://files.pythonhosted.org/packages/d7/a4/37f4d6035c89cac7930395a35cc0f1b872e652eaafb76a6075943754f095/charset_normalizer-3.4.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0c29de6a1a95f24b9a1aa7aefd27d2487263f00dfd55a77719b530788f75cff7", size = 199936, upload-time = "2025-05-02T08:32:33.712Z" },
|
35 |
+
{ url = "https://files.pythonhosted.org/packages/ee/8a/1a5e33b73e0d9287274f899d967907cd0bf9c343e651755d9307e0dbf2b3/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cddf7bd982eaa998934a91f69d182aec997c6c468898efe6679af88283b498d3", size = 143790, upload-time = "2025-05-02T08:32:35.768Z" },
|
36 |
+
{ url = "https://files.pythonhosted.org/packages/66/52/59521f1d8e6ab1482164fa21409c5ef44da3e9f653c13ba71becdd98dec3/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcbe676a55d7445b22c10967bceaaf0ee69407fbe0ece4d032b6eb8d4565982a", size = 153924, upload-time = "2025-05-02T08:32:37.284Z" },
|
37 |
+
{ url = "https://files.pythonhosted.org/packages/86/2d/fb55fdf41964ec782febbf33cb64be480a6b8f16ded2dbe8db27a405c09f/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d41c4d287cfc69060fa91cae9683eacffad989f1a10811995fa309df656ec214", size = 146626, upload-time = "2025-05-02T08:32:38.803Z" },
|
38 |
+
{ url = "https://files.pythonhosted.org/packages/8c/73/6ede2ec59bce19b3edf4209d70004253ec5f4e319f9a2e3f2f15601ed5f7/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e594135de17ab3866138f496755f302b72157d115086d100c3f19370839dd3a", size = 148567, upload-time = "2025-05-02T08:32:40.251Z" },
|
39 |
+
{ url = "https://files.pythonhosted.org/packages/09/14/957d03c6dc343c04904530b6bef4e5efae5ec7d7990a7cbb868e4595ee30/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf713fe9a71ef6fd5adf7a79670135081cd4431c2943864757f0fa3a65b1fafd", size = 150957, upload-time = "2025-05-02T08:32:41.705Z" },
|
40 |
+
{ url = "https://files.pythonhosted.org/packages/0d/c8/8174d0e5c10ccebdcb1b53cc959591c4c722a3ad92461a273e86b9f5a302/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a370b3e078e418187da8c3674eddb9d983ec09445c99a3a263c2011993522981", size = 145408, upload-time = "2025-05-02T08:32:43.709Z" },
|
41 |
+
{ url = "https://files.pythonhosted.org/packages/58/aa/8904b84bc8084ac19dc52feb4f5952c6df03ffb460a887b42615ee1382e8/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a955b438e62efdf7e0b7b52a64dc5c3396e2634baa62471768a64bc2adb73d5c", size = 153399, upload-time = "2025-05-02T08:32:46.197Z" },
|
42 |
+
{ url = "https://files.pythonhosted.org/packages/c2/26/89ee1f0e264d201cb65cf054aca6038c03b1a0c6b4ae998070392a3ce605/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:7222ffd5e4de8e57e03ce2cef95a4c43c98fcb72ad86909abdfc2c17d227fc1b", size = 156815, upload-time = "2025-05-02T08:32:48.105Z" },
|
43 |
+
{ url = "https://files.pythonhosted.org/packages/fd/07/68e95b4b345bad3dbbd3a8681737b4338ff2c9df29856a6d6d23ac4c73cb/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:bee093bf902e1d8fc0ac143c88902c3dfc8941f7ea1d6a8dd2bcb786d33db03d", size = 154537, upload-time = "2025-05-02T08:32:49.719Z" },
|
44 |
+
{ url = "https://files.pythonhosted.org/packages/77/1a/5eefc0ce04affb98af07bc05f3bac9094513c0e23b0562d64af46a06aae4/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dedb8adb91d11846ee08bec4c8236c8549ac721c245678282dcb06b221aab59f", size = 149565, upload-time = "2025-05-02T08:32:51.404Z" },
|
45 |
+
{ url = "https://files.pythonhosted.org/packages/37/a0/2410e5e6032a174c95e0806b1a6585eb21e12f445ebe239fac441995226a/charset_normalizer-3.4.2-cp312-cp312-win32.whl", hash = "sha256:db4c7bf0e07fc3b7d89ac2a5880a6a8062056801b83ff56d8464b70f65482b6c", size = 98357, upload-time = "2025-05-02T08:32:53.079Z" },
|
46 |
+
{ url = "https://files.pythonhosted.org/packages/6c/4f/c02d5c493967af3eda9c771ad4d2bbc8df6f99ddbeb37ceea6e8716a32bc/charset_normalizer-3.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:5a9979887252a82fefd3d3ed2a8e3b937a7a809f65dcb1e068b090e165bbe99e", size = 105776, upload-time = "2025-05-02T08:32:54.573Z" },
|
47 |
+
{ url = "https://files.pythonhosted.org/packages/ea/12/a93df3366ed32db1d907d7593a94f1fe6293903e3e92967bebd6950ed12c/charset_normalizer-3.4.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:926ca93accd5d36ccdabd803392ddc3e03e6d4cd1cf17deff3b989ab8e9dbcf0", size = 199622, upload-time = "2025-05-02T08:32:56.363Z" },
|
48 |
+
{ url = "https://files.pythonhosted.org/packages/04/93/bf204e6f344c39d9937d3c13c8cd5bbfc266472e51fc8c07cb7f64fcd2de/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eba9904b0f38a143592d9fc0e19e2df0fa2e41c3c3745554761c5f6447eedabf", size = 143435, upload-time = "2025-05-02T08:32:58.551Z" },
|
49 |
+
{ url = "https://files.pythonhosted.org/packages/22/2a/ea8a2095b0bafa6c5b5a55ffdc2f924455233ee7b91c69b7edfcc9e02284/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3fddb7e2c84ac87ac3a947cb4e66d143ca5863ef48e4a5ecb83bd48619e4634e", size = 153653, upload-time = "2025-05-02T08:33:00.342Z" },
|
50 |
+
{ url = "https://files.pythonhosted.org/packages/b6/57/1b090ff183d13cef485dfbe272e2fe57622a76694061353c59da52c9a659/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98f862da73774290f251b9df8d11161b6cf25b599a66baf087c1ffe340e9bfd1", size = 146231, upload-time = "2025-05-02T08:33:02.081Z" },
|
51 |
+
{ url = "https://files.pythonhosted.org/packages/e2/28/ffc026b26f441fc67bd21ab7f03b313ab3fe46714a14b516f931abe1a2d8/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c9379d65defcab82d07b2a9dfbfc2e95bc8fe0ebb1b176a3190230a3ef0e07c", size = 148243, upload-time = "2025-05-02T08:33:04.063Z" },
|
52 |
+
{ url = "https://files.pythonhosted.org/packages/c0/0f/9abe9bd191629c33e69e47c6ef45ef99773320e9ad8e9cb08b8ab4a8d4cb/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e635b87f01ebc977342e2697d05b56632f5f879a4f15955dfe8cef2448b51691", size = 150442, upload-time = "2025-05-02T08:33:06.418Z" },
|
53 |
+
{ url = "https://files.pythonhosted.org/packages/67/7c/a123bbcedca91d5916c056407f89a7f5e8fdfce12ba825d7d6b9954a1a3c/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1c95a1e2902a8b722868587c0e1184ad5c55631de5afc0eb96bc4b0d738092c0", size = 145147, upload-time = "2025-05-02T08:33:08.183Z" },
|
54 |
+
{ url = "https://files.pythonhosted.org/packages/ec/fe/1ac556fa4899d967b83e9893788e86b6af4d83e4726511eaaad035e36595/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ef8de666d6179b009dce7bcb2ad4c4a779f113f12caf8dc77f0162c29d20490b", size = 153057, upload-time = "2025-05-02T08:33:09.986Z" },
|
55 |
+
{ url = "https://files.pythonhosted.org/packages/2b/ff/acfc0b0a70b19e3e54febdd5301a98b72fa07635e56f24f60502e954c461/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:32fc0341d72e0f73f80acb0a2c94216bd704f4f0bce10aedea38f30502b271ff", size = 156454, upload-time = "2025-05-02T08:33:11.814Z" },
|
56 |
+
{ url = "https://files.pythonhosted.org/packages/92/08/95b458ce9c740d0645feb0e96cea1f5ec946ea9c580a94adfe0b617f3573/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:289200a18fa698949d2b39c671c2cc7a24d44096784e76614899a7ccf2574b7b", size = 154174, upload-time = "2025-05-02T08:33:13.707Z" },
|
57 |
+
{ url = "https://files.pythonhosted.org/packages/78/be/8392efc43487ac051eee6c36d5fbd63032d78f7728cb37aebcc98191f1ff/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4a476b06fbcf359ad25d34a057b7219281286ae2477cc5ff5e3f70a246971148", size = 149166, upload-time = "2025-05-02T08:33:15.458Z" },
|
58 |
+
{ url = "https://files.pythonhosted.org/packages/44/96/392abd49b094d30b91d9fbda6a69519e95802250b777841cf3bda8fe136c/charset_normalizer-3.4.2-cp313-cp313-win32.whl", hash = "sha256:aaeeb6a479c7667fbe1099af9617c83aaca22182d6cf8c53966491a0f1b7ffb7", size = 98064, upload-time = "2025-05-02T08:33:17.06Z" },
|
59 |
+
{ url = "https://files.pythonhosted.org/packages/e9/b0/0200da600134e001d91851ddc797809e2fe0ea72de90e09bec5a2fbdaccb/charset_normalizer-3.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:aa6af9e7d59f9c12b33ae4e9450619cf2488e2bbe9b44030905877f0b2324980", size = 105641, upload-time = "2025-05-02T08:33:18.753Z" },
|
60 |
+
{ url = "https://files.pythonhosted.org/packages/20/94/c5790835a017658cbfabd07f3bfb549140c3ac458cfc196323996b10095a/charset_normalizer-3.4.2-py3-none-any.whl", hash = "sha256:7f56930ab0abd1c45cd15be65cc741c28b1c9a34876ce8c17a2fa107810c0af0", size = 52626, upload-time = "2025-05-02T08:34:40.053Z" },
|
61 |
+
]
|
62 |
+
|
63 |
+
[[package]]
|
64 |
+
name = "click"
|
65 |
+
version = "8.2.1"
|
66 |
+
source = { registry = "https://pypi.org/simple" }
|
67 |
+
dependencies = [
|
68 |
+
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
69 |
+
]
|
70 |
+
sdist = { url = "https://files.pythonhosted.org/packages/60/6c/8ca2efa64cf75a977a0d7fac081354553ebe483345c734fb6b6515d96bbc/click-8.2.1.tar.gz", hash = "sha256:27c491cc05d968d271d5a1db13e3b5a184636d9d930f148c50b038f0d0646202", size = 286342, upload-time = "2025-05-20T23:19:49.832Z" }
|
71 |
+
wheels = [
|
72 |
+
{ url = "https://files.pythonhosted.org/packages/85/32/10bb5764d90a8eee674e9dc6f4db6a0ab47c8c4d0d83c27f7c39ac415a4d/click-8.2.1-py3-none-any.whl", hash = "sha256:61a3265b914e850b85317d0b3109c7f8cd35a670f963866005d6ef1d5175a12b", size = 102215, upload-time = "2025-05-20T23:19:47.796Z" },
|
73 |
+
]
|
74 |
+
|
75 |
+
[[package]]
|
76 |
+
name = "colorama"
|
77 |
+
version = "0.4.6"
|
78 |
+
source = { registry = "https://pypi.org/simple" }
|
79 |
+
sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" }
|
80 |
+
wheels = [
|
81 |
+
{ url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" },
|
82 |
+
]
|
83 |
+
|
84 |
+
[[package]]
|
85 |
+
name = "commonmark"
|
86 |
+
version = "0.9.1"
|
87 |
+
source = { registry = "https://pypi.org/simple" }
|
88 |
+
sdist = { url = "https://files.pythonhosted.org/packages/60/48/a60f593447e8f0894ebb7f6e6c1f25dafc5e89c5879fdc9360ae93ff83f0/commonmark-0.9.1.tar.gz", hash = "sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60", size = 95764, upload-time = "2019-10-04T15:37:39.817Z" }
|
89 |
+
wheels = [
|
90 |
+
{ url = "https://files.pythonhosted.org/packages/b1/92/dfd892312d822f36c55366118b95d914e5f16de11044a27cf10a7d71bbbf/commonmark-0.9.1-py2.py3-none-any.whl", hash = "sha256:da2f38c92590f83de410ba1a3cbceafbc74fee9def35f9251ba9a971d6d66fd9", size = 51068, upload-time = "2019-10-04T15:37:37.674Z" },
|
91 |
+
]
|
92 |
+
|
93 |
+
[[package]]
|
94 |
+
name = "docutils"
|
95 |
+
version = "0.21.2"
|
96 |
+
source = { registry = "https://pypi.org/simple" }
|
97 |
+
sdist = { url = "https://files.pythonhosted.org/packages/ae/ed/aefcc8cd0ba62a0560c3c18c33925362d46c6075480bfa4df87b28e169a9/docutils-0.21.2.tar.gz", hash = "sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f", size = 2204444, upload-time = "2024-04-23T18:57:18.24Z" }
|
98 |
+
wheels = [
|
99 |
+
{ url = "https://files.pythonhosted.org/packages/8f/d7/9322c609343d929e75e7e5e6255e614fcc67572cfd083959cdef3b7aad79/docutils-0.21.2-py3-none-any.whl", hash = "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2", size = 587408, upload-time = "2024-04-23T18:57:14.835Z" },
|
100 |
+
]
|
101 |
+
|
102 |
+
[[package]]
|
103 |
+
name = "faicons"
|
104 |
+
version = "0.2.2"
|
105 |
+
source = { registry = "https://pypi.org/simple" }
|
106 |
+
dependencies = [
|
107 |
+
{ name = "htmltools" },
|
108 |
+
]
|
109 |
+
sdist = { url = "https://files.pythonhosted.org/packages/06/e8/c12ef85c4444616ab1c1e96d5ecbadc8046d40b34797308846a2cfc06c80/faicons-0.2.2.tar.gz", hash = "sha256:6b7d7b19180179b6b83783f91bf6c9311c0f00ae0f97d41be1d24d9942361659", size = 604434, upload-time = "2024-01-16T23:27:21.634Z" }
|
110 |
+
wheels = [
|
111 |
+
{ url = "https://files.pythonhosted.org/packages/65/3c/1db1b0f878319bb227f35a0fca7cad64e1f528b518bcab1a708da305c86d/faicons-0.2.2-py3-none-any.whl", hash = "sha256:d45d7c2635b53582a3375c67d7e975a28a91d2c16ef5f6b5033b5cdd507224b6", size = 607225, upload-time = "2024-01-16T23:27:19.475Z" },
|
112 |
+
]
|
113 |
+
|
114 |
+
[[package]]
|
115 |
+
name = "great-tables"
|
116 |
+
version = "0.17.0"
|
117 |
+
source = { registry = "https://pypi.org/simple" }
|
118 |
+
dependencies = [
|
119 |
+
{ name = "babel" },
|
120 |
+
{ name = "commonmark" },
|
121 |
+
{ name = "faicons" },
|
122 |
+
{ name = "htmltools" },
|
123 |
+
{ name = "importlib-metadata" },
|
124 |
+
{ name = "importlib-resources" },
|
125 |
+
{ name = "numpy" },
|
126 |
+
{ name = "typing-extensions" },
|
127 |
+
]
|
128 |
+
sdist = { url = "https://files.pythonhosted.org/packages/62/6f/85b80bec676dfb04e167224215475c9c353f72e52d8905c6eb1d2c93ee6f/great_tables-0.17.0.tar.gz", hash = "sha256:1bece693e3e72bb194a7d0aad99ed7af0ec0486576fc00dea7013fa7753e6f17", size = 10921120, upload-time = "2025-03-11T15:34:32.284Z" }
|
129 |
+
wheels = [
|
130 |
+
{ url = "https://files.pythonhosted.org/packages/a7/fa/4889fc5115e3300bf192958642166f2b9309fab84d367339ddc76a683e43/great_tables-0.17.0-py3-none-any.whl", hash = "sha256:36597209cf7709772207e9b969a3ca62de1b147cc4f4cb69f2b90ec7b935fb3e", size = 1378698, upload-time = "2025-03-11T15:34:30.831Z" },
|
131 |
+
]
|
132 |
+
|
133 |
+
[[package]]
|
134 |
+
name = "h11"
|
135 |
+
version = "0.16.0"
|
136 |
+
source = { registry = "https://pypi.org/simple" }
|
137 |
+
sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" }
|
138 |
+
wheels = [
|
139 |
+
{ url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" },
|
140 |
+
]
|
141 |
+
|
142 |
+
[[package]]
|
143 |
+
name = "htmltools"
|
144 |
+
version = "0.6.0"
|
145 |
+
source = { registry = "https://pypi.org/simple" }
|
146 |
+
dependencies = [
|
147 |
+
{ name = "packaging" },
|
148 |
+
{ name = "typing-extensions" },
|
149 |
+
]
|
150 |
+
sdist = { url = "https://files.pythonhosted.org/packages/cd/1d/c568d17e9fb5ad5aa0ca3531c58d36fe69deb8eee4e53ff6425c1f99f210/htmltools-0.6.0.tar.gz", hash = "sha256:e8a3fb023d748935035db7ff17f620612ffc814a6a80b6ae388f7b7ab182adf7", size = 97152, upload-time = "2024-10-29T20:21:43.378Z" }
|
151 |
+
wheels = [
|
152 |
+
{ url = "https://files.pythonhosted.org/packages/0a/ba/aa99706246f1938ca905eb6eeb7db832ac2e157aa4b805acb5cd4cd1791a/htmltools-0.6.0-py3-none-any.whl", hash = "sha256:072a274ff5e2851e0acce13fc5bb2bbdbbad8268dc8b123f881c05012ce7dce0", size = 84954, upload-time = "2024-10-29T20:21:42.067Z" },
|
153 |
+
]
|
154 |
+
|
155 |
+
[[package]]
|
156 |
+
name = "idna"
|
157 |
+
version = "3.10"
|
158 |
+
source = { registry = "https://pypi.org/simple" }
|
159 |
+
sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload-time = "2024-09-15T18:07:39.745Z" }
|
160 |
+
wheels = [
|
161 |
+
{ url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" },
|
162 |
+
]
|
163 |
+
|
164 |
+
[[package]]
|
165 |
+
name = "importlib-metadata"
|
166 |
+
version = "8.7.0"
|
167 |
+
source = { registry = "https://pypi.org/simple" }
|
168 |
+
dependencies = [
|
169 |
+
{ name = "zipp" },
|
170 |
+
]
|
171 |
+
sdist = { url = "https://files.pythonhosted.org/packages/76/66/650a33bd90f786193e4de4b3ad86ea60b53c89b669a5c7be931fac31cdb0/importlib_metadata-8.7.0.tar.gz", hash = "sha256:d13b81ad223b890aa16c5471f2ac3056cf76c5f10f82d6f9292f0b415f389000", size = 56641, upload-time = "2025-04-27T15:29:01.736Z" }
|
172 |
+
wheels = [
|
173 |
+
{ url = "https://files.pythonhosted.org/packages/20/b0/36bd937216ec521246249be3bf9855081de4c5e06a0c9b4219dbeda50373/importlib_metadata-8.7.0-py3-none-any.whl", hash = "sha256:e5dd1551894c77868a30651cef00984d50e1002d06942a7101d34870c5f02afd", size = 27656, upload-time = "2025-04-27T15:29:00.214Z" },
|
174 |
+
]
|
175 |
+
|
176 |
+
[[package]]
|
177 |
+
name = "importlib-resources"
|
178 |
+
version = "6.5.2"
|
179 |
+
source = { registry = "https://pypi.org/simple" }
|
180 |
+
sdist = { url = "https://files.pythonhosted.org/packages/cf/8c/f834fbf984f691b4f7ff60f50b514cc3de5cc08abfc3295564dd89c5e2e7/importlib_resources-6.5.2.tar.gz", hash = "sha256:185f87adef5bcc288449d98fb4fba07cea78bc036455dd44c5fc4a2fe78fed2c", size = 44693, upload-time = "2025-01-03T18:51:56.698Z" }
|
181 |
+
wheels = [
|
182 |
+
{ url = "https://files.pythonhosted.org/packages/a4/ed/1f1afb2e9e7f38a545d628f864d562a5ae64fe6f7a10e28ffb9b185b4e89/importlib_resources-6.5.2-py3-none-any.whl", hash = "sha256:789cfdc3ed28c78b67a06acb8126751ced69a3d5f79c095a98298cd8a760ccec", size = 37461, upload-time = "2025-01-03T18:51:54.306Z" },
|
183 |
+
]
|
184 |
+
|
185 |
+
[[package]]
|
186 |
+
name = "itsdangerous"
|
187 |
+
version = "2.2.0"
|
188 |
+
source = { registry = "https://pypi.org/simple" }
|
189 |
+
sdist = { url = "https://files.pythonhosted.org/packages/9c/cb/8ac0172223afbccb63986cc25049b154ecfb5e85932587206f42317be31d/itsdangerous-2.2.0.tar.gz", hash = "sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173", size = 54410, upload-time = "2024-04-16T21:28:15.614Z" }
|
190 |
+
wheels = [
|
191 |
+
{ url = "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl", hash = "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef", size = 16234, upload-time = "2024-04-16T21:28:14.499Z" },
|
192 |
+
]
|
193 |
+
|
194 |
+
[[package]]
|
195 |
+
name = "jedi"
|
196 |
+
version = "0.19.2"
|
197 |
+
source = { registry = "https://pypi.org/simple" }
|
198 |
+
dependencies = [
|
199 |
+
{ name = "parso" },
|
200 |
+
]
|
201 |
+
sdist = { url = "https://files.pythonhosted.org/packages/72/3a/79a912fbd4d8dd6fbb02bf69afd3bb72cf0c729bb3063c6f4498603db17a/jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0", size = 1231287, upload-time = "2024-11-11T01:41:42.873Z" }
|
202 |
+
wheels = [
|
203 |
+
{ url = "https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9", size = 1572278, upload-time = "2024-11-11T01:41:40.175Z" },
|
204 |
+
]
|
205 |
+
|
206 |
+
[[package]]
|
207 |
+
name = "llm-text-preprocessing"
|
208 |
+
version = "0.1.0"
|
209 |
+
source = { virtual = "." }
|
210 |
+
dependencies = [
|
211 |
+
{ name = "charset-normalizer" },
|
212 |
+
{ name = "great-tables" },
|
213 |
+
{ name = "marimo" },
|
214 |
+
{ name = "pandas" },
|
215 |
+
]
|
216 |
+
|
217 |
+
[package.metadata]
|
218 |
+
requires-dist = [
|
219 |
+
{ name = "charset-normalizer", specifier = ">=3.4.2" },
|
220 |
+
{ name = "great-tables", specifier = ">=0.17.0" },
|
221 |
+
{ name = "marimo", specifier = ">=0.14.6" },
|
222 |
+
{ name = "pandas", specifier = ">=2.3.0" },
|
223 |
+
]
|
224 |
+
|
225 |
+
[[package]]
|
226 |
+
name = "loro"
|
227 |
+
version = "1.5.1"
|
228 |
+
source = { registry = "https://pypi.org/simple" }
|
229 |
+
sdist = { url = "https://files.pythonhosted.org/packages/42/d8/b90d66fb97a57c311f9d40fa48c5f997bec28c36faf2b720ece5c244aae0/loro-1.5.1.tar.gz", hash = "sha256:8376a14b23a11f934fcda8a02548a449ff4f5da816769c78a442a89a23cd9736", size = 60681, upload-time = "2025-05-15T00:24:36.215Z" }
|
230 |
+
wheels = [
|
231 |
+
{ url = "https://files.pythonhosted.org/packages/ef/36/04291632421f74c00f219fecf353000c0e722773c41d1e57731187b96be0/loro-1.5.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:3976d7cafa3dfd9e75f110e4cc8b1de4dba2709dbd42b99270f7139433bfa57e", size = 2952871, upload-time = "2025-05-15T00:22:36.556Z" },
|
232 |
+
{ url = "https://files.pythonhosted.org/packages/8c/70/faf6cfda83a9f3dba377261876dc649cbf6ad256c267d126125f8701cba8/loro-1.5.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:362c8388b4a3948d70bc6cf060b5149e716bd41ffc2fa028a77ecbd1dff2fa50", size = 2747990, upload-time = "2025-05-15T00:22:24.284Z" },
|
233 |
+
{ url = "https://files.pythonhosted.org/packages/86/5c/4f59d23293149b423af7a71f5a6320de48f2bdda64ea73e280d3a4394274/loro-1.5.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:97395b6c5844398a2cfb2906631fd49352482617006608f55d0dcefd794626ee", size = 2965889, upload-time = "2025-05-15T00:19:48.576Z" },
|
234 |
+
{ url = "https://files.pythonhosted.org/packages/9b/67/b317fd181f7a08aa4f5fb810dc8d40d69c7acab10c7cd0711e66281b0fa8/loro-1.5.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:11674be191a382e3d7fd8d2e2c8abcba70f30f0e1e65c7718ff57dacb972aa85", size = 3046859, upload-time = "2025-05-15T00:20:18.609Z" },
|
235 |
+
{ url = "https://files.pythonhosted.org/packages/17/a4/e3b0ab4071255dd9bb1ae8586b911586b7771a107dd50d6d6717814edbbb/loro-1.5.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:06c90cd3fbe10be068063828966cec19d5b2fa5897a103dc39f5162f31af1c3d", size = 3279261, upload-time = "2025-05-15T00:20:45.917Z" },
|
236 |
+
{ url = "https://files.pythonhosted.org/packages/9d/ce/19b13ac2b59c5c35dd5fc8c10c494296b65ae2101aaa5eaa1a0e590c60ae/loro-1.5.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:52665162bdabdf5bb835e94920995e4704722cab6569b63bef13867f5b29c3bd", size = 3800927, upload-time = "2025-05-15T00:21:13.528Z" },
|
237 |
+
{ url = "https://files.pythonhosted.org/packages/c2/84/15f9ce7e478cedf7739c349707ed090e2d55d463d8be646067f3656605c3/loro-1.5.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8f6f86d4ba56ab08616e111da658a8395a7ff8266cfa1a2355e73fec3f3e0ca", size = 3105034, upload-time = "2025-05-15T00:22:02.755Z" },
|
238 |
+
{ url = "https://files.pythonhosted.org/packages/25/c3/9eadd2a6c88cafa828b63a6423586d9ed732b0e817c311a9affae1509744/loro-1.5.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d4846f47eecc467a5a819d8352a7f5a3926126cb0fa4f29bae4d2013b716c9d3", size = 3364247, upload-time = "2025-05-15T00:21:41.163Z" },
|
239 |
+
{ url = "https://files.pythonhosted.org/packages/92/59/f312a5d6d865d526ae11a2126c1da473bd45cfdae57d5bb68c4a3db9cdf3/loro-1.5.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:dff6483163967b1096aefa035ad58e9164869bf02d63a6c8feb085755ebccff6", size = 3119271, upload-time = "2025-05-15T00:22:48.845Z" },
|
240 |
+
{ url = "https://files.pythonhosted.org/packages/a1/71/704a30f6c0b1a3da792e1ee5f6096ca6e389157afabcb26be7f5dd54e3a3/loro-1.5.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ce2feac62a2a2a996a198c06874597129a7d4fbb1ced2e752e7c36cb7ee38e67", size = 3312152, upload-time = "2025-05-15T00:23:14.456Z" },
|
241 |
+
{ url = "https://files.pythonhosted.org/packages/ca/5a/f2686fde16f41d7a2005cd0ad26b8df84fe51b1152e31100c59eb0580d78/loro-1.5.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:be1cac46a3473d6462f79a8630bded844e6b17698c0745b9c9ef072878fa3df6", size = 3367555, upload-time = "2025-05-15T00:23:44.239Z" },
|
242 |
+
{ url = "https://files.pythonhosted.org/packages/3f/e8/54fd01f24cf973d702f105cf23e3bd8ea79d5b0f022ab8ac74670a7ff70b/loro-1.5.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ecf70c9520c64e51e6fec24685c46398537fd2656b25b93875049956a304ef40", size = 3271211, upload-time = "2025-05-15T00:24:12.235Z" },
|
243 |
+
{ url = "https://files.pythonhosted.org/packages/03/e1/5f89b15040c8f5e2f1261639ee407ad39cc2e98a0760c703e0b2b00eec20/loro-1.5.1-cp312-cp312-win32.whl", hash = "sha256:853e12b72c3c69cf9facbae59a835369174649417d38ca221f5f523f2069c2ff", size = 2466741, upload-time = "2025-05-15T00:24:55.82Z" },
|
244 |
+
{ url = "https://files.pythonhosted.org/packages/7d/b2/cfa253e46326a1f3477cafa3c14a6a408c54d226abcbfc832b447e6f49ff/loro-1.5.1-cp312-cp312-win_amd64.whl", hash = "sha256:772bb6afc979e9bd43b19967d45e1e177051a9b89212efbc2492d36b48e2e625", size = 2630378, upload-time = "2025-05-15T00:24:40.093Z" },
|
245 |
+
{ url = "https://files.pythonhosted.org/packages/8d/cf/113776aaf5d4da883fbab2154c68d839b43d29cc61189f54af1b7044f521/loro-1.5.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:4e54819ce83d464afb1bfcd85174b1086f8bb723d8e90b189eac101780da8db3", size = 2952496, upload-time = "2025-05-15T00:22:38.134Z" },
|
246 |
+
{ url = "https://files.pythonhosted.org/packages/89/5b/f96b8e3f207bd1049ac10b2dff3c7f034463c4a4069a9568bd41e67f9364/loro-1.5.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1af8251ff5f3ea7bb0408e3cff61f9d26316c88c79c4264f351930569924d9c8", size = 2747958, upload-time = "2025-05-15T00:22:25.55Z" },
|
247 |
+
{ url = "https://files.pythonhosted.org/packages/19/77/3cb0e14bf751a7c9a281141d34686c6d2e6926b7a002e9023fed7925f903/loro-1.5.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb9c4bed00006ae19cc468b8f13b2f9639203d2425411949d6e372841d0e7ac2", size = 2965619, upload-time = "2025-05-15T00:19:49.949Z" },
|
248 |
+
{ url = "https://files.pythonhosted.org/packages/08/af/d5e26c146996ddb9b7360f27b2570e1910aa0e37c7e5bd4fd238ac38428e/loro-1.5.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:af4a0fd903523d7be9bf248b5eb572cff21b98cfd08eb87a145a891ad77616db", size = 3046490, upload-time = "2025-05-15T00:20:20.12Z" },
|
249 |
+
{ url = "https://files.pythonhosted.org/packages/42/33/a723c978be8fa0005e3ccb0a96824bd4fe4874e9d03a08c2fb24f5c03f13/loro-1.5.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b80fe509a566388e04813bfa99baff9a8026da8f3fcb639500ee21c795dbcefd", size = 3278208, upload-time = "2025-05-15T00:20:47.2Z" },
|
250 |
+
{ url = "https://files.pythonhosted.org/packages/49/ce/f2669e5af13524fbb9c89aad536d11446a339574b0598adf0191bd640aba/loro-1.5.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6dd4373dc6e5727b7666e44c6c5b1c705bb2a0dbedaaccf4a81580fc1910ba17", size = 3799882, upload-time = "2025-05-15T00:21:15.274Z" },
|
251 |
+
{ url = "https://files.pythonhosted.org/packages/8a/e5/7dbb63a7b53adf44e8b447c5f40e0116501035f587bdaf8feb9fc49b0bc3/loro-1.5.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff9be94c9704a0a7fd25f2ae00e4e37c26d4127ee12a3fe52bcc03d1e4584b67", size = 3104741, upload-time = "2025-05-15T00:22:04.141Z" },
|
252 |
+
{ url = "https://files.pythonhosted.org/packages/0a/48/fc11057467f84f84414b081de62e45d31c1029ed00254d1b90d1399a5233/loro-1.5.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b273de2c99f5a9cab143b1a25dc6c5e922e569497d126a4729ff8be88c7ccdfc", size = 3364304, upload-time = "2025-05-15T00:21:42.439Z" },
|
253 |
+
{ url = "https://files.pythonhosted.org/packages/9e/af/0edf2aad989b3d11585bc47289e22e4f0bfd7961ac4dbb121f8d54854f4d/loro-1.5.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a93ca575941c88c44a36e5b70079cfb300a4c9233cb94a2da73f385fbd1b442a", size = 3119348, upload-time = "2025-05-15T00:22:50.176Z" },
|
254 |
+
{ url = "https://files.pythonhosted.org/packages/b1/99/17870634a89beca680c952fc6e4cf1866da7e54729044502f4d2e58086b3/loro-1.5.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:122cebb72c9e83ffa94623a2b8017d4e7c49da9e04b56c6acd008e9af88707d3", size = 3311880, upload-time = "2025-05-15T00:23:16.326Z" },
|
255 |
+
{ url = "https://files.pythonhosted.org/packages/87/4b/55ec796fa81c2db75b15f7a61e44ce1ab4319e0b93fd77f6bbb3bd681c52/loro-1.5.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:758587fc262475afad8792add3f9c4b855bc44bcc79b2eeadb718ff68600c810", size = 3366918, upload-time = "2025-05-15T00:23:46.914Z" },
|
256 |
+
{ url = "https://files.pythonhosted.org/packages/c3/a0/5a690fd20822522841ed4e314f3a5a00e4cde2c4b9989e11c4d0ace31333/loro-1.5.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4e6e38d4143fd2e3e1ec299f9c764aa3786328b08c4c467a4cd10dcc626b38f2", size = 3270241, upload-time = "2025-05-15T00:24:13.818Z" },
|
257 |
+
{ url = "https://files.pythonhosted.org/packages/6b/42/5097c347e72e3e9a2f8d4cd2dede9928e4271c56dbe8b9701275461c3234/loro-1.5.1-cp313-cp313-win32.whl", hash = "sha256:d4730cd9489040176eabcc2d2d5d6333b9db280c1b8f563b51f34c242863c010", size = 2466351, upload-time = "2025-05-15T00:24:57.113Z" },
|
258 |
+
{ url = "https://files.pythonhosted.org/packages/5f/ec/3c0fce5a87b4e840ee26108129670b9335cac4fdbfd1b7b53bc7f7bd3b6a/loro-1.5.1-cp313-cp313-win_amd64.whl", hash = "sha256:f3381acb0132e856bd0000623d63718fda0168287cff726e57dfd8074991d2d5", size = 2628456, upload-time = "2025-05-15T00:24:41.656Z" },
|
259 |
+
{ url = "https://files.pythonhosted.org/packages/a9/88/643122473ec5ca39b62fc7583cd5b0b1100056435314bc454699b35069e7/loro-1.5.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7462bfadd8e51268d60429ca44717714e5f1430ef2be79adc87e84a5206158a3", size = 2965004, upload-time = "2025-05-15T00:19:51.604Z" },
|
260 |
+
{ url = "https://files.pythonhosted.org/packages/cc/1c/163d50dbbabdcca1772f77c089c72e2ada6318ec28aa8a06f3334a26d319/loro-1.5.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:33897717216c44137dac67e00c5be1a57631c722aa0cd7b0c19831562e6a74fa", size = 3043720, upload-time = "2025-05-15T00:20:21.676Z" },
|
261 |
+
{ url = "https://files.pythonhosted.org/packages/41/79/37ff3af1795bf84eb418878595ef3163d494d2fcb8272fd575e3a614266e/loro-1.5.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8b7ecf076f5ffcf2a69d6cb14c77cb8035e4c2c687e7934b3d192fbba8f4f15e", size = 3275171, upload-time = "2025-05-15T00:20:48.965Z" },
|
262 |
+
{ url = "https://files.pythonhosted.org/packages/11/b7/47a84f4041306c31211a2e4fd266820fcd7091ff3451e6c381411c4b763a/loro-1.5.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c3d35bdb2cb315f339d146b55a2daba6d892bb91bbb46eea8dcff4e633c3d3c2", size = 3792486, upload-time = "2025-05-15T00:21:16.642Z" },
|
263 |
+
{ url = "https://files.pythonhosted.org/packages/0e/14/97cbdcae7e079617b71702d0d47c51624fa6a573fc2b3cd4e242ffd6f743/loro-1.5.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b5b47bb658e8fde2e65d36c8fb03da2afe02e7db60e81548a2ccf4c7adf161e2", size = 3118535, upload-time = "2025-05-15T00:22:51.433Z" },
|
264 |
+
{ url = "https://files.pythonhosted.org/packages/4b/37/e17d4a9f6307db3d3aa05450ac88b0bf29980dcf59477f7a0a6c8683e4ba/loro-1.5.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:d8c497be06dd54c9520830bd1e8bb9b68c4f0ba0f735485a9a1281cb78d82d29", size = 3307450, upload-time = "2025-05-15T00:23:17.666Z" },
|
265 |
+
{ url = "https://files.pythonhosted.org/packages/bc/5f/4597b1b12d4ea378eba10683d2e157bdcd917482a92a7321877aa1236683/loro-1.5.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:5eb4fbe5bef38379372ddc1874f8aec8ef885274de800f770aa60988010ce588", size = 3369861, upload-time = "2025-05-15T00:23:48.24Z" },
|
266 |
+
{ url = "https://files.pythonhosted.org/packages/62/42/4a75638ed05156a185a89b705c01a76fefa01d2ca6690366b092ad5e93d9/loro-1.5.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:9489cdcfa887fabfc18e5aeb0e89098d5c908ab41ccf4cdc51f434effd741b10", size = 3265428, upload-time = "2025-05-15T00:24:15.488Z" },
|
267 |
+
]
|
268 |
+
|
269 |
+
[[package]]
|
270 |
+
name = "marimo"
|
271 |
+
version = "0.14.6"
|
272 |
+
source = { registry = "https://pypi.org/simple" }
|
273 |
+
dependencies = [
|
274 |
+
{ name = "click" },
|
275 |
+
{ name = "docutils" },
|
276 |
+
{ name = "itsdangerous" },
|
277 |
+
{ name = "jedi" },
|
278 |
+
{ name = "loro" },
|
279 |
+
{ name = "markdown" },
|
280 |
+
{ name = "narwhals" },
|
281 |
+
{ name = "packaging" },
|
282 |
+
{ name = "psutil" },
|
283 |
+
{ name = "pygments" },
|
284 |
+
{ name = "pymdown-extensions" },
|
285 |
+
{ name = "pyyaml" },
|
286 |
+
{ name = "starlette" },
|
287 |
+
{ name = "tomlkit" },
|
288 |
+
{ name = "uvicorn" },
|
289 |
+
{ name = "websockets" },
|
290 |
+
]
|
291 |
+
sdist = { url = "https://files.pythonhosted.org/packages/a8/41/8b4a32f7d6c0c1be046011870a843c81d18b7ef2a2f8791eb8aa2829f8bd/marimo-0.14.6.tar.gz", hash = "sha256:e4484af13924cd2c60811fd59d643e686fc78f5bbdae615876efac5bd9df94f8", size = 29111510, upload-time = "2025-06-21T22:34:11.439Z" }
|
292 |
+
wheels = [
|
293 |
+
{ url = "https://files.pythonhosted.org/packages/02/26/9a8b012fc9e2ccf6c26a72cbd2de45a2077b98d2910d60ad9d25e84c5916/marimo-0.14.6-py3-none-any.whl", hash = "sha256:e1061458fa1ff387e80b674f251cac729d07260036726e0693f915710e79b115", size = 29585644, upload-time = "2025-06-21T22:34:15.391Z" },
|
294 |
+
]
|
295 |
+
|
296 |
+
[[package]]
|
297 |
+
name = "markdown"
|
298 |
+
version = "3.8.2"
|
299 |
+
source = { registry = "https://pypi.org/simple" }
|
300 |
+
sdist = { url = "https://files.pythonhosted.org/packages/d7/c2/4ab49206c17f75cb08d6311171f2d65798988db4360c4d1485bd0eedd67c/markdown-3.8.2.tar.gz", hash = "sha256:247b9a70dd12e27f67431ce62523e675b866d254f900c4fe75ce3dda62237c45", size = 362071, upload-time = "2025-06-19T17:12:44.483Z" }
|
301 |
+
wheels = [
|
302 |
+
{ url = "https://files.pythonhosted.org/packages/96/2b/34cc11786bc00d0f04d0f5fdc3a2b1ae0b6239eef72d3d345805f9ad92a1/markdown-3.8.2-py3-none-any.whl", hash = "sha256:5c83764dbd4e00bdd94d85a19b8d55ccca20fe35b2e678a1422b380324dd5f24", size = 106827, upload-time = "2025-06-19T17:12:42.994Z" },
|
303 |
+
]
|
304 |
+
|
305 |
+
[[package]]
|
306 |
+
name = "narwhals"
|
307 |
+
version = "1.43.1"
|
308 |
+
source = { registry = "https://pypi.org/simple" }
|
309 |
+
sdist = { url = "https://files.pythonhosted.org/packages/61/82/9f351a79260a6456db3f53d248268b4c3791f1e3228eec3c745e8816afd6/narwhals-1.43.1.tar.gz", hash = "sha256:6ff56d600da67a0a0980b83bd5577d076772fdba96474076ba4e76c920dbc1e5", size = 496655, upload-time = "2025-06-19T09:37:56.398Z" }
|
310 |
+
wheels = [
|
311 |
+
{ url = "https://files.pythonhosted.org/packages/8f/1e/b741d4eabbde95b1790e7df3c33c6b19f9b48db98a1416c6a6f06572bc66/narwhals-1.43.1-py3-none-any.whl", hash = "sha256:1ee508fa4dc0e05aa5b88717ba11613d8d9ccf0dd1e48513d4a3afb237dba9f2", size = 362737, upload-time = "2025-06-19T09:37:54.415Z" },
|
312 |
+
]
|
313 |
+
|
314 |
+
[[package]]
|
315 |
+
name = "numpy"
|
316 |
+
version = "2.3.1"
|
317 |
+
source = { registry = "https://pypi.org/simple" }
|
318 |
+
sdist = { url = "https://files.pythonhosted.org/packages/2e/19/d7c972dfe90a353dbd3efbbe1d14a5951de80c99c9dc1b93cd998d51dc0f/numpy-2.3.1.tar.gz", hash = "sha256:1ec9ae20a4226da374362cca3c62cd753faf2f951440b0e3b98e93c235441d2b", size = 20390372, upload-time = "2025-06-21T12:28:33.469Z" }
|
319 |
+
wheels = [
|
320 |
+
{ url = "https://files.pythonhosted.org/packages/c6/56/71ad5022e2f63cfe0ca93559403d0edef14aea70a841d640bd13cdba578e/numpy-2.3.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2959d8f268f3d8ee402b04a9ec4bb7604555aeacf78b360dc4ec27f1d508177d", size = 20896664, upload-time = "2025-06-21T12:15:30.845Z" },
|
321 |
+
{ url = "https://files.pythonhosted.org/packages/25/65/2db52ba049813670f7f987cc5db6dac9be7cd95e923cc6832b3d32d87cef/numpy-2.3.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:762e0c0c6b56bdedfef9a8e1d4538556438288c4276901ea008ae44091954e29", size = 14131078, upload-time = "2025-06-21T12:15:52.23Z" },
|
322 |
+
{ url = "https://files.pythonhosted.org/packages/57/dd/28fa3c17b0e751047ac928c1e1b6990238faad76e9b147e585b573d9d1bd/numpy-2.3.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:867ef172a0976aaa1f1d1b63cf2090de8b636a7674607d514505fb7276ab08fc", size = 5112554, upload-time = "2025-06-21T12:16:01.434Z" },
|
323 |
+
{ url = "https://files.pythonhosted.org/packages/c9/fc/84ea0cba8e760c4644b708b6819d91784c290288c27aca916115e3311d17/numpy-2.3.1-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:4e602e1b8682c2b833af89ba641ad4176053aaa50f5cacda1a27004352dde943", size = 6646560, upload-time = "2025-06-21T12:16:11.895Z" },
|
324 |
+
{ url = "https://files.pythonhosted.org/packages/61/b2/512b0c2ddec985ad1e496b0bd853eeb572315c0f07cd6997473ced8f15e2/numpy-2.3.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:8e333040d069eba1652fb08962ec5b76af7f2c7bce1df7e1418c8055cf776f25", size = 14260638, upload-time = "2025-06-21T12:16:32.611Z" },
|
325 |
+
{ url = "https://files.pythonhosted.org/packages/6e/45/c51cb248e679a6c6ab14b7a8e3ead3f4a3fe7425fc7a6f98b3f147bec532/numpy-2.3.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:e7cbf5a5eafd8d230a3ce356d892512185230e4781a361229bd902ff403bc660", size = 16632729, upload-time = "2025-06-21T12:16:57.439Z" },
|
326 |
+
{ url = "https://files.pythonhosted.org/packages/e4/ff/feb4be2e5c09a3da161b412019caf47183099cbea1132fd98061808c2df2/numpy-2.3.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5f1b8f26d1086835f442286c1d9b64bb3974b0b1e41bb105358fd07d20872952", size = 15565330, upload-time = "2025-06-21T12:17:20.638Z" },
|
327 |
+
{ url = "https://files.pythonhosted.org/packages/bc/6d/ceafe87587101e9ab0d370e4f6e5f3f3a85b9a697f2318738e5e7e176ce3/numpy-2.3.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ee8340cb48c9b7a5899d1149eece41ca535513a9698098edbade2a8e7a84da77", size = 18361734, upload-time = "2025-06-21T12:17:47.938Z" },
|
328 |
+
{ url = "https://files.pythonhosted.org/packages/2b/19/0fb49a3ea088be691f040c9bf1817e4669a339d6e98579f91859b902c636/numpy-2.3.1-cp312-cp312-win32.whl", hash = "sha256:e772dda20a6002ef7061713dc1e2585bc1b534e7909b2030b5a46dae8ff077ab", size = 6320411, upload-time = "2025-06-21T12:17:58.475Z" },
|
329 |
+
{ url = "https://files.pythonhosted.org/packages/b1/3e/e28f4c1dd9e042eb57a3eb652f200225e311b608632bc727ae378623d4f8/numpy-2.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:cfecc7822543abdea6de08758091da655ea2210b8ffa1faf116b940693d3df76", size = 12734973, upload-time = "2025-06-21T12:18:17.601Z" },
|
330 |
+
{ url = "https://files.pythonhosted.org/packages/04/a8/8a5e9079dc722acf53522b8f8842e79541ea81835e9b5483388701421073/numpy-2.3.1-cp312-cp312-win_arm64.whl", hash = "sha256:7be91b2239af2658653c5bb6f1b8bccafaf08226a258caf78ce44710a0160d30", size = 10191491, upload-time = "2025-06-21T12:18:33.585Z" },
|
331 |
+
{ url = "https://files.pythonhosted.org/packages/d4/bd/35ad97006d8abff8631293f8ea6adf07b0108ce6fec68da3c3fcca1197f2/numpy-2.3.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:25a1992b0a3fdcdaec9f552ef10d8103186f5397ab45e2d25f8ac51b1a6b97e8", size = 20889381, upload-time = "2025-06-21T12:19:04.103Z" },
|
332 |
+
{ url = "https://files.pythonhosted.org/packages/f1/4f/df5923874d8095b6062495b39729178eef4a922119cee32a12ee1bd4664c/numpy-2.3.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7dea630156d39b02a63c18f508f85010230409db5b2927ba59c8ba4ab3e8272e", size = 14152726, upload-time = "2025-06-21T12:19:25.599Z" },
|
333 |
+
{ url = "https://files.pythonhosted.org/packages/8c/0f/a1f269b125806212a876f7efb049b06c6f8772cf0121139f97774cd95626/numpy-2.3.1-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:bada6058dd886061f10ea15f230ccf7dfff40572e99fef440a4a857c8728c9c0", size = 5105145, upload-time = "2025-06-21T12:19:34.782Z" },
|
334 |
+
{ url = "https://files.pythonhosted.org/packages/6d/63/a7f7fd5f375b0361682f6ffbf686787e82b7bbd561268e4f30afad2bb3c0/numpy-2.3.1-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:a894f3816eb17b29e4783e5873f92faf55b710c2519e5c351767c51f79d8526d", size = 6639409, upload-time = "2025-06-21T12:19:45.228Z" },
|
335 |
+
{ url = "https://files.pythonhosted.org/packages/bf/0d/1854a4121af895aab383f4aa233748f1df4671ef331d898e32426756a8a6/numpy-2.3.1-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:18703df6c4a4fee55fd3d6e5a253d01c5d33a295409b03fda0c86b3ca2ff41a1", size = 14257630, upload-time = "2025-06-21T12:20:06.544Z" },
|
336 |
+
{ url = "https://files.pythonhosted.org/packages/50/30/af1b277b443f2fb08acf1c55ce9d68ee540043f158630d62cef012750f9f/numpy-2.3.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:5902660491bd7a48b2ec16c23ccb9124b8abfd9583c5fdfa123fe6b421e03de1", size = 16627546, upload-time = "2025-06-21T12:20:31.002Z" },
|
337 |
+
{ url = "https://files.pythonhosted.org/packages/6e/ec/3b68220c277e463095342d254c61be8144c31208db18d3fd8ef02712bcd6/numpy-2.3.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:36890eb9e9d2081137bd78d29050ba63b8dab95dff7912eadf1185e80074b2a0", size = 15562538, upload-time = "2025-06-21T12:20:54.322Z" },
|
338 |
+
{ url = "https://files.pythonhosted.org/packages/77/2b/4014f2bcc4404484021c74d4c5ee8eb3de7e3f7ac75f06672f8dcf85140a/numpy-2.3.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a780033466159c2270531e2b8ac063704592a0bc62ec4a1b991c7c40705eb0e8", size = 18360327, upload-time = "2025-06-21T12:21:21.053Z" },
|
339 |
+
{ url = "https://files.pythonhosted.org/packages/40/8d/2ddd6c9b30fcf920837b8672f6c65590c7d92e43084c25fc65edc22e93ca/numpy-2.3.1-cp313-cp313-win32.whl", hash = "sha256:39bff12c076812595c3a306f22bfe49919c5513aa1e0e70fac756a0be7c2a2b8", size = 6312330, upload-time = "2025-06-21T12:25:07.447Z" },
|
340 |
+
{ url = "https://files.pythonhosted.org/packages/dd/c8/beaba449925988d415efccb45bf977ff8327a02f655090627318f6398c7b/numpy-2.3.1-cp313-cp313-win_amd64.whl", hash = "sha256:8d5ee6eec45f08ce507a6570e06f2f879b374a552087a4179ea7838edbcbfa42", size = 12731565, upload-time = "2025-06-21T12:25:26.444Z" },
|
341 |
+
{ url = "https://files.pythonhosted.org/packages/0b/c3/5c0c575d7ec78c1126998071f58facfc124006635da75b090805e642c62e/numpy-2.3.1-cp313-cp313-win_arm64.whl", hash = "sha256:0c4d9e0a8368db90f93bd192bfa771ace63137c3488d198ee21dfb8e7771916e", size = 10190262, upload-time = "2025-06-21T12:25:42.196Z" },
|
342 |
+
{ url = "https://files.pythonhosted.org/packages/ea/19/a029cd335cf72f79d2644dcfc22d90f09caa86265cbbde3b5702ccef6890/numpy-2.3.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:b0b5397374f32ec0649dd98c652a1798192042e715df918c20672c62fb52d4b8", size = 20987593, upload-time = "2025-06-21T12:21:51.664Z" },
|
343 |
+
{ url = "https://files.pythonhosted.org/packages/25/91/8ea8894406209107d9ce19b66314194675d31761fe2cb3c84fe2eeae2f37/numpy-2.3.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:c5bdf2015ccfcee8253fb8be695516ac4457c743473a43290fd36eba6a1777eb", size = 14300523, upload-time = "2025-06-21T12:22:13.583Z" },
|
344 |
+
{ url = "https://files.pythonhosted.org/packages/a6/7f/06187b0066eefc9e7ce77d5f2ddb4e314a55220ad62dd0bfc9f2c44bac14/numpy-2.3.1-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:d70f20df7f08b90a2062c1f07737dd340adccf2068d0f1b9b3d56e2038979fee", size = 5227993, upload-time = "2025-06-21T12:22:22.53Z" },
|
345 |
+
{ url = "https://files.pythonhosted.org/packages/e8/ec/a926c293c605fa75e9cfb09f1e4840098ed46d2edaa6e2152ee35dc01ed3/numpy-2.3.1-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:2fb86b7e58f9ac50e1e9dd1290154107e47d1eef23a0ae9145ded06ea606f992", size = 6736652, upload-time = "2025-06-21T12:22:33.629Z" },
|
346 |
+
{ url = "https://files.pythonhosted.org/packages/e3/62/d68e52fb6fde5586650d4c0ce0b05ff3a48ad4df4ffd1b8866479d1d671d/numpy-2.3.1-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:23ab05b2d241f76cb883ce8b9a93a680752fbfcbd51c50eff0b88b979e471d8c", size = 14331561, upload-time = "2025-06-21T12:22:55.056Z" },
|
347 |
+
{ url = "https://files.pythonhosted.org/packages/fc/ec/b74d3f2430960044bdad6900d9f5edc2dc0fb8bf5a0be0f65287bf2cbe27/numpy-2.3.1-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:ce2ce9e5de4703a673e705183f64fd5da5bf36e7beddcb63a25ee2286e71ca48", size = 16693349, upload-time = "2025-06-21T12:23:20.53Z" },
|
348 |
+
{ url = "https://files.pythonhosted.org/packages/0d/15/def96774b9d7eb198ddadfcbd20281b20ebb510580419197e225f5c55c3e/numpy-2.3.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c4913079974eeb5c16ccfd2b1f09354b8fed7e0d6f2cab933104a09a6419b1ee", size = 15642053, upload-time = "2025-06-21T12:23:43.697Z" },
|
349 |
+
{ url = "https://files.pythonhosted.org/packages/2b/57/c3203974762a759540c6ae71d0ea2341c1fa41d84e4971a8e76d7141678a/numpy-2.3.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:010ce9b4f00d5c036053ca684c77441f2f2c934fd23bee058b4d6f196efd8280", size = 18434184, upload-time = "2025-06-21T12:24:10.708Z" },
|
350 |
+
{ url = "https://files.pythonhosted.org/packages/22/8a/ccdf201457ed8ac6245187850aff4ca56a79edbea4829f4e9f14d46fa9a5/numpy-2.3.1-cp313-cp313t-win32.whl", hash = "sha256:6269b9edfe32912584ec496d91b00b6d34282ca1d07eb10e82dfc780907d6c2e", size = 6440678, upload-time = "2025-06-21T12:24:21.596Z" },
|
351 |
+
{ url = "https://files.pythonhosted.org/packages/f1/7e/7f431d8bd8eb7e03d79294aed238b1b0b174b3148570d03a8a8a8f6a0da9/numpy-2.3.1-cp313-cp313t-win_amd64.whl", hash = "sha256:2a809637460e88a113e186e87f228d74ae2852a2e0c44de275263376f17b5bdc", size = 12870697, upload-time = "2025-06-21T12:24:40.644Z" },
|
352 |
+
{ url = "https://files.pythonhosted.org/packages/d4/ca/af82bf0fad4c3e573c6930ed743b5308492ff19917c7caaf2f9b6f9e2e98/numpy-2.3.1-cp313-cp313t-win_arm64.whl", hash = "sha256:eccb9a159db9aed60800187bc47a6d3451553f0e1b08b068d8b277ddfbb9b244", size = 10260376, upload-time = "2025-06-21T12:24:56.884Z" },
|
353 |
+
]
|
354 |
+
|
355 |
+
[[package]]
|
356 |
+
name = "packaging"
|
357 |
+
version = "25.0"
|
358 |
+
source = { registry = "https://pypi.org/simple" }
|
359 |
+
sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" }
|
360 |
+
wheels = [
|
361 |
+
{ url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" },
|
362 |
+
]
|
363 |
+
|
364 |
+
[[package]]
|
365 |
+
name = "pandas"
|
366 |
+
version = "2.3.0"
|
367 |
+
source = { registry = "https://pypi.org/simple" }
|
368 |
+
dependencies = [
|
369 |
+
{ name = "numpy" },
|
370 |
+
{ name = "python-dateutil" },
|
371 |
+
{ name = "pytz" },
|
372 |
+
{ name = "tzdata" },
|
373 |
+
]
|
374 |
+
sdist = { url = "https://files.pythonhosted.org/packages/72/51/48f713c4c728d7c55ef7444ba5ea027c26998d96d1a40953b346438602fc/pandas-2.3.0.tar.gz", hash = "sha256:34600ab34ebf1131a7613a260a61dbe8b62c188ec0ea4c296da7c9a06b004133", size = 4484490, upload-time = "2025-06-05T03:27:54.133Z" }
|
375 |
+
wheels = [
|
376 |
+
{ url = "https://files.pythonhosted.org/packages/94/46/24192607058dd607dbfacdd060a2370f6afb19c2ccb617406469b9aeb8e7/pandas-2.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2eb4728a18dcd2908c7fccf74a982e241b467d178724545a48d0caf534b38ebf", size = 11573865, upload-time = "2025-06-05T03:26:46.774Z" },
|
377 |
+
{ url = "https://files.pythonhosted.org/packages/9f/cc/ae8ea3b800757a70c9fdccc68b67dc0280a6e814efcf74e4211fd5dea1ca/pandas-2.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b9d8c3187be7479ea5c3d30c32a5d73d62a621166675063b2edd21bc47614027", size = 10702154, upload-time = "2025-06-05T16:50:14.439Z" },
|
378 |
+
{ url = "https://files.pythonhosted.org/packages/d8/ba/a7883d7aab3d24c6540a2768f679e7414582cc389876d469b40ec749d78b/pandas-2.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9ff730713d4c4f2f1c860e36c005c7cefc1c7c80c21c0688fd605aa43c9fcf09", size = 11262180, upload-time = "2025-06-05T16:50:17.453Z" },
|
379 |
+
{ url = "https://files.pythonhosted.org/packages/01/a5/931fc3ad333d9d87b10107d948d757d67ebcfc33b1988d5faccc39c6845c/pandas-2.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba24af48643b12ffe49b27065d3babd52702d95ab70f50e1b34f71ca703e2c0d", size = 11991493, upload-time = "2025-06-05T03:26:51.813Z" },
|
380 |
+
{ url = "https://files.pythonhosted.org/packages/d7/bf/0213986830a92d44d55153c1d69b509431a972eb73f204242988c4e66e86/pandas-2.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:404d681c698e3c8a40a61d0cd9412cc7364ab9a9cc6e144ae2992e11a2e77a20", size = 12470733, upload-time = "2025-06-06T00:00:18.651Z" },
|
381 |
+
{ url = "https://files.pythonhosted.org/packages/a4/0e/21eb48a3a34a7d4bac982afc2c4eb5ab09f2d988bdf29d92ba9ae8e90a79/pandas-2.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6021910b086b3ca756755e86ddc64e0ddafd5e58e076c72cb1585162e5ad259b", size = 13212406, upload-time = "2025-06-05T03:26:55.992Z" },
|
382 |
+
{ url = "https://files.pythonhosted.org/packages/1f/d9/74017c4eec7a28892d8d6e31ae9de3baef71f5a5286e74e6b7aad7f8c837/pandas-2.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:094e271a15b579650ebf4c5155c05dcd2a14fd4fdd72cf4854b2f7ad31ea30be", size = 10976199, upload-time = "2025-06-05T03:26:59.594Z" },
|
383 |
+
{ url = "https://files.pythonhosted.org/packages/d3/57/5cb75a56a4842bbd0511c3d1c79186d8315b82dac802118322b2de1194fe/pandas-2.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2c7e2fc25f89a49a11599ec1e76821322439d90820108309bf42130d2f36c983", size = 11518913, upload-time = "2025-06-05T03:27:02.757Z" },
|
384 |
+
{ url = "https://files.pythonhosted.org/packages/05/01/0c8785610e465e4948a01a059562176e4c8088aa257e2e074db868f86d4e/pandas-2.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c6da97aeb6a6d233fb6b17986234cc723b396b50a3c6804776351994f2a658fd", size = 10655249, upload-time = "2025-06-05T16:50:20.17Z" },
|
385 |
+
{ url = "https://files.pythonhosted.org/packages/e8/6a/47fd7517cd8abe72a58706aab2b99e9438360d36dcdb052cf917b7bf3bdc/pandas-2.3.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb32dc743b52467d488e7a7c8039b821da2826a9ba4f85b89ea95274f863280f", size = 11328359, upload-time = "2025-06-05T03:27:06.431Z" },
|
386 |
+
{ url = "https://files.pythonhosted.org/packages/2a/b3/463bfe819ed60fb7e7ddffb4ae2ee04b887b3444feee6c19437b8f834837/pandas-2.3.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:213cd63c43263dbb522c1f8a7c9d072e25900f6975596f883f4bebd77295d4f3", size = 12024789, upload-time = "2025-06-05T03:27:09.875Z" },
|
387 |
+
{ url = "https://files.pythonhosted.org/packages/04/0c/e0704ccdb0ac40aeb3434d1c641c43d05f75c92e67525df39575ace35468/pandas-2.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1d2b33e68d0ce64e26a4acc2e72d747292084f4e8db4c847c6f5f6cbe56ed6d8", size = 12480734, upload-time = "2025-06-06T00:00:22.246Z" },
|
388 |
+
{ url = "https://files.pythonhosted.org/packages/e9/df/815d6583967001153bb27f5cf075653d69d51ad887ebbf4cfe1173a1ac58/pandas-2.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:430a63bae10b5086995db1b02694996336e5a8ac9a96b4200572b413dfdfccb9", size = 13223381, upload-time = "2025-06-05T03:27:15.641Z" },
|
389 |
+
{ url = "https://files.pythonhosted.org/packages/79/88/ca5973ed07b7f484c493e941dbff990861ca55291ff7ac67c815ce347395/pandas-2.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:4930255e28ff5545e2ca404637bcc56f031893142773b3468dc021c6c32a1390", size = 10970135, upload-time = "2025-06-05T03:27:24.131Z" },
|
390 |
+
{ url = "https://files.pythonhosted.org/packages/24/fb/0994c14d1f7909ce83f0b1fb27958135513c4f3f2528bde216180aa73bfc/pandas-2.3.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:f925f1ef673b4bd0271b1809b72b3270384f2b7d9d14a189b12b7fc02574d575", size = 12141356, upload-time = "2025-06-05T03:27:34.547Z" },
|
391 |
+
{ url = "https://files.pythonhosted.org/packages/9d/a2/9b903e5962134497ac4f8a96f862ee3081cb2506f69f8e4778ce3d9c9d82/pandas-2.3.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e78ad363ddb873a631e92a3c063ade1ecfb34cae71e9a2be6ad100f875ac1042", size = 11474674, upload-time = "2025-06-05T03:27:39.448Z" },
|
392 |
+
{ url = "https://files.pythonhosted.org/packages/81/3a/3806d041bce032f8de44380f866059437fb79e36d6b22c82c187e65f765b/pandas-2.3.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:951805d146922aed8357e4cc5671b8b0b9be1027f0619cea132a9f3f65f2f09c", size = 11439876, upload-time = "2025-06-05T03:27:43.652Z" },
|
393 |
+
{ url = "https://files.pythonhosted.org/packages/15/aa/3fc3181d12b95da71f5c2537c3e3b3af6ab3a8c392ab41ebb766e0929bc6/pandas-2.3.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a881bc1309f3fce34696d07b00f13335c41f5f5a8770a33b09ebe23261cfc67", size = 11966182, upload-time = "2025-06-05T03:27:47.652Z" },
|
394 |
+
{ url = "https://files.pythonhosted.org/packages/37/e7/e12f2d9b0a2c4a2cc86e2aabff7ccfd24f03e597d770abfa2acd313ee46b/pandas-2.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:e1991bbb96f4050b09b5f811253c4f3cf05ee89a589379aa36cd623f21a31d6f", size = 12547686, upload-time = "2025-06-06T00:00:26.142Z" },
|
395 |
+
{ url = "https://files.pythonhosted.org/packages/39/c2/646d2e93e0af70f4e5359d870a63584dacbc324b54d73e6b3267920ff117/pandas-2.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:bb3be958022198531eb7ec2008cfc78c5b1eed51af8600c6c5d9160d89d8d249", size = 13231847, upload-time = "2025-06-05T03:27:51.465Z" },
|
396 |
+
]
|
397 |
+
|
398 |
+
[[package]]
|
399 |
+
name = "parso"
|
400 |
+
version = "0.8.4"
|
401 |
+
source = { registry = "https://pypi.org/simple" }
|
402 |
+
sdist = { url = "https://files.pythonhosted.org/packages/66/94/68e2e17afaa9169cf6412ab0f28623903be73d1b32e208d9e8e541bb086d/parso-0.8.4.tar.gz", hash = "sha256:eb3a7b58240fb99099a345571deecc0f9540ea5f4dd2fe14c2a99d6b281ab92d", size = 400609, upload-time = "2024-04-05T09:43:55.897Z" }
|
403 |
+
wheels = [
|
404 |
+
{ url = "https://files.pythonhosted.org/packages/c6/ac/dac4a63f978e4dcb3c6d3a78c4d8e0192a113d288502a1216950c41b1027/parso-0.8.4-py2.py3-none-any.whl", hash = "sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18", size = 103650, upload-time = "2024-04-05T09:43:53.299Z" },
|
405 |
+
]
|
406 |
+
|
407 |
+
[[package]]
|
408 |
+
name = "psutil"
|
409 |
+
version = "7.0.0"
|
410 |
+
source = { registry = "https://pypi.org/simple" }
|
411 |
+
sdist = { url = "https://files.pythonhosted.org/packages/2a/80/336820c1ad9286a4ded7e845b2eccfcb27851ab8ac6abece774a6ff4d3de/psutil-7.0.0.tar.gz", hash = "sha256:7be9c3eba38beccb6495ea33afd982a44074b78f28c434a1f51cc07fd315c456", size = 497003, upload-time = "2025-02-13T21:54:07.946Z" }
|
412 |
+
wheels = [
|
413 |
+
{ url = "https://files.pythonhosted.org/packages/ed/e6/2d26234410f8b8abdbf891c9da62bee396583f713fb9f3325a4760875d22/psutil-7.0.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:101d71dc322e3cffd7cea0650b09b3d08b8e7c4109dd6809fe452dfd00e58b25", size = 238051, upload-time = "2025-02-13T21:54:12.36Z" },
|
414 |
+
{ url = "https://files.pythonhosted.org/packages/04/8b/30f930733afe425e3cbfc0e1468a30a18942350c1a8816acfade80c005c4/psutil-7.0.0-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:39db632f6bb862eeccf56660871433e111b6ea58f2caea825571951d4b6aa3da", size = 239535, upload-time = "2025-02-13T21:54:16.07Z" },
|
415 |
+
{ url = "https://files.pythonhosted.org/packages/2a/ed/d362e84620dd22876b55389248e522338ed1bf134a5edd3b8231d7207f6d/psutil-7.0.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1fcee592b4c6f146991ca55919ea3d1f8926497a713ed7faaf8225e174581e91", size = 275004, upload-time = "2025-02-13T21:54:18.662Z" },
|
416 |
+
{ url = "https://files.pythonhosted.org/packages/bf/b9/b0eb3f3cbcb734d930fdf839431606844a825b23eaf9a6ab371edac8162c/psutil-7.0.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b1388a4f6875d7e2aff5c4ca1cc16c545ed41dd8bb596cefea80111db353a34", size = 277986, upload-time = "2025-02-13T21:54:21.811Z" },
|
417 |
+
{ url = "https://files.pythonhosted.org/packages/eb/a2/709e0fe2f093556c17fbafda93ac032257242cabcc7ff3369e2cb76a97aa/psutil-7.0.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5f098451abc2828f7dc6b58d44b532b22f2088f4999a937557b603ce72b1993", size = 279544, upload-time = "2025-02-13T21:54:24.68Z" },
|
418 |
+
{ url = "https://files.pythonhosted.org/packages/50/e6/eecf58810b9d12e6427369784efe814a1eec0f492084ce8eb8f4d89d6d61/psutil-7.0.0-cp37-abi3-win32.whl", hash = "sha256:ba3fcef7523064a6c9da440fc4d6bd07da93ac726b5733c29027d7dc95b39d99", size = 241053, upload-time = "2025-02-13T21:54:34.31Z" },
|
419 |
+
{ url = "https://files.pythonhosted.org/packages/50/1b/6921afe68c74868b4c9fa424dad3be35b095e16687989ebbb50ce4fceb7c/psutil-7.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:4cf3d4eb1aa9b348dec30105c55cd9b7d4629285735a102beb4441e38db90553", size = 244885, upload-time = "2025-02-13T21:54:37.486Z" },
|
420 |
+
]
|
421 |
+
|
422 |
+
[[package]]
|
423 |
+
name = "pygments"
|
424 |
+
version = "2.19.2"
|
425 |
+
source = { registry = "https://pypi.org/simple" }
|
426 |
+
sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" }
|
427 |
+
wheels = [
|
428 |
+
{ url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" },
|
429 |
+
]
|
430 |
+
|
431 |
+
[[package]]
|
432 |
+
name = "pymdown-extensions"
|
433 |
+
version = "10.16"
|
434 |
+
source = { registry = "https://pypi.org/simple" }
|
435 |
+
dependencies = [
|
436 |
+
{ name = "markdown" },
|
437 |
+
{ name = "pyyaml" },
|
438 |
+
]
|
439 |
+
sdist = { url = "https://files.pythonhosted.org/packages/1a/0a/c06b542ac108bfc73200677309cd9188a3a01b127a63f20cadc18d873d88/pymdown_extensions-10.16.tar.gz", hash = "sha256:71dac4fca63fabeffd3eb9038b756161a33ec6e8d230853d3cecf562155ab3de", size = 853197, upload-time = "2025-06-21T17:56:36.974Z" }
|
440 |
+
wheels = [
|
441 |
+
{ url = "https://files.pythonhosted.org/packages/98/d4/10bb14004d3c792811e05e21b5e5dcae805aacb739bd12a0540967b99592/pymdown_extensions-10.16-py3-none-any.whl", hash = "sha256:f5dd064a4db588cb2d95229fc4ee63a1b16cc8b4d0e6145c0899ed8723da1df2", size = 266143, upload-time = "2025-06-21T17:56:35.356Z" },
|
442 |
+
]
|
443 |
+
|
444 |
+
[[package]]
|
445 |
+
name = "python-dateutil"
|
446 |
+
version = "2.9.0.post0"
|
447 |
+
source = { registry = "https://pypi.org/simple" }
|
448 |
+
dependencies = [
|
449 |
+
{ name = "six" },
|
450 |
+
]
|
451 |
+
sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" }
|
452 |
+
wheels = [
|
453 |
+
{ url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" },
|
454 |
+
]
|
455 |
+
|
456 |
+
[[package]]
|
457 |
+
name = "pytz"
|
458 |
+
version = "2025.2"
|
459 |
+
source = { registry = "https://pypi.org/simple" }
|
460 |
+
sdist = { url = "https://files.pythonhosted.org/packages/f8/bf/abbd3cdfb8fbc7fb3d4d38d320f2441b1e7cbe29be4f23797b4a2b5d8aac/pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3", size = 320884, upload-time = "2025-03-25T02:25:00.538Z" }
|
461 |
+
wheels = [
|
462 |
+
{ url = "https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00", size = 509225, upload-time = "2025-03-25T02:24:58.468Z" },
|
463 |
+
]
|
464 |
+
|
465 |
+
[[package]]
|
466 |
+
name = "pyyaml"
|
467 |
+
version = "6.0.2"
|
468 |
+
source = { registry = "https://pypi.org/simple" }
|
469 |
+
sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631, upload-time = "2024-08-06T20:33:50.674Z" }
|
470 |
+
wheels = [
|
471 |
+
{ url = "https://files.pythonhosted.org/packages/86/0c/c581167fc46d6d6d7ddcfb8c843a4de25bdd27e4466938109ca68492292c/PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", size = 183873, upload-time = "2024-08-06T20:32:25.131Z" },
|
472 |
+
{ url = "https://files.pythonhosted.org/packages/a8/0c/38374f5bb272c051e2a69281d71cba6fdb983413e6758b84482905e29a5d/PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", size = 173302, upload-time = "2024-08-06T20:32:26.511Z" },
|
473 |
+
{ url = "https://files.pythonhosted.org/packages/c3/93/9916574aa8c00aa06bbac729972eb1071d002b8e158bd0e83a3b9a20a1f7/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", size = 739154, upload-time = "2024-08-06T20:32:28.363Z" },
|
474 |
+
{ url = "https://files.pythonhosted.org/packages/95/0f/b8938f1cbd09739c6da569d172531567dbcc9789e0029aa070856f123984/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", size = 766223, upload-time = "2024-08-06T20:32:30.058Z" },
|
475 |
+
{ url = "https://files.pythonhosted.org/packages/b9/2b/614b4752f2e127db5cc206abc23a8c19678e92b23c3db30fc86ab731d3bd/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", size = 767542, upload-time = "2024-08-06T20:32:31.881Z" },
|
476 |
+
{ url = "https://files.pythonhosted.org/packages/d4/00/dd137d5bcc7efea1836d6264f049359861cf548469d18da90cd8216cf05f/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", size = 731164, upload-time = "2024-08-06T20:32:37.083Z" },
|
477 |
+
{ url = "https://files.pythonhosted.org/packages/c9/1f/4f998c900485e5c0ef43838363ba4a9723ac0ad73a9dc42068b12aaba4e4/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", size = 756611, upload-time = "2024-08-06T20:32:38.898Z" },
|
478 |
+
{ url = "https://files.pythonhosted.org/packages/df/d1/f5a275fdb252768b7a11ec63585bc38d0e87c9e05668a139fea92b80634c/PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", size = 140591, upload-time = "2024-08-06T20:32:40.241Z" },
|
479 |
+
{ url = "https://files.pythonhosted.org/packages/0c/e8/4f648c598b17c3d06e8753d7d13d57542b30d56e6c2dedf9c331ae56312e/PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", size = 156338, upload-time = "2024-08-06T20:32:41.93Z" },
|
480 |
+
{ url = "https://files.pythonhosted.org/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", size = 181309, upload-time = "2024-08-06T20:32:43.4Z" },
|
481 |
+
{ url = "https://files.pythonhosted.org/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", size = 171679, upload-time = "2024-08-06T20:32:44.801Z" },
|
482 |
+
{ url = "https://files.pythonhosted.org/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", size = 733428, upload-time = "2024-08-06T20:32:46.432Z" },
|
483 |
+
{ url = "https://files.pythonhosted.org/packages/a3/69/864fbe19e6c18ea3cc196cbe5d392175b4cf3d5d0ac1403ec3f2d237ebb5/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", size = 763361, upload-time = "2024-08-06T20:32:51.188Z" },
|
484 |
+
{ url = "https://files.pythonhosted.org/packages/04/24/b7721e4845c2f162d26f50521b825fb061bc0a5afcf9a386840f23ea19fa/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", size = 759523, upload-time = "2024-08-06T20:32:53.019Z" },
|
485 |
+
{ url = "https://files.pythonhosted.org/packages/2b/b2/e3234f59ba06559c6ff63c4e10baea10e5e7df868092bf9ab40e5b9c56b6/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", size = 726660, upload-time = "2024-08-06T20:32:54.708Z" },
|
486 |
+
{ url = "https://files.pythonhosted.org/packages/fe/0f/25911a9f080464c59fab9027482f822b86bf0608957a5fcc6eaac85aa515/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", size = 751597, upload-time = "2024-08-06T20:32:56.985Z" },
|
487 |
+
{ url = "https://files.pythonhosted.org/packages/14/0d/e2c3b43bbce3cf6bd97c840b46088a3031085179e596d4929729d8d68270/PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", size = 140527, upload-time = "2024-08-06T20:33:03.001Z" },
|
488 |
+
{ url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446, upload-time = "2024-08-06T20:33:04.33Z" },
|
489 |
+
]
|
490 |
+
|
491 |
+
[[package]]
|
492 |
+
name = "six"
|
493 |
+
version = "1.17.0"
|
494 |
+
source = { registry = "https://pypi.org/simple" }
|
495 |
+
sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" }
|
496 |
+
wheels = [
|
497 |
+
{ url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" },
|
498 |
+
]
|
499 |
+
|
500 |
+
[[package]]
|
501 |
+
name = "sniffio"
|
502 |
+
version = "1.3.1"
|
503 |
+
source = { registry = "https://pypi.org/simple" }
|
504 |
+
sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" }
|
505 |
+
wheels = [
|
506 |
+
{ url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" },
|
507 |
+
]
|
508 |
+
|
509 |
+
[[package]]
|
510 |
+
name = "starlette"
|
511 |
+
version = "0.47.1"
|
512 |
+
source = { registry = "https://pypi.org/simple" }
|
513 |
+
dependencies = [
|
514 |
+
{ name = "anyio" },
|
515 |
+
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
|
516 |
+
]
|
517 |
+
sdist = { url = "https://files.pythonhosted.org/packages/0a/69/662169fdb92fb96ec3eaee218cf540a629d629c86d7993d9651226a6789b/starlette-0.47.1.tar.gz", hash = "sha256:aef012dd2b6be325ffa16698f9dc533614fb1cebd593a906b90dc1025529a79b", size = 2583072, upload-time = "2025-06-21T04:03:17.337Z" }
|
518 |
+
wheels = [
|
519 |
+
{ url = "https://files.pythonhosted.org/packages/82/95/38ef0cd7fa11eaba6a99b3c4f5ac948d8bc6ff199aabd327a29cc000840c/starlette-0.47.1-py3-none-any.whl", hash = "sha256:5e11c9f5c7c3f24959edbf2dffdc01bba860228acf657129467d8a7468591527", size = 72747, upload-time = "2025-06-21T04:03:15.705Z" },
|
520 |
+
]
|
521 |
+
|
522 |
+
[[package]]
|
523 |
+
name = "tomlkit"
|
524 |
+
version = "0.13.3"
|
525 |
+
source = { registry = "https://pypi.org/simple" }
|
526 |
+
sdist = { url = "https://files.pythonhosted.org/packages/cc/18/0bbf3884e9eaa38819ebe46a7bd25dcd56b67434402b66a58c4b8e552575/tomlkit-0.13.3.tar.gz", hash = "sha256:430cf247ee57df2b94ee3fbe588e71d362a941ebb545dec29b53961d61add2a1", size = 185207, upload-time = "2025-06-05T07:13:44.947Z" }
|
527 |
+
wheels = [
|
528 |
+
{ url = "https://files.pythonhosted.org/packages/bd/75/8539d011f6be8e29f339c42e633aae3cb73bffa95dd0f9adec09b9c58e85/tomlkit-0.13.3-py3-none-any.whl", hash = "sha256:c89c649d79ee40629a9fda55f8ace8c6a1b42deb912b2a8fd8d942ddadb606b0", size = 38901, upload-time = "2025-06-05T07:13:43.546Z" },
|
529 |
+
]
|
530 |
+
|
531 |
+
[[package]]
|
532 |
+
name = "typing-extensions"
|
533 |
+
version = "4.14.0"
|
534 |
+
source = { registry = "https://pypi.org/simple" }
|
535 |
+
sdist = { url = "https://files.pythonhosted.org/packages/d1/bc/51647cd02527e87d05cb083ccc402f93e441606ff1f01739a62c8ad09ba5/typing_extensions-4.14.0.tar.gz", hash = "sha256:8676b788e32f02ab42d9e7c61324048ae4c6d844a399eebace3d4979d75ceef4", size = 107423, upload-time = "2025-06-02T14:52:11.399Z" }
|
536 |
+
wheels = [
|
537 |
+
{ url = "https://files.pythonhosted.org/packages/69/e0/552843e0d356fbb5256d21449fa957fa4eff3bbc135a74a691ee70c7c5da/typing_extensions-4.14.0-py3-none-any.whl", hash = "sha256:a1514509136dd0b477638fc68d6a91497af5076466ad0fa6c338e44e359944af", size = 43839, upload-time = "2025-06-02T14:52:10.026Z" },
|
538 |
+
]
|
539 |
+
|
540 |
+
[[package]]
|
541 |
+
name = "tzdata"
|
542 |
+
version = "2025.2"
|
543 |
+
source = { registry = "https://pypi.org/simple" }
|
544 |
+
sdist = { url = "https://files.pythonhosted.org/packages/95/32/1a225d6164441be760d75c2c42e2780dc0873fe382da3e98a2e1e48361e5/tzdata-2025.2.tar.gz", hash = "sha256:b60a638fcc0daffadf82fe0f57e53d06bdec2f36c4df66280ae79bce6bd6f2b9", size = 196380, upload-time = "2025-03-23T13:54:43.652Z" }
|
545 |
+
wheels = [
|
546 |
+
{ url = "https://files.pythonhosted.org/packages/5c/23/c7abc0ca0a1526a0774eca151daeb8de62ec457e77262b66b359c3c7679e/tzdata-2025.2-py2.py3-none-any.whl", hash = "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8", size = 347839, upload-time = "2025-03-23T13:54:41.845Z" },
|
547 |
+
]
|
548 |
+
|
549 |
+
[[package]]
|
550 |
+
name = "uvicorn"
|
551 |
+
version = "0.34.3"
|
552 |
+
source = { registry = "https://pypi.org/simple" }
|
553 |
+
dependencies = [
|
554 |
+
{ name = "click" },
|
555 |
+
{ name = "h11" },
|
556 |
+
]
|
557 |
+
sdist = { url = "https://files.pythonhosted.org/packages/de/ad/713be230bcda622eaa35c28f0d328c3675c371238470abdea52417f17a8e/uvicorn-0.34.3.tar.gz", hash = "sha256:35919a9a979d7a59334b6b10e05d77c1d0d574c50e0fc98b8b1a0f165708b55a", size = 76631, upload-time = "2025-06-01T07:48:17.531Z" }
|
558 |
+
wheels = [
|
559 |
+
{ url = "https://files.pythonhosted.org/packages/6d/0d/8adfeaa62945f90d19ddc461c55f4a50c258af7662d34b6a3d5d1f8646f6/uvicorn-0.34.3-py3-none-any.whl", hash = "sha256:16246631db62bdfbf069b0645177d6e8a77ba950cfedbfd093acef9444e4d885", size = 62431, upload-time = "2025-06-01T07:48:15.664Z" },
|
560 |
+
]
|
561 |
+
|
562 |
+
[[package]]
|
563 |
+
name = "websockets"
|
564 |
+
version = "15.0.1"
|
565 |
+
source = { registry = "https://pypi.org/simple" }
|
566 |
+
sdist = { url = "https://files.pythonhosted.org/packages/21/e6/26d09fab466b7ca9c7737474c52be4f76a40301b08362eb2dbc19dcc16c1/websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee", size = 177016, upload-time = "2025-03-05T20:03:41.606Z" }
|
567 |
+
wheels = [
|
568 |
+
{ url = "https://files.pythonhosted.org/packages/51/6b/4545a0d843594f5d0771e86463606a3988b5a09ca5123136f8a76580dd63/websockets-15.0.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3e90baa811a5d73f3ca0bcbf32064d663ed81318ab225ee4f427ad4e26e5aff3", size = 175437, upload-time = "2025-03-05T20:02:16.706Z" },
|
569 |
+
{ url = "https://files.pythonhosted.org/packages/f4/71/809a0f5f6a06522af902e0f2ea2757f71ead94610010cf570ab5c98e99ed/websockets-15.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:592f1a9fe869c778694f0aa806ba0374e97648ab57936f092fd9d87f8bc03665", size = 173096, upload-time = "2025-03-05T20:02:18.832Z" },
|
570 |
+
{ url = "https://files.pythonhosted.org/packages/3d/69/1a681dd6f02180916f116894181eab8b2e25b31e484c5d0eae637ec01f7c/websockets-15.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0701bc3cfcb9164d04a14b149fd74be7347a530ad3bbf15ab2c678a2cd3dd9a2", size = 173332, upload-time = "2025-03-05T20:02:20.187Z" },
|
571 |
+
{ url = "https://files.pythonhosted.org/packages/a6/02/0073b3952f5bce97eafbb35757f8d0d54812b6174ed8dd952aa08429bcc3/websockets-15.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8b56bdcdb4505c8078cb6c7157d9811a85790f2f2b3632c7d1462ab5783d215", size = 183152, upload-time = "2025-03-05T20:02:22.286Z" },
|
572 |
+
{ url = "https://files.pythonhosted.org/packages/74/45/c205c8480eafd114b428284840da0b1be9ffd0e4f87338dc95dc6ff961a1/websockets-15.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0af68c55afbd5f07986df82831c7bff04846928ea8d1fd7f30052638788bc9b5", size = 182096, upload-time = "2025-03-05T20:02:24.368Z" },
|
573 |
+
{ url = "https://files.pythonhosted.org/packages/14/8f/aa61f528fba38578ec553c145857a181384c72b98156f858ca5c8e82d9d3/websockets-15.0.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64dee438fed052b52e4f98f76c5790513235efaa1ef7f3f2192c392cd7c91b65", size = 182523, upload-time = "2025-03-05T20:02:25.669Z" },
|
574 |
+
{ url = "https://files.pythonhosted.org/packages/ec/6d/0267396610add5bc0d0d3e77f546d4cd287200804fe02323797de77dbce9/websockets-15.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d5f6b181bb38171a8ad1d6aa58a67a6aa9d4b38d0f8c5f496b9e42561dfc62fe", size = 182790, upload-time = "2025-03-05T20:02:26.99Z" },
|
575 |
+
{ url = "https://files.pythonhosted.org/packages/02/05/c68c5adbf679cf610ae2f74a9b871ae84564462955d991178f95a1ddb7dd/websockets-15.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5d54b09eba2bada6011aea5375542a157637b91029687eb4fdb2dab11059c1b4", size = 182165, upload-time = "2025-03-05T20:02:30.291Z" },
|
576 |
+
{ url = "https://files.pythonhosted.org/packages/29/93/bb672df7b2f5faac89761cb5fa34f5cec45a4026c383a4b5761c6cea5c16/websockets-15.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3be571a8b5afed347da347bfcf27ba12b069d9d7f42cb8c7028b5e98bbb12597", size = 182160, upload-time = "2025-03-05T20:02:31.634Z" },
|
577 |
+
{ url = "https://files.pythonhosted.org/packages/ff/83/de1f7709376dc3ca9b7eeb4b9a07b4526b14876b6d372a4dc62312bebee0/websockets-15.0.1-cp312-cp312-win32.whl", hash = "sha256:c338ffa0520bdb12fbc527265235639fb76e7bc7faafbb93f6ba80d9c06578a9", size = 176395, upload-time = "2025-03-05T20:02:33.017Z" },
|
578 |
+
{ url = "https://files.pythonhosted.org/packages/7d/71/abf2ebc3bbfa40f391ce1428c7168fb20582d0ff57019b69ea20fa698043/websockets-15.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:fcd5cf9e305d7b8338754470cf69cf81f420459dbae8a3b40cee57417f4614a7", size = 176841, upload-time = "2025-03-05T20:02:34.498Z" },
|
579 |
+
{ url = "https://files.pythonhosted.org/packages/cb/9f/51f0cf64471a9d2b4d0fc6c534f323b664e7095640c34562f5182e5a7195/websockets-15.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ee443ef070bb3b6ed74514f5efaa37a252af57c90eb33b956d35c8e9c10a1931", size = 175440, upload-time = "2025-03-05T20:02:36.695Z" },
|
580 |
+
{ url = "https://files.pythonhosted.org/packages/8a/05/aa116ec9943c718905997412c5989f7ed671bc0188ee2ba89520e8765d7b/websockets-15.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5a939de6b7b4e18ca683218320fc67ea886038265fd1ed30173f5ce3f8e85675", size = 173098, upload-time = "2025-03-05T20:02:37.985Z" },
|
581 |
+
{ url = "https://files.pythonhosted.org/packages/ff/0b/33cef55ff24f2d92924923c99926dcce78e7bd922d649467f0eda8368923/websockets-15.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:746ee8dba912cd6fc889a8147168991d50ed70447bf18bcda7039f7d2e3d9151", size = 173329, upload-time = "2025-03-05T20:02:39.298Z" },
|
582 |
+
{ url = "https://files.pythonhosted.org/packages/31/1d/063b25dcc01faa8fada1469bdf769de3768b7044eac9d41f734fd7b6ad6d/websockets-15.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:595b6c3969023ecf9041b2936ac3827e4623bfa3ccf007575f04c5a6aa318c22", size = 183111, upload-time = "2025-03-05T20:02:40.595Z" },
|
583 |
+
{ url = "https://files.pythonhosted.org/packages/93/53/9a87ee494a51bf63e4ec9241c1ccc4f7c2f45fff85d5bde2ff74fcb68b9e/websockets-15.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c714d2fc58b5ca3e285461a4cc0c9a66bd0e24c5da9911e30158286c9b5be7f", size = 182054, upload-time = "2025-03-05T20:02:41.926Z" },
|
584 |
+
{ url = "https://files.pythonhosted.org/packages/ff/b2/83a6ddf56cdcbad4e3d841fcc55d6ba7d19aeb89c50f24dd7e859ec0805f/websockets-15.0.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f3c1e2ab208db911594ae5b4f79addeb3501604a165019dd221c0bdcabe4db8", size = 182496, upload-time = "2025-03-05T20:02:43.304Z" },
|
585 |
+
{ url = "https://files.pythonhosted.org/packages/98/41/e7038944ed0abf34c45aa4635ba28136f06052e08fc2168520bb8b25149f/websockets-15.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:229cf1d3ca6c1804400b0a9790dc66528e08a6a1feec0d5040e8b9eb14422375", size = 182829, upload-time = "2025-03-05T20:02:48.812Z" },
|
586 |
+
{ url = "https://files.pythonhosted.org/packages/e0/17/de15b6158680c7623c6ef0db361da965ab25d813ae54fcfeae2e5b9ef910/websockets-15.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:756c56e867a90fb00177d530dca4b097dd753cde348448a1012ed6c5131f8b7d", size = 182217, upload-time = "2025-03-05T20:02:50.14Z" },
|
587 |
+
{ url = "https://files.pythonhosted.org/packages/33/2b/1f168cb6041853eef0362fb9554c3824367c5560cbdaad89ac40f8c2edfc/websockets-15.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:558d023b3df0bffe50a04e710bc87742de35060580a293c2a984299ed83bc4e4", size = 182195, upload-time = "2025-03-05T20:02:51.561Z" },
|
588 |
+
{ url = "https://files.pythonhosted.org/packages/86/eb/20b6cdf273913d0ad05a6a14aed4b9a85591c18a987a3d47f20fa13dcc47/websockets-15.0.1-cp313-cp313-win32.whl", hash = "sha256:ba9e56e8ceeeedb2e080147ba85ffcd5cd0711b89576b83784d8605a7df455fa", size = 176393, upload-time = "2025-03-05T20:02:53.814Z" },
|
589 |
+
{ url = "https://files.pythonhosted.org/packages/1b/6c/c65773d6cab416a64d191d6ee8a8b1c68a09970ea6909d16965d26bfed1e/websockets-15.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:e09473f095a819042ecb2ab9465aee615bd9c2028e4ef7d933600a8401c79561", size = 176837, upload-time = "2025-03-05T20:02:55.237Z" },
|
590 |
+
{ url = "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", size = 169743, upload-time = "2025-03-05T20:03:39.41Z" },
|
591 |
+
]
|
592 |
+
|
593 |
+
[[package]]
|
594 |
+
name = "zipp"
|
595 |
+
version = "3.23.0"
|
596 |
+
source = { registry = "https://pypi.org/simple" }
|
597 |
+
sdist = { url = "https://files.pythonhosted.org/packages/e3/02/0f2892c661036d50ede074e376733dca2ae7c6eb617489437771209d4180/zipp-3.23.0.tar.gz", hash = "sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166", size = 25547, upload-time = "2025-06-08T17:06:39.4Z" }
|
598 |
+
wheels = [
|
599 |
+
{ url = "https://files.pythonhosted.org/packages/2e/54/647ade08bf0db230bfea292f893923872fd20be6ac6f53b2b936ba839d75/zipp-3.23.0-py3-none-any.whl", hash = "sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e", size = 10276, upload-time = "2025-06-08T17:06:38.034Z" },
|
600 |
+
]
|