wherewolf 0.2.1__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.
- {wherewolf-0.2.1 → wherewolf-0.2.2}/.github/workflows/release.yml +40 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/PKG-INFO +1 -1
- {wherewolf-0.2.1 → wherewolf-0.2.2}/README.md +5 -5
- {wherewolf-0.2.1 → wherewolf-0.2.2}/pyproject.toml +1 -1
- wherewolf-0.2.2/src/wherewolf/assets/img/wherewolf_banner.png +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/src/wherewolf/execution/duckdb_engine.py +4 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/src/wherewolf/execution/spark_engine.py +6 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/src/wherewolf/ui/file_browser.py +1 -1
- wherewolf-0.2.2/tests/test_excel_support.py +36 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/uv.lock +1 -1
- wherewolf-0.2.1/src/wherewolf/assets/img/wherewolf_banner.png +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/.envrc +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/.github/workflows/ci.yml +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/.gitignore +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/.protocol +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/.streamlit/config.toml +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/AGENTS.md +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/GEMINI.md +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/LICENSE +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/docs/RELEASING.md +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/docs/agent_conversations/2026-03-09_file_browsing.json +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/docs/agent_conversations/2026-03-09_initial_implementation.json +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/docs/agent_conversations/2026-04-19_github_setup.json +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/docs/agent_conversations/2026-04-19_tag_v0.1.0.json +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/docs/agent_protocol.md +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/docs/execution_ledger.json +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/docs/plans/core_system_design.md +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/docs/plans/execution_engines.md +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/docs/plans/export_formats.md +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/docs/plans/file_browsing.md +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/docs/plans/file_browsing_v2.md +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/docs/plans/github_automation.md +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/docs/plans/initial_prompt.md +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/docs/plans/storage_and_history.md +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/docs/plans/streamlit_ui.md +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/run.sh +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/scripts/check_tdd.sh +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/scripts/take_screenshot.py +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/src/wherewolf/__init__.py +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/src/wherewolf/app.py +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/src/wherewolf/assets/img/screenshot.png +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/src/wherewolf/assets/img/wherewolf_logo.png +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/src/wherewolf/cli.py +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/src/wherewolf/execution/__init__.py +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/src/wherewolf/execution/models.py +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/src/wherewolf/export/__init__.py +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/src/wherewolf/export/exporter.py +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/src/wherewolf/storage/__init__.py +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/src/wherewolf/storage/history.py +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/src/wherewolf/translation/__init__.py +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/src/wherewolf/translation/translator.py +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/src/wherewolf/ui/__init__.py +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/tests/reproduce_issue_symlink.py +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/tests/reproduce_issue_symlink_v2.py +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/tests/sample_queries.md +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/tests/test___init__.py +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/tests/test_app.py +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/tests/test_app_cancel.py +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/tests/test_app_flow.py +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/tests/test_cli.py +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/tests/test_config_toml.py +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/tests/test_data.csv +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/tests/test_duckdb_engine.py +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/tests/test_duckdb_sql_injection.py +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/tests/test_execution___init__.py +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/tests/test_export___init__.py +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/tests/test_exporter.py +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/tests/test_file_browser.py +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/tests/test_file_browser_errors.py +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/tests/test_file_browser_navigation.py +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/tests/test_file_browser_v2.py +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/tests/test_history.py +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/tests/test_history_atomicity.py +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/tests/test_models.py +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/tests/test_protocol.py +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/tests/test_spark_engine.py +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/tests/test_spark_engine_logic.py +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/tests/test_spark_engine_optimization.py +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/tests/test_storage___init__.py +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/tests/test_translation___init__.py +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/tests/test_translation_integration.py +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/tests/test_translator.py +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/tests/test_ui___init__.py +0 -0
- {wherewolf-0.2.1 → wherewolf-0.2.2}/tests/test_ui_branding.py +0 -0
- {wherewolf-0.2.1 → 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,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=
|
|
3
|
+
<img src="https://raw.githubusercontent.com/beallio/wherewolf/main/src/wherewolf/assets/img/wherewolf_banner.png?cacheBuster=4" width="100%">
|
|
4
4
|
|
|
5
|
-
[](https://github.com/beallio/wherewolf/actions/workflows/ci.yml)
|
|
6
|
+
[](https://pypi.org/project/wherewolf/)
|
|
7
|
+
[](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
|
-

|
|
20
20
|
|
|
21
21
|
## Installation
|
|
22
22
|
|
|
Binary file
|
|
@@ -36,6 +36,10 @@ class DuckDBEngine:
|
|
|
36
36
|
elif suffix == ".json":
|
|
37
37
|
# Use SQL with read_json_auto to avoid ty check warning about missing attribute
|
|
38
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)])
|
|
39
43
|
else:
|
|
40
44
|
# Fallback to auto-detection
|
|
41
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
|
|
Binary file
|
|
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
|
{wherewolf-0.2.1 → wherewolf-0.2.2}/docs/agent_conversations/2026-03-09_initial_implementation.json
RENAMED
|
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
|
|
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
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|