Skip to content

Commit 3675cf9

Browse files
committed
v3.1.2
1 parent 438eeff commit 3675cf9

File tree

9 files changed

+54
-16
lines changed

9 files changed

+54
-16
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,9 @@ ipython_config.py
114114
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
115115
# in version control.
116116
# https://pdm.fming.dev/#use-with-ide
117+
stackql
118+
stackql-zip
119+
117120
.pdm.toml
118121

119122
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm

CHANGELOG.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
# Changelog
22

3-
## v3.1.1 (2023-10-16)
3+
## v3.1.2 (2023-10-16)
4+
5+
### Updates
6+
7+
* `pandas` type fixes
8+
9+
## v3.1.1 (2023-10-14)
410

511
### Updates
612

README.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ PyStackQL has been tested on:
112112
- Python 3.9
113113
- Python 3.10
114114
- Python 3.11
115-
- Python 3.12 (MacOS and Linux only
115+
- Python 3.12 (MacOS and Linux only)
116116

117117
Licensing
118118
~~~~~~~~~
@@ -193,4 +193,4 @@ To publish the package to PyPI, run the following command:
193193

194194
::
195195

196-
twine upload dist/pystackql-3.1.1.tar.gz
196+
twine upload dist/pystackql-3.1.2.tar.gz

docs/source/conf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
# The short X.Y version
2727
version = ''
2828
# The full version, including alpha/beta/rc tags
29-
release = '3.1.1'
29+
release = '3.1.2'
3030

3131

3232
# -- General configuration ---------------------------------------------------

pystackql/stackql.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
from psycopg2.extras import RealDictCursor
1313
import pandas as pd
1414

15+
from io import StringIO
16+
1517
class StackQL:
1618
"""
1719
A class representing an instance of the StackQL query engine.
@@ -453,7 +455,8 @@ def execute(self, query):
453455
result = self._run_server_query(query)
454456

455457
if self.output == 'pandas':
456-
return pd.DataFrame(result) # Convert dict results to DataFrame
458+
json_str = json.dumps(result)
459+
return pd.read_json(StringIO(json_str))
457460
elif self.output == 'csv':
458461
raise ValueError("CSV output is not supported in server_mode.")
459462
else: # Assume 'dict' output
@@ -466,15 +469,15 @@ def execute(self, query):
466469
return output
467470
elif self.output == 'pandas':
468471
try:
469-
json_output = json.loads(output)
470-
return pd.DataFrame(json_output)
472+
return pd.read_json(StringIO(output))
471473
except ValueError:
472474
return pd.DataFrame([{"error": "Invalid JSON output: {}".format(output.strip())}])
473475
else: # Assume 'dict' output
474476
try:
475477
return json.loads(output)
476478
except ValueError:
477479
return [{"error": "Invalid JSON output: {}".format(output.strip())}]
480+
478481
#
479482
# asnyc query support
480483
#

pystackql/stackql_magic.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ def run_query(self, query):
4343
:param query: StackQL query to be executed.
4444
:type query: str
4545
:return: Query results, returned as a Pandas DataFrame.
46-
:rtype: pandas.DataFrame or str
46+
:rtype: pandas.DataFrame
4747
"""
4848
return self.stackql_instance.execute(query)
4949

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
setup(
1212
name='pystackql',
13-
version='3.1.1',
13+
version='3.1.2',
1414
description='A Python interface for StackQL',
1515
long_description=readme,
1616
author='Jeffrey Aven',

tests/pystackql_tests.py

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -169,18 +169,26 @@ def test_11_execute_with_defaults(self):
169169
result = self.stackql.execute(google_query)
170170
is_valid_dict = isinstance(result, list) and all(isinstance(item, dict) for item in result)
171171
self.assertTrue(is_valid_dict, f"Result is not a valid dict: {result}")
172-
print_test_result(f"Test execute with defaults\nRESULT_COUNT: {len(result)}", is_valid_dict)
172+
print_test_result(f"Test execute with defaults\nRESULT: {result}", is_valid_dict)
173173

174174
@pystackql_test_setup(output='pandas')
175175
def test_12_execute_with_pandas_output(self):
176-
result = self.stackql.execute(google_query)
176+
result = self.stackql.execute(aws_query)
177177
is_valid_dataframe = isinstance(result, pd.DataFrame)
178178
self.assertTrue(is_valid_dataframe, f"Result is not a valid DataFrame: {result}")
179-
print_test_result(f"Test execute with pandas output\nRESULT_COUNT: {len(result)}", is_valid_dataframe)
179+
# Check datatypes of the columns
180+
expected_dtypes = {
181+
'instance_state': 'object', # This should be 'object' for older Pandas versions
182+
'num_instances': 'int64'
183+
}
184+
for col, expected_dtype in expected_dtypes.items():
185+
actual_dtype = result[col].dtype
186+
self.assertEqual(actual_dtype, expected_dtype, f"Column '{col}' has dtype '{actual_dtype}' but expected '{expected_dtype}'")
187+
print_test_result(f"Test execute with pandas output\nRESULT COUNT: {len(result)}", is_valid_dataframe)
180188

181189
@pystackql_test_setup(output='csv')
182190
def test_13_execute_with_csv_output(self):
183-
result = self.stackql.execute(google_query)
191+
result = self.stackql.execute(aws_query)
184192
is_valid_csv = isinstance(result, str) and result.count("\n") >= 1 and result.count(",") >= 1
185193
self.assertTrue(is_valid_csv, f"Result is not a valid CSV: {result}")
186194
print_test_result(f"Test execute with csv output\nRESULT_COUNT: {len(result.splitlines())}", is_valid_csv)
@@ -241,9 +249,18 @@ def test_21_execute_server_mode_default_output(self):
241249

242250
@pystackql_test_setup(server_mode=True, output='pandas')
243251
def test_22_execute_server_mode_pandas_output(self):
244-
result = self.stackql.execute(google_query)
245-
is_valid_pandas_output = isinstance(result, pd.DataFrame)
246-
print_test_result(f"""Test execute in server_mode with pandas output\nRESULT_COUNT: {len(result)}""", is_valid_pandas_output, True)
252+
result = self.stackql.execute(aws_query)
253+
is_valid_dataframe = isinstance(result, pd.DataFrame)
254+
self.assertTrue(is_valid_dataframe, f"Result is not a valid DataFrame: {result}")
255+
# Check datatypes of the columns
256+
expected_dtypes = {
257+
'instance_state': 'object', # This should be 'object' for older Pandas versions
258+
'num_instances': 'int64'
259+
}
260+
for col, expected_dtype in expected_dtypes.items():
261+
actual_dtype = result[col].dtype
262+
self.assertEqual(actual_dtype, expected_dtype, f"Column '{col}' has dtype '{actual_dtype}' but expected '{expected_dtype}'")
263+
print_test_result(f"Test execute in server_mode with pandas output\nRESULT COUNT: {len(result)}", is_valid_dataframe)
247264

248265
class MockInteractiveShell:
249266
"""A mock class for IPython's InteractiveShell."""

tests/test_params.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,15 @@ def registry_pull_resp_pattern(provider):
4141
GROUP BY status
4242
"""
4343

44+
aws_query = f"""
45+
SELECT
46+
split_part(instanceState, '\n', 3) as instance_state,
47+
count(*) as num_instances
48+
FROM aws.ec2.instances
49+
WHERE region = '{os.environ['AWS_REGION']}'
50+
GROUP BY instance_state
51+
"""
52+
4453
regions = os.environ.get('AWS_REGIONS').split(',')
4554

4655
async_queries = [

0 commit comments

Comments
 (0)