wherewolf 0.2.0__tar.gz → 0.2.2__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.
Files changed (85) hide show
  1. {wherewolf-0.2.0 → wherewolf-0.2.2}/.github/workflows/release.yml +40 -0
  2. {wherewolf-0.2.0 → wherewolf-0.2.2}/PKG-INFO +1 -1
  3. {wherewolf-0.2.0 → wherewolf-0.2.2}/README.md +5 -5
  4. {wherewolf-0.2.0 → wherewolf-0.2.2}/pyproject.toml +1 -1
  5. wherewolf-0.2.2/src/wherewolf/assets/img/wherewolf_banner.png +0 -0
  6. {wherewolf-0.2.0 → wherewolf-0.2.2}/src/wherewolf/execution/duckdb_engine.py +6 -3
  7. {wherewolf-0.2.0 → wherewolf-0.2.2}/src/wherewolf/execution/spark_engine.py +6 -0
  8. {wherewolf-0.2.0 → wherewolf-0.2.2}/src/wherewolf/ui/file_browser.py +1 -1
  9. wherewolf-0.2.2/tests/test_excel_support.py +36 -0
  10. {wherewolf-0.2.0 → wherewolf-0.2.2}/uv.lock +1 -1
  11. wherewolf-0.2.0/src/wherewolf/assets/img/wherewolf_banner.png +0 -0
  12. {wherewolf-0.2.0 → wherewolf-0.2.2}/.envrc +0 -0
  13. {wherewolf-0.2.0 → wherewolf-0.2.2}/.github/workflows/ci.yml +0 -0
  14. {wherewolf-0.2.0 → wherewolf-0.2.2}/.gitignore +0 -0
  15. {wherewolf-0.2.0 → wherewolf-0.2.2}/.protocol +0 -0
  16. {wherewolf-0.2.0 → wherewolf-0.2.2}/.streamlit/config.toml +0 -0
  17. {wherewolf-0.2.0 → wherewolf-0.2.2}/AGENTS.md +0 -0
  18. {wherewolf-0.2.0 → wherewolf-0.2.2}/GEMINI.md +0 -0
  19. {wherewolf-0.2.0 → wherewolf-0.2.2}/LICENSE +0 -0
  20. {wherewolf-0.2.0 → wherewolf-0.2.2}/docs/RELEASING.md +0 -0
  21. {wherewolf-0.2.0 → wherewolf-0.2.2}/docs/agent_conversations/2026-03-09_file_browsing.json +0 -0
  22. {wherewolf-0.2.0 → wherewolf-0.2.2}/docs/agent_conversations/2026-03-09_initial_implementation.json +0 -0
  23. {wherewolf-0.2.0 → wherewolf-0.2.2}/docs/agent_conversations/2026-04-19_github_setup.json +0 -0
  24. {wherewolf-0.2.0 → wherewolf-0.2.2}/docs/agent_conversations/2026-04-19_tag_v0.1.0.json +0 -0
  25. {wherewolf-0.2.0 → wherewolf-0.2.2}/docs/agent_protocol.md +0 -0
  26. {wherewolf-0.2.0 → wherewolf-0.2.2}/docs/execution_ledger.json +0 -0
  27. {wherewolf-0.2.0 → wherewolf-0.2.2}/docs/plans/core_system_design.md +0 -0
  28. {wherewolf-0.2.0 → wherewolf-0.2.2}/docs/plans/execution_engines.md +0 -0
  29. {wherewolf-0.2.0 → wherewolf-0.2.2}/docs/plans/export_formats.md +0 -0
  30. {wherewolf-0.2.0 → wherewolf-0.2.2}/docs/plans/file_browsing.md +0 -0
  31. {wherewolf-0.2.0 → wherewolf-0.2.2}/docs/plans/file_browsing_v2.md +0 -0
  32. {wherewolf-0.2.0 → wherewolf-0.2.2}/docs/plans/github_automation.md +0 -0
  33. {wherewolf-0.2.0 → wherewolf-0.2.2}/docs/plans/initial_prompt.md +0 -0
  34. {wherewolf-0.2.0 → wherewolf-0.2.2}/docs/plans/storage_and_history.md +0 -0
  35. {wherewolf-0.2.0 → wherewolf-0.2.2}/docs/plans/streamlit_ui.md +0 -0
  36. {wherewolf-0.2.0 → wherewolf-0.2.2}/run.sh +0 -0
  37. {wherewolf-0.2.0 → wherewolf-0.2.2}/scripts/check_tdd.sh +0 -0
  38. {wherewolf-0.2.0 → wherewolf-0.2.2}/scripts/take_screenshot.py +0 -0
  39. {wherewolf-0.2.0 → wherewolf-0.2.2}/src/wherewolf/__init__.py +0 -0
  40. {wherewolf-0.2.0 → wherewolf-0.2.2}/src/wherewolf/app.py +0 -0
  41. {wherewolf-0.2.0 → wherewolf-0.2.2}/src/wherewolf/assets/img/screenshot.png +0 -0
  42. {wherewolf-0.2.0 → wherewolf-0.2.2}/src/wherewolf/assets/img/wherewolf_logo.png +0 -0
  43. {wherewolf-0.2.0 → wherewolf-0.2.2}/src/wherewolf/cli.py +0 -0
  44. {wherewolf-0.2.0 → wherewolf-0.2.2}/src/wherewolf/execution/__init__.py +0 -0
  45. {wherewolf-0.2.0 → wherewolf-0.2.2}/src/wherewolf/execution/models.py +0 -0
  46. {wherewolf-0.2.0 → wherewolf-0.2.2}/src/wherewolf/export/__init__.py +0 -0
  47. {wherewolf-0.2.0 → wherewolf-0.2.2}/src/wherewolf/export/exporter.py +0 -0
  48. {wherewolf-0.2.0 → wherewolf-0.2.2}/src/wherewolf/storage/__init__.py +0 -0
  49. {wherewolf-0.2.0 → wherewolf-0.2.2}/src/wherewolf/storage/history.py +0 -0
  50. {wherewolf-0.2.0 → wherewolf-0.2.2}/src/wherewolf/translation/__init__.py +0 -0
  51. {wherewolf-0.2.0 → wherewolf-0.2.2}/src/wherewolf/translation/translator.py +0 -0
  52. {wherewolf-0.2.0 → wherewolf-0.2.2}/src/wherewolf/ui/__init__.py +0 -0
  53. {wherewolf-0.2.0 → wherewolf-0.2.2}/tests/reproduce_issue_symlink.py +0 -0
  54. {wherewolf-0.2.0 → wherewolf-0.2.2}/tests/reproduce_issue_symlink_v2.py +0 -0
  55. {wherewolf-0.2.0 → wherewolf-0.2.2}/tests/sample_queries.md +0 -0
  56. {wherewolf-0.2.0 → wherewolf-0.2.2}/tests/test___init__.py +0 -0
  57. {wherewolf-0.2.0 → wherewolf-0.2.2}/tests/test_app.py +0 -0
  58. {wherewolf-0.2.0 → wherewolf-0.2.2}/tests/test_app_cancel.py +0 -0
  59. {wherewolf-0.2.0 → wherewolf-0.2.2}/tests/test_app_flow.py +0 -0
  60. {wherewolf-0.2.0 → wherewolf-0.2.2}/tests/test_cli.py +0 -0
  61. {wherewolf-0.2.0 → wherewolf-0.2.2}/tests/test_config_toml.py +0 -0
  62. {wherewolf-0.2.0 → wherewolf-0.2.2}/tests/test_data.csv +0 -0
  63. {wherewolf-0.2.0 → wherewolf-0.2.2}/tests/test_duckdb_engine.py +0 -0
  64. {wherewolf-0.2.0 → wherewolf-0.2.2}/tests/test_duckdb_sql_injection.py +0 -0
  65. {wherewolf-0.2.0 → wherewolf-0.2.2}/tests/test_execution___init__.py +0 -0
  66. {wherewolf-0.2.0 → wherewolf-0.2.2}/tests/test_export___init__.py +0 -0
  67. {wherewolf-0.2.0 → wherewolf-0.2.2}/tests/test_exporter.py +0 -0
  68. {wherewolf-0.2.0 → wherewolf-0.2.2}/tests/test_file_browser.py +0 -0
  69. {wherewolf-0.2.0 → wherewolf-0.2.2}/tests/test_file_browser_errors.py +0 -0
  70. {wherewolf-0.2.0 → wherewolf-0.2.2}/tests/test_file_browser_navigation.py +0 -0
  71. {wherewolf-0.2.0 → wherewolf-0.2.2}/tests/test_file_browser_v2.py +0 -0
  72. {wherewolf-0.2.0 → wherewolf-0.2.2}/tests/test_history.py +0 -0
  73. {wherewolf-0.2.0 → wherewolf-0.2.2}/tests/test_history_atomicity.py +0 -0
  74. {wherewolf-0.2.0 → wherewolf-0.2.2}/tests/test_models.py +0 -0
  75. {wherewolf-0.2.0 → wherewolf-0.2.2}/tests/test_protocol.py +0 -0
  76. {wherewolf-0.2.0 → wherewolf-0.2.2}/tests/test_spark_engine.py +0 -0
  77. {wherewolf-0.2.0 → wherewolf-0.2.2}/tests/test_spark_engine_logic.py +0 -0
  78. {wherewolf-0.2.0 → wherewolf-0.2.2}/tests/test_spark_engine_optimization.py +0 -0
  79. {wherewolf-0.2.0 → wherewolf-0.2.2}/tests/test_storage___init__.py +0 -0
  80. {wherewolf-0.2.0 → wherewolf-0.2.2}/tests/test_translation___init__.py +0 -0
  81. {wherewolf-0.2.0 → wherewolf-0.2.2}/tests/test_translation_integration.py +0 -0
  82. {wherewolf-0.2.0 → wherewolf-0.2.2}/tests/test_translator.py +0 -0
  83. {wherewolf-0.2.0 → wherewolf-0.2.2}/tests/test_ui___init__.py +0 -0
  84. {wherewolf-0.2.0 → wherewolf-0.2.2}/tests/test_ui_branding.py +0 -0
  85. {wherewolf-0.2.0 → wherewolf-0.2.2}/tests/test_wherewolf___init__.py +0 -0
@@ -13,7 +13,47 @@ permissions:
13
13
  id-token: write
14
14
 
15
15
  jobs:
16
+ lint:
17
+ runs-on: ubuntu-latest
18
+ steps:
19
+ - uses: actions/checkout@v6
20
+ - name: Install uv
21
+ uses: astral-sh/setup-uv@v8.1.0
22
+ with:
23
+ enable-cache: true
24
+ cache-dependency-glob: "uv.lock"
25
+ - name: Set up Python
26
+ run: uv python install 3.12
27
+ - name: Install dependencies
28
+ run: ./run.sh uv sync --all-extras --dev
29
+ - name: Lint with ruff
30
+ run: |
31
+ ./run.sh uv run ruff check .
32
+ ./run.sh uv run ruff format --check .
33
+ - name: Type check with ty
34
+ run: ./run.sh uv run ty check . --python /tmp/wherewolf/.venv/bin/python
35
+
36
+ test:
37
+ runs-on: ubuntu-latest
38
+ strategy:
39
+ matrix:
40
+ python-version: ["3.11", "3.12"]
41
+ steps:
42
+ - uses: actions/checkout@v6
43
+ - name: Install uv
44
+ uses: astral-sh/setup-uv@v8.1.0
45
+ with:
46
+ enable-cache: true
47
+ cache-dependency-glob: "uv.lock"
48
+ - name: Set up Python ${{ matrix.python-version }}
49
+ run: uv python install ${{ matrix.python-version }}
50
+ - name: Install dependencies
51
+ run: ./run.sh uv sync --all-extras --dev
52
+ - name: Run tests
53
+ run: ./run.sh uv run pytest
54
+
16
55
  build:
56
+ needs: [lint, test]
17
57
  runs-on: ubuntu-latest
18
58
  steps:
19
59
  - uses: actions/checkout@v6
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wherewolf
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  License-File: LICENSE
5
5
  Requires-Python: >=3.11
6
6
  Requires-Dist: duckdb>=1.5.0
@@ -1,10 +1,10 @@
1
1
  # Wherewolf
2
2
 
3
- <img src="https://raw.githubusercontent.com/beallio/wherewolf/main/src/wherewolf/assets/img/wherewolf_banner.png?cacheBuster=1" width="100%">
3
+ <img src="https://raw.githubusercontent.com/beallio/wherewolf/main/src/wherewolf/assets/img/wherewolf_banner.png?cacheBuster=4" width="100%">
4
4
 
5
- [![CI](https://github.com/beallio/wherewolf/actions/workflows/ci.yml/badge.svg?cacheBuster=1)](https://github.com/beallio/wherewolf/actions/workflows/ci.yml)
6
- [![PyPI version](https://img.shields.io/pypi/v/wherewolf.svg?cacheBuster=1)](https://pypi.org/project/wherewolf/)
7
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg?cacheBuster=1)](https://opensource.org/licenses/MIT)
5
+ [![CI](https://github.com/beallio/wherewolf/actions/workflows/ci.yml/badge.svg?cacheBuster=4)](https://github.com/beallio/wherewolf/actions/workflows/ci.yml)
6
+ [![PyPI version](https://img.shields.io/pypi/v/wherewolf.svg?cacheBuster=4)](https://pypi.org/project/wherewolf/)
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg?cacheBuster=4)](https://opensource.org/licenses/MIT)
8
8
 
9
9
  A production-grade, local SQL workbench for querying files (CSV, Parquet, JSON) using DuckDB or Spark.
10
10
 
@@ -16,7 +16,7 @@ A production-grade, local SQL workbench for querying files (CSV, Parquet, JSON)
16
16
  - **Export:** Download query results as CSV, Excel, or Parquet.
17
17
  - **Execution Metrics:** Tracks row count and execution time.
18
18
 
19
- ![Wherewolf Screenshot](https://raw.githubusercontent.com/beallio/wherewolf/main/src/wherewolf/assets/img/screenshot.png?cacheBuster=1)
19
+ ![Wherewolf Screenshot](https://raw.githubusercontent.com/beallio/wherewolf/main/src/wherewolf/assets/img/screenshot.png?cacheBuster=4)
20
20
 
21
21
  ## Installation
22
22
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "wherewolf"
3
- version = "0.2.0"
3
+ version = "0.2.2"
4
4
  requires-python = ">=3.11"
5
5
  dependencies = [
6
6
  "duckdb>=1.5.0",
@@ -34,9 +34,12 @@ class DuckDBEngine:
34
34
  elif suffix == ".parquet":
35
35
  rel_source = self.con.from_parquet(str(abs_path))
36
36
  elif suffix == ".json":
37
- # read_json_auto doesn't have a direct 'from_json_auto' in all versions
38
- # so we can use the sql method with a Relation
39
- rel_source = self.con.read_json_auto(str(abs_path))
37
+ # Use SQL with read_json_auto to avoid ty check warning about missing attribute
38
+ rel_source = self.con.sql("SELECT * FROM read_json_auto(?)", params=[str(abs_path)])
39
+ elif suffix in [".xlsx", ".xls"]:
40
+ # Official DuckDB excel extension
41
+ self.con.execute("INSTALL excel; LOAD excel;")
42
+ rel_source = self.con.sql("SELECT * FROM read_xlsx(?)", params=[str(abs_path)])
40
43
  else:
41
44
  # Fallback to auto-detection
42
45
  rel_source = self.con.from_csv_auto(str(abs_path))
@@ -44,6 +44,12 @@ class SparkEngine:
44
44
  df_spark = spark.read.parquet(abs_path)
45
45
  elif abs_path.endswith(".json"):
46
46
  df_spark = spark.read.json(abs_path)
47
+ elif abs_path.endswith(".xlsx") or abs_path.endswith(".xls"):
48
+ # Use pandas as a bridge for Excel in local Spark
49
+ import pandas as pd
50
+
51
+ df_pd = pd.read_excel(abs_path)
52
+ df_spark = spark.createDataFrame(df_pd)
47
53
  else:
48
54
  # Default to automatic detection if supported,
49
55
  # but Spark is less automatic than DuckDB
@@ -88,7 +88,7 @@ class FileBrowser:
88
88
  st.caption("📁 *Directory selected. Change selection to enter.*")
89
89
  else:
90
90
  # Display file info
91
- valid_exts = {".csv", ".parquet", ".json"}
91
+ valid_exts = {".csv", ".parquet", ".json", ".xlsx", ".xls"}
92
92
  is_valid = Path(full_path).suffix.lower() in valid_exts
93
93
 
94
94
  if is_valid:
@@ -0,0 +1,36 @@
1
+ import pandas as pd
2
+ from wherewolf.execution import DuckDBEngine, SparkEngine
3
+
4
+
5
+ def test_excel_support_duckdb(tmp_path):
6
+ # 1. Create a dummy Excel file
7
+ excel_path = tmp_path / "test.xlsx"
8
+ df_orig = pd.DataFrame({"col1": [1, 2, 3], "col2": ["a", "b", "c"]})
9
+ df_orig.to_excel(excel_path, index=False)
10
+
11
+ engine = DuckDBEngine()
12
+ result = engine.execute("SELECT * FROM dataset", str(excel_path))
13
+
14
+ assert result.success, f"Execution failed: {result.error_message}"
15
+ assert len(result.df) == 3
16
+ assert result.df["col1"].tolist() == [1, 2, 3]
17
+
18
+
19
+ def test_excel_support_spark(tmp_path):
20
+ # 1. Create a dummy Excel file
21
+ excel_path = tmp_path / "test_spark.xlsx"
22
+ df_orig = pd.DataFrame({"col1": [10, 20], "col2": ["x", "y"]})
23
+ df_orig.to_excel(excel_path, index=False)
24
+
25
+ engine = SparkEngine()
26
+ result = engine.execute("SELECT * FROM dataset", str(excel_path))
27
+
28
+ assert result.success, f"Execution failed: {result.error_message}"
29
+ assert len(result.df) == 2
30
+ assert result.df["col1"].tolist() == [10, 20]
31
+
32
+
33
+ def test_ui_extension_recognition():
34
+ # This is a bit hard to test without full streamlit, but we can check the extension set
35
+ # if it's exposed or by mocking. Let's rely on integration tests or manual check if needed.
36
+ pass
@@ -2008,7 +2008,7 @@ wheels = [
2008
2008
 
2009
2009
  [[package]]
2010
2010
  name = "wherewolf"
2011
- version = "0.1.3"
2011
+ version = "0.2.1"
2012
2012
  source = { editable = "." }
2013
2013
  dependencies = [
2014
2014
  { name = "duckdb" },
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