pandas-query-sql 0.8.1__tar.gz → 0.8.3.dev0__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,26 +1,21 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: pandas_query_sql
3
- Version: 0.8.1
3
+ Version: 0.8.3.dev0
4
4
  Summary: sqldf for pandas
5
- Author-Email: Alexander Plavin <alexander@plav.in>, Greg Lamp <lamp.greg@gmail.com>, Michael Dempsey <bluestealth@bluestealth.pw>
6
- License: MIT
7
- Classifier: License :: OSI Approved :: MIT License
8
- Project-URL: Homepage, https://github.com/bluestealth/pandasql/
9
- Requires-Python: >=3.8
5
+ Author: Alexander Plavin, Greg Lamp, Michael Dempsey
6
+ Author-email: Alexander Plavin <alexander@plav.in>, Greg Lamp <lamp.greg@gmail.com>, Michael Dempsey <bluestealth@bluestealth.pw>
7
+ License-Expression: MIT
8
+ License-File: LICENSE.txt
10
9
  Requires-Dist: numpy
11
10
  Requires-Dist: packaging
12
11
  Requires-Dist: pandas
13
12
  Requires-Dist: sqlalchemy
14
- Requires-Dist: psycopg2; extra == "postgresql"
15
- Requires-Dist: psycopg2-binary; extra == "postgresql-binary"
16
- Requires-Dist: black; extra == "linters"
17
- Requires-Dist: ruff; extra == "linters"
18
- Requires-Dist: pytest; extra == "testing"
19
- Requires-Dist: psycopg2-binary; extra == "testing"
13
+ Requires-Dist: psycopg2 ; extra == 'postgresql'
14
+ Requires-Dist: psycopg2-binary ; extra == 'postgresql-binary'
15
+ Requires-Python: >=3.11
16
+ Project-URL: Homepage, https://github.com/bluestealth/pandasql/
20
17
  Provides-Extra: postgresql
21
18
  Provides-Extra: postgresql-binary
22
- Provides-Extra: linters
23
- Provides-Extra: testing
24
19
  Description-Content-Type: text/markdown
25
20
 
26
21
  pandasql
@@ -1,77 +1,65 @@
1
1
  [project]
2
2
  name = "pandas_query_sql"
3
- version = "0.8.1"
3
+ version = "0.8.3.dev0"
4
4
  description = "sqldf for pandas"
5
- authors = [
6
- { name = "Alexander Plavin", email = "alexander@plav.in" },
7
- { name = "Greg Lamp", email = "lamp.greg@gmail.com" },
8
- { name = "Michael Dempsey", email = "bluestealth@bluestealth.pw" },
9
- ]
10
5
  dependencies = [
11
6
  "numpy",
12
7
  "packaging",
13
8
  "pandas",
14
9
  "sqlalchemy",
15
10
  ]
16
- requires-python = ">=3.8"
11
+ requires-python = ">=3.11"
17
12
  readme = "README.md"
18
- classifiers = [
19
- "License :: OSI Approved :: MIT License",
20
- ]
13
+ license = "MIT"
14
+ license-files = ["LICENSE.txt"]
15
+
16
+ [[project.authors]]
17
+ name = "Alexander Plavin"
18
+ email = "alexander@plav.in"
21
19
 
22
- [project.license]
23
- text = "MIT"
20
+ [[project.authors]]
21
+ name = "Greg Lamp"
22
+ email = "lamp.greg@gmail.com"
23
+
24
+ [[project.authors]]
25
+ name = "Michael Dempsey"
26
+ email = "bluestealth@bluestealth.pw"
24
27
 
25
28
  [project.urls]
26
29
  Homepage = "https://github.com/bluestealth/pandasql/"
27
30
 
28
31
  [project.optional-dependencies]
29
- postgresql = [
30
- "psycopg2",
31
- ]
32
- postgresql-binary = [
33
- "psycopg2-binary",
34
- ]
35
- linters = [
36
- "black",
32
+ postgresql = ["psycopg2"]
33
+ postgresql-binary = ["psycopg2-binary"]
34
+
35
+ [dependency-groups]
36
+ dev = [
37
37
  "ruff",
38
- ]
39
- testing = [
40
38
  "pytest",
41
39
  "psycopg2-binary",
40
+ "testcontainers[postgres]",
41
+ "ty",
42
42
  ]
43
43
 
44
44
  [build-system]
45
- requires = [
46
- "pdm-backend",
47
- ]
48
- build-backend = "pdm.backend"
49
-
50
- [tool.pdm]
51
- distribution = true
45
+ requires = ["uv_build>=0.13.5,<0.14"]
46
+ build-backend = "uv_build"
52
47
 
53
- [tool.pdm.package-dir]
54
- pandasql = "pandasql"
48
+ [tool.uv.build-backend]
49
+ module-name = "pandasql"
55
50
 
56
- [tool.setuptools.package-data]
57
- pandasql = [
58
- "data/births.csv",
59
- "data/birth_by_months.csv",
60
- "data/meat.csv",
61
- "py.typed",
62
- ]
51
+ [tool.ty.src]
52
+ exclude = ["examples/**"]
63
53
 
64
54
  [tool.ruff]
65
55
  line-length = 120
66
- target-version = "py38"
56
+ target-version = "py311"
67
57
 
68
58
  [tool.ruff.lint]
69
- select = [
70
- "ALL",
71
- ]
59
+ select = ["ALL"]
72
60
  ignore = [
73
- "FA100",
74
- "ANN101",
61
+ "COM812",
62
+ "CPY001",
75
63
  "FBT001",
76
64
  "FBT002",
77
65
  "TRY003",
@@ -92,21 +80,18 @@ max-complexity = 14
92
80
  convention = "google"
93
81
 
94
82
  [tool.ruff.lint.per-file-ignores]
95
- "src/pandasql/__init__.py" = [
96
- "D",
97
- ]
83
+ "src/pandasql/__init__.py" = ["D"]
98
84
  "examples/**/*.py" = [
99
85
  "D",
100
86
  "INP001",
101
87
  ]
102
88
  "tests/**/*.py" = [
103
89
  "D",
90
+ "BLE001",
104
91
  ]
105
92
 
106
93
  [tool.ruff.lint.extend-per-file-ignores]
107
- "examples/**/*.py" = [
108
- "T",
109
- ]
94
+ "examples/**/*.py" = ["T"]
110
95
  "tests/**/*.py" = [
111
96
  "T",
112
97
  "S101",
@@ -0,0 +1,74 @@
1
+ [project]
2
+ name = "pandas_query_sql"
3
+ version = "0.8.3.dev0"
4
+ description = "sqldf for pandas"
5
+ authors = [
6
+ {name = "Alexander Plavin", email = "alexander@plav.in"},
7
+ {name = "Greg Lamp", email= "lamp.greg@gmail.com"},
8
+ {name = "Michael Dempsey", email = "bluestealth@bluestealth.pw"},
9
+ ]
10
+ dependencies = [
11
+ "numpy",
12
+ "packaging",
13
+ "pandas",
14
+ "sqlalchemy",
15
+ ]
16
+ requires-python = ">=3.11"
17
+ readme = "README.md"
18
+ license = "MIT"
19
+ license-files = ["LICENSE.txt"]
20
+
21
+ [project.urls]
22
+ Homepage = "https://github.com/bluestealth/pandasql/"
23
+
24
+ [project.optional-dependencies]
25
+ postgresql = [
26
+ "psycopg2",
27
+ ]
28
+ postgresql-binary = [
29
+ "psycopg2-binary",
30
+ ]
31
+
32
+ [dependency-groups]
33
+ dev = [
34
+ "ruff",
35
+ "pytest",
36
+ "psycopg2-binary",
37
+ "testcontainers[postgres]",
38
+ 'ty',
39
+ ]
40
+
41
+ [build-system]
42
+ requires = ["uv_build>=0.13.5,<0.14"]
43
+ build-backend = "uv_build"
44
+
45
+ [tool.uv.build-backend]
46
+ module-name = "pandasql"
47
+
48
+ [tool.ty.src]
49
+ exclude = ["examples/**"]
50
+
51
+ [tool.ruff]
52
+ line-length = 120
53
+ target-version = 'py311'
54
+
55
+ [tool.ruff.lint]
56
+ select = ['ALL']
57
+ ignore = ['COM812', "CPY001", 'FBT001', 'FBT002', 'TRY003', 'EM101', 'PLR2004', 'N818']
58
+ flake8-quotes = {}
59
+ isort = { known-first-party = [] }
60
+ mccabe = { max-complexity = 14 }
61
+ pydocstyle = { convention = 'google' }
62
+
63
+ [tool.ruff.format]
64
+ quote-style = "double"
65
+ indent-style = "space"
66
+
67
+ [tool.ruff.lint.per-file-ignores]
68
+ 'src/pandasql/__init__.py' = ['D']
69
+ "examples/**/*.py" = ['D', 'INP001']
70
+ "tests/**/*.py" = ['D', 'BLE001']
71
+
72
+ [tool.ruff.lint.extend-per-file-ignores]
73
+ "examples/**/*.py" = ['T']
74
+ "tests/**/*.py" = ['T', 'S101', 'PD901', 'PLR']
@@ -4,17 +4,20 @@ import importlib.metadata
4
4
  import inspect
5
5
  import re
6
6
  import sqlite3
7
+ from collections.abc import Generator
7
8
  from contextlib import contextmanager
8
- from typing import Any, Dict, Iterator, Optional, Set, Union
9
+ from typing import Any
9
10
  from warnings import catch_warnings, filterwarnings
10
11
 
11
12
  import packaging.version
12
13
  from pandas import DataFrame
14
+ from pandas.errors import DatabaseError as PandasDatabaseError
13
15
  from pandas.io.sql import read_sql_query
14
16
  from sqlalchemy import create_engine # pyright: ignore[reportUnknownVariableType]
15
17
  from sqlalchemy.engine import Connection, Engine
16
18
  from sqlalchemy.event import listen # pyright: ignore[reportUnknownVariableType]
17
- from sqlalchemy.exc import DatabaseError, ResourceClosedError
19
+ from sqlalchemy.exc import DatabaseError as SQLAlchemyDatabaseError
20
+ from sqlalchemy.exc import ResourceClosedError
18
21
  from sqlalchemy.pool import NullPool
19
22
  from sqlalchemy.pool.base import (
20
23
  _ConnectionRecord, # pyright: ignore[reportPrivateUsage]
@@ -40,7 +43,7 @@ class PandaSQL:
40
43
  loaded_tables: set of currently loaded table names
41
44
  """
42
45
 
43
- def __init__(self, db_uri: Optional[str], persist: bool = False) -> None:
46
+ def __init__(self, db_uri: str | None, persist: bool = False) -> None:
44
47
  """Initialize with a specific database.
45
48
 
46
49
  :param db_uri: SQLAlchemy-compatible database URI.
@@ -61,7 +64,7 @@ class PandaSQL:
61
64
  )
62
65
 
63
66
  self.persist = persist
64
- self.loaded_tables: Set[str] = set()
67
+ self.loaded_tables: set[str] = set()
65
68
  if self.persist:
66
69
  self._conn = self.engine.connect()
67
70
  self._init_connection(self._conn)
@@ -69,8 +72,8 @@ class PandaSQL:
69
72
  def __call__(
70
73
  self,
71
74
  query: str,
72
- env: Optional[Dict[str, Any]] = None,
73
- ) -> Optional[DataFrame]:
75
+ env: dict[str, Any] | None = None,
76
+ ) -> DataFrame | None:
74
77
  """Execute the SQL query.
75
78
 
76
79
  Automatically creates tables mentioned in the query from dataframes before executing.
@@ -96,17 +99,17 @@ class PandaSQL:
96
99
 
97
100
  try:
98
101
  result = read_sql_query(sql=query, con=conn)
99
- except DatabaseError as ex:
100
- raise PandaSQLException(ex) from ex
101
102
  except ResourceClosedError:
102
103
  # query returns nothing
103
104
  result = None
105
+ except (SQLAlchemyDatabaseError, PandasDatabaseError) as ex:
106
+ raise PandaSQLException(ex) from ex
104
107
 
105
108
  return result
106
109
 
107
110
  @property
108
111
  @contextmanager
109
- def conn(self) -> Iterator[Connection]:
112
+ def conn(self) -> Generator[Connection]:
110
113
  """Context Manager for database connection."""
111
114
  if self.persist:
112
115
  # the connection is created in __init__, so just return it
@@ -125,13 +128,13 @@ class PandaSQL:
125
128
  def _init_connection(self, conn: Connection) -> None:
126
129
  if self.engine.name == "postgresql":
127
130
  if SQLALCHEMY_MAJOR_VERSION >= 2:
128
- from sqlalchemy import text
131
+ from sqlalchemy import text # noqa: PLC0415
129
132
 
130
133
  conn.execute( # pyright: ignore[reportUnknownMemberType]
131
134
  statement=text("set search_path to pg_temp"),
132
135
  )
133
136
  else:
134
- conn.execute( # pyright: ignore[reportUnknownMemberType]
137
+ conn.execute( # ty: ignore[no-matching-overload]
135
138
  statement="set search_path to pg_temp",
136
139
  )
137
140
 
@@ -143,26 +146,22 @@ class PandaSQL:
143
146
  dbapi_conn.text_factory = str
144
147
 
145
148
 
146
- def get_outer_frame_variables() -> Dict[str, Any]:
149
+ def get_outer_frame_variables() -> dict[str, Any]:
147
150
  """Get a dict of local and global variables of the first outer frame from another file."""
148
151
  frame = inspect.currentframe()
149
- variables: Dict[str, Any] = {}
152
+ variables: dict[str, Any] = {}
150
153
 
151
154
  if not frame:
152
155
  return variables
153
156
 
154
157
  cur_filename = inspect.getframeinfo(frame).filename
155
- outer_frame = next(
156
- f
157
- for f in inspect.getouterframes(inspect.currentframe())
158
- if f.filename != cur_filename
159
- )
158
+ outer_frame = next(f for f in inspect.getouterframes(inspect.currentframe()) if f.filename != cur_filename)
160
159
  variables.update(outer_frame.frame.f_globals)
161
160
  variables.update(outer_frame.frame.f_locals)
162
161
  return variables
163
162
 
164
163
 
165
- def extract_table_names(query: str) -> Set[str]:
164
+ def extract_table_names(query: str) -> set[str]:
166
165
  """Extract table names from an SQL query."""
167
166
  # a good old fashioned regex. turns out this worked better than actually parsing the code
168
167
  tables_blocks = re.findall(
@@ -176,7 +175,7 @@ def extract_table_names(query: str) -> Set[str]:
176
175
  def write_table(
177
176
  df: DataFrame,
178
177
  tablename: str,
179
- conn: Union[Engine, Connection, sqlite3.Connection],
178
+ conn: Engine | Connection | sqlite3.Connection,
180
179
  ) -> None:
181
180
  """Write Pandas DataFrame to SQL Table.
182
181
 
@@ -205,9 +204,9 @@ def write_table(
205
204
 
206
205
  def sqldf(
207
206
  query: str,
208
- env: Optional[Dict[str, Any]] = None,
209
- db_uri: Optional[str] = None,
210
- ) -> Optional[DataFrame]:
207
+ env: dict[str, Any] | None = None,
208
+ db_uri: str | None = None,
209
+ ) -> DataFrame | None:
211
210
  """Query pandas data frames using sql syntax.
212
211
 
213
212
  This function is meant for backward compatibility only. New users are encouraged to use the PandaSQL class.
@@ -1,11 +0,0 @@
1
- ##Authors
2
-
3
- - Greg Lamp
4
- - Austin Ogilvie
5
-
6
- ##Patches
7
- - Colin Dickson
8
- - stonebig
9
-
10
- ##Fork author
11
- - Alexander Plavin
File without changes
File without changes
@@ -1,335 +0,0 @@
1
- import importlib.metadata
2
- import string
3
- from typing import Dict
4
-
5
- import packaging.version
6
- import pandas as pd
7
- import pandas.testing as pdtest
8
- import pytest
9
-
10
- from pandasql import PandaSQL, PandaSQLException, load_meat, sqldf
11
-
12
- PANDAS_MAJOR_VERSION = packaging.version.Version(
13
- importlib.metadata.version("pandas"),
14
- ).major
15
-
16
-
17
- @pytest.fixture()
18
- def db_uris() -> Dict[str, str]:
19
- return {
20
- "sqlite": "sqlite:///:memory:",
21
- "postgres": "postgresql://postgres@localhost/",
22
- }
23
-
24
-
25
- @pytest.fixture(params=["sqlite", "postgres"])
26
- def db_flavor(request: pytest.FixtureRequest) -> str:
27
- return str(request.param)
28
-
29
-
30
- @pytest.fixture()
31
- def db_uri(db_uris: Dict[str, str], db_flavor: str) -> str:
32
- return db_uris[db_flavor]
33
-
34
-
35
- @pytest.fixture(params=[False, True])
36
- def pdsql(db_uri: str, request: pytest.FixtureRequest) -> PandaSQL:
37
- return PandaSQL(db_uri, persist=request.param)
38
-
39
-
40
- def test_select_legacy(db_uri: str) -> None:
41
- df = pd.DataFrame(
42
- {
43
- "letter_pos": range(len(string.ascii_letters)),
44
- "l2": list(string.ascii_letters),
45
- },
46
- )
47
- result = sqldf("SELECT * FROM df LIMIT 10", db_uri=db_uri)
48
-
49
- assert result is not None
50
- assert len(result) == 10
51
- pdtest.assert_frame_equal(df.head(10), result)
52
-
53
-
54
- def test_select(pdsql: PandaSQL) -> None:
55
- df = pd.DataFrame(
56
- {
57
- "letter_pos": range(len(string.ascii_letters)),
58
- "l2": list(string.ascii_letters),
59
- },
60
- )
61
- result = pdsql("SELECT * FROM df LIMIT 10")
62
-
63
- assert result is not None
64
- assert len(result) == 10
65
- pdtest.assert_frame_equal(df.head(10), result)
66
-
67
-
68
- def test_join(pdsql: PandaSQL) -> None:
69
- df = pd.DataFrame(
70
- {
71
- "letter_pos": range(len(string.ascii_letters)),
72
- "l2": list(string.ascii_letters),
73
- },
74
- )
75
-
76
- df2 = pd.DataFrame(
77
- {
78
- "letter_pos": range(len(string.ascii_letters)),
79
- "letter": list(string.ascii_letters),
80
- },
81
- )
82
-
83
- result = pdsql(
84
- "SELECT a.*, b.letter FROM df a INNER JOIN df2 b ON a.l2 = b.letter LIMIT 20",
85
- )
86
-
87
- assert result is not None
88
- assert len(result) == 20
89
- pdtest.assert_frame_equal(
90
- df[["letter_pos", "l2"]].head(20),
91
- result[["letter_pos", "l2"]],
92
- )
93
- pdtest.assert_frame_equal(df2[["letter"]].head(20), result[["letter"]])
94
-
95
-
96
- def test_query_with_spacing(pdsql: PandaSQL) -> None:
97
- df = pd.DataFrame(
98
- {
99
- "letter_pos": range(len(string.ascii_letters)),
100
- "l2": list(string.ascii_letters),
101
- },
102
- )
103
- assert df is not None
104
-
105
- df2 = pd.DataFrame(
106
- {
107
- "letter_pos": range(len(string.ascii_letters)),
108
- "letter": list(string.ascii_letters),
109
- },
110
- )
111
- assert df2 is not None
112
-
113
- expected = pdsql(
114
- "SELECT a.*, b.letter FROM df a INNER JOIN df2 b ON a.l2 = b.letter LIMIT 20",
115
- )
116
- assert expected is not None
117
-
118
- q = """
119
- SELECT
120
- a.*
121
- , b.letter
122
- FROM
123
- df a
124
- INNER JOIN
125
- df2 b
126
- on a.l2 = b.letter
127
- LIMIT 20
128
- """
129
- result = pdsql(q)
130
- assert result is not None
131
- assert len(result) == 20
132
- pdtest.assert_frame_equal(expected, result)
133
-
134
-
135
- def test_subquery(pdsql: PandaSQL) -> None:
136
- kermit = pd.DataFrame({"x": range(10)})
137
- result = pdsql("SELECT * FROM (SELECT * FROM kermit) tbl LIMIT 2")
138
- assert result is not None
139
- pdtest.assert_frame_equal(kermit.head(2), result)
140
- assert len(result) == 2
141
-
142
-
143
- def test_in(pdsql: PandaSQL) -> None:
144
- course_data = {
145
- "coursecode": ["TM351", "TU100", "M269"],
146
- "points": [30, 60, 30],
147
- "level": ["3", "1", "2"],
148
- }
149
- course_df = pd.DataFrame(course_data)
150
- assert not course_df.empty
151
-
152
- result = pdsql("SELECT * FROM course_df WHERE coursecode IN ( 'TM351', 'TU100' )")
153
- assert result is not None
154
- assert len(result) == 2
155
-
156
-
157
- def test_in_with_subquery(pdsql: PandaSQL) -> None:
158
- program_data = {
159
- "coursecode": [
160
- "TM351",
161
- "TM351",
162
- "TM351",
163
- "TU100",
164
- "TU100",
165
- "TU100",
166
- "M269",
167
- "M269",
168
- "M269",
169
- ],
170
- "programCode": ["AB1", "AB2", "AB3", "AB1", "AB3", "AB4", "AB3", "AB4", "AB5"],
171
- }
172
- program_df = pd.DataFrame(program_data)
173
- assert not program_df.empty
174
-
175
- course_data = {
176
- "coursecode": ["TM351", "TU100", "M269"],
177
- "points": [30, 60, 30],
178
- "level": ["3", "1", "2"],
179
- }
180
- course_df = pd.DataFrame(course_data)
181
- assert not course_df.empty
182
-
183
- result = pdsql(
184
- "SELECT * FROM course_df WHERE coursecode IN ( SELECT DISTINCT coursecode FROM program_df )",
185
- )
186
- assert result is not None
187
- assert len(result) == 3
188
-
189
-
190
- def test_datetime_query(pdsql: PandaSQL, db_flavor: str) -> None:
191
- meat = load_meat()
192
- expected = meat[meat["date"] >= "2012-01-01"].reset_index(drop=True)
193
- result = pdsql("SELECT * FROM meat WHERE date >= '2012-01-01'")
194
- assert result is not None
195
-
196
- if db_flavor == "sqlite":
197
- # sqlite uses strings instead of datetimes
198
- pdtest.assert_frame_equal(
199
- expected.drop(labels="date", axis="columns"),
200
- result.drop(labels="date", axis="columns"),
201
- )
202
- else:
203
- pdtest.assert_frame_equal(expected, result)
204
-
205
-
206
- def test_returning_single(pdsql: PandaSQL) -> None:
207
- meat = load_meat()
208
- result = pdsql("SELECT beef FROM meat LIMIT 10")
209
- assert result is not None
210
- assert len(result) == 10
211
- pdtest.assert_frame_equal(meat[["beef"]].head(10), result)
212
-
213
-
214
- def test_name_index(pdsql: PandaSQL) -> None:
215
- df = pd.DataFrame(
216
- {
217
- "index": range(len(string.ascii_letters)),
218
- "level_0": range(len(string.ascii_letters)),
219
- "level_1": range(len(string.ascii_letters)),
220
- "letter": list(string.ascii_letters),
221
- },
222
- )
223
- result = pdsql("SELECT * FROM df")
224
- assert result is not None
225
- pdtest.assert_frame_equal(df, result)
226
-
227
-
228
- def test_nonexistent_table(pdsql: PandaSQL) -> None:
229
- with pytest.raises(PandaSQLException):
230
- pdsql("SELECT * FROM nosuchtablereally")
231
-
232
-
233
- def test_system_tables(pdsql: PandaSQL, db_flavor: str) -> None:
234
- if db_flavor == "sqlite":
235
- # sqlite doesn't have information_schema
236
- result = pdsql("SELECT * FROM sqlite_master")
237
- else:
238
- result = pdsql("SELECT * FROM information_schema.tables")
239
- assert result is not None
240
- assert len(result.columns) > 1
241
-
242
-
243
- @pytest.mark.parametrize(
244
- "db_flavor",
245
- ["postgres"],
246
- ) # sqlite doesn't support tables with no columns
247
- def test_no_columns(pdsql: PandaSQL) -> None:
248
- df = pd.DataFrame()
249
- result = pdsql("SELECT * FROM df")
250
- assert result is not None
251
- assert df.empty
252
- assert result.empty
253
- pdtest.assert_frame_equal(df, result, check_column_type=(PANDAS_MAJOR_VERSION < 2))
254
-
255
-
256
- def test_empty(pdsql: PandaSQL) -> None:
257
- df = pd.DataFrame({"x": []})
258
- result = pdsql("SELECT * FROM df")
259
- assert result is not None
260
- assert result.empty
261
- pdtest.assert_index_equal(df.columns, result.columns)
262
-
263
-
264
- def test_noleak_legacy(db_uri: str) -> None:
265
- df = pd.DataFrame({"x": [1]})
266
- result = sqldf("SELECT * FROM df", db_uri=db_uri)
267
- assert result is not None
268
- pdtest.assert_frame_equal(df, result)
269
- del df
270
- with pytest.raises(PandaSQLException):
271
- result = sqldf("SELECT * FROM df", db_uri=db_uri)
272
-
273
-
274
- @pytest.mark.parametrize("pdsql", [False], indirect=True)
275
- def test_noleak_class(pdsql: PandaSQL) -> None:
276
- df = pd.DataFrame({"x": [1]})
277
- result = pdsql("SELECT * FROM df")
278
- assert result is not None
279
- pdtest.assert_frame_equal(df, result)
280
- del df
281
- with pytest.raises(PandaSQLException):
282
- result = pdsql("SELECT * FROM df")
283
-
284
-
285
- def test_same_query_noerr(pdsql: PandaSQL) -> None:
286
- df = pd.DataFrame({"x": [1]})
287
- result1 = pdsql("SELECT * FROM df")
288
- assert result1 is not None
289
- pdtest.assert_frame_equal(df, result1)
290
- result2 = pdsql("SELECT * FROM df")
291
- assert result2 is not None
292
- pdtest.assert_frame_equal(result1, result2)
293
-
294
-
295
- @pytest.mark.parametrize("pdsql", [True], indirect=True)
296
- def test_persistent(pdsql: PandaSQL) -> None:
297
- df = pd.DataFrame({"x": [1]})
298
- result1 = pdsql("SELECT * FROM df")
299
- assert result1 is not None
300
- pdtest.assert_frame_equal(df, result1)
301
-
302
- del df
303
- result2 = pdsql("SELECT * FROM df")
304
- assert result2 is not None
305
- pdtest.assert_frame_equal(result1, result2)
306
-
307
- df = pd.DataFrame({"x": [1, 2]}) # will not have any effect
308
- assert not df.empty
309
- result3 = pdsql("SELECT * FROM df")
310
- assert result3 is not None
311
- pdtest.assert_frame_equal(result1, result3)
312
-
313
- df1 = pd.DataFrame({"x": [1, 2, 3]})
314
- result4 = pdsql("SELECT * FROM df1")
315
- assert result4 is not None
316
- pdtest.assert_frame_equal(df1, result4)
317
-
318
-
319
- def test_noreturn_query(pdsql: PandaSQL) -> None:
320
- assert pdsql("CREATE TABLE tbl (col INTEGER)") is None
321
-
322
-
323
- @pytest.mark.parametrize("pdsql", [False], indirect=True)
324
- def test_no_sideeffect_leak(pdsql: PandaSQL) -> None:
325
- pdsql("CREATE TABLE tbl (col INTEGER)")
326
- with pytest.raises(PandaSQLException):
327
- pdsql("SELECT * FROM tbl")
328
-
329
-
330
- @pytest.mark.parametrize("pdsql", [True], indirect=True)
331
- def test_sideeffect_persist(pdsql: PandaSQL) -> None:
332
- pdsql("CREATE TABLE tbl (col INTEGER)")
333
- result = pdsql("SELECT * FROM tbl")
334
- assert result is not None
335
- assert list(result.columns) == ["col"]
@@ -1,46 +0,0 @@
1
- from typing import Set
2
-
3
- import pytest
4
-
5
- from pandasql.sqldf import extract_table_names, get_outer_frame_variables
6
-
7
-
8
- def test_get_vars() -> None:
9
- var_a = 123
10
- variable = {"a": "b", "c": "d"}
11
- assert get_outer_frame_variables()["var_a"] == var_a
12
- assert get_outer_frame_variables()["variable"] == variable
13
-
14
-
15
- @pytest.mark.parametrize(
16
- ("query", "expected"),
17
- [
18
- ("", set()),
19
- ("SELECT * FROM dbtbl LIMIT 10", {"dbtbl"}),
20
- ("SELECT * from dbtbl LIMIT 10", {"dbtbl"}),
21
- (
22
- "SELECT * FROM dbtbl JOIN table_2 USING (a) LEFT JOIN mytable USING (b)",
23
- {"dbtbl", "table_2", "mytable"},
24
- ),
25
- (
26
- "SELECT * FROM dbtbl, table_2, mytable JOIN another USING (a)",
27
- {"dbtbl", "table_2", "mytable", "another"},
28
- ),
29
- ("SELECT * FROM dbtbl, table_2 JOIN dbtbl USING (a)", {"dbtbl", "table_2"}),
30
- pytest.param(
31
- "SELECT * FROM dbtbl WHERE col = 'Go and join us!'",
32
- {"dbtbl"},
33
- marks=pytest.mark.xfail,
34
- ),
35
- (
36
- "SELECT * FROM course_df WHERE coursecode IN ( SELECT DISTINCT coursecode FROM program_df )",
37
- {"course_df", "program_df"},
38
- ),
39
- (
40
- "SELECT * FROM course_df, (SELECT coursecode FROM program_df) ssel",
41
- {"course_df", "program_df"},
42
- ),
43
- ],
44
- )
45
- def test_extract_table_names(query: str, expected: Set[str]) -> None:
46
- assert extract_table_names(query) == expected