Skip to content

Loading KDB-X Modules

This page documents how to load KDB-X q modules into Python with kx.use, the QModule objects returned, and the SearchPath used to locate them.

For a guided introduction with examples of each published module, see Load KDB-X modules. For the list of available modules, see the KDB-X module index.

pykx.module

Loading KDB-X modules.

When pykx.use is called KDB-X will attempt to load a module with the given name.

QModule

QModule(qns, qdict)

A loaded KDB-X q Module.

Example loading the pq module and the pq.t submodule within KDB-X Python.

>>> import pykx as kx
>>> pq = kx.use('kx.pq')
>>> pq
pykx.QModule(pykx.q('
pq| pykx.Lambda
op| pykx.Lambda
rd| pykx.Lambda
'))
>>> len(pq)
3
>>> pq['pq']                    # a key reaches the same export as the attribute
pykx.Lambda(pykx.q('locked'))
>>> pq.t = kx.use('kx.pq.t')
>>> pq
pykx.QModule(pykx.q('
pq| pykx.Lambda
op| pykx.Lambda
rd| pykx.Lambda
t | pykx.QModule(pykx.q('
    mkT| pykx.Lambda
    mkP| pykx.Lambda
    tt | pykx.Lambda
    mt | pykx.Lambda
    fv | pykx.Lambda
    '))
'))

Assigning to an exported name writes to the module's private q namespace, which is how a module's own function or configuration variable is patched from Python:

>>> greet = kx.use('kx.greet')
>>> greet.hello = kx.q('{"Hi, ",x,"!"}')
>>> print(greet.hello(b'KDB-X'))
Hi, KDB-X!

Where no q namespace is known, as for a dictionary presented through wrap, assignment raises TypeError rather than writing somewhere else.

QNamespaceProxy

QNamespaceProxy(qns, value)

Bases: QModule

A q namespace nested inside a loaded module.

q marks a namespace with an empty-symbol key whose value is ::. A member carrying that entry is presented as one of these rather than as a pykx.Dictionary, so its own members are reachable by attribute and by key, and a write reaches the q namespace behind it where the member really is one.

>>> kafka = kx.use('kx.kafka')
>>> type(kafka.OFFSET)
<class 'pykx.module.QNamespaceProxy'>
>>> kafka.OFFSET['BEGINNING']
pykx.LongAtom(pykx.q('-2'))
>>> kafka.OFFSET.BEGINNING
pykx.LongAtom(pykx.q('-2'))

use

use(module_name, export_argument=None)

Function for loading KDB-X modules.

Parameters:

Name Type Description Default
module_name str

The name of the KDB-X module to load as a string.

required
export_argument object

Optional argument to pass to the module export function. Default None.

None

Returns:

Type Description
QModule

A loaded QModule instance.

Examples:

Example loading the pq module and the pq.t submodule within KDB-X Python.

>>> import pykx as kx
>>> from pathlib import Path
>>> pq = kx.module.use('kx.pq')
>>> pq.t = kx.module.use('kx.pq.t')
>>> tab = pq.pq(Path('../types.parquet'))
>>> tab
pykx.VirtualTable(pykx.q('`T!`f`m`t!(k){[f;t;c;b;a;v]g:$[s:-1h=@b;0;#b];(bf;b1):$[g;df[t;0,0b;b];(::;()..'))
>>> tab.select()
pykx.Table(pykx.q('
col0 col1 col2
---------------
1    1    "asd"
1    2    "bsd"
0    3    "csd"
1    4    "asd"
0    5    "bsd"
0    6    "csd"
1    7    "asd"
0    8    "bsd"
0    9    "csd"
'))

wrap

wrap(qdict)

Present a q dictionary of names as an attribute-accessible object.

Some modules expose functionality through a function which returns a dictionary rather than through their export variable. The KDB-X Logging module is one: its createLog builds an independent logger and returns it as a dictionary, whose members would otherwise have to be reached by key. wrap presents such a dictionary the way a loaded module is presented, with attribute access and dir support.

The result is not a loaded module and has no q namespace behind it, so attribute assignment raises TypeError. Use whatever setter the dictionary provides.

Parameters:

Name Type Description Default
qdict Dictionary

The q dictionary to wrap.

required

Returns:

Type Description
QModule

A QModule whose attributes are the dictionary's keys.

Raises:

Type Description
TypeError

If qdict is not a q dictionary.

Wrap a logger returned by the Logging module's createLog:

>>> import pykx as kx
>>> logger = kx.use('kx.log')
>>> log = kx.module.wrap(logger.createLog())
>>> dir(log)
['add', 'addfmt', 'debug', 'error', 'fatal', 'fmts', 'getfmt', 'getlvl', 'info',
 'remove', 'setfmt', 'setlvl', 'sinks', 'trace', 'warn']
>>> log.info(b'Hello World!')
2026.09.04D10:45:45.780488685 info PID[320523] HOST[localhost] Hello World!
>>> log.setlvl('trace')
>>> log.getfmt()
pykx.SymbolAtom(pykx.q('`basic'))

Not every entry is callable. Some are symbols naming a q variable rather than a function, and q dereferences those when they are applied. Python has no equivalent overload, so read them with kx.q.get:

>>> log.getlvl
pykx.SymbolAtom(pykx.q('`.m.kx.0log.log.1.lvl'))
>>> kx.q.get(log.getlvl)
pykx.SymbolAtom(pykx.q('`trace'))

unwrap

unwrap(module)

Recover the q dictionary behind a QModule or a QNamespaceProxy.

This is the inverse of wrap. Use it when a member has been presented as a QNamespaceProxy and you need the dictionary itself.

A q namespace is identified by an empty-symbol key whose value is ::. A dictionary can carry that same entry deliberately, as a placeholder which keeps the values a general list and stops q promoting them to a typed vector. Such a dictionary is indistinguishable from a namespace, so it is presented as a QNamespaceProxy.

Parameters:

Name Type Description Default
module Union[QModule, QNamespaceProxy]

The QModule or QNamespaceProxy to unwrap.

required

Returns:

Type Description
Dictionary

The underlying q dictionary. For a loaded module this is its export dictionary.

Raises:

Type Description
TypeError

If module is neither a QModule nor a QNamespaceProxy.

A module exporting a dictionary that uses the placeholder entry:

>>> import pykx as kx
>>> mod = kx.use('kx.mymodule')
>>> mod.opts                     # looks like a namespace, so presented as one
pykx.QNamespaceProxy(pykx.q('
headers| pykx.Dictionary
'))
>>> opts = kx.module.unwrap(mod.opts)
>>> opts['headers']
pykx.Dictionary(pykx.q('
Accept| "a"
X     | "b"
'))

A nested member reached by attribute arrives as a kx.module.QNamespaceProxy, which unwrap also accepts:

>>> kafka = kx.use('kx.kafka')
>>> type(kafka.OFFSET)
<class 'pykx.module.QNamespaceProxy'>
>>> kx.module.unwrap(kafka.OFFSET)['BEGINNING']
pykx.LongAtom(pykx.q('-2'))

SearchPath

SearchPath(
    entry=None, *, add=False, remove=False, prepend=False, strict=False, allow_duplicates=False
)

Manage the module SearchPath.

Parameters:

Name Type Description Default
entry Optional[str]

The path string to add or remove. If omitted, the current SearchPath is returned.

None
add bool

If True, add the entry to the SearchPath. Default False.

False
remove bool

If True, remove all occurrences of the entry from the SearchPath. Default False.

False
prepend bool

If True, insert the entry at the front rather than the end. Default False.

False
strict bool

If True, raise a ValueError when attempting to remove an entry that is not present. Default False.

False
allow_duplicates bool

If True, allow the same entry to appear more than once in the SearchPath. Default False.

False

Examples:

Retrieve the current SearchPath:

>>> kx.module.SearchPath()
[]

Append and prepend entries:

>>> kx.module.SearchPath("/home/user/.kx/mod", add=True)
>>> kx.module.SearchPath("/home/user/mod", add=True)
>>> kx.module.SearchPath("/other/mod", add=True, prepend=True)
>>> kx.module.SearchPath()
['/other/mod', '/home/user/.kx/mod', '/home/user/mod']

Remove an entry:

>>> kx.module.SearchPath("/other/mod", remove=True)
>>> kx.module.SearchPath()
['/home/user/.kx/mod', '/home/user/mod']