querychat 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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: querychat
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: Chat with your data using natural language
5
5
  Project-URL: Homepage, https://github.com/posit-dev/querychat
6
6
  Project-URL: Repository, https://github.com/posit-dev/querychat
@@ -3,12 +3,13 @@ from __future__ import annotations
3
3
  from typing import TYPE_CHECKING, ClassVar, Protocol
4
4
 
5
5
  import duckdb
6
- import narwhals as nw
6
+ import narwhals.stable.v1 as nw
7
7
  import pandas as pd
8
8
  from sqlalchemy import inspect, text
9
9
  from sqlalchemy.sql import sqltypes
10
10
 
11
11
  if TYPE_CHECKING:
12
+ from narwhals.stable.v1.typing import IntoFrame
12
13
  from sqlalchemy.engine import Connection, Engine
13
14
 
14
15
 
@@ -58,8 +59,9 @@ class DataFrameSource:
58
59
  """A DataSource implementation that wraps a pandas DataFrame using DuckDB."""
59
60
 
60
61
  db_engine: ClassVar[str] = "DuckDB"
62
+ _df: nw.DataFrame | nw.LazyFrame
61
63
 
62
- def __init__(self, df: pd.DataFrame, table_name: str):
64
+ def __init__(self, df: IntoFrame, table_name: str):
63
65
  """
64
66
  Initialize with a pandas DataFrame.
65
67
 
@@ -69,9 +71,10 @@ class DataFrameSource:
69
71
 
70
72
  """
71
73
  self._conn = duckdb.connect(database=":memory:")
72
- self._df = df
74
+ self._df = nw.from_native(df)
73
75
  self._table_name = table_name
74
- self._conn.register(table_name, df)
76
+ # TODO(@gadenbuie): If the data frame is already SQL-backed, maybe we shouldn't be making a new copy here.
77
+ self._conn.register(table_name, self._df.lazy().collect().to_pandas())
75
78
 
76
79
  def get_schema(self, *, categorical_threshold: int) -> str:
77
80
  """
@@ -86,10 +89,15 @@ class DataFrameSource:
86
89
  String describing the schema
87
90
 
88
91
  """
89
- ndf = nw.from_native(self._df)
90
-
91
92
  schema = [f"Table: {self._table_name}", "Columns:"]
92
93
 
94
+ # Ensure we're working with a DataFrame, not a LazyFrame
95
+ ndf = (
96
+ self._df.head(10).collect()
97
+ if isinstance(self._df, nw.LazyFrame)
98
+ else self._df
99
+ )
100
+
93
101
  for column in ndf.columns:
94
102
  # Map pandas dtypes to SQL-like types
95
103
  dtype = ndf[column].dtype
@@ -149,7 +157,8 @@ class DataFrameSource:
149
157
  The complete dataset as a pandas DataFrame
150
158
 
151
159
  """
152
- return self._df.copy()
160
+ # TODO(@gadenbuie): This should just return `self._df` and not a pandas DataFrame
161
+ return self._df.lazy().collect().to_pandas()
153
162
 
154
163
 
155
164
  class SQLAlchemySource:
@@ -18,7 +18,7 @@ from typing import (
18
18
 
19
19
  import chatlas
20
20
  import chevron
21
- import narwhals as nw
21
+ import narwhals.stable.v1 as nw
22
22
  import sqlalchemy
23
23
  from shiny import Inputs, Outputs, Session, module, reactive, ui
24
24
 
@@ -26,7 +26,7 @@ from ._utils import temp_env_vars
26
26
 
27
27
  if TYPE_CHECKING:
28
28
  import pandas as pd
29
- from narwhals.typing import IntoFrame
29
+ from narwhals.stable.v1.typing import IntoFrame
30
30
 
31
31
  from .datasource import DataFrameSource, DataSource, SQLAlchemySource
32
32
 
@@ -224,16 +224,15 @@ def df_to_html(df: IntoFrame, maxrows: int = 5) -> str:
224
224
  HTML string representation of the table
225
225
 
226
226
  """
227
- df_short: nw.DataFrame[Any]
228
-
229
- if isinstance(df, nw.LazyFrame):
230
- ndf_eager = df.collect()
231
- df_short = df.head(maxrows).collect()
232
- elif isinstance(df, nw.DataFrame):
233
- ndf_eager = df
234
- df_short = df.head(maxrows)
227
+ ndf = nw.from_native(df)
228
+
229
+ if isinstance(ndf, (nw.LazyFrame, nw.DataFrame)):
230
+ df_short = ndf.lazy().head(maxrows).collect()
231
+ nrow_full = ndf.lazy().select(nw.len()).collect().item()
235
232
  else:
236
- raise TypeError("df must be a Narwhals DataFrame or LazyFrame")
233
+ raise TypeError(
234
+ "Must be able to convert `df` into a Narwhals DataFrame or LazyFrame",
235
+ )
237
236
 
238
237
  # Generate HTML table
239
238
  table_html = df_short.to_pandas().to_html(
@@ -242,9 +241,9 @@ def df_to_html(df: IntoFrame, maxrows: int = 5) -> str:
242
241
  )
243
242
 
244
243
  # Add note about truncated rows if needed
245
- if len(df_short) != len(ndf_eager):
244
+ if len(df_short) != nrow_full:
246
245
  rows_notice = (
247
- f"\n\n(Showing only the first {maxrows} rows out of {len(ndf_eager)}.)\n"
246
+ f"\n\n(Showing only the first {maxrows} rows out of {nrow_full}.)\n"
248
247
  )
249
248
  else:
250
249
  rows_notice = ""
@@ -415,15 +414,12 @@ def init(
415
414
  data_source_obj: DataSource
416
415
  if isinstance(data_source, sqlalchemy.Engine):
417
416
  data_source_obj = SQLAlchemySource(data_source, table_name)
418
- elif isinstance(data_source, (nw.DataFrame, nw.LazyFrame)):
417
+ else:
419
418
  data_source_obj = DataFrameSource(
420
- nw.to_native(data_source),
419
+ data_source,
421
420
  table_name,
422
421
  )
423
- else:
424
- raise TypeError(
425
- "`data_source` must be a Narwhals DataFrame or LazyFrame, or a SQLAlchemy Engine",
426
- )
422
+
427
423
  # Process greeting
428
424
  if greeting is None:
429
425
  print(
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "querychat"
7
- version = "0.2.0"
7
+ version = "0.2.2"
8
8
  description = "Chat with your data using natural language"
9
9
  readme = "pkg-py/README.md"
10
10
  requires-python = ">=3.9"
@@ -124,6 +124,7 @@ extend-ignore = [
124
124
  "D107", # Missing docstring in __init__
125
125
  "D205", # 1 blank line required between summary line and description
126
126
  "UP045", # Use `X | NULL` for type annotations, not `Optional[X]`
127
+ "TD003", # TODO doesn't need to have an issue link
127
128
  ]
128
129
  extend-select = [
129
130
  # "C90", # C90; mccabe: https://docs.astral.sh/ruff/rules/complex-structure/
File without changes
File without changes
File without changes
File without changes