qutePandas 1.1.0__py3-none-any.whl → 1.1.2__py3-none-any.whl

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.
qutePandas/__init__.py CHANGED
@@ -1,11 +1,11 @@
1
- """
2
- qutePandas - A pandas-like library for q/kdb+
3
- """
4
-
5
1
  import os
2
+ import sys
6
3
 
7
- def _setup_environment():
8
- """Validates and sets up the environment for PyKX."""
4
+ def _setup_pykx_environment():
5
+ """
6
+ Sets up the environment for PyKX BEFORE any PyKX imports.
7
+ This must run before importing any module that uses PyKX.
8
+ """
9
9
  root = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
10
10
  env_path = os.path.join(root, ".env")
11
11
 
@@ -20,17 +20,47 @@ def _setup_environment():
20
20
  if len(parts) == 2:
21
21
  key, value = parts
22
22
  value = value.strip().strip('"').strip("'")
23
+ # Only set if not already in environment
23
24
  if key.strip() and key.strip() not in os.environ:
24
25
  os.environ[key.strip()] = value
25
-
26
+
27
+ # Check for valid license files in priority order
26
28
  qutepandas_home = os.path.expanduser("~/.qutepandas")
27
29
  local_kdb = os.path.join(root, "kdb_lic")
30
+
31
+ license_found = False
32
+ valid_license_path = None
33
+
28
34
  if os.path.exists(os.path.join(local_kdb, "kc.lic")):
29
- os.environ['QLIC'] = local_kdb
35
+ valid_license_path = local_kdb
36
+ license_found = True
30
37
  elif os.path.exists(os.path.join(qutepandas_home, "kc.lic")):
31
- os.environ['QLIC'] = qutepandas_home
38
+ valid_license_path = qutepandas_home
39
+ license_found = True
40
+
41
+ if license_found and valid_license_path:
42
+ os.environ['QLIC'] = valid_license_path
43
+ os.environ.pop('PYKX_UNLICENSED', None)
44
+ elif 'QLIC' in os.environ:
45
+ qlic_path = os.environ['QLIC']
46
+ if not (os.path.exists(os.path.join(qlic_path, "kc.lic")) or
47
+ os.path.exists(os.path.join(qlic_path, "k4.lic"))):
48
+ del os.environ['QLIC']
49
+ if 'QHOME' in os.environ:
50
+ del os.environ['QHOME']
51
+ license_found = False
52
+
53
+ if not license_found and 'PYKX_UNLICENSED' not in os.environ:
54
+ os.environ['PYKX_UNLICENSED'] = 'true'
55
+
56
+ if 'PYKX_RELEASE_GIL' not in os.environ:
57
+ os.environ['PYKX_RELEASE_GIL'] = 'true'
58
+
59
+ if 'PYKX_ENFORCE_EMBEDDED_IMPORT' not in os.environ:
60
+ os.environ['PYKX_ENFORCE_EMBEDDED_IMPORT'] = '0'
61
+
62
+ _setup_pykx_environment()
32
63
 
33
- _setup_environment()
34
64
  from .core.dataframe import DataFrame
35
65
  from .core.connection import connect, get_license_info, install_license
36
66
  from .core.display import py, np, pd, pa, pt, print
@@ -59,4 +89,4 @@ from .introspection.dtypes import dtypes
59
89
 
60
90
  from .indexing import loc, iloc
61
91
 
62
- __version__ = "1.0.0"
92
+ __version__ = "1.1.2"
qutePandas/apply/apply.py CHANGED
@@ -2,6 +2,10 @@ import pykx as kx
2
2
  import pandas as pd
3
3
  from ..utils import _ensure_q_table, _handle_return
4
4
 
5
+ _VECTORIZED_AXIS1 = {
6
+ 'sum': '{sum (0^) each value flip x}',
7
+ }
8
+
5
9
 
6
10
  def apply(df, func, axis=0, return_type='q'):
7
11
  """
@@ -39,7 +43,9 @@ def apply(df, func, axis=0, return_type='q'):
39
43
  return pd.Series(ret) if return_type == 'p' else ret
40
44
 
41
45
  if isinstance(func, str):
42
- if axis == 1:
46
+ if axis == 1 and func in _VECTORIZED_AXIS1:
47
+ result = kx.q(_VECTORIZED_AXIS1[func], q_table)
48
+ elif axis == 1:
43
49
  result = kx.q(f"{{({func}) each x}}", q_table)
44
50
  else:
45
51
  result = kx.q(f"{{({func}) each flip x}}", q_table)
@@ -2,16 +2,23 @@ import pykx as kx
2
2
  import pandas as pd
3
3
  from ..utils import _ensure_q_table, _handle_return
4
4
 
5
- def fillna(df, values, return_type='q'):
5
+ def fillna(df, col_or_values, fill_value=None, return_type='q'):
6
6
  """
7
- Fills null values using a dictionary mapping of columns to fill values.
7
+ Fills null values in specified columns.
8
+
9
+ Can be called in two ways:
10
+ fillna(df, values_dict, return_type='q')
11
+ fillna(df, col_name, fill_value, return_type='q')
8
12
 
9
13
  Parameters
10
14
  ----------
11
15
  df : pandas.DataFrame or pykx.Table
12
16
  Input DataFrame.
13
- values : dict
14
- Mapping of column names to fill values.
17
+ col_or_values : str or dict
18
+ If str, the column name to fill (requires fill_value).
19
+ If dict, a mapping of column names to fill values.
20
+ fill_value : scalar, optional
21
+ The value to fill nulls with when col_or_values is a column name.
15
22
  return_type : str, default 'q'
16
23
  Desired return type ('p' or 'q').
17
24
 
@@ -21,8 +28,14 @@ def fillna(df, values, return_type='q'):
21
28
  DataFrame with nulls filled.
22
29
  """
23
30
  try:
24
- if not isinstance(values, dict):
25
- raise ValueError("values must be a dictionary")
31
+ if isinstance(col_or_values, str):
32
+ if fill_value is None:
33
+ raise ValueError("fill_value is required when col_or_values is a column name")
34
+ values = {col_or_values: fill_value}
35
+ elif isinstance(col_or_values, dict):
36
+ values = col_or_values
37
+ else:
38
+ raise ValueError("col_or_values must be a column name (str) or a dictionary")
26
39
 
27
40
  q_table = _ensure_q_table(df)
28
41
  result = q_table
@@ -33,4 +46,4 @@ def fillna(df, values, return_type='q'):
33
46
 
34
47
  return _handle_return(result, return_type)
35
48
  except Exception as e:
36
- raise RuntimeError(f"Failed to fillna: {e}")
49
+ raise RuntimeError(f"Failed to fillna: {e}")
@@ -1,11 +1,8 @@
1
1
  import pykx as kx
2
2
  import pandas as pd
3
- import os
4
3
  import atexit
5
4
  from ..utils import _handle_return
6
5
 
7
- os.environ['PYKX_ENFORCE_EMBEDDED_IMPORT'] = '0'
8
-
9
6
  def DataFrame(data, columns=None):
10
7
  """
11
8
  Creates a qutePandas DataFrame (internal pykx Table).
@@ -22,10 +22,15 @@ def iloc(df, rows=None, cols=None, return_type='q'):
22
22
  Subset of the inputs.
23
23
  """
24
24
  table = _ensure_q_table(df)
25
-
25
+
26
26
  count = kx.q("count", table).py()
27
27
  all_cols = kx.q("cols", table).py()
28
-
28
+
29
+ # Track whether we can use the fast sublist path for contiguous row slices
30
+ _use_sublist = False
31
+ _slice_start = 0
32
+ _slice_count = 0
33
+
29
34
  if rows is None:
30
35
  row_indices = None
31
36
  elif isinstance(rows, int):
@@ -33,7 +38,14 @@ def iloc(df, rows=None, cols=None, return_type='q'):
33
38
  if q_rows < 0: q_rows += count
34
39
  row_indices = [q_rows]
35
40
  elif isinstance(rows, slice):
36
- row_indices = list(range(*rows.indices(count)))
41
+ start, stop, step = rows.indices(count)
42
+ if step == 1:
43
+ _use_sublist = True
44
+ _slice_start = start
45
+ _slice_count = stop - start
46
+ row_indices = None # Not needed — sublist handles it
47
+ else:
48
+ row_indices = list(range(start, stop, step))
37
49
  else:
38
50
  row_indices = list(rows)
39
51
  row_indices = [r + count if r < 0 else r for r in row_indices]
@@ -47,27 +59,36 @@ def iloc(df, rows=None, cols=None, return_type='q'):
47
59
  target_cols = [all_cols[i] for i in range(*cols.indices(len(all_cols)))]
48
60
  else:
49
61
  target_cols = [all_cols[i] for i in cols]
50
-
51
- if row_indices is None and target_cols is None:
62
+
63
+ if not _use_sublist and row_indices is None and target_cols is None:
52
64
  return _handle_return(table, return_type)
53
65
 
54
- if row_indices is not None and target_cols is not None:
66
+ # Fast path: contiguous row slice via q's sublist (no Python list overhead)
67
+ if _use_sublist:
68
+ sublist_args = kx.LongVector([_slice_start, _slice_count])
69
+ if target_cols is not None:
70
+ syms = kx.SymbolVector(target_cols)
71
+ cols_dict = kx.q('!', syms, syms)
72
+ q_res = kx.q('{?[sublist[y;x];();0b;z]}', table, sublist_args, cols_dict)
73
+ else:
74
+ q_res = kx.q('{sublist[y;x]}', table, sublist_args)
75
+ elif row_indices is not None and target_cols is not None:
55
76
  q_query = '{?[x y;();0b;z]}'
56
77
  syms = kx.SymbolVector(target_cols)
57
78
  cols_dict = kx.q('!', syms, syms)
58
79
  q_res = kx.q(q_query, table, kx.LongVector(row_indices), cols_dict)
59
-
80
+
60
81
  elif row_indices is not None:
61
82
  q_query = '{x y}'
62
83
  q_res = kx.q(q_query, table, kx.LongVector(row_indices))
63
-
84
+
64
85
  elif target_cols is not None:
65
86
  q_query = '{?[x;();0b;y]}'
66
87
  syms = kx.SymbolVector(target_cols)
67
88
  cols_dict = kx.q('!', syms, syms)
68
89
  q_res = kx.q(q_query, table, cols_dict)
69
-
90
+
70
91
  else:
71
92
  q_res = table
72
93
 
73
- return _handle_return(q_res, return_type)
94
+ return _handle_return(q_res, return_type)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: qutePandas
3
- Version: 1.1.0
3
+ Version: 1.1.2
4
4
  Summary: A pandas-like library for kdb+/q using pykx
5
5
  Home-page: https://ishapatro.github.io/qutePandas/
6
6
  Author: Isha Patro
@@ -1,22 +1,22 @@
1
- qutePandas/__init__.py,sha256=BO7UwZvxdpkHzCeXWasLf6mSVx-wOpaBNyXCDlEb_80,2012
1
+ qutePandas/__init__.py,sha256=USg_a44fbQDKf5Ads1vgqyHNqU6AKrVM5eFfEJhLXrc,3143
2
2
  qutePandas/utils.py,sha256=X0GODOBxuAFOtjjFb6IGlzjDhhrkwH_6ErIMypiFhUM,1026
3
3
  qutePandas/apply/__init__.py,sha256=tdjeqTQI6jH530lTmpd9dkUPese6B22uI2P4ATKoGzc,92
4
- qutePandas/apply/apply.py,sha256=OqeNwgoD1G5Y6PK7G_2CX7fswq4_Fl0YDDaqWI7O-a4,2275
4
+ qutePandas/apply/apply.py,sha256=5Fa4I7_zkILk0TMJioWoAFh9kgrb-jVI4PMBcjIkWmQ,2465
5
5
  qutePandas/apply/apply_col.py,sha256=h6nAsAXLIC4WcMD-amW3bXkaNEe30SgKEBfUr3eKTng,1597
6
6
  qutePandas/cleaning/__init__.py,sha256=6tRzTPgCEumZ7c_TvsMit3pRxZhdzf1Pd4y23ozv_2k,204
7
7
  qutePandas/cleaning/dropna.py,sha256=SGIPg8vk4PB1jtnH8hDComuMz8omdraJhOPzKTRiUgI,739
8
8
  qutePandas/cleaning/dropna_col.py,sha256=hpR4BN-ZuYdz222aUlYKyrEA7QmYomAMqTK6ebVB0ro,831
9
- qutePandas/cleaning/fillna.py,sha256=NhYlNpHIlFMMd9ws0dKvw1njxUOmuf6VHLo8oQSUpEA,1057
9
+ qutePandas/cleaning/fillna.py,sha256=9PDZCM1hyLtxFkVfQz7NJu1xrjDSW-nPQU47hysfDTI,1689
10
10
  qutePandas/cleaning/remove_duplicates.py,sha256=zf6TTbkuSh5S4ZCmgznPLl-erw-umVP7K0EqOyv9wUM,757
11
11
  qutePandas/core/__init__.py,sha256=o8WuiBhI5jBqKXTL80kBTNcxZo1aO45dQx2Z6UwWg50,311
12
12
  qutePandas/core/connection.py,sha256=CsBWI2jwIO1kNicA42AefmlRgVx5WqayCJPhHzJHhFc,4275
13
- qutePandas/core/dataframe.py,sha256=bwdm-MVIpoXRo0RblJ_crZVCJlUZgQLN4PmcYu6mdzk,3269
13
+ qutePandas/core/dataframe.py,sha256=ehfz8lMIV_Yj1f9bMpY25TH3EMbR02Dvji9lhGg395E,3209
14
14
  qutePandas/core/display.py,sha256=ubSZM8yf0kARuiSXpUHJ0WmIt4syjkp-VuV2NAXbiGc,5058
15
15
  qutePandas/grouping/__init__.py,sha256=GOBRAWDuh3PnKHEVDzmEqoG_GIfU4G6Gtk0aeSG92lE,116
16
16
  qutePandas/grouping/groupby_avg.py,sha256=F8Gc6XdOKiWyNKOoDURgYeeIxIduzbds2mHCfxEtvw4,1129
17
17
  qutePandas/grouping/groupby_sum.py,sha256=9XZ2tITeCMRtdnpwH2CpoQh3Y3NDC-ufwiDg6EQUJOA,1128
18
18
  qutePandas/indexing/__init__.py,sha256=2MmNlO54FOdIaaPSzegum3QmeO-Ts8ya3xSCodQjTIo,45
19
- qutePandas/indexing/iloc.py,sha256=g-fG0pxYHn7_qrBwDQ3MRsTi-U_VEtrN4_z5kDNmZaM,2272
19
+ qutePandas/indexing/iloc.py,sha256=g0LYKZAqdVk6Xz--RUdb-VtECnzFRET28qh6KL5SRgE,3117
20
20
  qutePandas/indexing/loc.py,sha256=Xn_043CrKyJBTXhRUYWtU0ZF1yikIGxTI0gTJAYIEfA,1511
21
21
  qutePandas/introspection/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
22
  qutePandas/introspection/dtypes.py,sha256=h3qImsu3JBuELp2zeIfwyOlFTsC513U_qSRNuYzeXWw,705
@@ -29,7 +29,7 @@ qutePandas/transformation/__init__.py,sha256=ECPmFXZq-uh5ajkgAVQbdc8flVzrcwkhEqw
29
29
  qutePandas/transformation/cast.py,sha256=VD8D0gPs9GJX52bqu_LKt7BHU69Iv-scOq-E2Q_MGQU,2226
30
30
  qutePandas/transformation/drop_col.py,sha256=4hdGjitDbYSfxj-4jo73NmTa2qKed-NjGj0jGBfiANY,1509
31
31
  qutePandas/transformation/rename.py,sha256=MwWjbhaZCUdQgkObaMPIB8fUY240x_EdD41cwszCa4o,948
32
- qutepandas-1.1.0.dist-info/METADATA,sha256=-8cJlJSnucXHNZMShlp5osW2NzdJvg2jcntF-qVsbXE,2540
33
- qutepandas-1.1.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
34
- qutepandas-1.1.0.dist-info/top_level.txt,sha256=O_6KkoxW8KjgZX5o7sYwYVb8XPtNBA7PRSTE08qda1k,11
35
- qutepandas-1.1.0.dist-info/RECORD,,
32
+ qutepandas-1.1.2.dist-info/METADATA,sha256=C49oFk4j_KXUAABQfcYnZeSJaxmBKhly2t_Cv_aaF_Y,2540
33
+ qutepandas-1.1.2.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
34
+ qutepandas-1.1.2.dist-info/top_level.txt,sha256=O_6KkoxW8KjgZX5o7sYwYVb8XPtNBA7PRSTE08qda1k,11
35
+ qutepandas-1.1.2.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.9.0)
2
+ Generator: setuptools (80.10.2)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5