laketower 0.4.0__tar.gz → 0.4.1__tar.gz

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.

Potentially problematic release.


This version of laketower might be problematic. Click here for more details.

Files changed (47) hide show
  1. {laketower-0.4.0 → laketower-0.4.1}/CHANGELOG.md +12 -1
  2. {laketower-0.4.0 → laketower-0.4.1}/PKG-INFO +1 -1
  3. laketower-0.4.1/laketower/__about__.py +1 -0
  4. {laketower-0.4.0 → laketower-0.4.1}/laketower/templates/queries/view.html +13 -1
  5. {laketower-0.4.0 → laketower-0.4.1}/laketower/templates/tables/query.html +5 -1
  6. {laketower-0.4.0 → laketower-0.4.1}/laketower/templates/tables/view.html +1 -1
  7. {laketower-0.4.0 → laketower-0.4.1}/pyproject.toml +1 -1
  8. {laketower-0.4.0 → laketower-0.4.1}/tests/test_web.py +29 -14
  9. {laketower-0.4.0 → laketower-0.4.1}/uv.lock +4 -4
  10. laketower-0.4.0/laketower/__about__.py +0 -1
  11. {laketower-0.4.0 → laketower-0.4.1}/.github/workflows/ci-cd.yml +0 -0
  12. {laketower-0.4.0 → laketower-0.4.1}/.gitignore +0 -0
  13. {laketower-0.4.0 → laketower-0.4.1}/.python-version +0 -0
  14. {laketower-0.4.0 → laketower-0.4.1}/LICENSE.md +0 -0
  15. {laketower-0.4.0 → laketower-0.4.1}/README.md +0 -0
  16. {laketower-0.4.0 → laketower-0.4.1}/demo/generate.py +0 -0
  17. {laketower-0.4.0 → laketower-0.4.1}/demo/laketower.yml +0 -0
  18. {laketower-0.4.0 → laketower-0.4.1}/demo/sample_table/_delta_log/00000000000000000000.json +0 -0
  19. {laketower-0.4.0 → laketower-0.4.1}/demo/sample_table/_delta_log/00000000000000000001.json +0 -0
  20. {laketower-0.4.0 → laketower-0.4.1}/demo/sample_table/_delta_log/00000000000000000002.json +0 -0
  21. {laketower-0.4.0 → laketower-0.4.1}/demo/sample_table/_delta_log/00000000000000000003.json +0 -0
  22. {laketower-0.4.0 → laketower-0.4.1}/demo/sample_table/part-00001-1a31a393-6db6-4d1a-bf4e-81ea061ff8cd-c000.snappy.parquet +0 -0
  23. {laketower-0.4.0 → laketower-0.4.1}/demo/sample_table/part-00001-5af77102-9207-4c89-aaf6-37e1f815ec26-c000.snappy.parquet +0 -0
  24. {laketower-0.4.0 → laketower-0.4.1}/demo/sample_table/part-00001-b11bab55-43d0-4d05-ae88-5b9481ae57db-c000.snappy.parquet +0 -0
  25. {laketower-0.4.0 → laketower-0.4.1}/demo/weather/_delta_log/00000000000000000000.json +0 -0
  26. {laketower-0.4.0 → laketower-0.4.1}/demo/weather/_delta_log/00000000000000000001.json +0 -0
  27. {laketower-0.4.0 → laketower-0.4.1}/demo/weather/_delta_log/00000000000000000002.json +0 -0
  28. {laketower-0.4.0 → laketower-0.4.1}/demo/weather/part-00001-2323b963-be56-44e0-8c10-e237e7e6d4b9-c000.snappy.parquet +0 -0
  29. {laketower-0.4.0 → laketower-0.4.1}/demo/weather/part-00001-6360cbf8-f8a9-475f-8729-6f20b4ca64a9-c000.snappy.parquet +0 -0
  30. {laketower-0.4.0 → laketower-0.4.1}/laketower/__init__.py +0 -0
  31. {laketower-0.4.0 → laketower-0.4.1}/laketower/__main__.py +0 -0
  32. {laketower-0.4.0 → laketower-0.4.1}/laketower/cli.py +0 -0
  33. {laketower-0.4.0 → laketower-0.4.1}/laketower/config.py +0 -0
  34. {laketower-0.4.0 → laketower-0.4.1}/laketower/static/.gitkeep +0 -0
  35. {laketower-0.4.0 → laketower-0.4.1}/laketower/tables.py +0 -0
  36. {laketower-0.4.0 → laketower-0.4.1}/laketower/templates/_base.html +0 -0
  37. {laketower-0.4.0 → laketower-0.4.1}/laketower/templates/index.html +0 -0
  38. {laketower-0.4.0 → laketower-0.4.1}/laketower/templates/tables/_macros.html +0 -0
  39. {laketower-0.4.0 → laketower-0.4.1}/laketower/templates/tables/history.html +0 -0
  40. {laketower-0.4.0 → laketower-0.4.1}/laketower/templates/tables/index.html +0 -0
  41. {laketower-0.4.0 → laketower-0.4.1}/laketower/templates/tables/statistics.html +0 -0
  42. {laketower-0.4.0 → laketower-0.4.1}/laketower/web.py +0 -0
  43. {laketower-0.4.0 → laketower-0.4.1}/renovate.json +0 -0
  44. {laketower-0.4.0 → laketower-0.4.1}/tasks.py +0 -0
  45. {laketower-0.4.0 → laketower-0.4.1}/tests/__init__.py +0 -0
  46. {laketower-0.4.0 → laketower-0.4.1}/tests/conftest.py +0 -0
  47. {laketower-0.4.0 → laketower-0.4.1}/tests/test_cli.py +0 -0
@@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.4.1] - 2025-03-02
11
+ Minor release with fixes.
12
+
13
+ ### Added
14
+ - web: allow editing queries
15
+
16
+ ### Fixed
17
+ - web: missing tables query page title
18
+ - web: urlencode table view sql query link
19
+
10
20
  ## [0.4.0] - 2025-03-01
11
21
  Introducing new features:
12
22
  - Display tables statistics
@@ -59,7 +69,8 @@ Initial release of `laketower`.
59
69
  - View a given table with simple query builder
60
70
  - Query all registered tables with DuckDB SQL dialect
61
71
 
62
- [Unreleased]: https://github.com/datalpia/laketower/compare/0.4.0...HEAD
72
+ [Unreleased]: https://github.com/datalpia/laketower/compare/0.4.1...HEAD
73
+ [0.4.1]: https://github.com/datalpia/laketower/compare/0.4.0...0.4.1
63
74
  [0.4.0]: https://github.com/datalpia/laketower/compare/0.3.0...0.4.0
64
75
  [0.3.0]: https://github.com/datalpia/laketower/compare/0.2.0...0.3.0
65
76
  [0.2.0]: https://github.com/datalpia/laketower/compare/0.1.0...0.2.0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: laketower
3
- Version: 0.4.0
3
+ Version: 0.4.1
4
4
  Summary: Oversee your lakehouse
5
5
  Project-URL: Repository, https://github.com/datalpia/laketower
6
6
  Project-URL: Issues, https://github.com/datalpia/laketower/issues
@@ -0,0 +1 @@
1
+ __version__ = "0.4.1"
@@ -12,7 +12,19 @@
12
12
 
13
13
  <div class="mb-3">
14
14
  <div class="d-flex justify-content-end">
15
- <button type="submit" class="btn btn-primary">Execute</button>
15
+ <div class="row">
16
+ <div class="col">
17
+ <a href="/tables/query?sql={{ query.sql | urlencode }}" class="btn btn-secondary" type="button" >
18
+ <i class="bi-code" aria-hidden="true"></i> Edit SQL
19
+ </a>
20
+ </div>
21
+
22
+ <div class="col-auto">
23
+ <button type="submit" class="btn btn-primary">
24
+ <i class="bi-lightning" aria-hidden="true"></i> Execute
25
+ </button>
26
+ </div>
27
+ </div>
16
28
  </div>
17
29
  </div>
18
30
  </form>
@@ -4,6 +4,8 @@
4
4
  {% block body %}
5
5
  <div class="row">
6
6
  <div class="col">
7
+ <h2 class="mb-3">SQL Query</h2>
8
+
7
9
  <form action="{{ request.url.path }}" method="get">
8
10
  <div class="mb-3">
9
11
  <textarea name="sql" rows="5" class="form-control">{{ sql_query }}</textarea>
@@ -11,7 +13,9 @@
11
13
 
12
14
  <div class="mb-3">
13
15
  <div class="d-flex justify-content-end">
14
- <button type="submit" class="btn btn-primary">Execute</button>
16
+ <button type="submit" class="btn btn-primary">
17
+ <i class="bi-lightning" aria-hidden="true"></i> Execute
18
+ </button>
15
19
  </div>
16
20
  </div>
17
21
  </form>
@@ -86,7 +86,7 @@
86
86
  </form>
87
87
  </div>
88
88
 
89
- <a class="btn btn-primary" href="/tables/query?sql={{ sql_query }}" role="button">
89
+ <a href="/tables/query?sql={{ sql_query | urlencode }}" class="btn btn-primary" role="button">
90
90
  <i class="bi-code" aria-hidden="true"></i> SQL Query
91
91
  </a>
92
92
  </div>
@@ -60,7 +60,7 @@ dev = [
60
60
  "pandas-stubs==2.2.3.241126",
61
61
  "pip-audit==2.8.0",
62
62
  "pyarrow-stubs==17.17",
63
- "pytest==8.3.4",
63
+ "pytest==8.3.5",
64
64
  "pytest-cov==6.0.0",
65
65
  "ruff==0.9.9",
66
66
  "types-pyyaml==6.0.12.20241230",
@@ -324,7 +324,7 @@ def test_tables_view_version(
324
324
  )
325
325
 
326
326
 
327
- def test_table_query(
327
+ def test_tables_query(
328
328
  client: TestClient, sample_config: dict[str, Any], delta_table: deltalake.DeltaTable
329
329
  ) -> None:
330
330
  selected_column = delta_table.schema().fields[0].name
@@ -336,13 +336,20 @@ def test_table_query(
336
336
  assert response.status_code == HTTPStatus.OK
337
337
 
338
338
  html = response.content.decode()
339
- assert sql_query in html
340
- assert selected_column in html
341
- assert not all(col in html for col in filtered_columns)
339
+ soup = BeautifulSoup(html, "html.parser")
340
+
341
+ assert soup.find("h2", string="SQL Query")
342
+ assert (textarea := soup.find("textarea")) and textarea.text.strip() == sql_query
343
+ assert next(filter(lambda a: a.text.strip() == "Execute", soup.find_all("button")))
344
+
345
+ all_th = [th.text.strip() for th in soup.find_all("th")]
346
+ assert selected_column in all_th
347
+ assert not all(col in all_th for col in filtered_columns)
342
348
 
343
349
  df = delta_table.to_pandas()
344
- assert all(str(row) in html for row in df[selected_column][0:selected_limit])
345
- assert not all(str(row) in html for row in df[selected_column][selected_limit:])
350
+ all_td = [td.text.strip() for td in soup.find_all("td")]
351
+ assert all(str(row) in all_td for row in df[selected_column][0:selected_limit])
352
+ assert not all(str(row) in all_td for row in df[selected_column][selected_limit:])
346
353
 
347
354
 
348
355
  def test_tables_query_invalid(
@@ -354,12 +361,20 @@ def test_tables_query_invalid(
354
361
  assert response.status_code == HTTPStatus.OK
355
362
 
356
363
  html = response.content.decode()
364
+ soup = BeautifulSoup(html, "html.parser")
365
+
366
+ assert soup.find("h2", string="SQL Query")
367
+ assert (textarea := soup.find("textarea")) and textarea.text.strip() == sql_query
368
+ assert next(filter(lambda a: a.text.strip() == "Execute", soup.find_all("button")))
357
369
  assert "Error" in html
358
- assert not all(field.name in html for field in delta_table.schema().fields)
370
+
371
+ all_th = [th.text.strip() for th in soup.find_all("th")]
372
+ assert not all(field.name in all_th for field in delta_table.schema().fields)
359
373
 
360
374
  df = delta_table.to_pandas()
375
+ all_td = [td.text.strip() for td in soup.find_all("td")]
361
376
  assert not all(
362
- str(row[col]) in html for _, row in df.iterrows() for col in row.index
377
+ str(row[col]) in all_td for _, row in df.iterrows() for col in row.index
363
378
  )
364
379
 
365
380
 
@@ -373,9 +388,9 @@ def test_queries_view(client: TestClient, sample_config: dict[str, Any]) -> None
373
388
  soup = BeautifulSoup(html, "html.parser")
374
389
 
375
390
  assert soup.find("h2", string=query["title"])
376
-
377
- textarea = soup.find("textarea")
378
- assert textarea and textarea.text.strip() == query["sql"]
391
+ assert (textarea := soup.find("textarea")) and textarea.text.strip() == query["sql"]
392
+ assert next(filter(lambda a: a.text.strip() == "Edit SQL", soup.find_all("a")))
393
+ assert next(filter(lambda a: a.text.strip() == "Execute", soup.find_all("button")))
379
394
 
380
395
  all_th = [th.text.strip() for th in soup.find_all("th")]
381
396
  assert all(col in all_th for col in {"day", "avg_temperature"})
@@ -399,9 +414,9 @@ def test_queries_view_invalid(
399
414
  soup = BeautifulSoup(html, "html.parser")
400
415
 
401
416
  assert soup.find("h2", string=query["title"])
402
-
403
- textarea = soup.find("textarea")
404
- assert textarea and textarea.text.strip() == query["sql"]
417
+ assert (textarea := soup.find("textarea")) and textarea.text.strip() == query["sql"]
418
+ assert next(filter(lambda a: a.text.strip() == "Edit SQL", soup.find_all("a")))
419
+ assert next(filter(lambda a: a.text.strip() == "Execute", soup.find_all("button")))
405
420
 
406
421
  all_th = [th.text.strip() for th in soup.find_all("th")]
407
422
  assert not all(col in all_th for col in {"day", "avg_temperature"})
@@ -490,7 +490,7 @@ dev = [
490
490
  { name = "pandas-stubs", specifier = "==2.2.3.241126" },
491
491
  { name = "pip-audit", specifier = "==2.8.0" },
492
492
  { name = "pyarrow-stubs", specifier = "==17.17" },
493
- { name = "pytest", specifier = "==8.3.4" },
493
+ { name = "pytest", specifier = "==8.3.5" },
494
494
  { name = "pytest-cov", specifier = "==6.0.0" },
495
495
  { name = "ruff", specifier = "==0.9.9" },
496
496
  { name = "types-pyyaml", specifier = "==6.0.12.20241230" },
@@ -1097,7 +1097,7 @@ wheels = [
1097
1097
 
1098
1098
  [[package]]
1099
1099
  name = "pytest"
1100
- version = "8.3.4"
1100
+ version = "8.3.5"
1101
1101
  source = { registry = "https://pypi.org/simple" }
1102
1102
  dependencies = [
1103
1103
  { name = "colorama", marker = "sys_platform == 'win32'" },
@@ -1107,9 +1107,9 @@ dependencies = [
1107
1107
  { name = "pluggy" },
1108
1108
  { name = "tomli", marker = "python_full_version < '3.11'" },
1109
1109
  ]
1110
- sdist = { url = "https://files.pythonhosted.org/packages/05/35/30e0d83068951d90a01852cb1cef56e5d8a09d20c7f511634cc2f7e0372a/pytest-8.3.4.tar.gz", hash = "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761", size = 1445919 }
1110
+ sdist = { url = "https://files.pythonhosted.org/packages/ae/3c/c9d525a414d506893f0cd8a8d0de7706446213181570cdbd766691164e40/pytest-8.3.5.tar.gz", hash = "sha256:f4efe70cc14e511565ac476b57c279e12a855b11f48f212af1080ef2263d3845", size = 1450891 }
1111
1111
  wheels = [
1112
- { url = "https://files.pythonhosted.org/packages/11/92/76a1c94d3afee238333bc0a42b82935dd8f9cf8ce9e336ff87ee14d9e1cf/pytest-8.3.4-py3-none-any.whl", hash = "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6", size = 343083 },
1112
+ { url = "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl", hash = "sha256:c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820", size = 343634 },
1113
1113
  ]
1114
1114
 
1115
1115
  [[package]]
@@ -1 +0,0 @@
1
- __version__ = "0.4.0"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes