<python.builtin.ModuleNotFoundError/python.builtin.ImportError/python.builtin.Exception/python.builtin.BaseException/python.builtin.object/error/condition>
Error in `py_run_string_impl(code, local, convert)`: ModuleNotFoundError: No module named 'kuzu'
Run `reticulate::py_last_error()` for details.

skip_if_not(reticulate::py_available(), "Python not available for testing")
test_that("Connection object is created", {
test_that("Queries execute and results can be converted", {
"CREATE NODE TABLE User(name STRING, age INT64, PRIMARY KEY (name))"
kuzu_execute(conn, "CREATE (:User {name: 'Alice', age: 25})")
result <- kuzu_execute(conn, "MATCH (a:User) RETURN a.name, a.age")
test_that("Result schema functions work correctly", {
expect_equal(schema, list("a.name" = "STRING", "a.age" = "INT64"))
rm(conn, result, col_names, col_types, schema)
test_that("kuzu_get_all, kuzu_get_n, and kuzu_get_next work correctly", {
kuzu_execute(conn, "CREATE (:User {name: 'Bob', age: 30})")
kuzu_execute(conn, "CREATE (:User {name: 'Charlie', age: 35})")
"MATCH (a:User) RETURN a.name, a.age ORDER BY a.name"
# Test kuzu_get_n (needs a fresh result object)
# Test kuzu_get_next (needs a fresh result object)
expect_false(result_next$has_next()) # No more rows

"Queries execute and results can be converted"
"CREATE (:User {name: 'Alice', age: 25})"
"Result schema functions work correctly"
"kuzu_get_all, kuzu_get_n, and kuzu_get_next work correctly"
"CREATE (:User {name: 'Charlie', age: 35})"

Queries execute and results can be converted

kuzu_get_all, kuzu_get_n, and kuzu_get_next work correctly

test_that("kuzu_copy_from_df works for node and rel tables", {
"CREATE NODE TABLE Product(id INT64, name STRING, PRIMARY KEY (id))"
products_df <- data.frame(id = c(1, 2), name = c("Laptop", "Mouse"))
"MATCH (p:Product) RETURN p.id, p.name ORDER BY p.id"
"CREATE NODE TABLE Person(name STRING, PRIMARY KEY (name))"
"CREATE REL TABLE Follows(FROM Person TO Person, since INT64)"
persons_df <- data.frame(name = c("Alice", "Bob"))
"MATCH (a:Person)-[f:Follows]->(b:Person) RETURN a.name, b.name, f.since"
test_that("kuzu_copy_from_df handles various data types", {
# Create table with various Kuzu data types
# Create a data frame with corresponding R data types
stringsAsFactors = FALSE # Ensure strings are not converted to factors
paste("MATCH (m:MixedTypes) RETURN m.id, m.name, m.is_active, m.value,",
"m.amount, m.event_date, m.timestamp, m.price, m.price2,m.int8_col,",
"m.int16_col, m.int32_col, m.int128_col, m.uint8_col, m.uint16_col,",
expect_equal(df_check$m.name, c("Test Item", "Another Item"))
# Format both actual and expected to UTC strings for a robust comparison
format(df_check$m.timestamp, tz = "UTC", format = "%Y-%m-%d %H:%M:%S"),
format(expected_timestamps_df, tz = "UTC", format = "%Y-%m-%d %H:%M:%S")
test_that("kuzu_copy_from_df handles empty data frames", {
"CREATE NODE TABLE EmptyTestTable(col1 STRING, PRIMARY KEY (col1))"
empty_df <- data.frame(col1 = character(0))
# Query and verify that the table is empty
result <- kuzu_execute(conn, "MATCH (e:EmptyTestTable) RETURN count(e)")
# Test with a table that has multiple columns
paste("CREATE NODE TABLE AnotherEmptyTable(id INT64, name STRING, ",
empty_df_multi <- data.frame(id = integer(0), name = character(0))
test_that("kuzu_merge_df works for insertion and update", {
paste("CREATE NODE TABLE Person(name STRING, current_city STRING, age",
kuzu_copy_from_df(conn, df = initial_data, table_name = "Person")
"MATCH (p:Person) RETURN p.name, p.current_city, p.age ORDER BY p.name"
name = c("Alice", "Charlie"), # Alice to be updated, Charlie to be inserted
current_city = c("Los Angeles", "Paris"),
merge_statement_update <- "MERGE (p:Person {name: name})
ON MATCH SET p.current_city = current_city, p.age = age
ON CREATE SET p.current_city = current_city, p.age = age"
kuzu_merge_df(conn, df = update_data, merge_statement_update)
expect_equal(nrow(df_update), 3) # Alice, Bob, Charlie
expect_equal(df_update$p.current_city, c("Los Angeles", "London", "Paris"))
test_that("kuzu_copy_from_csv loads data correctly", {
# Create table with corresponding Kuzu data types
paste("MATCH (c:CsvLoadedTypes) RETURN c.id, c.name, c.is_active, c.value,",
"c.amount, c.event_date, c.timestamp, c.price ORDER BY c.id")
expect_equal(df_check$c.name, c("Test Item", "Another Item"))
format(df_check$c.timestamp, tz = "UTC", format = "%Y-%m-%d %H:%M:%S"),
format(expected_timestamps_csv, tz = "UTC", format = "%Y-%m-%d %H:%M:%S")
# Helper to create a temporary JSON file
create_temp_json <- function(file_path, content) {
test_that("kuzu_copy_from_json loads data correctly", {
# Create a JSON file with an array of objects
{"id": 101, "name": "JSON Item 1", "is_active": true, "value": 5.5},
{"id": 102, "name": "JSON Item 2", "is_active": false, "value": 10.1}
paste("MATCH (j:JsonLoadedTable) RETURN j.id, j.name, j.is_active, j.value",
expect_equal(df_check$j.name, c("JSON Item 1", "JSON Item 2"))
test_that("kuzu_copy_from_json handles empty JSON files", {
# Create an empty JSON file (empty array)
"CREATE NODE TABLE EmptyJsonTable(id INT64, name STRING, PRIMARY KEY (id))"
result <- kuzu_execute(conn, "MATCH (e:EmptyJsonTable) RETURN count(e)")
test_that("kuzu handles data types DECIMAL and UUID", {
"MATCH (m:MixedTypes) RETURN m.id, m.price, m.uuid_col ORDER BY m.id"