Skip to content

Commit 4833d60

Browse files
authored
Merge pull request #60 from amcdonald3/3.1.8
3.1.8
2 parents 267a7f1 + 235d15f commit 4833d60

7 files changed

Lines changed: 251 additions & 14 deletions

File tree

docs/release-notes/changelog.md

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,22 @@
44

55
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](./underq-changelog.md).
66

7-
# PyKX 3.1.7
7+
# PyKX 3.1.8
88

99
#### Release Date
1010

11-
2026-02-09
11+
2026-02-18
12+
13+
### Additions
14+
15+
- Added `connection_timeout` keyword argument to `AsyncQConnection` objects allowing the specification of a timeout for the initial connection to a `q` server.
16+
- Added the usage of `.q.Q.ens` for `sym_enum` argument in `DB` objects.
17+
18+
## PyKX 3.1.7
19+
20+
#### Release Date
21+
22+
2026-02-10
1223

1324
### Additions
1425

mkdocs.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,7 @@ nav:
283283
- PyKX as a server: examples/server/server.md
284284
- Real-time streaming: examples/streaming/index.md
285285
- Multithreaded execution: examples/threaded_execution/threading.md
286-
- Asyncronous Queries: examples/AsynchronousQueries/async_querying.md
286+
- Asynchronous Queries: examples/AsynchronousQueries/async_querying.md
287287
- Releases:
288288
- Release notes:
289289
- PyKX: release-notes/changelog.md

src/pykx/db.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,13 @@ def __init__(self,
146146
>>> db.tables
147147
['quote', 'trade']
148148
```
149+
!!! note "Loading root-level objects"
150+
When using `pykx.DB`, only partitioned tables are exposed as attributes of the
151+
`DB` object. Root-level splayed objects (for example, dictionaries or lists stored
152+
alongside partitions) are **not** attached to the `DB` instance, but are still loaded
153+
into the q process and can be accessed directly using `kx.q`.
149154
155+
For example, you can retrieve a variable `mySplayTab` by running `kx.q['mySplayTab']`.
150156
Define the path to be used for a database which does not initially exist
151157
152158
```python
@@ -323,7 +329,10 @@ def create(self,
323329
qfunc = q(_func_mapping[func_name])
324330
try:
325331
if format == 'splayed':
326-
table = q.Q.en(save_dir, table)
332+
if sym_enum is None:
333+
table = q.Q.en(save_dir, table)
334+
else:
335+
table = q.Q.ens(save_dir, table, sym_enum)
327336
q('{.Q.dd[x;`] set y}', save_dir/table_name, table)
328337
else:
329338
if isinstance(partition, str):

src/pykx/ipc.py

Lines changed: 48 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,9 @@ def __init__(self,
458458
no_ctx: bool = False,
459459
reconnection_attempts: int = -1,
460460
reconnection_delay: float = 0.5,
461-
reconnection_function: callable = reconnection_function
461+
reconnection_function: callable = reconnection_function,
462+
connection_timeout: Optional[float] = None,
463+
462464
):
463465
"""Interface with a q process using the q IPC protocol.
464466
@@ -498,6 +500,9 @@ def __init__(self,
498500
reconnection_delay: A `#!python float` for the initial delay between reconnect attempts
499501
(in seconds). This is passed to the provided `#!python reconnection_function` that
500502
is executed on reconnect attempt.
503+
connection_timeout: Timeout in seconds for connection to `q` server. If left as default
504+
`None`, the socket will not timeout when connecting.
505+
501506
502507
Note: The `#!python username` and `#!python password` parameters are not required.
503508
The `#!python username` and `#!python password` parameters are only required if the
@@ -518,6 +523,9 @@ def __init__(self,
518523
super().__init__()
519524

520525
def _create_connection_to_server(self):
526+
con_timeout = self._connection_info['connection_timeout']\
527+
if self._connection_info['connection_timeout'] is not None\
528+
else self._connection_info['timeout']
521529
object.__setattr__(
522530
self,
523531
'_handle',
@@ -527,7 +535,7 @@ def _create_connection_to_server(self):
527535
self._connection_info['credentials'],
528536
self._connection_info['unix'],
529537
self._connection_info['tls'],
530-
self._connection_info['timeout'],
538+
con_timeout,
531539
self._connection_info['large_messages']
532540
)
533541
)
@@ -564,7 +572,8 @@ def _init(self,
564572
conn_gc_time: float = 0.0,
565573
reconnection_attempts: int = -1,
566574
reconnection_delay: float = 0.5,
567-
reconnection_function: callable = reconnection_function
575+
reconnection_function: callable = reconnection_function,
576+
connection_timeout: Optional[float] = None,
568577
):
569578
credentials = f'{normalize_to_str(username, "Username")}:' \
570579
f'{normalize_to_str(password, "Password")}'
@@ -585,7 +594,8 @@ def _init(self,
585594
'conn_gc_time': conn_gc_time,
586595
'reconnection_attempts': reconnection_attempts,
587596
'reconnection_delay': reconnection_delay,
588-
'reconnection_function': reconnection_function
597+
'reconnection_function': reconnection_function,
598+
'connection_timeout': connection_timeout,
589599
})
590600
if system == 'Windows' and unix: # nocov
591601
raise TypeError('Unix domain sockets cannot be used on Windows')
@@ -600,13 +610,14 @@ def _init(self,
600610
object.__setattr__(self, '_handle', server_sock.fileno())
601611
object.__setattr__(self, '_finalizer', lambda: server_sock.close())
602612
else:
613+
con_timeout = connection_timeout if connection_timeout is not None else timeout
603614
try:
604615
handle = _ipc.init_handle(host,
605616
port,
606617
credentials,
607618
unix,
608619
tls,
609-
timeout,
620+
con_timeout,
610621
large_messages)
611622
except BaseException as e:
612623
if isinstance(e, QError):
@@ -1140,7 +1151,8 @@ def __init__(self,
11401151
no_ctx: bool = False,
11411152
reconnection_attempts: int = -1,
11421153
reconnection_delay: float = 0.5,
1143-
reconnection_function: callable = reconnection_function
1154+
reconnection_function: callable = reconnection_function,
1155+
connection_timeout: Optional[float] = None,
11441156
):
11451157
"""Interface with a q process using the q IPC protocol.
11461158
@@ -1181,6 +1193,9 @@ def __init__(self,
11811193
`#!python reconnection_delay` on successive attempts to reconnect to the server. By
11821194
default this is an exponential backoff where the `#!python reconnection_delay` is
11831195
multiplied by two on each invocation.
1196+
connection_timeout: Timeout in seconds for connection to `q` server. If left as default
1197+
`None`, the socket will not timeout when connecting.
1198+
11841199
11851200
Note: The `#!python username` and `#!python password` parameters are not required.
11861201
The `#!python username` and `#!python password` parameters are only required if the
@@ -1247,7 +1262,9 @@ def __init__(self,
12471262
no_ctx=no_ctx,
12481263
reconnection_attempts=reconnection_attempts,
12491264
reconnection_delay=reconnection_delay,
1250-
reconnection_function=reconnection_function
1265+
reconnection_function=reconnection_function,
1266+
connection_timeout=connection_timeout,
1267+
12511268
)
12521269
super().__init__()
12531270

@@ -1453,7 +1470,9 @@ def __init__(self,
14531470
no_ctx: bool = False,
14541471
reconnection_attempts: int = -1,
14551472
reconnection_delay: float = 0.5,
1456-
reconnection_function: callable = reconnection_function
1473+
reconnection_function: callable = reconnection_function,
1474+
connection_timeout: Optional[float] = None,
1475+
14571476
):
14581477
"""Interface with a q process using the q IPC protocol.
14591478
@@ -1499,6 +1518,9 @@ def __init__(self,
14991518
`#!python reconnection_delay` on successive attempts to reconnect to the server. By
15001519
default this is an exponential backoff where the `#!python reconnection_delay` is
15011520
multiplied by two on each invocation
1521+
connection_timeout: Timeout in seconds for connection to `q` server. If left as default
1522+
`None`, the socket will not timeout when connecting.
1523+
15021524
15031525
Note: The `#!python username` and `#!python password` parameters are not required.
15041526
The `#!python username` and `#!python password` parameters are only required if
@@ -1593,6 +1615,7 @@ async def main():
15931615
'reconnection_attempts':reconnection_attempts,
15941616
'reconnection_delay': reconnection_delay,
15951617
'reconnection_function': reconnection_function,
1618+
'connection_timeout': connection_timeout,
15961619
})
15971620
object.__setattr__(self, '_initialized', False)
15981621

@@ -1613,6 +1636,7 @@ async def _async_init(self,
16131636
reconnection_attempts: int = -1,
16141637
reconnection_delay: float = 0.5,
16151638
reconnection_function: callable = reconnection_function,
1639+
connection_timeout: float = 0.0,
16161640
):
16171641
object.__setattr__(self, '_call_stack', [])
16181642
self._init(host,
@@ -1630,6 +1654,7 @@ async def _async_init(self,
16301654
reconnection_attempts=reconnection_attempts,
16311655
reconnection_delay=reconnection_delay,
16321656
reconnection_function=reconnection_function,
1657+
connection_timeout=connection_timeout,
16331658
)
16341659
object.__setattr__(self, '_loop', event_loop)
16351660
con_info = object.__getattribute__(self, '_connection_info')
@@ -1657,6 +1682,7 @@ async def _initobj(self): # nocov
16571682
reconnection_attempts=self._stored_args['reconnection_attempts'],
16581683
reconnection_delay=self._stored_args['reconnection_delay'],
16591684
reconnection_function=self._stored_args['reconnection_function'],
1685+
connection_timeout=self._stored_args['connection_timeout'],
16601686
)
16611687
return self
16621688

@@ -2055,6 +2081,7 @@ def __init__(self,
20552081
no_ctx: bool = False,
20562082
as_server: bool = False,
20572083
conn_gc_time: float = 0.0,
2084+
connection_timeout: Optional[float] = None,
20582085
):
20592086
"""Interface with a q process using the q IPC protocol.
20602087
@@ -2093,6 +2120,9 @@ def __init__(self,
20932120
going through the list of opened connections and closing any that the clients have
20942121
closed. If not set the default of 0.0 will cause any old connections to never be
20952122
closed unless `#!python self.clean_open_connections()` is manually called.
2123+
connection_timeout: Timeout in seconds for connection to `q` server. If left as default
2124+
`None`, the socket will not timeout when connecting.
2125+
20962126
20972127
Note: The `#!python username` and `#!python password` parameters are not required.
20982128
The `#!python username` and `#!python password` parameters are only required if the q
@@ -2137,7 +2167,7 @@ def __init__(self,
21372167
```
21382168
"""
21392169
if timeout > 0.0:
2140-
warnings.warn('Timeout is not supported when using AsyncQConnection objects.')
2170+
warnings.warn('Timeout is not supported when using RawQConnection objects.')
21412171
# TODO: Remove this once TLS support is fixed
21422172
if tls:
21432173
raise PyKXException('TLS is currently only supported for SyncQConnections')
@@ -2164,6 +2194,7 @@ def __init__(self,
21642194
'no_ctx': True if as_server else no_ctx,
21652195
'as_server': as_server,
21662196
'conn_gc_time': conn_gc_time,
2197+
'connection_timeout': connection_timeout,
21672198
})
21682199
object.__setattr__(self, '_initialized', False)
21692200

@@ -2182,6 +2213,7 @@ async def _async_init(self,
21822213
no_ctx: bool = False,
21832214
as_server: bool = False,
21842215
conn_gc_time: float = 0.0,
2216+
connection_timeout: Optional[float] = None,
21852217
):
21862218
object.__setattr__(self, '_call_stack', [])
21872219
object.__setattr__(self, '_send_stack', [])
@@ -2198,6 +2230,7 @@ async def _async_init(self,
21982230
no_ctx=no_ctx,
21992231
as_server=as_server,
22002232
conn_gc_time=conn_gc_time,
2233+
connection_timeout=connection_timeout,
22012234
)
22022235
object.__setattr__(self, '_loop', event_loop)
22032236
con_info = object.__getattribute__(self, '_connection_info')
@@ -2222,6 +2255,7 @@ async def _initobj(self): # nocov
22222255
no_ctx=self._stored_args['no_ctx'],
22232256
as_server=self._stored_args['as_server'],
22242257
conn_gc_time=self._stored_args['conn_gc_time'],
2258+
connection_timeout=self._stored_args['connection_timeout'],
22252259
)
22262260
return self
22272261

@@ -2788,6 +2822,7 @@ def __init__(self,
27882822
reconnection_attempts: int = -1,
27892823
reconnection_delay: float = 0.5,
27902824
reconnection_function: callable = reconnection_function,
2825+
connection_timeout: Optional[float] = None,
27912826
):
27922827
"""Interface with a q process using the q IPC protocol.
27932828
@@ -2828,6 +2863,9 @@ def __init__(self,
28282863
`#!python reconnection_delay` on successive attempts to reconnect to the server. By
28292864
default this is an exponential backoff where the `#!python reconnection_delay` is
28302865
multiplied by two on each invocation
2866+
connection_timeout: Timeout in seconds for connection to `q` server. If left as default
2867+
`None`, the socket will not timeout when connecting.
2868+
28312869
28322870
Note: The `#!python username` and `#!python password` parameters are not required.
28332871
The `#!python username` and `#!python password` parameters are only required if
@@ -2869,6 +2907,7 @@ def __init__(self,
28692907
reconnection_attempts=reconnection_attempts,
28702908
reconnection_delay=reconnection_delay,
28712909
reconnection_function=reconnection_function,
2910+
connection_timeout=connection_timeout,
28722911
)
28732912
super().__init__()
28742913

src/pykx/pykxq_m.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ EXPORT K k_pykx_init(K k_q_lib_pat, K _pykx_threading) {
157157
return (K)0;
158158
}
159159

160-
void* thread_init();
160+
void* thread_init(void* args);
161161
EXPORT K k_init_python(K x, K y, K z) {
162162
pthread_mutex_init(&head_mutex, NULL);
163163
pthread_mutex_init(&cond_mutex, NULL);

0 commit comments

Comments
 (0)