Skip to content

Commit 998634e

Browse files
Merge branch 'wjakob:master' into master
2 parents 1769537 + 892dd81 commit 998634e

12 files changed

Lines changed: 88 additions & 12 deletions

cmake/nanobind-config.cmake

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -246,15 +246,20 @@ function (nanobind_build_library TARGET_NAME)
246246
# However, if the directory _does_ exist, then the user is free to choose
247247
# whether nanobind uses them (based on `NB_USE_SUBMODULE_DEPS`), with a
248248
# preference to choose them if `NB_USE_SUBMODULE_DEPS` is not defined
249-
if (NOT IS_DIRECTORY ${NB_DIR}/ext/robin_map/include OR
250-
(DEFINED NB_USE_SUBMODULE_DEPS AND NOT NB_USE_SUBMODULE_DEPS))
249+
if(IS_DIRECTORY ${NB_DIR}/ext/robin_map/include
250+
AND (DEFINED NB_USE_SUBMODULE_DEPS AND NB_USE_SUBMODULE_DEPS)
251+
AND NOT TARGET tsl::robin_map
252+
)
253+
add_library(tsl::robin_map INTERFACE IMPORTED)
254+
set_target_properties(tsl::robin_map PROPERTIES
255+
INTERFACE_INCLUDE_DIRECTORIES ${NB_DIR}/ext/robin_map/include)
256+
endif()
257+
258+
if(NOT TARGET tsl::robin_map)
251259
include(CMakeFindDependencyMacro)
252-
find_dependency(tsl-robin-map)
253-
target_link_libraries(${TARGET_NAME} PRIVATE tsl::robin_map)
254-
else()
255-
target_include_directories(${TARGET_NAME} PRIVATE
256-
${NB_DIR}/ext/robin_map/include)
260+
find_dependency(tsl-robin-map CONFIG REQUIRED)
257261
endif()
262+
target_link_libraries(${TARGET_NAME} PRIVATE tsl::robin_map)
258263

259264
target_include_directories(${TARGET_NAME} ${AS_SYSINCLUDE} PUBLIC
260265
${Python_INCLUDE_DIRS}
@@ -352,7 +357,7 @@ function(nanobind_add_module name)
352357
set(ARG_STABLE_ABI FALSE)
353358
endif()
354359

355-
if (NB_ABI MATCHES "t")
360+
if (NB_ABI MATCHES "[0-9]t")
356361
# Free-threaded Python interpreters don't support building a nanobind
357362
# module that uses the stable ABI.
358363
set(ARG_STABLE_ABI FALSE)

docs/typing.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -714,6 +714,6 @@ you may use the special ``\from`` escape code to import them:
714714
def lookup(array: Array[T], index: Literal[0] = 0) -> _Opt[T]:
715715
\doc
716716
717-
You may also add free-form text the beginning or the end of the generated stub.
718-
To do so, add an entry that matches on ``module_name.__prefix__`` or
719-
``module_name.__suffix__``.
717+
You may also add free-form text the beginning or the end of the generated stub
718+
module or of a class. To do so, add an entry that matches on ``name.__prefix__``
719+
or ``name.__suffix__`` where ``name`` is the name of the module or class.

include/nanobind/nanobind.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
// Core C++ headers that nanobind depends on
3030
#include <cstddef>
3131
#include <cstdint>
32+
#include <cstdlib>
3233
#include <exception>
3334
#include <stdexcept>
3435
#include <type_traits>

include/nanobind/trampoline.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ NB_CORE void trampoline_leave(ticket *ticket) noexcept;
2626
template <size_t Size> struct trampoline {
2727
mutable void *data[2 * Size + 1];
2828

29-
NB_INLINE trampoline(void *ptr) { trampoline_new(data, Size, ptr); }
29+
NB_INLINE constexpr trampoline(void *ptr) { trampoline_new(data, Size, ptr); }
3030
NB_INLINE ~trampoline() { trampoline_release(data, Size); }
3131

3232
NB_INLINE handle base() const { return (PyObject *) data[0]; }

src/common.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -451,13 +451,23 @@ void setattr(PyObject *obj, PyObject *key, PyObject *value) {
451451
}
452452

453453
void delattr(PyObject *obj, const char *key) {
454+
#if defined(Py_LIMITED_API) && PY_LIMITED_API < 0x030D0000
455+
int rv = PyObject_SetAttrString(obj, key, nullptr);
456+
#else
454457
int rv = PyObject_DelAttrString(obj, key);
458+
#endif
459+
455460
if (rv)
456461
raise_python_error();
457462
}
458463

459464
void delattr(PyObject *obj, PyObject *key) {
465+
#if defined(Py_LIMITED_API) && PY_LIMITED_API < 0x030D0000
466+
int rv = PyObject_SetAttr(obj, key, nullptr);
467+
#else
460468
int rv = PyObject_DelAttr(obj, key);
469+
#endif
470+
461471
if (rv)
462472
raise_python_error();
463473
}

src/nb_ndarray.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -704,6 +704,9 @@ ndarray_handle *ndarray_import(PyObject *src, const ndarray_config *c,
704704
case (uint8_t) dlpack::dtype_code::Float:
705705
prefix = "float";
706706
break;
707+
case (uint8_t) dlpack::dtype_code::Bfloat:
708+
prefix = "bfloat";
709+
break;
707710
case (uint8_t) dlpack::dtype_code::Complex:
708711
prefix = "complex";
709712
break;

src/stubgen.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -567,8 +567,10 @@ def put_type(self, tp: NbType, name: Optional[str]):
567567
self.put_docstr(docstr)
568568
if len(tp_dict):
569569
self.write("\n")
570+
self.apply_pattern(self.prefix + ".__prefix__", None)
570571
for k, v in tp_dict.items():
571572
self.put(v, k, tp)
573+
self.apply_pattern(self.prefix + ".__suffix__", None)
572574
if output_len == len(self.output):
573575
self.write_ln("pass\n")
574576
self.depth -= 1

tests/pattern_file.nb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,9 @@ test_typing_ext.__prefix__:
1717

1818
test_typing_ext.__suffix__:
1919
# a suffix
20+
21+
test_typing_ext.Foo.__prefix__:
22+
# a class prefix
23+
24+
test_typing_ext.Foo.__suffix__:
25+
# a class suffix

tests/test_classes.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -747,4 +747,34 @@ NB_MODULE(test_classes_ext, m) {
747747
.def_prop_ro_static("x", [](nb::handle /*unused*/) { return 42; });
748748
nb::class_<StaticPropertyOverride2, StaticPropertyOverride>(m, "StaticPropertyOverride2")
749749
.def_prop_ro_static("x", [](nb::handle /*unused*/) { return 43; });
750+
751+
752+
// nanobind::detail::trampoline's constructor must be constexpr otherwise
753+
// the trampoline will not compile under MSVC
754+
struct ConstexprClass {
755+
constexpr ConstexprClass(int i) : something(i) {}
756+
virtual ~ConstexprClass() = default;
757+
758+
virtual int getInt() const {
759+
return 1;
760+
};
761+
762+
int something;
763+
};
764+
765+
struct PyConstexprClass : ConstexprClass {
766+
NB_TRAMPOLINE(ConstexprClass, 1);
767+
768+
int getInt() const override {
769+
NB_OVERRIDE(getInt);
770+
}
771+
};
772+
773+
auto constexpr_class = nb::class_<ConstexprClass, PyConstexprClass>(m, "ConstexprClass")
774+
.def(nb::init<int>())
775+
.def("getInt", &ConstexprClass::getInt);
776+
777+
m.def("constexpr_call_getInt", [](ConstexprClass *c) {
778+
return c->getInt();
779+
});
750780
}

tests/test_classes.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -981,3 +981,11 @@ class SubSubClass(SubClass):
981981
# Clean up
982982
del x
983983
gc.collect()
984+
985+
def test51_constexpr_trampoline():
986+
class PyConstexprClass(t.ConstexprClass):
987+
def getInt(self):
988+
return 42
989+
990+
c = PyConstexprClass(4)
991+
assert t.constexpr_call_getInt(c) == 42

0 commit comments

Comments
 (0)