Skip to content

Commit

Permalink
pantab 4.0 with C++/nanobind and friends
Browse files Browse the repository at this point in the history
  • Loading branch information
WillAyd committed Jan 8, 2024
1 parent f91465c commit 505ddeb
Show file tree
Hide file tree
Showing 25 changed files with 850 additions and 1,806 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
.mypy_cache
*.hyper
hyper_db*
compile_commands.json

#########################################
# Editor temporary/working/backup files #
Expand Down
35 changes: 35 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
project(pantab)

cmake_minimum_required(VERSION 3.18)
find_package(Python COMPONENTS Interpreter Development.Module NumPy REQUIRED)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++20 -Wall")

if (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build." FORCE)
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
endif()

# Detect the installed nanobind package and import it into CMake
execute_process(
COMMAND "${Python_EXECUTABLE}" -m nanobind --cmake_dir
OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE NB_DIR)
list(APPEND CMAKE_PREFIX_PATH "${NB_DIR}")
find_package(nanobind CONFIG REQUIRED)

include(FetchContent)
FetchContent_Declare(
tableauhyperapi-cxx
FIND_PACKAGE_ARGS NAMES Tableau
URL "https://downloads.tableau.com/tssoftware/tableauhyperapi-cxx-linux-x86_64-release-main.0.0.18369.r86e960ca.zip"
)

FetchContent_MakeAvailable(tableauhyperapi-cxx)
list(APPEND CMAKE_PREFIX_PATH "${tableauhyperapi-cxx_SOURCE_DIR}/share/cmake")
find_package(tableauhyperapi-cxx CONFIG REQUIRED)

if (PANTAB_USE_SANITIZERS)
add_compile_options(-fsanitize=address -fsanitize=undefined)
add_link_options(-fsanitize=address -fsanitize=undefined)
endif()

add_subdirectory(pantab/src)
3 changes: 2 additions & 1 deletion environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@ dependencies:
- black
- flake8
- isort
- meson-python
- mypy
- nanobind
- pandas
- pip
- pyarrow
- python
- pytest
- scikit-build-core
- sphinx
- pre-commit
- sphinx_rtd_theme
Expand Down
33 changes: 0 additions & 33 deletions meson.build

This file was deleted.

113 changes: 1 addition & 112 deletions pantab/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
__version__ = "3.0.3"
__version__ = "4.0.0"

import libpantab # type: ignore
from tableauhyperapi import __version__ as hyperapi_version

from ._reader import frame_from_hyper, frame_from_hyper_query, frames_from_hyper
from ._tester import test
Expand All @@ -16,112 +14,3 @@
"frames_to_hyper",
"test",
]

# We link against HyperAPI in a fun way: In Python, we extract the function
# pointers directly from the Python HyperAPI. We pass those function pointers
# over to the C module which will then use those pointers to directly interact
# with HyperAPI. Furthermore, we check the function signatures to guard
# against API-breaking changes in HyperAPI.
#
# Directly using HyperAPI's C functions always was and still is discouraged and
# unsupported by Tableu. In particular, Tableau will not be able to provide
# official support for this hack.
#
# Because this is highly brittle, we try to make the error message as
# actionable as possible and guide users in the right direction.

api_incompatibility_msg = """
pantab is incompatible with version {} of Tableau Hyper API. Please upgrade
both `tableauhyperapi` and `pantab` to the latest version. See also
https://pantab.readthedocs.io/en/latest/caveats.html#tableauhyperapi-compatability
""".format(
hyperapi_version
)

try:
from tableauhyperapi.impl.dll import ffi, lib
except ImportError as e:
raise NotImplementedError(api_incompatibility_msg) from e


def _check_compatibility(check, message):
if not check:
raise NotImplementedError(message + "\n" + api_incompatibility_msg)


def _get_hapi_function(name, sig):
_check_compatibility(hasattr(lib, name), f"function '{name}' missing")
f = getattr(lib, name)
func_type = ffi.typeof(f)
_check_compatibility(
func_type.kind == "function",
f"expected '{name}' to be a function, got {func_type.kind}",
)
_check_compatibility(
func_type.cname == sig,
f"expected '{name}' to have the signature '{sig}', got '{func_type.cname}'",
)
return f


libpantab.load_hapi_functions(
_get_hapi_function("hyper_decode_date", "hyper_date_components_t(*)(uint32_t)"),
_get_hapi_function("hyper_encode_date", "uint32_t(*)(hyper_date_components_t)"),
_get_hapi_function("hyper_decode_time", "hyper_time_components_t(*)(uint64_t)"),
_get_hapi_function("hyper_encode_time", "uint64_t(*)(hyper_time_components_t)"),
_get_hapi_function(
"hyper_inserter_buffer_add_null",
"struct hyper_error_t *(*)(struct hyper_inserter_buffer_t *)",
),
_get_hapi_function(
"hyper_inserter_buffer_add_bool",
"struct hyper_error_t *(*)(struct hyper_inserter_buffer_t *, _Bool)",
),
_get_hapi_function(
"hyper_inserter_buffer_add_int16",
"struct hyper_error_t *(*)(struct hyper_inserter_buffer_t *, int16_t)",
),
_get_hapi_function(
"hyper_inserter_buffer_add_int32",
"struct hyper_error_t *(*)(struct hyper_inserter_buffer_t *, int32_t)",
),
_get_hapi_function(
"hyper_inserter_buffer_add_int64",
"struct hyper_error_t *(*)(struct hyper_inserter_buffer_t *, int64_t)",
),
_get_hapi_function(
"hyper_inserter_buffer_add_double",
"struct hyper_error_t *(*)(struct hyper_inserter_buffer_t *, double)",
),
_get_hapi_function(
"hyper_inserter_buffer_add_binary",
(
"struct hyper_error_t *(*)"
"(struct hyper_inserter_buffer_t *, uint8_t *, size_t)"
),
),
_get_hapi_function(
"hyper_inserter_buffer_add_raw",
(
"struct hyper_error_t *(*)(struct hyper_inserter_buffer_t *"
", uint8_t *, size_t)"
),
),
_get_hapi_function(
"hyper_rowset_get_next_chunk",
(
"struct hyper_error_t *(*)(struct hyper_rowset_t *"
", struct hyper_rowset_chunk_t * *)"
),
),
_get_hapi_function(
"hyper_destroy_rowset_chunk", "void(*)(struct hyper_rowset_chunk_t *)"
),
_get_hapi_function(
"hyper_rowset_chunk_field_values",
(
"void(*)(struct hyper_rowset_chunk_t *"
", size_t *, size_t *, uint8_t * * *, size_t * *)"
),
),
)
Loading

0 comments on commit 505ddeb

Please sign in to comment.