parqv 0.1.0__py3-none-any.whl → 0.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- parqv/app.py +87 -50
- parqv/handlers/__init__.py +13 -0
- parqv/handlers/base_handler.py +114 -0
- parqv/handlers/json.py +450 -0
- parqv/handlers/parquet.py +640 -0
- parqv/views/metadata_view.py +11 -4
- parqv/views/schema_view.py +147 -88
- parqv-0.2.0.dist-info/METADATA +104 -0
- parqv-0.2.0.dist-info/RECORD +17 -0
- {parqv-0.1.0.dist-info → parqv-0.2.0.dist-info}/WHEEL +1 -1
- parqv/parquet_handler.py +0 -389
- parqv/views/row_group_view.py +0 -33
- parqv-0.1.0.dist-info/METADATA +0 -91
- parqv-0.1.0.dist-info/RECORD +0 -15
- {parqv-0.1.0.dist-info → parqv-0.2.0.dist-info}/entry_points.txt +0 -0
- {parqv-0.1.0.dist-info → parqv-0.2.0.dist-info}/licenses/LICENSE +0 -0
- {parqv-0.1.0.dist-info → parqv-0.2.0.dist-info}/top_level.txt +0 -0
parqv/views/schema_view.py
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
import json
|
2
1
|
import logging
|
3
2
|
from typing import Dict, Any, Optional, List, Union
|
4
3
|
|
@@ -12,176 +11,236 @@ log = logging.getLogger(__name__)
|
|
12
11
|
|
13
12
|
|
14
13
|
class ColumnListItem(ListItem):
|
14
|
+
"""A ListItem that stores the column name."""
|
15
|
+
|
15
16
|
def __init__(self, column_name: str) -> None:
|
16
|
-
|
17
|
+
# Ensure IDs are CSS-safe (replace spaces, etc.)
|
18
|
+
safe_id_name = "".join(c if c.isalnum() else '_' for c in column_name)
|
19
|
+
super().__init__(Label(column_name), name=column_name, id=f"col-item-{safe_id_name}")
|
17
20
|
self.column_name = column_name
|
18
21
|
|
19
22
|
|
20
23
|
def format_stats_for_display(stats_data: Dict[str, Any]) -> List[Union[str, Text]]:
|
24
|
+
"""Formats the statistics dictionary for display as lines of text."""
|
21
25
|
if not stats_data:
|
22
26
|
return [Text.from_markup("[red]No statistics data available.[/red]")]
|
23
27
|
|
24
28
|
lines: List[Union[str, Text]] = []
|
25
29
|
col_name = stats_data.get("column", "N/A")
|
26
30
|
col_type = stats_data.get("type", "Unknown")
|
27
|
-
|
28
|
-
|
31
|
+
nullable_val = stats_data.get("nullable")
|
32
|
+
|
33
|
+
if nullable_val is True:
|
34
|
+
nullable_str = "Nullable"
|
35
|
+
elif nullable_val is False:
|
36
|
+
nullable_str = "Required"
|
37
|
+
else:
|
38
|
+
nullable_str = "Unknown Nullability"
|
29
39
|
lines.append(Text.assemble(("Column: ", "bold"), f"`{col_name}`"))
|
30
|
-
lines.append(Text.assemble(("Type: ", "bold"), f"{col_type} ({
|
40
|
+
lines.append(Text.assemble(("Type: ", "bold"), f"{col_type} ({nullable_str})"))
|
31
41
|
lines.append("─" * (len(col_name) + len(col_type) + 20))
|
32
42
|
|
33
43
|
calc_error = stats_data.get("error")
|
34
44
|
if calc_error:
|
35
45
|
lines.append(Text("Calculation Error:", style="bold red"))
|
36
|
-
lines.append(f"
|
46
|
+
lines.append(f"```\n{calc_error}\n```")
|
47
|
+
lines.append("")
|
48
|
+
|
49
|
+
message = stats_data.get("message")
|
50
|
+
if message:
|
51
|
+
lines.append(Text(f"Info: {message}", style="italic cyan"))
|
52
|
+
lines.append("")
|
37
53
|
|
38
54
|
calculated = stats_data.get("calculated")
|
39
55
|
if calculated:
|
40
56
|
lines.append(Text("Calculated Statistics:", style="bold"))
|
41
57
|
keys_to_display = [
|
42
58
|
"Total Count", "Valid Count", "Null Count", "Null Percentage",
|
43
|
-
"Min", "Max", "Mean", "StdDev", "
|
59
|
+
"Min", "Max", "Mean", "StdDev", "Variance",
|
60
|
+
"Distinct Count", "Min Length", "Max Length", "Avg Length",
|
61
|
+
"Value Counts"
|
44
62
|
]
|
63
|
+
found_stats = False
|
45
64
|
for key in keys_to_display:
|
46
65
|
if key in calculated:
|
66
|
+
found_stats = True
|
47
67
|
value = calculated[key]
|
48
|
-
if isinstance(value, dict):
|
68
|
+
if key == "Value Counts" and isinstance(value, dict):
|
49
69
|
lines.append(f" - {key}:")
|
50
70
|
for sub_key, sub_val in value.items():
|
51
|
-
|
71
|
+
sub_val_str = f"{sub_val:,}" if isinstance(sub_val, (int, float)) else str(sub_val)
|
72
|
+
lines.append(f" - {sub_key}: {sub_val_str}")
|
73
|
+
elif isinstance(value, (int, float)):
|
74
|
+
lines.append(f" - {key}: {value:,}")
|
52
75
|
else:
|
53
76
|
lines.append(f" - {key}: {value}")
|
54
|
-
|
55
|
-
|
56
|
-
meta_stats = stats_data.get("basic_metadata_stats")
|
57
|
-
if meta_stats:
|
58
|
-
lines.append(Text("Stats from File Metadata (Per Row Group):", style="bold"))
|
59
|
-
try:
|
60
|
-
json_str = json.dumps(meta_stats, indent=2, default=str)
|
61
|
-
lines.append(f"```json\n{json_str}\n```")
|
62
|
-
except Exception as e:
|
63
|
-
lines.append(f" (Error formatting metadata: {e})")
|
64
|
-
lines.append("")
|
65
|
-
|
66
|
-
meta_stats_error = stats_data.get("metadata_stats_error")
|
67
|
-
if meta_stats_error:
|
68
|
-
lines.append(Text(f"Metadata Stats Warning: {meta_stats_error}", style="yellow"))
|
69
|
-
|
70
|
-
message = stats_data.get("message")
|
71
|
-
if message and not calculated:
|
72
|
-
lines.append(Text(message, style="italic"))
|
73
|
-
|
77
|
+
if not found_stats and not calc_error:
|
78
|
+
lines.append(Text(" (No specific stats calculated for this type)", style="dim"))
|
74
79
|
return lines
|
75
80
|
|
76
81
|
|
77
82
|
class SchemaView(VerticalScroll):
|
78
|
-
|
83
|
+
"""Displays a list of columns and the statistics for the selected column."""
|
84
|
+
DEFAULT_STATS_MESSAGE = "Select a column from the list above to view its statistics."
|
79
85
|
loading = var(False)
|
80
86
|
|
81
87
|
def compose(self) -> ComposeResult:
|
88
|
+
"""Create child widgets for the SchemaView."""
|
82
89
|
yield ListView(id="column-list-view")
|
83
90
|
yield LoadingIndicator(id="schema-loading-indicator")
|
84
|
-
yield Container(id="schema-stats-content")
|
91
|
+
yield VerticalScroll(Container(id="schema-stats-content"), id="schema-stats-scroll")
|
85
92
|
|
86
93
|
def on_mount(self) -> None:
|
87
|
-
|
94
|
+
"""Called when the widget is mounted."""
|
95
|
+
self.query_one("#schema-loading-indicator", LoadingIndicator).display = False
|
96
|
+
self.query_one("#schema-stats-content", Container).display = False
|
88
97
|
self.call_later(self.load_column_list)
|
89
|
-
self.call_later(self.
|
98
|
+
self.call_later(self._display_default_message)
|
99
|
+
|
100
|
+
def _display_default_message(self):
|
101
|
+
"""Helper to display the initial message in the stats area."""
|
102
|
+
try:
|
103
|
+
stats_container = self.query_one("#schema-stats-content", Container)
|
104
|
+
stats_container.query("*").remove()
|
105
|
+
stats_container.mount(Static(self.DEFAULT_STATS_MESSAGE, classes="stats-line"))
|
106
|
+
stats_container.display = True
|
107
|
+
except Exception as e:
|
108
|
+
log.error(f"Failed to display default stats message: {e}")
|
90
109
|
|
91
110
|
def load_column_list(self):
|
92
|
-
|
111
|
+
"""Loads the list of columns from the data handler."""
|
112
|
+
list_view: Optional[ListView] = self.query_one("#column-list-view", ListView)
|
113
|
+
list_view.clear()
|
114
|
+
|
93
115
|
try:
|
94
|
-
|
95
|
-
|
96
|
-
|
116
|
+
if not self.app.handler:
|
117
|
+
log.error("SchemaView: Data handler not available.")
|
118
|
+
list_view.append(ListItem(Label("[red]Data handler not available.[/red]")))
|
97
119
|
return
|
98
|
-
list_view = list_views.first()
|
99
|
-
log.debug("ListView widget found.")
|
100
120
|
|
101
|
-
|
121
|
+
schema_data: Optional[List[Dict[str, str]]] = self.app.handler.get_schema_data()
|
122
|
+
log.debug(f"SchemaView: Received schema data for list: {schema_data}")
|
102
123
|
|
103
|
-
if
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
log.warning("Schema has no columns.")
|
110
|
-
list_view.append(ListItem(Label("[yellow]Schema has no columns.[/yellow]")))
|
111
|
-
elif not self.app.handler:
|
112
|
-
log.error("Parquet handler not available.")
|
113
|
-
list_view.append(ListItem(Label("[red]Parquet handler not available.[/red]")))
|
124
|
+
if schema_data is None:
|
125
|
+
log.error("SchemaView: Failed to retrieve schema data (handler returned None).")
|
126
|
+
list_view.append(ListItem(Label("[red]Could not load schema.[/red]")))
|
127
|
+
elif not schema_data:
|
128
|
+
log.warning("SchemaView: Schema has no columns.")
|
129
|
+
list_view.append(ListItem(Label("[yellow]Schema has no columns.[/yellow]")))
|
114
130
|
else:
|
115
|
-
|
116
|
-
|
131
|
+
column_count = 0
|
132
|
+
for col_info in schema_data:
|
133
|
+
column_name = col_info.get("name")
|
134
|
+
if column_name:
|
135
|
+
list_view.append(ColumnListItem(column_name))
|
136
|
+
column_count += 1
|
137
|
+
else:
|
138
|
+
log.warning("SchemaView: Found column info without a 'name' key.")
|
139
|
+
log.info(f"SchemaView: Populated column list with {column_count} columns.")
|
117
140
|
|
118
141
|
except Exception as e:
|
119
142
|
log.exception("Error loading column list in SchemaView:")
|
120
|
-
|
121
|
-
|
122
|
-
list_view.append(ListItem(Label(f"[red]Error loading schema view: {e}[/red]")))
|
143
|
+
list_view.clear()
|
144
|
+
list_view.append(ListItem(Label(f"[red]Error loading schema: {e}[/red]")))
|
123
145
|
|
124
146
|
def watch_loading(self, loading: bool) -> None:
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
147
|
+
"""React to changes in the loading state."""
|
148
|
+
try:
|
149
|
+
loading_indicator = self.query_one("#schema-loading-indicator", LoadingIndicator)
|
150
|
+
stats_scroll = self.query_one("#schema-stats-scroll", VerticalScroll)
|
151
|
+
loading_indicator.display = loading
|
152
|
+
stats_scroll.display = not loading
|
153
|
+
if loading:
|
154
|
+
stats_content = self.query_one("#schema-stats-content", Container)
|
155
|
+
stats_content.display = False
|
156
|
+
except Exception as e:
|
157
|
+
log.error(f"Error updating loading display: {e}")
|
129
158
|
|
130
159
|
async def _update_stats_display(self, lines: List[Union[str, Text]]) -> None:
|
160
|
+
"""Updates the statistics display area with formatted lines."""
|
131
161
|
try:
|
132
|
-
|
133
|
-
|
162
|
+
stats_content_container = self.query_one("#schema-stats-content", Container)
|
163
|
+
stats_scroll_container = self.query_one("#schema-stats-scroll", VerticalScroll)
|
164
|
+
await stats_content_container.query("*").remove()
|
134
165
|
|
135
166
|
if not lines:
|
136
|
-
await
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
167
|
+
await stats_content_container.mount(Static(self.DEFAULT_STATS_MESSAGE, classes="stats-line"))
|
168
|
+
else:
|
169
|
+
new_widgets: List[Static] = []
|
170
|
+
for line in lines:
|
171
|
+
content: Union[str, Text] = line
|
172
|
+
css_class = "stats-line"
|
173
|
+
if isinstance(line, str) and line.startswith("```"):
|
174
|
+
content = line.strip()
|
175
|
+
if content.startswith("```json"):
|
176
|
+
content = content[7:]
|
177
|
+
elif content.startswith("```"):
|
178
|
+
content = content[3:]
|
179
|
+
if content.endswith("```"):
|
180
|
+
content = content[:-3]
|
181
|
+
content = content.strip()
|
182
|
+
css_class = "stats-code"
|
183
|
+
elif isinstance(line, Text):
|
184
|
+
style_str = str(line.style).lower()
|
185
|
+
if "red" in style_str:
|
186
|
+
css_class = "stats-error stats-line"
|
187
|
+
elif "yellow" in style_str:
|
188
|
+
css_class = "stats-warning stats-line"
|
189
|
+
elif "italic" in style_str:
|
190
|
+
css_class = "stats-info stats-line"
|
191
|
+
elif "bold" in style_str:
|
192
|
+
css_class = "stats-header stats-line"
|
193
|
+
new_widgets.append(Static(content, classes=css_class))
|
194
|
+
if new_widgets:
|
195
|
+
await stats_content_container.mount_all(new_widgets)
|
196
|
+
|
197
|
+
stats_content_container.display = True
|
198
|
+
stats_scroll_container.display = True
|
199
|
+
stats_scroll_container.scroll_home(animate=False)
|
153
200
|
except Exception as e:
|
154
201
|
log.error(f"Error updating stats display: {e}", exc_info=True)
|
155
202
|
try:
|
156
|
-
await
|
157
|
-
await
|
203
|
+
await stats_content_container.query("*").remove()
|
204
|
+
await stats_content_container.mount(Static(f"[red]Internal error displaying stats: {e}[/red]"))
|
205
|
+
stats_content_container.display = True
|
206
|
+
stats_scroll_container.display = True
|
158
207
|
except Exception:
|
159
208
|
pass
|
160
209
|
|
161
210
|
async def on_list_view_selected(self, event: ListView.Selected) -> None:
|
211
|
+
"""Handle column selection in the ListView."""
|
162
212
|
event.stop()
|
163
213
|
selected_item = event.item
|
164
214
|
|
165
215
|
if isinstance(selected_item, ColumnListItem):
|
166
216
|
column_name = selected_item.column_name
|
167
|
-
log.info(f"Column selected: {column_name}")
|
168
217
|
self.loading = True
|
169
218
|
|
170
219
|
stats_data: Dict[str, Any] = {}
|
171
|
-
|
220
|
+
error_markup: Optional[str] = None
|
221
|
+
|
172
222
|
try:
|
173
223
|
if self.app.handler:
|
174
224
|
stats_data = self.app.handler.get_column_stats(column_name)
|
225
|
+
if stats_data.get("error"):
|
226
|
+
log.warning(f"Handler returned error for column '{column_name}': {stats_data['error']}")
|
227
|
+
error_markup = f"[red]Error getting stats: {stats_data['error']}[/]"
|
228
|
+
stats_data = {}
|
175
229
|
else:
|
176
|
-
|
177
|
-
log.error("
|
230
|
+
error_markup = "[red]Error: Data handler not available.[/]"
|
231
|
+
log.error("SchemaView: Data handler not found on app.")
|
178
232
|
except Exception as e:
|
179
|
-
log.exception(f"
|
180
|
-
|
233
|
+
log.exception(f"Exception calculating stats for {column_name}")
|
234
|
+
error_markup = f"[red]Error loading stats for '{column_name}':\n{type(e).__name__}: {e}[/]"
|
235
|
+
|
236
|
+
if error_markup:
|
237
|
+
lines_to_render = [Text.from_markup(error_markup)]
|
238
|
+
else:
|
239
|
+
lines_to_render = format_stats_for_display(stats_data)
|
181
240
|
|
182
|
-
lines_to_render = format_stats_for_display(stats_data) if not error_str else [Text.from_markup(error_str)]
|
183
241
|
await self._update_stats_display(lines_to_render)
|
184
242
|
self.loading = False
|
185
243
|
else:
|
244
|
+
log.debug("Non-column item selected in ListView.")
|
186
245
|
await self._update_stats_display([])
|
187
246
|
self.loading = False
|
@@ -0,0 +1,104 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: parqv
|
3
|
+
Version: 0.2.0
|
4
|
+
Summary: An interactive Python TUI for visualizing, exploring, and analyzing files directly in your terminal.
|
5
|
+
Author-email: Sangmin Yoon <sanspareilsmyn@gmail.com>
|
6
|
+
License-Expression: Apache-2.0
|
7
|
+
Requires-Python: >=3.10
|
8
|
+
Description-Content-Type: text/markdown
|
9
|
+
License-File: LICENSE
|
10
|
+
Requires-Dist: textual>=1.0.0
|
11
|
+
Requires-Dist: pyarrow>=16.0.0
|
12
|
+
Requires-Dist: pandas>=2.0.0
|
13
|
+
Requires-Dist: numpy>=1.20.0
|
14
|
+
Requires-Dist: duckdb>=1.2.0
|
15
|
+
Dynamic: license-file
|
16
|
+
|
17
|
+
# parqv
|
18
|
+
|
19
|
+
[](https://www.python.org/)
|
20
|
+
[](LICENSE)
|
21
|
+
[](https://badge.fury.io/py/parqv) <!-- TODO: Link after first PyPI release -->
|
22
|
+
[](https://textual.textualize.io/)
|
23
|
+
|
24
|
+
---
|
25
|
+
|
26
|
+
**Supported File Formats:** ✅ **Parquet** | ✅ **JSON** / **JSON Lines (ndjson)** | *(More planned!)*
|
27
|
+
|
28
|
+
---
|
29
|
+
|
30
|
+
**`parqv` is a Python-based interactive TUI (Text User Interface) tool designed to explore, analyze, and understand various data file formats directly within your terminal.** Initially supporting Parquet and JSON, `parqv` aims to provide a unified, visual experience for quick data inspection without leaving your console.
|
31
|
+
|
32
|
+
## 💻 Demo (Showing Parquet)
|
33
|
+
|
34
|
+

|
35
|
+
*(Demo shows Parquet features; UI adapts for other formats)*
|
36
|
+
|
37
|
+
## 🤔 Why `parqv`?
|
38
|
+
1. **Unified Interface:** Launch `parqv <your_data_file>` to access **metadata, schema, data preview, and column statistics** all within a single, navigable terminal window. No more juggling different commands for different file types.
|
39
|
+
2. **Interactive Exploration:**
|
40
|
+
* **🖱️ Keyboard & Mouse Driven:** Navigate using familiar keys (arrows, `hjkl`, Tab) or even your mouse (thanks to `Textual`).
|
41
|
+
* **📜 Scrollable Views:** Easily scroll through large schemas, data tables, or column lists.
|
42
|
+
* **🌲 Clear Schema View:** Understand column names, data types, and nullability at a glance. (Complex nested structures visualization might vary by format).
|
43
|
+
* **📊 Dynamic Stats:** Select a column and instantly see its detailed statistics (counts, nulls, min/max, mean, distinct values, etc.).
|
44
|
+
3. **Cross-Format Consistency:**
|
45
|
+
* **🎨 Rich Display:** Leverages `rich` and `Textual` for colorful, readable tables and text across supported formats.
|
46
|
+
* **📈 Quick Stats:** Get key statistical insights consistently, regardless of the underlying file type.
|
47
|
+
* **🔌 Extensible:** Designed with a handler interface to easily add support for more file formats in the future (like CSV, Arrow IPC, etc.).
|
48
|
+
|
49
|
+
## ✨ Features (TUI Mode)
|
50
|
+
* **Multi-Format Support:** Currently supports **Parquet** (`.parquet`) and **JSON/JSON Lines** (`.json`, `.ndjson`). Run `parqv <your_file.{parquet,json,ndjson}>`.
|
51
|
+
* **Metadata Panel:** Displays key file information (path, format, size, total rows, column count, etc.). *Fields may vary slightly depending on the file format.*
|
52
|
+
* **Schema Explorer:**
|
53
|
+
* Interactive list view of columns.
|
54
|
+
* Clearly shows column names, data types, and nullability.
|
55
|
+
* **Data Table Viewer:**
|
56
|
+
* Scrollable table preview of the file's data.
|
57
|
+
* Attempts to preserve data types for better representation.
|
58
|
+
* **Column Statistics Viewer:**
|
59
|
+
* Select a column in the Schema tab to view detailed statistics.
|
60
|
+
* Shows counts (total, valid, null), percentages, and type-specific stats (min/max, mean, stddev, distinct counts, length stats, boolean value counts where applicable).
|
61
|
+
* **Row Group Inspector (Parquet Specific):**
|
62
|
+
* *This panel only appears when viewing Parquet files.*
|
63
|
+
* Lists row groups with stats (row count, compressed/uncompressed size).
|
64
|
+
* (Planned) Select a row group for more details.
|
65
|
+
|
66
|
+
## 🚀 Getting Started
|
67
|
+
|
68
|
+
**1. Prerequisites:**
|
69
|
+
* **Python:** Version 3.10 or higher.
|
70
|
+
* **pip:** The Python package installer.
|
71
|
+
|
72
|
+
**2. Install `parqv`:**
|
73
|
+
* Open your terminal and run:
|
74
|
+
```bash
|
75
|
+
pip install parqv
|
76
|
+
```
|
77
|
+
*(This will also install dependencies like `textual`, `pyarrow`, `pandas`, and `duckdb`)*
|
78
|
+
* **Updating `parqv`:**
|
79
|
+
```bash
|
80
|
+
pip install --upgrade parqv
|
81
|
+
```
|
82
|
+
|
83
|
+
**3. Run `parqv`:**
|
84
|
+
* Point `parqv` to your data file:
|
85
|
+
```bash
|
86
|
+
#parquet
|
87
|
+
parqv /path/to/your/data.parquet
|
88
|
+
|
89
|
+
# json
|
90
|
+
parqv /path/to/your/data.json
|
91
|
+
* The interactive TUI will launch. Use your keyboard (and mouse, if supported by your terminal) to navigate:
|
92
|
+
* **Arrow Keys / `j`,`k` (in lists):** Move selection up/down.
|
93
|
+
* **`Tab` / `Shift+Tab`:** Cycle focus between the main tab content and potentially other areas. (Focus handling might evolve).
|
94
|
+
* **`Enter` (in column list):** Select a column to view statistics.
|
95
|
+
* **View Switching:** Use `Ctrl+N` (Next Tab) and `Ctrl+P` (Previous Tab) or click on the tabs (Metadata, Schema, Data Preview).
|
96
|
+
* **Scrolling:** Use `PageUp` / `PageDown` / `Home` / `End` or arrow keys/mouse wheel within scrollable areas (like Schema stats or Data Preview).
|
97
|
+
* **`q` / `Ctrl+C`:** Quit `parqv`.
|
98
|
+
* *(Help Screen `?` is planned)*
|
99
|
+
|
100
|
+
---
|
101
|
+
|
102
|
+
## 📄 License
|
103
|
+
|
104
|
+
Licensed under the Apache License, Version 2.0. See [LICENSE](LICENSE) for the full license text.
|
@@ -0,0 +1,17 @@
|
|
1
|
+
parqv/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
+
parqv/app.py,sha256=QmGEBtHoASdNzDmSgLQ2BvpTnZOuxQj2l0QGhYfp48w,6476
|
3
|
+
parqv/parqv.css,sha256=C42ZXUwMX1ZXfGo0AmixbHxz0CWKzWBHZ_hkhq5aehg,2920
|
4
|
+
parqv/handlers/__init__.py,sha256=gplqWWpt0npYosDZfoX1Ek0sfvAD0YITMjlQEo-IYVc,343
|
5
|
+
parqv/handlers/base_handler.py,sha256=JjlI0QdUZmozaMhAZnhzzS8nC2J63QRDX3rZqzXOpW8,3662
|
6
|
+
parqv/handlers/json.py,sha256=KgujRGimqzE3kVGQFwfkCb2Yv3YWxB8w-b17q5X2Yj8,19794
|
7
|
+
parqv/handlers/parquet.py,sha256=kG46oeVONmi6cCVzf5MaF88PkmXP7jCEGIAlDkG6N2M,32221
|
8
|
+
parqv/views/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
9
|
+
parqv/views/data_view.py,sha256=T_LPbXdxm_KOmwtTQWAxlUeNTlSGfIgQIg853WDMAME,2355
|
10
|
+
parqv/views/metadata_view.py,sha256=GnzhPJolMDZU8AAwY0h_uToz1sdM54iJbM2GLkD3caI,1013
|
11
|
+
parqv/views/schema_view.py,sha256=3QUYlOxTk9DYKdipEmt79U6hSlNJa_j3a3SK9UNwWHk,11332
|
12
|
+
parqv-0.2.0.dist-info/licenses/LICENSE,sha256=Ewl2wCa8r6ncxHlpf-ZZXb77c82zdfxHuEeKzBbm6nM,11324
|
13
|
+
parqv-0.2.0.dist-info/METADATA,sha256=q1K9Vqntt70-ffbJ3eT2g8_TW4XABsFHCkdYbBF4nXM,5387
|
14
|
+
parqv-0.2.0.dist-info/WHEEL,sha256=pxyMxgL8-pra_rKaQ4drOZAegBVuX-G_4nRHjjgWbmo,91
|
15
|
+
parqv-0.2.0.dist-info/entry_points.txt,sha256=8Tm8rTiIB-tbVItoOA4M7seEmFnrtK25BMH9UKzqfXg,44
|
16
|
+
parqv-0.2.0.dist-info/top_level.txt,sha256=_t3_49ZluJbvl0QU_P3GNVuXxCffqiTp37dzZIa2GEw,6
|
17
|
+
parqv-0.2.0.dist-info/RECORD,,
|