PyKX Changelog
Note
The changelog presented here outlines changes to PyKX when operating within a Python environment specifically, if you require changelogs associated with PyKX operating under a q environment see here.
Warning
Currently PyKX is not compatible with Pandas 2.2.0 or above as it introduced breaking changes which cause data to be cast to the incorrect type.
PyKX 2.4.2
Release Date
2024-04-03
Fixes and Improvements
- Updated
libqto 2024.03.28 for all supported OS's.
PyKX 2.4.1
Release Date
2024-03-27
Fixes and Improvements
- Previously calls to
qsql.select,qsql.exec,qsql.updateandqsql.deletewould require multiple calls to parse the content ofwhere,columsandbyclauses. These have now been removed with all parsing now completed within the functional query when called via IPC or local to the Python process. -
Linux x86 and Mac x86/ARM unlicensed mode
e.olibrary updated to 2023.11.22. Fixes subnormals issue:>>> import os >>> os.environ['PYKX_UNLICENSED']='true' >>> import pykx as kx >>> import numpy as np >>> np.finfo(np.float64).smallest_subnormal + 0. /usr/local/anaconda3/lib/python3.8/site-packages/numpy/core/getlimits.py:518: UserWarning: The value of the smallest subnormal for <class 'numpy.float64'> type is zero. setattr(self, word, getattr(machar, word).flat[0]) /usr/local/anaconda3/lib/python3.8/site-packages/numpy/core/getlimits.py:89: UserWarning: The value of the smallest subnormal for <class 'numpy.float64'> type is zero. return self._float_to_str(self.smallest_subnormal) 0.0>>> import os >>> os.environ['PYKX_UNLICENSED']='true' >>> import pykx as kx >>> import numpy as np >>> np.finfo(np.float64).smallest_subnormal + 0. 5e-324
PyKX 2.4.0
Release Date
2024-03-20
Additions
-
Support for q/kdb+
4.1documentation here added as an opt-in capability, this functionality is enabled through settingPYKX_4_1_ENABLEDenvironment variable.>>> import os >>> os.environ['PYKX_4_1_ENABLED'] = 'True' >>> import pykx as kx >>> kx.q.z.K pykx.FloatAtom(pykx.q('4.1')) -
Added support for Python
3.12.- Support for PyArrow in this python version is currently in Beta.
- Added conversion of NumPy arrays of type
datetime64[s],datetime64[ms],datetime64[us]tokx.TimestampVector - Added Table.sort_values(), Table.nsmallest() and Table.nlargest() to the Pandas like API for sorting tables.
Table.rename()now supports non-numerical index columns and improved the quality of errors thrown.-
Added the
reconnection_attemptskey word argument toSyncQConnection,SecureQConnection, andAsyncQConnectionIPC classes. This argument allows IPC connection to be automatically re-established when it is lost and a server has reinitialized.>>> import pykx as kx >>> conn = kx.SyncQConnection(port = 5050, reconnection_attempts=4) >>> conn('1+1') # Following this call the server on port 5050 was closed for 2 seconds pykx.LongVector(pykx.q('2')) >>> conn('1+2') WARNING: Connection lost attempting to reconnect. Failed to reconnect, trying again in 0.5 seconds. Failed to reconnect, trying again in 1.0 seconds. Connection successfully reestablished. pykx.LongAtom(pykx.q('3')) -
Added
--reconnection_attemptsoption to Jupyter%%qmagic making use of the above IPC logic changes. -
Addition of environment variable/configuration value
PYKX_QDEBUGwhich allows debugging backtrace to be displayed for all calls into q instead of requiring a user to specify debugging is enabled per-call. This additionally works for remote IPC calls and utilisation of Jupyter magic commands.>>> import pykx as kx >>> kx.q('{x+1}', 'e') Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/local/anaconda3/lib/python3.8/site-packages/pykx/embedded_q.py", line 230, in __call__ return factory(result, False) File "pykx/_wrappers.pyx", line 493, in pykx._wrappers._factory File "pykx/_wrappers.pyx", line 486, in pykx._wrappers.factory pykx.exceptions.QError: type >>> kx.q('{x+1}', 'e', debug=True) backtrace: [2] {x+1} ^ [1] (.Q.trp) [0] {[pykxquery] .Q.trp[value; pykxquery; {if[y~();:(::)];2@"backtrace: ^ ",.Q.sbt y;'x}]} Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/local/anaconda3/lib/python3.8/site-packages/pykx/embedded_q.py", line 230, in __call__ return factory(result, False) File "pykx/_wrappers.pyx", line 493, in pykx._wrappers._factory File "pykx/_wrappers.pyx", line 486, in pykx._wrappers.factory pykx.exceptions.QError: type>>> import os >>> os.environ['PYKX_QDEBUG'] = 'True' >>> import pykx as kx >>> kx.q('{x+1}', 'e') backtrace: [2] {x+1} ^ [1] (.Q.trp) [0] {[pykxquery] .Q.trp[value; pykxquery; {if[y~();:(::)];2@"backtrace: ^ ",.Q.sbt y;'x}]} Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/local/anaconda3/lib/python3.8/site-packages/pykx/embedded_q.py", line 230, in __call__ return factory(result, False) File "pykx/_wrappers.pyx", line 493, in pykx._wrappers._factory File "pykx/_wrappers.pyx", line 486, in pykx._wrappers.factory pykx.exceptions.QError: type
Fixes and Improvements
- Added instructions for script to install Windows dependencies.
-
Resolved segfaults on Windows when PyKX calls Python functions under q.
>>> import pykx as kx >>> kx.q('{[f;x] f x}', sum, kx.q('4 4#til 16')) Sorry, this application or an associated library has encountered a fatal error and will exit. If known, please email the steps to reproduce this error to tech@kx.com with a copy of the kdb+ startup banner and the info printed below. Thank you. Fault address 0000000066110980>>> import pykx as kx >>> kx.q('{[f;x] f x}', sum, kx.q('4 4#til 16')) pykx.LongVector(pykx.q('24 28 32 36')) -
Updated kdb Insights Core libraries to 4.0.8, see here for more information.
- Updated
libq4.0 version to 2024.03.04 for all supported OS's. -
Fix issue where use of valid C backed q
codeAPIs could result in segmentation faults when called.>>> import pykx as kx >>> isf = kx.q('.pykx.util.isf') >>> isf pykx.Foreign(pykx.q('code')) >>> isf(True) Sorry, this application or an associated library has encountered a fatal error and will exit. If known, please email the steps to reproduce this error to tech@kx.com with a copy of the kdb+ startup banner and the info printed below. Thank you. SIGSEGV: Fault address 0x85>>> import pykx as kx >>> isf = kx.q('.pykx.util.isf') >>> isf pykx.Foreign(pykx.q('code')) >>> isf(True) pykx.BooleanAtom(pykx.q('0b')) -
Fixed error since 2.2.1 in unlicensed mode when converting
TimestampVectorcontaining nulls to Python.>>> conn('enlist 0Np').py() Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/home/rocuinneagain/.local/lib/python3.10/site-packages/pykx/wrappers.py", line 2443, in py converted_vector[i]=q('0Np') File "/home/rocuinneagain/.local/lib/python3.10/site-packages/pykx/embedded_q.py", line 216, in __call__ raise LicenseException("run q code via 'pykx.q'") pykx.exceptions.LicenseException: A valid q license must be in a known location (e.g. `$QLIC`) to run q code via 'pykx.q'.>>> conn('enlist 0Np').py() [pykx.TimestampAtom(pykx.q('0Np'))] -
Each call to the PyKX query API interned 3 new unique symbols. This has now been removed.
-
When using
pykx.schema.builderusers could not make use ofpykx.*Vectorobjects for defining column types. This could result in confusion due to support for these types in other areas of the library (type casting etc).>>> pykx.schema.builder({'x': pykx.LongVector, 'x1': pykx.LongAtom}) Exception: Error: <class 'KeyError'> raised for column x error>>> pykx.schema.builder({'x': pykx.LongVector, 'x1': pykx.LongAtom}) pykx.Table(pykx.q(' x x1 ---- ')) -
Application of
astypeconversions could error if attempting to convert the column of a dataset to it's current type, this could be raised if usingastypeexplicitly or when used internal to PyKX such as when defining the expected type when reading a CSV file. -
PyKX database table listing now uses
kx.q.Q.ptinstead ofkx.q.tables()when presenting the available tables to a users, this more accurately reflects the tables that can be interacted with by a users within the process.>>> tab = kx.Table(data = {'sym': ['a', 'b', 'c'], 'num': [1, 2, 3]}) >>> tab.astype({'sym': kx.SymbolAtom}) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/local/anaconda3/lib/python3.8/site-packages/pykx/embedded_q.py", line 229, in __call__ return factory(result, False) File "pykx/_wrappers.pyx", line 493, in pykx._wrappers._factory File "pykx/_wrappers.pyx", line 486, in pykx._wrappers.factory pykx.exceptions.QError: typepykx.Table(pykx.q(' sym num ------- a 1 b 2 c 3 ')) -
Fix to ensure that if set
PYKX_Q_LIB_LOCATIONis used as the value forQHOMEwhen initializing PyKX. This ensures all symlinking happens in the expected location and that\lloading of files behaves correctly. - Renamed
labelsparameter inTable.rename()tomapperto match Pandas. Added deprecation warning tolabels. -
Fixed bug where keys were being enlisted when
Table.rename()called.>>> tab = kx.KeyedTable(data=kx.q('([] Policy: 1 2 3)')) >>> tab.rename(index={0:'a'}) idx Policy -------------- ,`a 1 ,1 2 ,2 3>>> tab = kx.KeyedTable(data=kx.q('([] Policy: 1 2 3)')) >>> tab.rename(index={0:'a'}) idx Policy -------------- `a 1 1 2 2 3 -
Deprecation of
typecolumn indtypesoutput as it is a reserved keyword. Use newdatatypescolumn instead. -
Query API
mergemethod no longer attempts to automatically key/unkey input tables whenq_join=True. Users must pass correctly formed inputs.>>> import pykx as kx >>> tab1 = kx.Table(data={'k': ['foo', 'bar', 'baz', 'foo'], 'v': [1, 2, 3, 5]}) >>> tab2 = kx.Table(data={'k': ['foo', 'bar', 'baz', 'foo'], 'v': [5, 6, 7, 8]}) >>> tab1_keyed = tab1.set_index('k') >>> tab1.merge(tab2, how='left', q_join=True)>>> tab1.merge(tab2_keyed, how='left', q_join=True)
Beta Features
-
Addition of
CompressandEncryptclasses to allow users to set global configuration and for usage within Database partition persistence.>>> import pykx as kx >>> compress = kx.Compress(algo=kx.CompressionAlgorithm.gzip, level=8) >>> kx.q.z.zd pykx.Identity(pykx.q('::')) >>> compress.global_init() pykx.LongVector(pykx.q('17 2 8')) >>> encrypt = kx.Encrypt(path='/path/to/the.key', password='PassWord') >>> encrypt.load_key()>>> import pykx as kx >>> compress = kx.Compress(algo=kx.CompressionAlgorithm.lz4hc, level=10) >>> db = kx.DB(path='/tmp/db') >>> db.create(kx.q('([]10?1f;10?1f)', 'tab', kx.q('2020.03m'), compress=compress) >>> kx.q('-21!`:/tmp/db/2020.03/tab/x') pykx.Dictionary(pykx.q(' compressedLength | 140 uncompressedLength| 96 algorithm | 4i logicalBlockSize | 17i zipLevel | 10i ')) -
On Windows from version 2.3.0 PyKX would raise the following warning message at startup about incompatibility between Threading feature and Windows, this now is only raised when
PYKX_THREADINGis set.C:\Users\username\AppData\Roaming\Python\Python311\site-packages\pykx\config.py:220: UserWarning: PYKX_THREADING is only supported on Linux / MacOS, it has been disabled. warn('PYKX_THREADING is only supported on Linux / MacOS, it has been disabled.')
PyKX 2.3.2
Release Date
2024-02-12
Fixes and Improvements
- Update of PyKX 4.0 linux shared object to version 2024.02.09, this update is to facilitate deployments on more secure linux/linux-arm environments.
- Update
Table.rename()to skip over columns not in table instead of throwing error to matchpandas.
PyKX 2.3.1
Release Date
2024-02-07
Fixes and Improvements
-
Python functions saved to q would error if passed
''or'.'. These now pass without issue.>>> def func(n=2): ... return n ... >>> kx.q['func']= func >>> kx.q('func', '') Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/home/rocuinneagain/.local/lib/python3.10/site-packages/pykx/embedded_q.py", line 227, in __call__ return factory(result, False) File "pykx/_wrappers.pyx", line 493, in pykx._wrappers._factory File "pykx/_wrappers.pyx", line 486, in pykx._wrappers.factory pykx.exceptions.QError: Provided foreign object is not a Python object >>> kx.q('func', '.') Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/home/rocuinneagain/.local/lib/python3.10/site-packages/pykx/embedded_q.py", line 227, in __call__ return factory(result, False) File "pykx/_wrappers.pyx", line 493, in pykx._wrappers._factory File "pykx/_wrappers.pyx", line 486, in pykx._wrappers.factory pykx.exceptions.QError: rank>>> def func(n=2): ... return n ... >>> kx.q['func']= func >>> kx.q('func', '') pykx.SymbolAtom(pykx.q('`')) >>> kx.q('func', '.') pykx.SymbolAtom(pykx.q('`.')) -
Changed
Table.rename()to ignore anycolumnsvalues that are of the wrong type instead of throwing an unhelpful error.>>> key_tab.rename({0:'PolicyID'}, axis = 1) ValueError('nyi')>>> key_tab.rename({0:'PolicyID'}, axis = 1) pykx.KeyedTable(pykx.q(' idx| x y ---| --- 0 | 0 3 1 | 1 2 2 | 2 1 ')) -
Improved upon the quality of
Table.rename()error messages and documentation on the function. - PyKX would error with
_get_config_value() missing 1 required positional argument: 'default'on import if a license was not found since 2.3.0. Now correctly opens the license walkthrough. -
Pandas 2.2.0 introduced breaking changes which effect PyKX. PyKX dependencies have been updated to
pandas>=1.2, < 2.2.0until these are resolved. Data casting behavior leads to an unexpected datatype being returned:>>> pd.Series([1, pd.NA, 3], dtype=pd.Int64Dtype()).to_numpy() array([1, <NA>, 3], dtype=object) >>> kx.K(pd.Series([1, pd.NA, 3], dtype=pd.Int64Dtype())) pykx.LongVector(pykx.q('1 0N 3'))>>> pd.Series([1, pd.NA, 3], dtype=pd.Int64Dtype()).to_numpy() array([ 1., nan, 3.]) >>> kx.K(pd.Series([1, pd.NA, 3], dtype=pd.Int64Dtype())) pykx.FloatVector(pykx.q('1 -9.223372e+18 3')) -
df.select_dtypes()updated to now acceptkx.*Atomvalues forinclude/excludeparams. Use ofkx.CharVectorwill return error. - To align with other areas of PyKX the
upsertandinsertmethods for PyKX tables and keyed tables now support the keyword argumentinplace, this change will deprecate usage ofreplace_selfwith the next major release of PyKX.
Beta Features
-
Addition of the concept of
Remote Functionexecution to PyKX, this allows users, from a Python session to define Python functions which will be executed on a remote q/kdb+ server running PyKX under q. The intention with this feature is to allow onboarding of Python first operations within existing or q/kdb+ first infrastructures>>> from pykx.remote import function, session >>> remote_session = session() >>> remote_session.create('localhost', 5050) >>> @function(remote_session) ... def func(x): ... return x+1 >>> func(2) # Functionality run on q server pykx.LongAtom(pykx.q('3')) >>> remote_session.clear()
PyKX 2.3.0
Release Date
2024-01-22
Additions
- PyKX now supports the use of
KDB_LICENSE_B64orKDB_K4LICENSE_B64configuration values/environment variables to define the content of akc.licork4.liclicense respectively if no license is found on initial usage of PyKX. -
Shortcut provided for access to current date, time and timestamp information using
'today'and'now'.>>> kx.DateAtom('today') pykx.DateAtom(pykx.q('2024.01.05')) >>> kx.TimeAtom('now') pykx.TimeAtom(pykx.q('16:15:32.724')) >>> kx.TimestampAtom('now') pykx.TimestampAtom(pykx.q('2024.01.05T16:15:42.926631000')) -
Addition of support for
inplaceupdates of PyKX tables modified using qsql select/update/delete operations on in-memory data. Application ofinplacemodifications is not supported for direct application on Partitioned/Splayed tables.>>> N = 1000 >>> qtab = kx.Table(data={'x': kx.random.random(N, 1.0, seed=10)}) >>> qtab pykx.Table(pykx.q(' x ----------- 0.0891041 0.8345194 0.3621949 0.999934 0.3837986 .. ')) >>> kx.q.qsql.select(qtab, where = ['x>0.5'], inplace=True) pykx.Table(pykx.q(' x ----------- 0.8345194 0.999934 0.8619188 0.7517286 0.6348263 .. ')) >>> qtab pykx.Table(pykx.q(' x ----------- 0.8345194 0.999934 0.8619188 0.7517286 0.6348263 .. ')) -
Addition of
reset_index,add_suffix,add_prefix,count,skewandstdfunctionality to Pandas Like API- See here for details of supported keyword arguments, limitations and examples.
%%qJupyter Notebook magic adds--debugoption which prints the q backtrace if the cell execution fails.- Release 2.3.0 adds to PyKX the concept of Beta features, these features are available to users through setting the configuration/environment variable
PYKX_BETA_FEATURES. For more information on Beta features see further documentation here
Fixes and Improvements
%%qJupyter Notebook magic now returns all outputs up to and including an error when thrown. Previously only the error was returned.-
%%qJupyter Notebook magic ignores accidental whitespace in execution options. Below example no longer fails withReceived unknown argumenterror:%%q --port 5000 -
In cases where PyKX IPC sockets read data from unexpected publishers it could raise an
IndexError. PyKX will now provide a more verbose error indicating that an unexpected message has been received, the bytes processed and requests a reproducible example to be provided if possible. -
Update to table column retrieval logic to error when a user attempts to access a non-existent column with a queried table.
>>> tab = kx.Table(data = {'a': [1, 2, 3]}) >>> tab['c'] pykx.LongVector(pykx.q('`long$()'))>>> tab = kx.Table(data = {'a': [1, 2, 3]}) >>> tab['c'] .. QError: Attempted to retrieve inaccessible column: c -
Improved error message for conversion failures.
- Fixes an issue where a user would receive a length error when attempting to apply
min,max,prodandsumfunctions onpykx.KeyedTableobjects.
Beta Features
-
Database Management functionality has been added for the creation, loading and maintenance of PyKX Partitioned Databases. A full worked example of this functionality can be found here along with full API documentation which includes examples of each function here. The API includes but is not limited to the following:
- Database table creation and renaming.
- Enumeration of in-memory tables against on-disk sym file.
- Column listing, addition, reordering, renaming copying, function application and deletion on-disk.
- Attribute setting and removal.
- Addition of missing tables from partitions within a database.
- Database table creation and renaming.
-
Added
PYKX_THREADINGenvironment variable that allows multithreaded programs to modify state when calling into python on secondary threads. Note: This behaviour is only supported on Linux / MacOS.Note
When using
PYKX_THREADINGyou must ensure you callkx.shutdown_thread()at the end of the script to ensure the background thread is properly closed.
PyKX 2.2.3
Release Date
2024-01-11
Fixes and Improvements
- PyKX now raises an error appropriately when failing to locate
msvcr100.dllwhen loading on Windows. - Config values now default to
Falsewhen not set rather thanNone. - Resolved issue where both
PYKX_NO_SIGNALandPYKX_NO_SIGINTneeded to be set to take effect. Now correctly accepts either. - Reduced signal handling list to only
SIGINTandSIGTERM. The inclusion ofSIGSEGVsince 2.2.1 could cause segfaults with compressed enum files. - Updated q libraries to 2024.01.09
Note
PyKX 2.2.3 is currently not available for Mac x86 for all Python versions, additionally it is unavailable for Mac ARM on Python 3.7. Updated builds will be provided once available.
PyKX 2.2.2
Warning
Please skip this release and use 2.2.3 or newer. This is due to potential segfaults when reading compressed files.
Release Date
2023-12-12
Fixes and Improvements
- Conversions between
UUIDandpykx.GUIDtypes could produce invalid results under various conditions in both licensed and unlicensed mode. - A regression in 2.2.1 resulted in
SIGINTsignals being incorrectly treated asSIGTERMstyle signals, PyKX now resets all signals overwritten by PyKX to their values prior to import. - Indexing regression in 2.2.1 causing hangs for certain inputs such as
tbl[::-1]has been resolved.
PyKX 2.2.1
Warning
Please skip this release and use 2.2.3 or newer. This is due to potential segfaults when reading compressed files.
Release Date
2023-11-30
Fixes and Improvements
- Some messages to
stdoutwere not being captured when redirecting. Now all are captured. - Deprecation of internally used environment variable
UNDER_PYTHONwhich has been replaced byPYKX_UNDER_PYTHONto align with other internally used environment variables. - Fix
Unknown default conversion typeerror whenPYKX_DEFAULT_CONVERSIONis set tok - Numpy dependency for Python 3.11 corrected to
numpy~=1.23.2 pykx.q.qsql.selectandpykx.q.qsql.execstatements no longer usegetcalls for table retrieval unnecessarily when operating locally or via IPC.-
Null integral values in table keys will no longer convert the underlying vectors to floats when converting from a
pykx.KeyedTabletopandas.DataFrame>>> kx.q('`col1 xkey ([] col1: (1j; 2j; 0Nj); col2:(1j; 2j; 0Nj); col3:`a`b`c)').pd() col2 col3 col1 1.0 1 a 2.0 2 b 0.0 -- c>>> kx.q('`col1 xkey ([] col1: (1j; 2j; 0Nj); col2:(1j; 2j; 0Nj); col3:`a`b`c)').pd() col2 col3 col1 1 1 a 2 2 b -- -- cWarning
For multi-keyed PyKX tables converted to Pandas the appropriate round-trip behaviour is supported however due to limitations in Pandas displaying of these as masked arrays is not supported as below
>>> kx.q('`col1`col2 xkey ([] col1: (1j; 2j; 0Nj); col2:(1j; 2j; 0Nj); col3:`a`b`c)').pd() col3 col1 col2 1 1 a 2 2 b -9223372036854775808 -9223372036854775808 c -
Fix to issue where providing
SIGTERMsignals to Python processes running PyKX would not result in the Python process being terminated. - Addition of deprecation warning for environmental configuration option
PYKX_NO_SIGINTwhich is to be replaced byPYKX_NO_SIGNAL. This is used when users require no signal handling logic overwrites and now coversSIGTERM,SIGINT,SIGABRTsignals amongst others. -
Use of
pykx.q.system.variablesno longer prepends leading.to supplied string allowing users to get the variables associated with dictionary like namespaces.>>> kx.q('.test.a:1;.test.b:2') >>> kx.q('test.c:3;test.d:4') >>> kx.q.system.variables('.test') pykx.SymbolVector(pykx.q('`s#`a`b')) >>> kx.q.system.variables('test') pykx.SymbolVector(pykx.q('`s#`a`b'))>>> kx.q('.test.a:1;.test.b:2') >>> kx.q('test.c:3;test.d:4') >>> kx.q.system.variables('.test') pykx.SymbolVector(pykx.q('`s#`a`b')) >>> kx.q.system.variables('test') pykx.SymbolVector(pykx.q('`s#`c`d')) -
q dictionaries with tables as keys were being incorrectly wrapped as
pykx.KeyedTable. Now corrected topykx.Dictionary:>>> type(pykx.q('([] a:1 2 3;b:2 3 4)!enlist each 1 2 3')) <class 'pykx.wrappers.KeyedTable'>>>> type(pykx.q('([] a:1 2 3;b:2 3 4)!enlist each 1 2 3')) <class 'pykx.wrappers.Dictionary'>- Added consistent conversion of
datetime.timeobjects
q).pykx.pyexec"from datetime import time" q).pykx.eval["time(11, 34, 56)"]` foreign>>> kx.toq(time(11, 34, 56)) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "pykx/toq.pyx", line 2641, in pykx.toq.ToqModule.__call__ File "pykx/toq.pyx", line 270, in pykx.toq._default_converter TypeError: Cannot convert <class 'datetime.time'> 'datetime.time(11, 34, 56)' to K objectq).pykx.pyexec"from datetime import time" q).pykx.eval["time(11, 34, 56)"]` 0D11:34:56.000000000>>> kx.toq(time(11, 34, 56)) pykx.TimespanAtom(pykx.q('0D11:34:56.000000000')) - Added consistent conversion of
-
Fixed null value for
TimestampVectorreturningNoneTypeinstead ofpykx.wrappers.TimestampAtomfor.py()method>>> for x in kx.q('0Np,.z.p').py(): ... print(type (x)) <class 'NoneType'> <class 'datetime.datetime'>>>> for x in kx.q('0Np,.z.p').py(): ... print(type (x)) <class 'pykx.wrappers.TimestampAtom'> <class 'datetime.datetime'>
Upgrade considerations
- If dependent on the environment variable
UNDER_PYTHONplease upgrade your code to usePYKX_UNDER_PYTHON
PyKX 2.2.0
Release Date
2023-11-09
Additions
-
Addition of
aggmethod for application of aggregation functions onpykx.Tableandpykx.GroupbyTableobjects>>> import pykx as kx >>> import numpy as np >>> import statistics >>> def mode(x): ... return statistics.mode(x) >>> tab = kx.Table(data={ ... 'x': kx.random.random(1000, 10), ... 'x1': kx.random.random(1000, 10.0)}) >>> tab.agg(mode) pykx.Dictionary(pykx.q(' x | 6 x1| 2.294631 ')) >>> tab.agg(['min', 'mean']) pykx.KeyedTable(pykx.q(' function| x x1 --------| ----------------- min | 0 0.009771725 mean | 4.588 5.152194 ')) >>> >>> group_tab = kx.Table(data={ ... 'x': kx.random.random(1000, ['a', 'b']), ... 'y': kx.random.random(1000, 10.0)}) >>> group_tab.groupby('x').agg('mean') pykx.KeyedTable(pykx.q(' x| y -| -------- a| 5.239048 b| 4.885599 ')) >>> group_tab.groupby('x').agg(mode) pykx.KeyedTable(pykx.q(' x| y -| -------- a| 1.870281 b| 4.46898 ')) -
Addition of the ability for users to run
min,max,mean,median,sumandmodemethods on vector objects within PyKX.>>> import pykx as kx >>> random_vec = kx.random.random(5, 3, seed=20) pykx.LongVector(pykx.q('0 1 0 1 1')) >>> random_vec.mode() pykx.LongVector(pykx.q(',1')) >>> random_vec.mean() pykx.FloatAtom(pykx.q('0.6')) -
Addition of the ability for users to assign objects to
pykx.*Vectorandpykx.Listobjects>>> import pykx as kx >>> qvec = kx.q.til(10) >>> qvec pykx.LongVector(pykx.q('0 1 2 3 4 5 6 7 8 9')) >>> qvec[3] = 45 >>> qvec pykx.LongVector(pykx.q('0 1 2 45 4 5 6 7 8 9')) >>> qvec[-1] = 20 >>> qvec pykx.LongVector(pykx.q('0 1 2 45 4 5 6 7 8 20')) -
Users can now assign/update keys of a
pykx.Dictionaryobject using an in-built__setitem__method as follows>>> import pykx as kx >>> pykx_dict = kx.toq({'x': 1}) >>> pykx_dict pykx.Dictionary(pykx.q('x| 1')) >>> pykx_dict['x1'] = 2 >>> pykx_dict pykx.Dictionary(pykx.q(' x | 1 x1| 2 ')) >>> for i in range(3): ... pykx_dict['x']+=i ... >>> pykx_dict pykx.Dictionary(pykx.q(' x | 4 x1| 2 ')) -
Addition of
nullandinfproperties forpykx.Atomobjects allowing for Pythonic retrieval of nulls and infinities>>> import pykx as kx >>> kx.FloatAtom.null pykx.FloatAtom(pykx.q('0n')) >>> kx.GUIDAtom.null pykx.GUIDAtom(pykx.q('00000000-0000-0000-0000-000000000000')) >>> kx.IntAtom.inf pykx.IntAtom(pykx.q('0Wi')) >>> -kx.IntAtom.inf pykx.IntAtom(pykx.q('-0Wi')) -
Users can now use the environment variables
PYKX_UNLICENSED="true"orPYKX_LICENSED="true"set this as part of configuration within their.pykx-configfile to allowunlicensedorlicensedmode to be the default behaviour on initialisation for example:>>> import os >>> os.environ['PYKX_UNLICESED'] = "true" >>> import pykx as kx >>> kx.toq([1, 2, 3]) pykx.List._from_addr(0x7fee46000a00) -
Addition of
appendandextendmethods topykx.*Vectorandpykx.Listobjects>>> import pykx as kx >>> qvec = kx.q.til(5) >>> qvec.append(100) >>> qvec pykx.LongVector(pykx.q('0 1 2 3 4 100')) >>> qvec.extend([1, 2, 3]) >>> qvec pykx.LongVector(pykx.q('0 1 2 3 4 100 1 2 3')) -
Addition of
debugkeyword argument to the__call__method onEmbeddedQandQConnectionobjects to provide backtraces onqcode.>>> import pykx as kx >>> kx.q('{[x] a: 5; b: til a; c: til x; b,c}', b'foo', debug=True) backtrace: [3] (.q.til) [2] {[x] a: 5; b: til a; c: til x; b,c} ^ [1] (.Q.trp) [0] {[pykxquery] .Q.trp[value; pykxquery; {2@"backtrace: ^ ",.Q.sbt y;'x}]} Traceback (most recent call last): File "<stdin>", line 1, in <module> File "...\site-packages\pykx\embedded_q.py", line 226, in __call__ return factory(result, False) File "pykx\\_wrappers.pyx", line 504, in pykx._wrappers._factory File "pykx\\_wrappers.pyx", line 497, in pykx._wrappers.factory pykx.exceptions.QError: type -
Added feature to extract individual elements of both
TimestampAtomandTimestampVectorin a pythonic way including:date- DateAtom / DateVectortime- TimeAtom / TimeVectoryear- IntAtom / IntVectormonth- IntAtom / IntVectorday- IntAtom / IntVectorhour- IntAtom / IntVectorminute- IntAtom / IntVectorsecond- IntAtom / IntVector
>>> timestamp_atom = kx.q('2023.10.25D16:42:01.292070013') >>> timestamp_atom.time pykx.TimeAtom(pykx.q('16:42:01.292')) >>> timestamp_atom.date pykx.DateAtom(pykx.q('2023.10.25')) >>> timestamp_atom.minute pykx.IntAtom(pykx.q('42i')) >>> timestamp_atom_2 = kx.q('2018.11.09D12:21:08.456123789') >>> timestamp_vector = kx.q('enlist', timestamp_atom, timestamp_atom_2) >>> timestamp_vector.time pykx.TimeVector(pykx.q('16:42:01.292 12:21:08.456')) >>> timestamp_vector.date pykx.DateVector(pykx.q('2023.10.25 2018.11.09')) >>> timestamp_vector.hour pykx.IntVector(pykx.q('16 12i')) -
Addition of
poll_recv_asynctoRawQConnectionobjects to support asynchronous polling. -
Addition of negative slicing to
list,vectorandtableobjects```python >>> import pykx as kx >>> qlist = kx.q('("a";2;3.3;`four)') >>> qlist[-3:] pykx.List(pykx.q(' 2 3.3 `four ')) >>> vector = kx.q('til 5') >>> vector[:-1] pykx.LongVector(pykx.q('0 1 2 3')) >>> table = kx.q('([] a:1 2 3; b:4 5 6; c:7 8 9)') >>> table[-2:] pykx.Table(pykx.q(' a b c ----- 2 5 8 3 6 9 ')) ```
Fixes and Improvements
-
Fix to allow users to use Python functions when operating on a
pykx.GroupbyTablewith anapplyfunction>>> import pykx as kx >>> import statistics >>> def mode(x): ... return statistics.mode(x) >>> tab = kx.q('([]sym:`a`b`a`a;1 1 0 0)') >>> tab.groupby('sym').apply(mode) pykx.KeyedTable(pykx.q(' sym| x ---| - a | 0 b | 1 ')) -
Added debug dependency for
find-libpythonthat can be installed usingpip install "pykx[debug]". This dependency can be used to help findlibpythonin the scenario thatpykx.qfails to find it. -
Usage of the
QARGSto enable/disable various elements of kdb Insights functionality has been formalised, outlined here. For example users can now useQARGS="--no-objstor"to disable object storage capabilities. -
Failure to initialise PyKX with
exporembedqlicense errors will now prompt users to ask if they wish to download an appropriate license following expiry or use of an invalid licenseYour PyKX license has now expired. Captured output from initialization attempt: '2023.10.18T13:27:59.719 licence error: exp Would you like to renew your license? [Y/n]:You appear to be using a non kdb Insights license. Captured output from initialization attempt: '2023.10.18T13:27:59.719 licence error: embedq Running PyKX in the absence of a kdb Insights license has reduced functionality. Would you like to install a kdb Insights personal license? [Y/n]:Your installed license is out of date for this version of PyKX and must be updated. Captured output from initialization attempt: '2023.10.18T13:27:59.719 licence error: upd Would you like to install an updated kdb Insights personal license? [Y/n]: -
PyKX sets
PYKX_EXECUTABLEto use when loading embedded q to prevent errors if launched using a different Python executable than that which will be found inPATH -
Jupyter Notebook:
- Removal of
FutureWarningwhen displaying tables and dictionaries. - Revert issue causing results to be displayed as pointer references rather than Python objects in unlicensed mode.
%%qmagic now suppresses displaying of::.%%qmagic addition of--displayoption to havedisplaybe called on returned items in place of the defaultprint.
- Removal of
-
PyKXReimportnow additionally unsets/resets:PYKX_SKIP_UNDERQ,PYKX_EXECUTABLE,PYKX_DIR -
When attempting to deserialize unsupported byte representations
pykx.deserializewould result in a segmentation fault, this has been updated such that an error message is now raised.>>> import pykx as kx >>> kx.deserialize(b'invalid byte string') Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/local/anaconda3/lib/python3.8/site-packages/pykx/serialize.py", line 123, in deserialize return _deserialize(data) File "pykx/_wrappers.pyx", line 131, in pykx._wrappers.deserialize File "pykx/_wrappers.pyx", line 135, in pykx._wrappers.deserialize pykx.exceptions.QError: Failed to deserialize supplied non PyKX IPC serialized format object -
Fixed an issue when using multiple asynchronous
QConnectionconnected to multiple servers. -
Users can now access the length of and index into
pykx.CharAtomobjects to align with Pythonic equivalent data>>> qatom = kx.CharAtom('a') >>> len(qatom) 1 >>> qatom[0] pykx.CharAtom(pykx.q('"a"'))
PyKX 2.1.2
Release Date
2023-10-24
Fixes and Improvements
-
Fix to issue where functions retrieved using the Context Interface with names
update/delete/select/execwould result in anAttributeError>>> import pykx as kx >>> kx.q.test <pykx.ctx.QContext of .test with [ctx]> >>> kx.q.test.ctx.update(1) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/local/anaconda3/lib/python3.8/site-packages/pykx/ctx.py", line 121, in __getattr__ raise AttributeError(f'{key}: {self._unsupported_keys_with_msg[key]}') AttributeError: update: Usage of 'update' function directly via 'q' context not supported, please consider using 'pykx.q.qsql.update'>>> import pykx as kx >>> kx.q.test <pykx.ctx.QContext of .test with [ctx]> >>> kx.q.test.ctx.update(1) pykx.LongAtom(pykx.q('2'))
PyKX 2.1.1
Release Date
2023-10-10
Fixes and Improvements
-
Fix to regression in PyKX 2.1.0 where execution of
from pykx import *would result in the following behaviour>>> from pykx import * ... AttributeError: module 'pykx' has no attribute 'PyKXSerialized'
PyKX 2.1.0
Release Date
2023-10-09
Additions
-
Added functionality to the CSV Reader to allow for the input of data structures while defining column types. For example, the following reads a CSV file and specifies the types of the three columns named
x1,x2andx3to be of typeInteger,GUIDandTimestamp.>>> table = q.read.csv('example.csv', {'x1':kx.IntAtom,'x2':kx.GUIDAtom,'x3':kx.TimestampAtom}) -
Conversions from Pandas Dataframes and PyArrow tables using
pykx.toqcan now specify thektypeargument as a dictionary allowing selective type conversions for defined columns>>> import pykx as kx >>> import pandas as pd >>> df = pd.DataFrame.from_dict({'x': [1, 2], 'y': ['a', 'b']}) >>> kx.toq(df).dtypes pykx.Table(pykx.q(' columns type ----------------------- x "kx.LongAtom" y "kx.SymbolAtom" ')) >>> kx.toq(df, ktype={'x': kx.FloatAtom}).dtypes pykx.Table(pykx.q(' columns type ----------------------- x "kx.FloatAtom" y "kx.SymbolAtom" ')) -
Addition of the ability for users to run an
applymethod on vector objects within PyKX allowing the application of Python/PyKX functionality on these vectors directly>>> import pykx as kx >>> random_vec = kx.random.random(2, 10.0, seed=100) >>> random_vec pykx.FloatVector(pykx.q('8.909647 3.451941')) >>> random_vec.apply(lambda x:x+1) pykx.FloatVector(pykx.q('9.909647 4.451941')) >>> def func(x, y): ... return x+y >>> random_vec.apply(func, y=2) pykx.FloatVector(pykx.q('10.909647 5.451941')) -
Notebooks will HTML print tables and dictionaries through the addition of
_repr_html_. Previousqstyle output is still available usingprint. - Added
serializeanddeserializeas base methods to assist with the serialization ofKobjects for manual use over IPC. - Added support for
pandasversion2.0.
Pandas 2.0 has deprecated the datetime64[D/M] types.
Due to this change it is not always possible to determine if the resulting q Table should
use a MonthVector or a DayVector. In the scenario that it is not possible to determine
the expected type a warning will be raised and the DayVector type will be used as a
default.
Fixes and Improvements
-
Empty PyKX keyed tables can now be converted to Pandas DataFrames, previously this would raise a
ValueError>>> import pykx as kx >>> df = kx.q('0#`a xkey ([]a:1 2 3;b:3 4 5)').pd() >>> df Empty DataFrame Columns: [b] Index: [] >>> df.index.name 'a' >>> kx.toq(df) pykx.KeyedTable(pykx.q(' a| b -| - ')) -
Fix to issue introduced in 2.0.0 where indexing of
pykx.Tablereturned incorrect values when passed negative/out of range values>>> import pykx as kx >>> tab = kx.Table(data={"c1": list(range(3))}) >>> tbl[-1] pykx.Table(pykx.q(' c1 -- ')) >>> tab[-4] pykx.Table(pykx.q(' c1 -- ')) >>> tab[3] pykx.Table(pykx.q(' c1 -- '))>>> import pykx as kx >>> tab = kx.Table(data={"c1": list(range(3))}) >>> tab[-1] pykx.Table(pykx.q(' c1 -- 2 ')) >>> tab[-4] ... IndexError: index out of range >>> tab[3] ... IndexError: index out of range -
Fix to issue where PyKX would not initialize when users with a
QINITenvironment variable set which pointed to a file contained ashowstatement - Retrieval of
dtypeswith tables containingrealcolumns will now returnkx.RealAtomfor the type rather than incorrectly returningkx.ShortAtom - Users with
QINITenvironment variable would previously load twice on initialization within PyKX - Users installing PyKX under q on Windows had been missing installation of required files using
pykx.install_into_QHOME()
Dependency Updates
- The version of
Cythonused to buildPyKXwas updated to the full3.0.xrelease version.
PyKX 2.0.1
Release Date
2023-09-21
Fixes and Improvements
- User input based license initialization introduced in 2.0.0 no longer expects user input when operating in a non-interactive modality, use of PyKX in this mode will revert to previous behavior
- Use of the environment variables
QARGS='--unlicensed'orQARGS='--licensed'operate correctly following regression in 2.0.0 - Fix to issue where
OSErrorwould be raised whenclose()was called on an IPC connection which has already disconnected server side
PyKX 2.0.0
Release Date
2023-09-18
- PyKX 2.0.0 major version increase is required due to the following major changes which are likely to constitute breaking changes
- Pandas API functionality is enabled permanently which will modify data indexing and retrieval of
pykx.Tableobjects. Users should ensure to review and test their codebase before upgrading. - EmbedPy replacement functionality for PyKX under q is now non-beta for Linux and MacOS installations, see here for full information on 2.0.0 changelog.
- Pandas API functionality is enabled permanently which will modify data indexing and retrieval of
Additions
- Pandas API is enabled by default allowing users to treat PyKX Tables similarly to Pandas Dataframes for a limited subset of Pandas like functionality. As a result of this change the environment variable
PYKX_ENABLE_PANDAS_APIis no longer required. - Addition of file based configuration setting allowing users to define profiles for various PyKX modalities through definition of the file
.pykx.configsee here for more information. - Addition of new PyKX license installation workflow for users who do not have a PyKX license allowing for installation of personal licenses via a form based install process. This updated flow is outlined here.
-
Addition of a new module
pykx.licensewhich provides functionality for the installation of licenses, checking of days to expiry and validation that the license which PyKX is using matches the file/base64 string the user expects. For more information see here. -
Addition of
applyandgroupbymethods to PyKX Tables allowing users to perform additional advanced analytics for example:>>> import pykx as kx >>> N = 1000000 >>> tab = kx.Table(data = { ... 'price': kx.random.random(N, 10.0), ... 'sym': kx.random.random(N, ['a', 'b', 'c']) ... }) >>> tab.groupby('sym').apply(kx.q.sum) pykx.KeyedTable(pykx.q(' sym| price ---| -------- a | 166759.4 b | 166963.6 c | 166444.1 ')) -
Addition of a new module
pykx.randomwhich provides functionality for the generation of random data and setting of random seeds. For more information see here>>> import pykx as kx >>> kx.random.random(5, 1.0, seed=123) pykx.FloatVector(pykx.q('0.1959057 0.06460555 0.9550039 0.4991214 0.3207941')) >>> kx.random.seed(123) >>> kx.random.random(5, 1.0) pykx.FloatVector(pykx.q('0.1959057 0.06460555 0.9550039 0.4991214 0.3207941')) >>> kx.random.random([3, 4], ['a', 'b', 'c']) pykx.List(pykx.q(' b c a b b a b a a a a a ')) -
Addition of a new module
pykx.registerwhich provides functionality for the addition of user specified type conversions for Python objects to q via the functionpy_toqfor more information see here. The following is an example of using this function>>> import pykx as kx >>> def complex_conversion(data): ... return kx.q([data.real, data.imag]) >>> kx.register.py_toq(complex, complex_conversion) >>> kx.toq(complex(1, 2)) pykx.FloatVector(pykx.q('1 2f')) -
Support for fixed length string dtype with Numpy arrays
>>> import pykx as kx >>> import numpy as np >>> kx.toq(np.array([b'string', b'test'], dtype='|S7')) pykx.List(pykx.q(' "string" "test" '))
Fixes and Improvements
- Update to environment variable definitions in all cases to be prefixed with
PYKX_* - Return of Pandas API functions
dtypes,columns,empty,ndim,sizeandshapereturnkxobjects rather than Pythonic objects - Removed GLIBC_2.34 dependency for conda installs
- Removed the ability for users to incorrectly call
pykx.q.{select/exec/update/delete}with error message now suggesting usage ofpykx.q.qsql.{function} - Fixed behavior of
locwhen used onKeyedTableobjects to match the pandas behavior. - Addition of warning on failure to link the content of a users
QHOMEdirectory pointing users to documentation for warning suppression - Update to PyKX foreign function handling to support application of Path objects as first argument i.e.
q("{[f;x] f x}")(lambda x: x)(Path('test')) - SQL interface will attempt to automatically load on Windows and Mac
- Attempts to serialize
pykx.Foreign,pykx.SplayedTableandpykx.PartitionedTableobjects will now result in a type error fixing a previous issue where this could result in a segmentation fault. - Messages mistakenly sent to a PyKX client handle are now gracefully ignored.
-
Application of Pandas API
dtypesoperations return a table containingcolumntotypemappings withPyKXobject specific types rather than Pandas/Python types>>> table = kx.Table([[1, 'a', 2.0, b'testing', b'b'], [2, 'b', 3.0, b'test', b'a']]) >>> print(table) x x1 x2 x3 x4 -------------------- 1 a 2 "testing" b 2 b 3 "test" a >>> table.dtypes x int64 x1 object x2 float64 x3 object x4 |S1 dtype: object>>> table = kx.Table([[1, 'a', 2.0, b'testing', b'b'], [2, 'b', 3.0, b'test', b'a']]) >>> print(table) x x1 x2 x3 x4 -------------------- 1 a 2 "testing" b 2 b 3 "test" a >>> table.dtypes pykx.Table(pykx.q(' columns type ----------------------- x "kx.LongAtom" x1 "kx.SymbolAtom" x2 "kx.FloatAtom" x3 "kx.CharVector" x4 "kx.CharAtom" ')) -
Fixed an issue where inequality checks would return
Falseincorrectly>>> import pykx as kx >>> kx.q('5') != None pykx.q('0b')>>> import pykx as kx >>> kx.q('5') != None pykx.q('1b')
Breaking Changes
- Pandas API functionality is enabled permanently which will modify data indexing and retrieval. Users should ensure to review and test their codebase before upgrading.
PyKX 1.6.3
Release Date
2023-08-18
Additions
- Addition of argument
return_infotopykx.util.debug_environmentallowing user to optionally return the result as astrrather than to stdout
Fixes and Improvements
- Fixed Pandas API use of
ndimfunctionality which should return2when interacting with tables following the expected Pandas behavior. - Fixed an error when using the Pandas API to update a column with a
Symbols,Characters, andGeneric Lists. - Prevent attempting to pass wrapped Python functions over IPC.
- Support IPC payloads over 4GiB.
PyKX 1.6.2
Release Date
2023-08-15
Additions
- Added
to_local_folderkwarg toinstall_into_QHOMEto enable use ofpykx.qwithout write access toQHOME. - Added an example that shows how to use
EmbeddedQin a multithreaded context where the threads need to modify global state. - Added PYKX_NO_SIGINT environment variable.
Fixes and Improvements
- Fixed an issue causing a crash when closing
QConnectioninstances on Windows. - Updated q 4.0 libraries to 2023.08.11. Note: Mac ARM release remains on 2022.09.30.
- Fix Jupyter Magic in local mode.
- Fix error when binding with FFI in
QINIT. - Fix issue calling
peachwithPYKX_RELEASE_GILset to true when calling a Python function.
PyKX 1.6.1
Release Date
2023-07-19
Additions
- Added
sorted,grouped,parted, andunique. As methods off ofTablesandVectors. - Added
PyKXReimportclass to allow subprocesses to reimportPyKXsafely.- Also includes
.pykx.safeReimportinpykx.qto allows this behavior when running under q as well.
- Also includes
- Added environment variables to specify a path to
libpythonin the casepykx.qcannot find it.
Fixes and Improvements
- Fixed memory leaks within the various
QConnectionsubclasses. - Added deprecation warning around the discontinuing of support for Python 3.7.
- Fixed bug in Jupyter Notebook magic command.
- Fixed a bug causing
np.ndarray's to not work withinufuncs. - Fixed a memory leak within all
QConnectionsubclasses. Fixed for bothPyKXas a client and as a server. - Updated insights libraries to 4.0.2
- Fixed
pykx.qfunctionality when run on Windows. - Fixed an issue where reimporting
PyKXwhen run under q would cause a segmentation fault. - Updated the warning message for the insights core libraries failing to load to make it more clear that no error has occurred.
PyKX 1.6.0
Release Date
2023-06-16
Additions
- Added
merge_asofto the Pandas like API.- See here for details of supported keyword arguments and limitations.
- Added
set_indexto the Pandas like API.- See here for details of supported keyword arguments and limitations.
- Added a set of basic computation methods operating on tabular data to the Pandas like API. See here for available methods and examples.
pykx.util.debug_environmentadded to help with import errors.- q vector type promotion in licensed mode.
- Added
.pykx.torawtopykx.qto enable raw conversions (e.g.kx.toq(x, raw=True)) - Added support for Python
3.11.- Support for PyArrow in this python version is currently in Beta.
- Added the ability to use
kx.RawQConnectionas a Python basedqserver usingkx.RawQConnection(port=x, as_server=True).- More documentation around using this functionality can be found here.
Fixes and Improvements
- Improved error on Windows if
msvcr100.dllis not found - Updated q libraries to 2023.04.17
- Fixed an issue that caused
qfunctions that shared a name with python key words to be inaccessible using the context interface.- It is now possible to access any
qfunction that uses a python keyword as its name by adding an underscore to the name (e.g.exceptcan now be accessed usingq.except_).
- It is now possible to access any
- Fixed an issue with
.pykx.getand.pykx.getattrnot raising errors correctly. - Fixed an issue where
deserializingdata would sometimes not error correctly. -
Users can now add new column(s) to an in-memory table using assignment when using the Pandas like API.
>>> import os >>> os.environ['PYKX_ENABLE_PANDAS_API'] = 'true' >>> import pykx as kx >>> import numpy as np >>> tab = kx.q('([]100?1f;100?1f)') >>> tab['x2'] = np.arange(0, 100) >>> tab pykx.Table(pykx.q(' x x1 x2 ------------------------- 0.1485357 0.1780839 0 0.4857547 0.3017723 1 0.7123602 0.785033 2 0.3839461 0.5347096 3 0.3407215 0.7111716 4 0.05400102 0.411597 5 .. '))
PyKX 1.5.3
Release Date
2023-05-18
Additions
- Added support for Pandas
Float64Index. - Wheels for ARM64 based Macs are now available for download.
PyKX 1.5.2
Release Date
2023-04-30
Additions
- Added support for ARM 64 Linux.
PyKX 1.5.1
Release Date
2023-04-28
Fixes and Improvements
- Fixed an issue with
pykx.qthat caused errors to not be raised properly under q. - Fixed an issue when using
.pykx.getand.pykx.getattrthat caused multiple calls to be made.
PyKX 1.5.0
Release Date
2023-04-17
Additions
- Added wrappers around various
qsystem commands. - Added
mergemethod to tables when using thePandas API. - Added
mean/median/modefunctions to tables when using thePandas API. - Added various functions around type conversions on tables when using the
Pandas API.
Fixes and Improvements
- Fix to allow GUIDs to be sent over IPC.
- Fix an issue related to IPC connection using compression.
- Improved the logic behind loading
pykx.qunder aqprocess allowing it to run on MacOS and Linux in any environment thatEmbedPyworks in. - Fix an issue that cause the default handler for
SIGINTto be overwritten. pykx.toq.from_callablereturns apykx.Compositionrather thanpykx.Lambda. When executed returns an unwrapped q object.- Fixed conversion of Pandas Timestamp objects.
- Fixed an issue around the
PyKXqmagic command failing to load properly. - Fixed a bug around conversions of
Pandastables with no column names. - Fixed an issue around
.pykx.qevalnot returning unwrapped results in certain scenarios.
PyKX 1.4.2
Release Date
2023-03-08
Fixes and Improvements
- Fixed an issue that would cause
EmbeddedQto fail to load.
PyKX 1.4.1
Release Date
2023-03-06
Fixes and Improvements
- Added constructors for
TableandKeyedTableobjects to allow creation of these objects from dictionaries and list like objects. - Fixed a memory leak around calling wrapped
Foreignobjects inpykx.q. - Fixed an issue around the
tlskeyword argument when creatingQConnectioninstances, as well as a bug in the unlicensed behavior ofSecureQConnection's.
PyKX 1.4.0
Release Date
2023-01-23
Additions
- Addition of a utility function
kx.ssl_info()to retrieve the SSL configuration when running in unlicensed mode (returns the same info as kx.q('-26!0') with a license). - Addition of a utility function
kx.schema.builderto allow for the generation ofpykx.Tableandpykx.KeyedTabletypes with a defined schema and zero rows, this provides an alternative to writing q code to create an empty table. - Added helper functions for inserting and upserting to
k.Tableinstances. These functions provide new keyword arguments to run a test insert against the table or to enforce that the schema of the new row matches the existing table. - Added environment variable
PYKX_NOQCE=1to skip the loading of q Cloud Edition in order to speed up the import of PyKX. - Added environment variable
PYKX_LOAD_PYARROW_UNSAFE=1to import PyArrow without the "subprocess safety net" which is here to prevent some hard crashes (but is slower than a simple import). - Addition of method
file_executetokx.QConnectionobjects which allows the execution of a local.qscript on a server instance as outlined here. - Added
kx.RawQConnectionwhich extendskx.AsyncQConnectionwith extra functions that allow a user to directly poll the send and receive selectors. - Added environment variable
PYKX_RELEASE_GIL=1to drop thePython GILon calls into embedded q. - Added environment variable
PYKX_Q_LOCK=1to enable a Mutex Lock around calls into q, setting this environment variable to a number greater than 0 will set the max length in time to block before raising an error, a value of '-1' will block indefinitely and will not error, any other value will cause an error to be raised immediately if the lock cannot be acquired. - Added
insertandupsertmethods toTableandKeyedTableobjects.
Fixes and Improvements
- Fixed
has_nullsandhas_infsproperties for subclasses ofk.Collection. - Improved error output of
kx.QConnectionobjects when an error is raised within the context interface. - Fixed
.py()conversion of nestedk.Dictionaryobjects and keyedk.Dictionaryobjects. - Fixed unclear error message when querying a
QConnectioninstance that has been closed. - Added support for conversions of non C contiguous Numpy arrays.
- Fixed conversion of null
GUIDAtom's to and from Numpy types. - Improved performance of converting
qenums to pandas Categoricals.
Beta Features
- Added support for a Pandas like API around
TableandKeyedTableinstances, documentation for the specific functionality can be found here. - Added
.pykx.setdefaulttopykx.qwhich allows the default conversion type to be set without using environment variables.
PyKX 1.3.2
Release Date
2023-01-06
Features and Fixes
- Fixed support for using TLS with
SyncQConnectioninstances.
PyKX 1.3.1
Release Date
2022-11-16
Features and Fixes
- Added environment variable
PYKX_Q_LIB_LOCATIONto specify a path to load the PyKX q libraries from.- Required files in this directory
- If you are using the kdb+/q Insights core libraries they all must be present within this folder.
- The
read.q,write.q, andcsvutil.qlibraries that are bundled with PyKX. - A
q.kthat matches the version ofqyou are loading. - There must also be a subfolder (
l64/m64/w64) based on the platform you are using.- Within this subfolder a copy of these files must also be present.
libq.(so / dylib)/q.dll.libe.(so / dylib)/e.dll.- If using the Insights core libraries their respective shared objects must also be present here.
- Within this subfolder a copy of these files must also be present.
- Required files in this directory
- Updated core q libraries
- PyKX now supports M1 Macs
- OpenSSLv3 support
- Added ability to specify maximum length for IPC error messages. The default is 256 characters and this can be changed by setting the
PYKX_MAX_ERROR_LENGTHenvironment variable.
PyKX 1.3.0
Release Date
2022-10-20
Features and Fixes
- Support for converting
datetime.datetimeobjects with time zone information intopykx.TimestampAtoms andpykx.TimestampVectors. - Added a magic command to run cells of q code in a Jupyter Notebook. The addition of
%%qat the start of a Jupyter Notebook cell will allow a user to execute q code locally similarly to loading a q file. - Added
no_ctxkey word argument topykx.QConnectioninstances to disable sending extra queries to/from q to manage the context interface. - Improvements to SQL interface for PyKX including the addition of support for prepared statements, execution of these statements and retrieval of inputs see here for more information.
- Fix to memory leak seen when converting Pandas Dataframes to q tables.
- Removed unnecessary copy when sending
qobjects over IPC.
Beta Features
- EmbedPy replacement functionality
pykx.qupdated significantly to provide parity with embedPy from a syntax perspective. Documentation of the interface here provides API usage. Note that initialization requires the first version of Python to be retrieved on a usersPATHto have PyKX installed. Additional flexibility with respect to installation location is expected in1.4.0please provide any feedback topykx@kx.com
PyKX 1.2.2
Release Date
2022-10-01
Features and Fixes
- Fixed an issue causing the timeout argument for
QConnectioninstances to not work properly.
PyKX 1.2.1
Release Date
2022-09-27
Features and Fixes
- Added support for OpenSSLv3 for IPC connections created when in 'licensed' mode.
- Updated conversion functionality for timestamps to support conversions within Pandas 1.5.0
PyKX 1.2.0
Release Date
2022-09-01
Features and Fixes
- Support for converting any python type to a
qForeign object has been added. - Support for converting Pandas categorical types into
pykx.EnumVectortype objects. - Support for q querying against Pandas/PyArrow tables through internal conversion to q representation and subsequent query.
kx.q.qsql.select(<pd.DataFrame>) - Support for casting Python objects prior to converting into K objects. (e.g.
kx.IntAtom(3.14, cast=True)orkx.toq("3.14", ktype=kx.FloatAtom, cast=True)). - Support usage of Numpy
__array_ufunc__'s directly onpykx.Vectortypes. - Support usage of Numpy
__array_function__'s directly onpykx.Vectortypes (Note: these will return a Numpy ndarray object not an analogouspykx.Kobject). - Improved performance of
pykx.SymbolVectorconversion into native Python type (e.g..py()conversion forpykx.SymbolVector's). - Improved performance and memory usage of various comparison operators between
Ktypes. - Improved performance of various
pykx.toqconversions. pykx.Vectortypes will now automatically enlist atomic types instead of erroring.- Fixed conversions of Numpy float types into
pykx.FloatAtomandpykx.RealAtomtypes. - Fixed conversion of
NonePython objects into analogous nullKtypes if aktypeis specified. - Added
event_loopparameter topykx.AsyncQConnectionthat takes a running event loop as a parameter and allows the event loop to managepykx.QFutureobjects.
Beta Features
- Added extra functionality to
pykx.qrelated to the calling and use of python foreign objects directly within aqprocess. - Support for NEP-49, which allows Numpy arrays to be converted into
qVectors without copying the underlying data. This behavior is opt-in and you can do so by setting the environment variablePYKX_ALLOCATORto 1, "1" or True or by adding the flag--pykxallocto theQARGSenvironment variable. Note: This feature also requires a python version of at least 3.8. - Support the ability to trigger early garbage collection of objects in the
qmemory space by adding--pykxgcto the QARGS environment variable, or by setting thePYKX_GCenvironment variable to 1, "1" or True.
PyKX 1.1.1
Release Date
2022-06-13
Features & Fixes
- Added ability to skip symlinking
$QHOMEtoPyKX's local$QHOMEby setting the environment variableIGNORE_QHOME.
PyKX 1.1.0
Release Date
2022-06-07
Dependencies
- The dependency on the system library
libcurlhas been made optional for Linux. If it is missing on Linux, a warning will be emitted instead of an error being raised, and the KX Insights Core librarykurlwill not be fully loaded. Windows and macOS are unaffected, as they don't support the KX Insights Core features to begin with.
Features & Fixes
- Splayed and partitioned tables no longer emit warnings when instantiated.
- Added
pykx.Q.sql, which is a wrapper around KXI Core SQL. .pykx.pyexecand.pykx.pyevalno longer segfault when called with a character atom.- Updated several
pykx.toqtests so that they would not randomly fail. - Fixed error when pickling
pykx.util.BlockManagerin certain esoteric situations. - Fixed
pandas.MultiIndexobjects created by PyKX havingpykx.SymbolAtomobjects within them - now they havestrobjects instead, as they normally would. - Upgraded the included KX Insights Core libraries to version 3.0.0.
- Added
pykx.toq.from_datetime_date, which convertsdatetime.dateobjects into any q temporal atom that can represent a date (defaulting to a date atom). - Fixed error when user specifies
-sor-qin$QARGS. - Fixed recursion error when accessing a non-existent attribute of
pykx.qwhile in unlicensed mode. Now an attribute error is raised instead. - Fixed build error introduced by new rules enforced by new versions of setuptools.
- Added
pykx.Anymap. - Fixed support for
kx.liclicenses. - The KXIC libraries are now loaded after q has been fully initialized, rather than during the initialization. This significantly reduces the time it takes to import PyKX.
- PyKX now uses a single location for
$QHOME: itslibdirectory within the installed package. The top-level contents of the$QHOMEdirectory (prior to PyKX updating the env var when embedded q is initialized) will be symlinked into PyKX'slibdirectory, along with the content of any subdirectories underlib(e.g.l64,m64,w64). This enables loading scripts and libraries located in the original$QHOMEdirectory during q initialization. - Improved performance (both execution speed and memory usage) of calling
np.arrayonpykx.Vectorinstances. The best practice is still to use thenpmethod instead of callingnp.arrayon thepykx.Vectorinstance. pykx.Vectoris now a subclass ofcollections.abc.Sequence.pykx.Mappingis not a subclass ofcollections.abc.Mapping.- Split
pykx.QConnectionintopykx.SyncQConnectionandpykx.AsyncQConnectionand added support for asynchronous IPC withqusingasync/await. Refer to thepykx.AsyncQConnectiondocs for more details. - Pandas dataframes containing Pandas extension arrays not originally created as Numpy arrays would result in errors when attempting to convert to q. For example a Dataframe with index of type
pandas.MultiIndex.from_arrayswould result in an error in conversion. - Improved performance of converting
pykx.SymbolVectortonumpy.arrayof strings, and also the conversion back from anumpy.arrayofstringsto aqSymbolVector. - Improved performance of converting
numpy.array's ofdtypesdatetime64/timedelta64to the variouspykx.TemporalTypes.
PyKX 1.0.1
Release Date
2022-03-18
Deprecations & Removals
- The
syncparameter forpykx.QConnectionandpykx.QConnection.__call__has been renamed to the less confusing namewait. Thesyncparameter remains, but its usage will result in aDeprecationWarningbeing emitted. Thesyncparameter will be removed in a future version.
Features & Fixes
- Updated to stable classifier (
Development Status :: 5 - Production/Stable) in project metadata. Despite this update being done in version 1.0.1, version 1.0.0 is still the first stable release of PyKX. - PyKX now provides source distributions (
sdist). It can be downloaded from PyPI usingpip download --no-binary=:all: --no-deps pykx. As noted in the installation docs, installations built from the source will only receive support on a best-effort basis. - Fixed Pandas NaT conversion to q types. Now
pykx.toq(pandas.NaT, ktype=ktype)produces a null temporal atom for any givenktype(e.g.pykx.TimeAtom). - Added a doc page for limitations of embedded q.
- Added a test to ensure large vectors are correctly handled (5 GiB).
- Always use synchronous queries internally, i.e. fix
QConnection(sync=False). - Disabled the context interface over IPC. This is a temporary measure that will be reversed once q function objects are updated to run in the environment they were defined in by default.
- Reduced the time it takes to import PyKX. There are plans to reduce it further, as
import pykxremains fairly slow. - Updated to KXI Core 2.1 & rename
qce->kxic. - Misc test updates.
- Misc doc updates.
PyKX 1.0.0
Release Date
2022-02-14
Migration Notes
To switch from Pykdb to PyKX, you will need to update the name of the dependency from pykdb to pykx in your pyproject.toml/requirements.txt/setup.cfg/etc. When Pykdb was renamed to PyKX, its version number was reset. The first public release of PyKX has the version number 1.0.0, and will employ semantic versioning.
Pay close attention to the renames listed below, as well as the removals. Many things have been moved to the top-level, or otherwise reorganized. A common idiom with Pykdb was the following:
from pykdb import q, k
It is recommended that the following be used instead:
import pykx as kx
This way the many attributes at the top-level can be easily accessed without any loss of context, for example:
kx.q # Can be called to execute q code
kx.K # Base type for objects in q; can be used to convert a Python object into a q type
kx.SymbolAtom # Type for symbol atoms; can be used to convert a `str` or `bytes` into a symbol atom
kx.QContext # Represents a q context via the PyKX context interface
kx.QConnection # Can be called to connect to a q process via q IPC
kx.PyKXException # Base exception type for exceptions specific to PyKX and q
kx.QError # Exception type for errors that occur in q
kx.LicenseException # Exception type raised when features that require a license are used without
kx.QHOME # Path from which to load q files, set by $QHOME environment variable
kx.QARGS # List of arguments provided to the embedded q instance at startup, set by $QARGS environment variable
# etc.
You can no longer rely on the context being reset to the global context after each call into embedded q, however IPC calls are unaffected.
Renames
- Pykdb has been renamed to PyKX.
Pykdb->PyKX;PYKDB->PYKX;pykdb->pykx. - The
adaptmodule has been renamed totoq, and it can be called directly. Instead ofpykdb.adapt.adapt(x)one should writepykx.toq(x). - The
kmodule has been renamed towrappers. All wrapper classes can be accessed from the top-level, i.e.pykx.K,pykx.SymbolAtom, etc. - The "module interface" (
pykdb.module_interface) has been renamed to the "context interface" (pykx.ctx). Allpykx.Qinstances (i.e.pykx.qand allpykx.QConnectioninstances) have actxattribute, which is the globalQContextfor thatpykx.Qinstance. Usually, one need not directly access the global context. Instead, one can access its subcontexts directly e.g.q.dbmaintinstead ofq.ctx.dbmaint. KdbError(and its subclasses) have been renamed toQErrorpykdb.ctx.KdbContexthas been renamed topykx.ctx.QContext, and is available from the top-level, i.e.pykx.QContext.- The
Connectionclass in the IPC module has been renamed toQConnection, and is now available at the top-level, i.e.pykx.QConnection. - The q type wrapper
DynamicLoadhas been renamed toForeign(pykdb.k.DynamicLoad->pykx.Foreign).
Deprecations & Removals
- The
pykdb.q.ipcattribute has been removed. The IPC module can be accessed directly instead atpykx.ipc, but generally one will only need to access theQConnectionclass, which can be accessed at the top-level:pykx.QConnection. - The
pykdb.q.Kattribute has been removed. Instead,Ktypes can be used as constructors for that type by leveraging thetoqmodule. For example, instead ofpykdb.q.K(x)one should writepykx.K(x). Instead ofpykx.q.K(x, k_type=pykx.k.SymbolAtom)one should writepykx.SymbolAtom(x)orpykx.toq(x, ktype=pykx.SymbolAtom). - Most
KdbError/QErrorsubclasses have been removed, as identifying them is error prone, and we are unable to provide helpful error messages for most of them. - The
pykx.kdbsingleton class has been removed.
Dependencies
- More Numpy, Pandas, and PyArrow versions are supported. Current
pandas~=1.0,numpy~=1.20,<1.22, andpyarrow>=3.0.0are supported. PyArrow remains an optional dependency. - A dependency on
find-libpython~=0.2was added. This is only used when running PyKX under a q process (see details in the section below about new alpha features). - A dependency on the system library
libcurlwas added for Linux. This dependency will be made optional in a future release.
Features & Fixes
- The
pykx.Qclass has been added as the base class forpykx.EmbeddedQ(the class forpykx.q) andpykx.QConnection. - The
pykx.EmbeddedQprocess now persists its context between calls. - The console now works over IPC.
- The query module now works over IPC. Because
Kobjects hold no reference to theqinstance that created them (be it local or over IPC),Ktables no longer haveselect/exec/update/deletemethods with themselves projected in as the first argument. That is to say, instead of writingt.select(...), writeq.qsql.select(t, ...), whereqis eitherpykx.qor an instance ofpykx.QConnection, andtwas obtained fromq. - The context interface now works over IPC.
- Nulls and infinities are now handled as nulls and infinities, rather than as their underlying values.
pykx.Atom.is_null,pykx.Atom.is_inf,pykx.Collection.has_nulls, andpykx.Collection.has_infshave been added. Numpy, Pandas, and PyArrow handles integral nulls with masked arrays, and they handle temporal nulls withNaT.NaNcontinues to be used for real/float nulls. The general Python representation (from.py()) usesKobjects for nulls and infinities. - Calling
boolonpykx.Kobjects now either raises aTypeError, or return the unambiguously correct result. For ambiguous cases such aspykx.Collectioninstances, use.any(),.all(), or a length check instead. - Assignment to q reserved words or the q context now raises a
pykx.PyKXException. pykx.toq.from_list(previouslypykdb.adapt.adapt_list) now works in unlicensed mode.q.queryandq.sqlare now placeholders (set toNone). The query interface can be accessed fromq.qsql.- Ternary
pownow raisesTypeErrorforRealNumericVectorandRealNumericAtom. QContextobjects are now context handlers, e.g.with pykx.q.dbmaint: # operate in .dbmaint within this block. This context handler supports arbitrary nesting.__getitem__now raises apykx.LicenseExceptionwhen used in unlicensed mode. Previously it worked for a few select types only. If running in unlicensed mode, one should perform all q indexing in the connected q process, and all Python indexing after converting theKobject to a Python/Numpy/Pandas/PyArrow object.pykx.QConnection(previouslypykdb.ipc.Connection) objects now have an informative/idiomatic repr.- Calls to
pykx.qnow support up to 8 arguments beyond the required query at position 0, similar to callingpykx.QConnectioninstances. These arguments are applied to the result of the query. - Embedded q is now used to count the number of rows a table has.
- All dynamic linking to
libqandlibehas been replaced by dynamic loading. As a result, the modules previously known asadaptandadapt_unlicensedhave been unified underpykx.toq. - PyKX now attempts to initialize embedded q when
pykxis imported, rather than whenpykx.qis first accessed. As a result, the error-prone practice of supplying thepykx.kdbsingleton class with arguments for embedded q is now impossible. - Arguments for embedded q can now be supplied via the environment variable
$QARGSin the form of command-line arguments. For example,QARGS='--unlicensed'causes PyKX to enter unlicensed mode when it is started, andQARGS='-o 8'causes embedded q to use an offset from UTC of 8 hours. These could be combined asQARGS='--unlicensed -o 8'. - Added the
--licensedstartup flag (to be provided via the$QARGSenvironment variable), which can be used to raise apykx.PyKXException(rather than emitting a warning) if PyKX fails to start in licensed mode (likely because of a missing/invalid q license). - PyKX Linux wheels are now PEP 600 compliant, built to the
manylinux_2_17standard. - Misc other bug fixes.
- Misc doc improvements.
Performance Improvements
- Converting nested lists from q to Python is much faster.
- Internally, PyKX now calls q functions with arguments directly instead of creating a
pykx.Functioninstance then calling it. This results in modest performance benefits in some cases. - The context interface no longer loads every element of a context when the context is first accessed, thereby removing the computation spike, which could be particularly intense for large q contexts.
New Alpha Features
Alpha features are subject to change
Alpha features are not stable will be subject to changes without notice. Use at your own risk.
- q can now load PyKX by loading the q file
pykx.q.pykx.qcan be copied into$QHOMEby runningpykx.install_into_QHOME(). When loaded into q, it will define the.pykxnamespace, which notably has.pykx.execand.pykx.pyeval. This allows for Python code to be run within q libraries and applications without some of the limitations of embedded q such as the lack of the q main loop, or the lack of timers. When q loadspykx.q, it attempts to source the currently active Python environment by runningpython, then fetching the environment details from it.