Changelog¶
All notable changes to Rayforce-Py will be documented in this file.
You can also subscribe for release notifications by joining our Zulip!
2.3.0¶
Improvements¶
- Rebuilt against Rayforce C core
v2.8.0, up from the2.5.xline2.2.1shipped with. The core is now pinned by tag —RAYFORCE_REF(defaultv2.8.0) in theMakefileandscripts/prepare_build.sh, next to the existingRAYFORCE_Q_REF— so a wheel is built from a known core rather than from whatevermasterholds on release day. Engine highlights since2.5.x: a groupedselectthat matches no row keeps every aggregate and literal projection column; every sort path keeps equal keys in source order, andpivotemits rows and columns in first-seen order; groupedvar/stddevare computed numerically stably andpearson_corris null when a side has no variance;count (distinct …)accepts a symbol-vectorby:; the key map a keyedupsertbuilds is kept on the table and maintained across in-place writes, and a new in-placedeletekeeps it too; integer partitions of a parted table are ordered by value;.ipc.opentakes an options dict with acompressthreshold and loopback links are never compressed; plus a broad grouped-aggregate performance sweep. See the core release notes forv2.6.0throughv2.8.0. TCPServerruns on the core's poll-based IPC server. The legacy blocking server API the extension used was removed from the core inv2.8.0; the server now owns a dedicated core poll with an IPC listener registered on it and drives it in bounded passes. The Python API and its blocking, interruptiblelisten()loop are unchanged.
Notes¶
- Empty symbols are nulls. Since core
v2.6.0the engine recognises in-band nulls at construction and treats the empty symbol and the empty string as their types' nulls. Reading such an element out of aSymbolVector(v[i],to_python()) or aTablerow now yieldsNullwhere it used to yieldSymbol(""). Atoms are unaffected:Symbol("").valueis still"", andString("")still round-trips as"".
2.2.1¶
Bug fixes¶
Table.drop()no longer reorders the surviving columns. The columns left behind now keep the order they had before the drop. (#19)- SQL
SELECT DISTINCTnow deduplicates instead of returning every matching row. (#20) - SQL
WHEREclauses accept a literal on the left of a comparison.WHERE 100 < pricenow compiles the same asWHERE price > 100; previously the literal-on-left form produced a broken query. (#23) - Unsigned integer columns no longer wrap to negative values. The
PyArrow plugin was sign-flipping
uint16/uint32/uint64values, and the Pandas and Polars converters had the same gap. All three now widen an unsigned column to the next signed width, so the values survive the conversion.uint64has no lossless target and still maps toI64. (#18, #22) - Raw vector readers reject nulls and atoms rather than reading past the object header. (#21)
Notes¶
- Out-of-range date strings now raise instead of rolling over. Rebuilding
against the current Rayforce C core picks up bounds validation in the
DATEstring cast, soDate("2025-02-30"),Date("2023-02-29")andDate("2025-13-01")raise rather than silently normalizing into the following month. Valid dates, including leap days such asDate("2024-02-29"), are unaffected.
2.2.0¶
New Features¶
- Q connection authentication and connect timeout.
KDBEnginenow acceptsuser,password, andtimeout_msarguments. Credentials are sent during the Q login handshake, andtimeout_msbounds the connect attempt. Both default to off, so existing code is unaffected.
Improvements¶
- Q client rebuilt on the shared
rayforce-qcore. The Q wire-format implementation moved out of the Python extension into the standalone, language-neutralrayforce-qC library (pinned tov2.0.0), shared across Rayforce language bindings. The blocking network round-trip now releases the GIL, so other Python threads keep running while a query is in flight, and KDB+ dictionaries decode natively.
2.1.1¶
New Features¶
- Rebuilt against the latest Rayforce C core, picking up a batch of engine
fixes and improvements. Highlights: new partitioned-store helpers
(
.db.parted.fill,.db.parted.tables) and journal.log.purge; an.ipc.openconnect timeout plus fixes forlocalhost/ lazy-result IPC hangs; and a broad reliability sweep (silent-failure hardening, durable column-store format versioning, and a worker-heap teardown crash fix).
2026-06-24 | 🔗 PyPI | 🔗 GitHub
2.1.0¶
New Features¶
- Restored WebSocket support. The
WSClient/WSServerclasses and therayforce.network.websocketmodule are back (they were removed in2.0.0). The server is an async Python implementation, built on thewebsocketslibrary, that evaluates Rayforce queries in-process. Install with thewebsocketextra (pip install rayforce-py[websocket]). See the WebSocket guide. - Added the PyArrow plugin.
from_arrow()converts apyarrow.Tableinto a RayforceTable, mirroring the Polars / Pandas plugins. A column of strings maps toStringby default, or toSymbolvia the opt-instrings_as_symbols=Trueflag. Requires theparquetextra (pip install rayforce-py[parquet]).
Bug fixes¶
- Fixed mis-scaled Parquet timestamps.
load_parquet()now reads microsecond- and millisecond-precision timestamp columns at the correct precision; previously non-nanosecond units were mis-scaled. Parquet reading now shares the PyArrow plugin's conversion path.
2026-06-19 | 🔗 PyPI | 🔗 GitHub
2.0.2¶
New Features¶
- Added the
ungroupverb.Table.ungroup()flattens nestedLISTcolumns into row form — each list cell expands to one row, with atom columns replicated per element (the inverse of aby-grouping). Also available as a deferred step on select queries:t.select(...).by(...).ungroup().execute().
Bug fixes¶
- Fixed a bug when the Timestamp type didn't account for TZ offset when using from_csv handler
2026-06-18 | 🔗 PyPI | 🔗 GitHub
2.0.1¶
Bug Fixes¶
Fix Type error when attempting to insert/upsert into an empty table.
2026-06-17 | 🔗 PyPI | 🔗 GitHub
2.0.0¶
First release against the Rayforce v2 C core. This is a major release with
breaking changes to the type system, the network layer, and the plugin surface.
The 1.0.x line continues to be maintained against the v1 core.
Breaking Changes¶
- Built against the Rayforce v2 C core. The bundled engine, build pipeline
(
make app), and binary protocol all target v2. Code written against the v1 core may need updates — see the items below. - Removed the
C8/Chartype. v2 has no standalone character type; a single character is now a length-1String.C8is no longer importable fromrayforce. - Removed WebSocket support. The
WSClient/WSServerclasses and the entirerayforce.network.websocketmodule have been removed. Use TCP IPC (TCPClient/TCPServer) for networked queries. - Renamed the KDB+ plugin.
rayforce.plugins.raykxis nowrayforce.plugins.kdb; importKDBEnginefrom the new path. - Renumbered scalar type codes to match the v2 core. Atoms use the negative of these values (see the Data Types overview):
| Type | v1 code | v2 code |
|---|---|---|
Symbol |
6 | 12 |
F64 |
10 | 7 |
Date |
7 | 8 |
Time |
8 | 9 |
Timestamp |
9 | 10 |
String |
— | 13 |
F32 |
— | 6 |
New Features¶
- Added the
F32(32-bit floating-point) type. Arithmetic onF32promotes toF64. - Added the
RayforceLimitErrorexception class (coreEC_LIMIT).
Notes¶
Stringis now a first-class type (no longer modeled as a vector ofC8).
2026-06-12 | 🔗 PyPI | 🔗 GitHub
1.0.0¶
- Project has came out of beta. Stable release
2026-04-20 | 🔗 PyPI | 🔗 GitHub
0.6.3¶
Bug Fixes¶
- Integer null sentinel handling: I16, I32, and I64 scalars now correctly recognize null sentinels (
0Nh,0Ni,0Nj) and returnNonefromto_python(). This fixes null comparisons in operations where unmatched rows returned raw sentinel values (e.g.,-9223372036854775808) instead ofNone.
2026-04-15 | 🔗 PyPI | 🔗 GitHub
0.6.2¶
Bug Fixes¶
- Now library passes correct contiguous numpy arrays within
from_numpyfunction - F64 vectors can now be used in
mediancalculations
2026-03-15 | 🔗 PyPI | 🔗 GitHub
0.6.1¶
New Features¶
-
Fancy indexing for Tables:
Table.__getitem__now supports multiple indexing modes beyond column access:- Expression filter:
table[Column("age") > 35]— filter rows by condition. Supports&(and) and|(or) for combining expressions. - Integer row access:
table[0],table[-1]— access a single row by index, returns a Dict. - Slicing:
table[1:3],table[:5],table[-2:]— row slicing backed by the C-levelTAKEoperation. - Index list:
table[[0, 2, 5]]— select specific rows by position.
- Expression filter:
-
Vector.from_numpy()auto-widening: Unsupported numpy dtypes are now automatically widened to the nearest supported type:float32/float16→F64,int8→I16,uint16→I32,uint32→I64. -
Vector.from_numpy()bytes and UUID support: Byte string arrays (dtype='S') are automatically decoded to Symbol vectors. Object arrays ofuuid.UUIDvalues are detected and converted to GUID vectors. -
NaT preservation:
NaT(Not-a-Time) values in numpydatetime64andtimedelta64arrays now survive round-trips throughVector.from_numpy()andVector.to_numpy().
Bug Fixes¶
-
Table.to_numpy()with Timestamp columns: FixedDTypePromotionErrorwhen callingto_numpy()on tables containing a mix of incompatible column types (e.g., integers, strings, and timestamps). Mixed-type tables now gracefully fall back toobjectdtype. -
Filtering F64 by distinct - fixed
-
Vector.__getitem__for U8 vectors: Fixed U8 vector elements being returned asB8(True/False)instead ofU8(value). Both types are 1-byte, causing the C-levelat_idxto misinterpret the type. -
Vector.from_numpy()with explicitray_typefor temporal arrays: FixedValueError: cannot include dtype 'M' in a bufferwhen passingray_type=Timestamp,ray_type=Date, orray_type=Timewith datetime64/timedelta64 arrays.
2026-03-03 | 🔗 PyPI | 🔗 GitHub
0.6.0¶
New Features¶
-
Vector.from_numpy()classmethod: Create vectors from NumPy arrays via bulk memory copy. Supports numeric types (int16,int32,int64,float64,uint8,bool), string arrays, and temporal types (datetime64→Timestamp/Date,timedelta64→Time). Handles epoch adjustment between NumPy (1970-01-01) and Rayforce (2000-01-01) automatically. -
Vector.to_numpy()method: Export vector data to a NumPy array via bulk memory copy. -
Vector.to_list()method: Export vector data to a Python list via bulk memory copy from the underlying C buffer. -
Table.from_dict()classmethod: Create tables from a dictionary of NumPy arrays, Python lists, or Vectors. -
Table.to_dict()method: Export table data to a Python dictionary of lists via bulk memory copy. -
Table.to_numpy()method: Export table data to a 2D NumPy array via bulk memory copy. -
select("*", col=value)fix: Using"*"with computed columns inselect()now correctly preserves all existing columns
Dependencies¶
- NumPy (
>=2.0.0) is now a required dependency.
2026-02-21 | 🔗 PyPI | 🔗 GitHub
0.5.11¶
New Features¶
-
Timestamp.shift_tz()method: Shift aTimestampvalue by a timezone offset. Accepts anydatetime.tzinfo(includingdatetime.timezoneandzoneinfo.ZoneInfo). -
Column.shift_tz()for queries: Shift an entire column of timestamps by a timezone offset withinselect()expressions.
2026-02-19 | 🔗 PyPI | 🔗 GitHub
0.5.10¶
Bug Fixes¶
- Various bugfixes to the database operations
2026-02-11 | 🔗 PyPI | 🔗 GitHub
0.5.9¶
Bug Fixes¶
- Fix boolean operator
is_performed over lists and vectors within table aggregations
2026-02-11 | 🔗 PyPI | 🔗 GitHub
0.5.8¶
Bug Fixes¶
- Fix type conversion error during upsert operation
2026-02-10 | 🔗 PyPI | 🔗 GitHub
0.5.7¶
Bug Fixes¶
- Fix boolean operator
is_performed over lists within table aggregations
2026-02-10 | 🔗 PyPI | 🔗 GitHub
0.5.6¶
Bug Fixes¶
- Fix sorting for symbol vectors larger than 32 elements
2026-01-29 | 🔗 PyPI | 🔗 GitHub
0.5.5¶
Breaking Changes¶
- SQLQuery API changed:
SQLQuerynow accepts aTableobject instead of a table name string. Update calls fromSQLQuery("table_name", query)toSQLQuery(Table("table_name"), query).
Bug Fixes¶
- Division operators fixed: Fixed
__truediv__(/) and__floordiv__(//) being incorrectly swapped for scalars and vectors. - Sorting MAPCOMMON columns: Fixed issue when tables containing MAPCOMMON columns were sorted incorrectly.
2026-01-28 | 🔗 PyPI | 🔗 GitHub
0.5.4¶
New Features¶
- SQL over IPC: Send SQL queries to remote Rayforce servers via TCP or WebSocket using the new
SQLQueryclass. Documentation
2026-01-17 | 🔗 PyPI | 🔗 GitHub
0.5.3¶
New Features¶
-
SQL Query Support: Query tables using familiar SQL syntax with the new
Table.sql()method. SupportsSELECT,UPDATE,INSERT, andUPSERT(viaON CONFLICT) statements. Requires optionalsqlglotdependency. See SQL documentation for details. -
Vector type inference:
Vectornow automatically infers the element type from the first item whenray_typeis not specified.
2026-01-17 | 🔗 PyPI | 🔗 GitHub
0.5.2¶
New Features¶
-
Vector operations: Added operations for Vector types including arithmetic (
+,-,*,/), comparison (<,<=,>,>=,eq,ne), logical (and_,or_,not_), aggregation (sum,min,max,average), element access (first,last,take,at), set operations (union,sect,except_), search (find,within,filter), sort (asc,desc,iasc,rank,reverse,negate), and functional (map). -
Dict operations: Added key/value access (
key,value) and sort operations (asc,desc) for Dict types. -
Scalar operations: Added arithmetic, comparison, and math operations (
ceil,floor,round) for numeric scalar types (I16, I32, I64, F64).
2026-01-16 | 🔗 PyPI | 🔗 GitHub
0.5.1¶
New Features¶
pivot()method: Reshape data from long to wide format. Supports multiple index columns and aggregation functions (sum,count,avg,min,max,first,last). See Pivot documentation for details.
2026-01-16 | 🔗 PyPI | 🔗 GitHub
0.5.0¶
Breaking Changes¶
-
slice()renamed totake(): Theslice(start_idx, tail)method has been renamed totake(n, offset=0)with a cleaner signature. -
match_by_firstrenamed tokey_columns: Inupsert(), the parametermatch_by_firsthas been renamed tokey_columnsfor clarity. -
Table.from_partednow acceptsnameinstead ofsymfileargument. -
Sorting API changed:
xasc()andxdesc()methods have been replaced withorder_by(*cols, desc=False)which returns a query that must be executed. This allows chaining with other query operations. See Order By documentation.
New Features¶
-
Bracket notation access: Access columns using
table["col"]for a single column ortable[["col1", "col2"]]for multiple columns. -
shape(): method returns(rows, cols)to see table shape -
len()support: Get row count withlen(table). -
head()andtail()methods: Get first/last n rows withtable.head(5)ortable.tail(5). -
describe()method: Get summary statistics (count, mean, min, max) for numeric columns. -
dtypesproperty: Get column types as a dictionary withtable.dtypes. -
drop()method: Remove columns withtable.drop("col1", "col2"). See Transform documentation. -
rename()method: Rename columns withtable.rename({"old": "new"}). See Transform documentation. -
cast()method: Change column types withtable.cast("col", I64). See Transform documentation. -
Chainable
order_by(): Sort results as part of query chain:table.select(...).where(...).order_by("col").execute().
Bug fixes¶
- Fix issue when applying a boolean vector filter for a table.
2026-01-15 | 🔗 PyPI | 🔗 GitHub
0.4.3¶
New Features¶
- Apache Parquet Support (Beta): Added
load_parquet()function to read Parquet files directly into Rayforce Tables. Uses PyArrow for efficient zero-copy data access where possible. See Parquet documentation for details.
2026-01-14 | 🔗 PyPI | 🔗 GitHub
0.4.2¶
Bug fixes¶
- Fix CI/CD Makefile patch for manylinux container CPU flags
2026-01-14 | 🔗 PyPI | 🔗 GitHub
0.4.0¶
Breaking Changes¶
-
Network module restructuring: IPC classes (
IPCClient,IPCConnection,IPCServer) have been removed from the main package exports and replaced with TCP classes (TCPClient,TCPServer). The IPC functionality has been reorganized into therayforce.networkmodule. -
Error class renamed:
RayforceIPCErrorhas been removed and replaced withRayforceTCPErrorfor network-related errors. -
Table initialization API changed:
Table.from_dict()andTable.from_name()methods are removed. Use Table(dict/str) constructor directly instead.
New Features¶
- Added WebSocket support: New
WSClientandWSServerclasses in therayforce.network.websocketmodule for WebSocket-based communication. - Added TCP client/server: New
TCPClientandTCPServerclasses inrayforce.network.tcpmodule exported from the main package. - Added
asof_join()method toTableclass for as-of joins (time-based joins). See Joins documentation for details. - Added
ipcsave()method toTableand query objects (SelectQuery,UpdateQuery,InsertQuery,UpsertQuery,LeftJoin,InnerJoin,AsofJoin,WindowJoin) for saving query results in IPC connections.
2026-01-08 | 🔗 PyPI | 🔗 GitHub
0.3.1¶
- Improve client-side IPC by allowing sending pythonic queries into the IPC connection https://py.rayforcedb.com/content/documentation/IPC.html#sending-query-objects
2026-01-04 | 🔗 PyPI | 🔗 GitHub
0.3.0¶
- Add server-side IPC - initializing a Rayforce server via Python runtime
- Improve IPC Client-side interface
2026-01-03 | 🔗 PyPI | 🔗 GitHub
0.2.2¶
- Better C API error handling
- Performance improvements for initializing RF types from python collections (List, Vector, Table)
2026-01-02 | 🔗 PyPI | 🔗 GitHub
0.2.1¶
- C API speedup improvements
- Add thread-safety block to disallow calling runtime from multiple threads
2025-12-28 | 🔗 PyPI | 🔗 GitHub
0.2.0¶
- Enhanced error handling
- Core speedup improvements
2025-12-28 | 🔗 PyPI | 🔗 GitHub
0.1.5¶
- Added
slice()method to Table for extracting subsets of rows (renamed totake()in 0.4.4)