Library of Assembled Shared Sources
enum_definition.h
Go to the documentation of this file.
1/** @file
2 * @author Bram de Greve (bram@cocamware.com)
3 * @author Tom De Muer (tom@cocamware.com)
4 *
5 * *** BEGIN LICENSE INFORMATION ***
6 *
7 * The contents of this file are subject to the Common Public Attribution License
8 * Version 1.0 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://lass.sourceforge.net/cpal-license. The License is based on the
11 * Mozilla Public License Version 1.1 but Sections 14 and 15 have been added to cover
12 * use of software over a computer network and provide for limited attribution for
13 * the Original Developer. In addition, Exhibit A has been modified to be consistent
14 * with Exhibit B.
15 *
16 * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
17 * WARRANTY OF ANY KIND, either express or implied. See the License for the specific
18 * language governing rights and limitations under the License.
19 *
20 * The Original Code is LASS - Library of Assembled Shared Sources.
21 *
22 * The Initial Developer of the Original Code is Bram de Greve and Tom De Muer.
23 * The Original Developer is the Initial Developer.
24 *
25 * All portions of the code written by the Initial Developer are:
26 * Copyright (C) 2022-2025 the Initial Developer.
27 * All Rights Reserved.
28 *
29 * Contributor(s):
30 *
31 * Alternatively, the contents of this file may be used under the terms of the
32 * GNU General Public License Version 2 or later (the GPL), in which case the
33 * provisions of GPL are applicable instead of those above. If you wish to allow use
34 * of your version of this file only under the terms of the GPL and not to allow
35 * others to use your version of this file under the CPAL, indicate your decision by
36 * deleting the provisions above and replace them with the notice and other
37 * provisions required by the GPL License. If you do not delete the provisions above,
38 * a recipient may use your version of this file under either the CPAL or the GPL.
39 *
40 * *** END LICENSE INFORMATION ***
41 */
42
43#pragma once
44
45#include "python_common.h"
46#include "pyobject_ptr.h"
47#include "py_tuple.h"
48#include "../num/num_traits.h"
49#include "../stde/vector_map.h"
50
51#include <unordered_map>
52#include <optional>
53
54namespace lass
55{
56 namespace python
57 {
58 /** @defgroup EnumDefinition Enum Definitions
59 * @brief Defining first-class enum types in Python from C++ enums.
60 *
61 * This module provides helper macros and classes to define Python enum types that derive
62 * from `enum.Enum`, `enum.IntEnum`, `enum.StrEnum` or `enum.IntFlag`.
63 *
64 *
65 * ### Python Enum Types
66 *
67 * The following Python enum types can be created:
68 *
69 * - `enum.IntEnum`: Values are integers, allows direct int conversion and comparison (recommended for most C++ enums)
70 * - `enum.StrEnum`: Values are strings, allows direct string operations
71 * - `enum.IntFlag`: Integer flags supporting bitwise operations (`|`, `&`, `^`, `~`)
72 * - `enum.Enum`: Generic enums with custom value types (advanced use)
73 *
74 *
75 * ### Usage Overview
76 *
77 * To export a C++ enum to Python, you need **3 macros**:
78 *
79 * 1. One `PY_SHADOW_*` macro in the header file to specialize `PyExportTraits`
80 * 2. One `PY_DECLARE_*` macro in the source file to define the enum mapping
81 * 3. One PY_MODULE_ENUM() or PY_CLASS_ENUM() macro to add the enum to a module or class
82 *
83 * Once defined, the enum can be used as parameters or return types in function signatures,
84 * as class members, etc. The header defining `PY_SHADOW_*` must be included in source
85 * files that export these functions to Python, or add the enum to a module or class.
86 *
87 * #### For `enum.IntEnum` (most common case):
88 * ```cpp
89 * // In header:
90 * PY_SHADOW_INT_ENUM(LASS_DLL_EXPORT, MyEnum);
91 *
92 * // In source:
93 * PY_DECLARE_INT_ENUM_EX(MyEnum)("MyEnum", "MyEnum documentation", {
94 * { "VALUE1", MyEnum::Value1 },
95 * { "VALUE2", MyEnum::Value2 },
96 * });
97 *
98 * // Add to module or class:
99 * PY_MODULE_ENUM(mymodule, MyEnum); // or PY_CLASS_ENUM(MyClass, MyEnum);
100 * ```
101 *
102 * #### For `enum.StrEnum` (string-based enums):
103 * ```cpp
104 * // In header:
105 * PY_SHADOW_STR_ENUM(LASS_DLL_EXPORT, Shape);
106 *
107 * // In source:
108 * PY_DECLARE_STR_ENUM_EX(Shape)("Shape", "Shape documentation", {
109 * { "CIRCLE", Shape::Circle, "circle" },
110 * { "SQUARE", Shape::Square, "square" },
111 * });
112 *
113 * // Add to module or class:
114 * PY_MODULE_ENUM(mymodule, Shape); // or PY_CLASS_ENUM(MyClass, Shape);
115 * ```
116 *
117 * #### For `enum.IntFlag` (bitfield enums):
118 * ```cpp
119 * // In header:
120 * PY_SHADOW_INT_FLAG(LASS_DLL_EXPORT, Breakfast);
121 *
122 * // In source:
123 * PY_DECLARE_INT_FLAG_EX(Breakfast)("Breakfast", "Breakfast documentation", FlagBoundary::Keep, {
124 * { "EGG", Breakfast::Egg },
125 * { "BACON", Breakfast::Bacon },
126 * { "ALL", Breakfast::All },
127 * });
128 *
129 * // Add to module or class:
130 * PY_MODULE_ENUM(mymodule, Breakfast); // or PY_CLASS_ENUM(MyClass, Breakfast);
131 * ```
132 *
133 * #### For `enum.Enum` (generic enums):
134 * ```cpp
135 * // In header:
136 * using WeekdayPair = std::pair<int, std::string>;
137 * PY_SHADOW_ENUM(LASS_DLL_EXPORT, Weekday, WeekdayPair)
138 *
139 * // In source:
140 * PY_DECLARE_ENUM_EX(Weekday, WeekdayPair)("Weekday", "Weekday documentation", {
141 * { "MONDAY", Weekday::Monday, std::make_pair(Weekday::Monday, "Monday") },
142 * { "TUESDAY", Weekday::Tuesday, std::make_pair(Weekday::Tuesday, "Tuesday") },
143 * });
144 *
145 * // Add to module or class:
146 * PY_MODULE_ENUM(mymodule, Weekday); // or PY_CLASS_ENUM(MyClass, Weekday);
147 * ```
148 * @ingroup Python
149 */
150
151 /** Defines the boundary behavior for `enum.IntFlag`-derived enums.
152 *
153 * Controls how Python handles flag values that are outside the defined enumerators
154 *
155 * @note This feature requires Python 3.11 or later. On earlier versions, only `Keep` is supported.
156 *
157 * @sa IntFlagDefinition
158 * @sa PY_DECLARE_INT_FLAG_EX
159 * @ingroup EnumDefinition
160 */
161 enum class FlagBoundary
162 {
163 Keep, ///< Allow any integer value (most permissive)
164 Strict, ///< Only allow exact flag combinations
165 Conform, ///< Mask to defined bits only
166 };
167
168 namespace impl
169 {
170 /** Creates a basic `enum.Enum` type.
171 * @param name Python class name for the enum
172 * @param enumerators Tuple of (name, value) pairs
173 * @param kwargs Additional keyword arguments for enum constructor
174 * @return New enum type object
175 * @ingroup EnumDefinition
176 */
177 LASS_PYTHON_DLL TPyObjPtr makeEnumType(const char* name, TPyObjPtr&& enumerators, TPyObjPtr&& kwargs);
178
179 /** Creates an `enum.IntEnum` type.
180 * @param name Python class name for the enum
181 * @param enumerators Tuple of (name, value) pairs
182 * @param kwargs Additional keyword arguments for enum constructor
183 * @return New `enum.IntEnum` type object
184 * @ingroup EnumDefinition
185 */
186 LASS_PYTHON_DLL TPyObjPtr makeIntEnumType(const char* name, TPyObjPtr&& enumerators, TPyObjPtr&& kwargs);
187
188 /** Creates an `enum.IntFlag` type.
189 * @param name Python class name for the flag enum
190 * @param enumerators Tuple of (name, value) pairs
191 * @param kwargs Additional keyword arguments for enum constructor
192 * @param boundary Boundary behavior for invalid flag combinations
193 * @return New `enum.IntFlag` type object
194 * @ingroup EnumDefinition
195 */
196 LASS_PYTHON_DLL TPyObjPtr makeIntFlagType(const char* name, TPyObjPtr&& enumerators, TPyObjPtr&& kwargs, FlagBoundary boundary=FlagBoundary::Keep);
197
198 /** Creates an `enum.StrEnum` type (or equivalent for Python < 3.11).
199 * @param name Python class name for the string enum
200 * @param enumerators Tuple of (name, value) pairs where values are strings
201 * @param kwargs Additional keyword arguments for enum constructor
202 * @return New `enum.StrEnum` type object
203 * @ingroup EnumDefinition
204 */
205 LASS_PYTHON_DLL TPyObjPtr makeStrEnumType(const char* name, TPyObjPtr&& enumerators, TPyObjPtr&& kwargs);
206 }
207
208 /** Base class of all enum definitions.
209 *
210 * If you define your own custom enum definition, you must derive from this class so that
211 * you can add your enum to a module or class with `PY_MODULE_ENUM()` or `PY_CLASS_ENUM()`.
212 *
213 * This class is typically not used directly by user code. Use the provided
214 * IntEnumDefinition, StrEnumDefinition, IntFlagDefinition, or EnumDefinition
215 * template classes instead.
216 *
217 * @ingroup EnumDefinition
218 */
219 class LASS_PYTHON_DLL EnumDefinitionBase
220 {
221 public:
222 virtual ~EnumDefinitionBase();
223
224 const char* name() const; ///< The name of the Python enum type
225 const char* doc() const; ///< Optional docstring for the Python enum type
226 PyObject* type() const; ///< The Python enum type object, after freezeDefinition() has been called
227
228 /** Freeze the enum definition and create the Python enum type.
229 *
230 * @note This method should _not_ be called directly. Instead, use `PY_MODULE_ENUM()` or
231 * `PY_CLASS_ENUM()` to add the enum to a module or class, which will call this method
232 * at the appropriate time.
233 */
234 PyObject* freezeDefinition(const char* moduleName, const char* scopeName);
235
236 protected:
237 /** Construct enum definition with name only.
238 * @param name Python class name for the enum type (must have static storage duration)
239 */
240 EnumDefinitionBase(const char* name);
241
242 /** Construct enum definition with name and documentation.
243 * @param name Python class name for the enum type (must have static storage duration)
244 * @param doc Optional docstring for the Python enum type (must have static storage duration, or nullptr)
245 */
246 EnumDefinitionBase(const char* name, const char* doc);
247
248 /** Returns the value of an enum instances as a Python object
249 *
250 * If the object is not an instance of this enum type, a Python exception will be set
251 * and a null pointer will be returned.
252 */
253 TPyObjPtr valueObject(PyObject* obj) const;
254
255 private:
256 /** Creates the actual Python enum type object.
257 * Derived classes implement this to create the appropriate enum type (IntEnum, StrEnum, etc.).
258 */
259 virtual TPyObjPtr doFreezeDefinition(TPyObjPtr&& kwargs) = 0;
260
261 /** Extracts the value from a Python object for type conversion.
262 * Derived classes can override this to customize value extraction logic.
263 */
264 virtual TPyObjPtr doValueObject(PyObject* obj) const;
265
266 TPyObjPtr type_;
267 const char* name_;
268 const char* doc_;
269 };
270
271 /** Definition of an `enum.IntEnum`-derived enum type in Python.
272 *
273 * C++ enums exported using IntEnumDefinition will generate a new
274 * enum type derived from `enum.IntEnum`. The values of the Python enum
275 * will map directly on the C++ enum values, but then names need to
276 * be defined at export.
277 *
278 * As `enum.IntEnum` is used, the Python enum instances will also be
279 * valid int instances, and int instances are accepted when converting
280 * from Python to C++.
281 *
282 * Because this defines a new type, it must be added to a module or
283 * other class.
284 *
285 * This class is typically not used directly. Use PY_SHADOW_INT_ENUM
286 * and PY_DECLARE_INT_ENUM_* macros instead.
287 *
288 * @par Usage Example:
289 * ```cpp
290 * // In header:
291 * PY_SHADOW_INT_ENUM(LASS_DLL_EXPORT, MyEnum);
292 *
293 * // In source:
294 * PY_DECLARE_INT_ENUM_EX(MyEnum)("MyEnum", "MyEnum documentation", {
295 * { "VALUE1", MyEnum::Value1 },
296 * { "VALUE2", MyEnum::Value2 },
297 * });
298 *
299 * // Add to module or class:
300 * PY_MODULE_ENUM(mymodule, MyEnum); // or PY_CLASS_ENUM(MyClass, MyEnum);
301 * ```
302 *
303 * @sa PY_SHADOW_INT_ENUM
304 * @sa PY_DECLARE_INT_ENUM_NAME
305 * @sa PY_DECLARE_INT_ENUM_NAME_DOC
306 * @sa PY_DECLARE_INT_ENUM_EX
307 * @sa PY_MODULE_ENUM
308 * @sa PY_CLASS_ENUM
309 * @ingroup EnumDefinition
310 */
311 template <typename EnumType>
313 {
314 public:
315 using TEnum = EnumType;
316 using TBase = typename std::underlying_type<EnumType>::type;
317
318 /** Represents a single enumerator member with name and C++ enum value. */
320 {
321 std::string name; ///< Python name for the member
322 TEnum enumerator; ///< Corresponding C++ enum value
323 };
324
325 /** Construct with enum name only.
326 * @param name Python class name for the enum type (must have static storage duration)
327 */
328 IntEnumDefinition(const char* name) :
330 {
331 }
332
333 /** Construct with name and documentation.
334 * @param name Python class name for the enum type (must have static storage duration)
335 * @param doc Optional docstring for the Python enum type (must have static storage duration, or nullptr)
336 */
337 IntEnumDefinition(const char* name, const char* doc) :
339 {
340 }
341
342 /** Construct with name and enumerators list.
343 * @param name Python class name for the enum type (must have static storage duration)
344 * @param enumerators List of name-value pairs defining the enum members
345 */
346 IntEnumDefinition(const char* name, std::initializer_list<Enumerator> enumerators) :
348 enumerators_(enumerators)
349 {
350 }
351
352 /** Construct with name, documentation, and enumerators list.
353 * @param name Python class name for the enum type (must have static storage duration)
354 * @param doc Optional docstring for the Python enum type (must have static storage duration, or nullptr)
355 * @param enumerators List of name-value pairs defining the enum members
356 */
357 IntEnumDefinition(const char* name, const char* doc, std::initializer_list<Enumerator> enumerators) :
359 enumerators_(enumerators)
360 {
361 }
362
363 /** Add an enumerator member to the definition.
364 * @param name Python name for the enumerator member
365 * @param value C++ enum value
366 */
367 void addEnumerator(std::string name, TEnum value)
368 {
369 enumerators_.emplace_back(std::move(name), value);
370 }
371
372 /** Creates a Python enum instance from a C++ enum value.
373 * Converts the C++ enum to its corresponding Python enum instance.
374 */
375 PyObject* build(TEnum value) const
376 {
377 LockGIL LASS_UNUSED(lock);
378 TPyObjPtr args = makeTuple(static_cast<TBase>(value));
379 return PyObject_Call(type(), args.get(), nullptr);
380 }
381
382 /** Extracts a C++ enum value from a Python object.
383 * Accepts both enum instances and raw integers. Returns 0 on success, 1 on failure.
384 */
385 int get(PyObject* obj, TEnum& value) const
386 {
387 LockGIL LASS_UNUSED(lock);
388 const TPyObjPtr o = valueObject(obj);
389 if (!o)
390 {
391 return 1;
392 }
393 TBase v;
394 if (PyExportTraits<TBase>::get(o.get(), v) != 0)
395 {
396 // this can only happen for IntFlag with FlagBoundary::KEEP
397 return 1;
398 }
399 value = static_cast<TEnum>(v);
400 return 0;
401 }
402
403 protected:
404 /** Creates an `enum.IntEnum`-derived type.
405 * Converts enumerators to Python tuple format and creates the integer enum type.
406 */
408 {
409 const Py_ssize_t n = static_cast<Py_ssize_t>(enumerators_.size());
410 TPyObjPtr pyEnumerators(PyTuple_New(n));
411 if (!pyEnumerators)
412 {
413 return TPyObjPtr();
414 }
415 for (Py_ssize_t i = 0; i < n; ++i)
416 {
417 const Enumerator& enumerator = enumerators_[static_cast<size_t>(i)];
418 TPyObjPtr pyEnumerator(makeTuple(enumerator.name, static_cast<TBase>(enumerator.enumerator)));
419 if (!pyEnumerator || PyTuple_SetItem(pyEnumerators.get(), i, fromSharedPtrToNakedCast(pyEnumerator)) != 0)
420 {
421 return TPyObjPtr();
422 }
423 }
424
425 return this->doMakeEnumType(std::move(pyEnumerators), std::move(kwargs));
426 }
427
428 /** Extracts integer values from enum instances or integer objects.
429 * Handles both integer enum instances and raw Python integers.
430 */
431 TPyObjPtr doValueObject(PyObject* obj) const override
432 {
433 PyObject* type = this->type();
434 if (PyObject_TypeCheck(obj, (PyTypeObject*) type))
435 {
436 return TPyObjPtr(PyObject_GetAttrString(obj, "value"));
437 }
438
439 // try to convert it to an enum first ...
440 if (!PyLong_Check(obj))
441 {
442 PyErr_Format(PyExc_TypeError, "Expected %S or int, got %S", type, obj);
443 return TPyObjPtr();
444 }
445 TPyObjPtr o(PyObject_CallFunctionObjArgs(type, obj, nullptr));
446 if (!o)
447 {
448 return TPyObjPtr();
449 }
450 return TPyObjPtr(PyObject_GetAttrString(o.get(), "value"));
451 }
452
453 /** Creates the actual `enum.IntEnum` type object.
454 * Can be overridden by derived classes to create different enum types (e.g., IntFlag).
455 */
456 virtual TPyObjPtr doMakeEnumType(TPyObjPtr&& enumerators, TPyObjPtr&& kwargs)
457 {
458 return impl::makeIntEnumType(this->name(), std::move(enumerators), std::move(kwargs));
459 }
460
461 private:
462 std::vector<Enumerator> enumerators_;
463 };
464
465 /** Definition of an `enum.IntFlag`-derived enum type in Python.
466 *
467 * C++ enums exported using IntFlagDefinition will generate a new
468 * enum type derived from `enum.IntFlag`. The values of the Python enum
469 * will map directly on the C++ enum values, but then names need to
470 * be defined at export.
471 *
472 * As `enum.IntFlag` is used, the Python enum instances will also be
473 * valid int instances, and int instances are accepted when converting
474 * from Python to C++. Additionally, bitwise operations are supported.
475 *
476 * Because this defines a new type, it must be added to a module or
477 * other class.
478 *
479 * This class is typically not used directly. Use PY_SHADOW_INT_FLAG
480 * and PY_DECLARE_INT_FLAG_* macros instead.
481 *
482 * @par Usage Example:
483 * ```cpp
484 * // In header:
485 * PY_SHADOW_INT_FLAG(LASS_DLL_EXPORT, Breakfast);
486 *
487 * // In source:
488 * PY_DECLARE_INT_FLAG_EX(Breakfast)("Breakfast", "Breakfast documentation", FlagBoundary::Keep, {
489 * { "EGG", Breakfast::Egg },
490 * { "BACON", Breakfast::Bacon },
491 * { "ALL", Breakfast::All },
492 * });
493 *
494 * // Add to module or class:
495 * PY_MODULE_ENUM(mymodule, Breakfast); // or PY_CLASS_ENUM(MyClass, Breakfast);
496 * ```
497 *
498 * @sa PY_SHADOW_INT_FLAG
499 * @sa PY_DECLARE_INT_FLAG_NAME
500 * @sa PY_DECLARE_INT_FLAG_NAME_DOC
501 * @sa PY_DECLARE_INT_FLAG_EX
502 * @sa PY_MODULE_ENUM
503 * @sa PY_CLASS_ENUM
504 * @sa FlagBoundary
505 * @ingroup EnumDefinition
506 */
507 template <typename EnumType>
508 class IntFlagDefinition : public IntEnumDefinition<EnumType>
509 {
510 public:
511 using TEnum = typename IntFlagDefinition<EnumType>::TEnum;
512 using TBase = typename IntFlagDefinition<EnumType>::TBase;
513 using Enumerator = typename IntEnumDefinition<EnumType>::Enumerator;
514
515 /// Inherits all constructors from IntEnumDefinition
517
518 /** Construct with name, documentation, boundary behavior, and enumerators.
519 * @param name Python class name for the flag enum type (must have static storage duration)
520 * @param doc Optional docstring for the Python enum type (must have static storage duration, or nullptr)
521 * @param boundary Flag boundary behavior controlling how invalid flag combinations are handled
522 * @param enumerators List of name-value pairs defining the flag members
523 *
524 * @note The boundary parameter requires Python 3.11 or later. On earlier versions, only `Keep` is supported
525 * (which is the default if this constructor is not used).
526 */
527 IntFlagDefinition(const char* name, const char* doc, FlagBoundary boundary, std::initializer_list<Enumerator> enumerators) :
528 IntEnumDefinition<EnumType>(name, doc, enumerators),
529 boundary_(boundary)
530 {
531 }
532
533 protected:
534 /** Creates an `enum.IntFlag`-derived type with boundary behavior.
535 * Overrides the base class to create a flag enum with bitwise operations support.
536 */
537 TPyObjPtr doMakeEnumType(TPyObjPtr&& enumerators, TPyObjPtr&& kwargs) override
538 {
539 return impl::makeIntFlagType(this->name(), std::move(enumerators), std::move(kwargs), boundary_);
540 }
541
542 private:
544 };
545
546 /** Definition of a general `enum.Enum`-derived enum type in Python.
547 *
548 * This creates enums with custom value types (not just integers or strings).
549 * This is the base class for StrEnumDefinition and can be used directly
550 * for advanced enum types with custom value types.
551 *
552 * This class is typically not used directly. Use PY_SHADOW_ENUM
553 * and PY_DECLARE_ENUM_* macros instead.
554 *
555 * @par Usage Example:
556 * ```cpp
557 * // In header:
558 * PY_SHADOW_ENUM(LASS_DLL_EXPORT, MyEnum, std::string);
559 *
560 * // In source:
561 * PY_DECLARE_ENUM_EX(MyEnum, std::string)("MyEnum", "MyEnum documentation", {
562 * { "VALUE1", MyEnum::Value1, "custom_value_1" },
563 * { "VALUE2", MyEnum::Value2, "custom_value_2" },
564 * });
565 *
566 * // Add to module or class:
567 * PY_MODULE_ENUM(mymodule, MyEnum); // or PY_CLASS_ENUM(MyClass, MyEnum);
568 * ```
569 *
570 * @sa PY_SHADOW_ENUM
571 * @sa PY_DECLARE_ENUM_NAME
572 * @sa PY_DECLARE_ENUM_NAME_DOC
573 * @sa PY_DECLARE_ENUM_EX
574 * @sa PY_MODULE_ENUM
575 * @sa PY_CLASS_ENUM
576 * @ingroup EnumDefinition
577 */
578 template <typename EnumType, typename ValueType>
580 {
581 public:
582 using TEnum = EnumType;
583 using TValue = ValueType;
584
585 /** Represents a single enumerator with name, C++ enum value, and Python value. */
587 {
588 std::string name; ///< Python name for the enumerator
589 TEnum enumerator; ///< Corresponding C++ enum value
590 TValue value; ///< Python value for the enumerator
591 };
592
593 /** Construct with enum name only.
594 * @param name Python class name for the enum type (must have static storage duration)
595 */
596 EnumDefinition(const char* name) :
598 {
599 }
600
601 /** Construct with name and documentation.
602 * @param name Python class name for the enum type (must have static storage duration)
603 * @param doc Optional docstring for the Python enum type (must have static storage duration, or nullptr)
604 */
605 EnumDefinition(const char* name, const char* doc) :
607 {
608 }
609
610 /** Construct with name and enumerators list.
611 * @param name Python class name for the enum type (must have static storage duration)
612 * @param enumerators List of name-enum-value triples defining the enum members
613 */
614 EnumDefinition(const char* name, std::initializer_list<Enumerator> enumerators) :
616 enumerators_(enumerators)
617 {
618 }
619
620 /** Construct with name, documentation, and enumerators list.
621 * @param name Python class name for the enum type (must have static storage duration)
622 * @param doc Optional docstring for the Python enum type (must have static storage duration, or nullptr)
623 * @param enumerators List of name-enum-value triples defining the enum members
624 */
625 EnumDefinition(const char* name, const char* doc, std::initializer_list<Enumerator> enumerators) :
627 enumerators_(enumerators)
628 {
629 }
630
631 /** Add an enumerator to the definition.
632 * @param name Python name for the enumerator
633 * @param enumerator C++ enum value
634 * @param value Python value for the enumerator
635 */
636 void addEnumerator(std::string name, TEnum enumerator, TValue value)
637 {
638 enumerators_.emplace_back(std::move(name), enumerator, std::move(value));
639 }
640
641 /** Creates a Python enum instance from a C++ enum value.
642 * Looks up the Python value corresponding to the C++ enum and creates an enum instance.
643 */
644 PyObject* build(TEnum value) const
645 {
646 LockGIL LASS_UNUSED(lock);
647 auto val = this->getValue(value);
648 if (!val)
649 {
650 PyErr_Format(PyExc_ValueError, "%lld is not a valid C++ value for %S",
651 static_cast<PY_LONG_LONG>(value), type());
652 return nullptr;
653 }
654 TPyObjPtr args = makeTuple(*val);
655 return PyObject_Call(type(), args.get(), nullptr);
656 }
657
658 /** Extracts a C++ enum value from a Python object.
659 * Accepts enum instances and compatible value types. Returns 0 on success, 1 on failure.
660 */
661 int get(PyObject* obj, TEnum& value) const
662 {
663 LockGIL LASS_UNUSED(lock);
664 const TPyObjPtr o = valueObject(obj);
665 if (!o)
666 {
667 return 1;
668 }
669 TValue v;
670 if (PyExportTraits<TValue>::get(o.get(), v) != 0)
671 {
672 // by construction this should never happen
673 // o should always be the right type ...
674 return 1;
675 }
676 auto val = getEnum(v);
677 if (!val)
678 {
679 // this should never happen, by construction o _must_ be a valid enumerator
680 PyErr_Format(PyExc_ValueError, "%S is not a valid value for %S", o.get(), type());
681 return 1;
682 }
683 value = *val;
684 return 0;
685 }
686
687 std::optional<TValue> getValue(TEnum enumerator) const
688 {
689 auto it = enumToValue_.find(enumerator);
690 if (it == enumToValue_.end())
691 {
692 return std::nullopt;
693 }
694 return it->second;
695 }
696
697 std::optional<TEnum> getEnum(const TValue& value) const
698 {
699 auto it = valueToEnum_.find(value);
700 if (it == valueToEnum_.end())
701 {
702 return std::nullopt;
703 }
704 return it->second;
705 }
706
707 protected:
708 /** Converts stored enumerators to Python tuple format and builds lookup tables.
709 * Creates bidirectional mappings between C++ enum values and Python values.
710 */
712 {
713 const Py_ssize_t n = static_cast<Py_ssize_t>(enumerators_.size());
714 TPyObjPtr pyEnumerators(PyTuple_New(n));
715 for (Py_ssize_t i = 0; i < n; ++i)
716 {
717 const Enumerator& enumerator = enumerators_[static_cast<size_t>(i)];
718 assert(!enumToValue_.contains(enumerator.enumerator));
719 enumToValue_.emplace(enumerator.enumerator, enumerator.value);
720 assert(!valueToEnum_.contains(enumerator.value));
721 valueToEnum_.emplace(enumerator.value, enumerator.enumerator);
722 TPyObjPtr pyEnumerator(makeTuple(enumerator.name, enumerator.value));
723 PyTuple_SetItem(pyEnumerators.get(), i, fromSharedPtrToNakedCast(pyEnumerator));
724 }
725 return pyEnumerators;
726 }
727
728 /** Creates a generic `enum.Enum`-derived type.
729 * Processes enumerators and creates a Python enum type with custom value types.
730 */
732 {
733 TPyObjPtr pyEnumerators = freezeEnumerators();
734 if (!pyEnumerators)
735 {
736 return TPyObjPtr();
737 }
738 return impl::makeEnumType(this->name(), std::move(pyEnumerators), std::move(kwargs));
739 }
740
741 private:
742 std::vector<Enumerator> enumerators_;
745 };
746
747 /** Definition of an `enum.StrEnum`-derived enum type in Python.
748 *
749 * C++ enums exported using StrEnumDefinition will generate a new
750 * enum type derived from `enum.StrEnum` (or `enum.Enum` + str for Python < 3.11).
751 * The values of the Python enum will be strings, and how they map on the
752 * C++ enum values needs to be defined at export.
753 *
754 * As `enum.StrEnum` is used, the Python enum instances will also be
755 * valid str instances, and str instances are accepted when
756 * converting from Python to C++.
757 *
758 * Because this defines a new type, it must be added to a module or
759 * other class.
760 *
761 * This class is typically not used directly. Use PY_SHADOW_STR_ENUM
762 * and PY_DECLARE_STR_ENUM_* macros instead.
763 *
764 * @par Usage Example:
765 * ```cpp
766 * // In header:
767 * PY_SHADOW_STR_ENUM(LASS_DLL_EXPORT, Shape);
768 *
769 * // In source:
770 * PY_DECLARE_STR_ENUM_EX(Shape)("Shape", "Shape documentation", {
771 * { "CIRCLE", Shape::Circle, "circle" },
772 * { "SQUARE", Shape::Square, "square" },
773 * });
774 *
775 * // Add to module or class:
776 * PY_MODULE_ENUM(mymodule, Shape); // or PY_CLASS_ENUM(MyClass, Shape);
777 * ```
778 *
779 * @sa PY_SHADOW_STR_ENUM
780 * @sa PY_DECLARE_STR_ENUM_NAME
781 * @sa PY_DECLARE_STR_ENUM_NAME_DOC
782 * @sa PY_DECLARE_STR_ENUM_EX
783 * @sa PY_MODULE_ENUM
784 * @sa PY_CLASS_ENUM
785 * @ingroup EnumDefinition
786 */
787 template <typename EnumType, typename ValueType=std::string>
788 class StrEnumDefinition : public EnumDefinition<EnumType, ValueType>
789 {
790 public:
791 using EnumDefinition<EnumType, ValueType>::EnumDefinition;
792
793 protected:
794 /** Creates an `enum.StrEnum`-derived type.
795 * Processes enumerators and creates a Python string enum type.
796 */
798 {
799 return impl::makeStrEnumType(this->name(), this->freezeEnumerators(), std::move(kwargs));
800 }
801
802 /** Extracts string values from enum instances or string objects.
803 * Handles both string enum instances and raw Python strings.
804 */
805 TPyObjPtr doValueObject(PyObject* obj) const override
806 {
807 PyObject* type = this->type();
808 if (PyObject_TypeCheck(obj, (PyTypeObject*) type))
809 {
810 return TPyObjPtr(PyObject_GetAttrString(obj, "value"));
811 }
812
813 // try to convert it to an enum first ...
814
815 if (!PyUnicode_Check(obj))
816 {
817 PyErr_Format(PyExc_TypeError, "Expected %S or str, got %S", type, obj);
818 return TPyObjPtr();
819 }
820 TPyObjPtr o(PyObject_CallFunctionObjArgs(type, obj, nullptr));
821 if (!o)
822 {
823 return TPyObjPtr();
824 }
825 return TPyObjPtr(PyObject_GetAttrString(o.get(), "value"));
826 }
827 };
828 }
829}
830
831
832
833/** @addtogroup EnumDefinition
834 * @name Integer Enum Support
835 * Macros for exporting C++ integer enums as Python `enum.IntEnum` types.
836 * @{
837 */
838
839/** Specializes PyExportTraits for a C++ enum using `enum.IntEnum`.
840 * Use this in header files, then use PY_DECLARE_INT_ENUM_* in source files.
841 * @param dllInterface Export specification (e.g., LASS_DLL_EXPORT)
842 * @param t_cppEnum C++ enum type
843 * @sa lass::python::IntEnumDefinition
844 * @ingroup EnumDefinition
845 */
846#define PY_SHADOW_INT_ENUM(dllInterface, t_cppEnum)\
847 namespace lass \
848 { \
849 namespace python \
850 { \
851 template <> \
852 struct PyExportTraits<t_cppEnum> \
853 { \
854 using TEnum = t_cppEnum; \
855 using TEnumDefinition = IntEnumDefinition<TEnum>; \
856 static dllInterface TEnumDefinition enumDefinition; \
857 static PyObject* build(TEnum value) { return enumDefinition.build(value); } \
858 static int get(PyObject* obj, TEnum& value) { return enumDefinition.get(obj, value); } \
859 }; \
860 } \
861 } \
862 /**/
863
864/** Defines the enumDefinition with name only for `enum.IntEnum`.
865 * @param t_cppEnum C++ enum type
866 * @param s_name Python enum name (const char* string with static storage duration)
867 * @sa lass::python::IntEnumDefinition
868 * @ingroup EnumDefinition
869 */
870#define PY_DECLARE_INT_ENUM_NAME(t_cppEnum, s_name) \
871 ::lass::python::IntEnumDefinition<t_cppEnum> lass::python::PyExportTraits<t_cppEnum>::enumDefinition(s_name);
872
873/** Defines the enumDefinition with name and docstring for `enum.IntEnum`.
874 * @param t_cppEnum C++ enum type
875 * @param s_name Python enum name (const char* string with static storage duration)
876 * @param s_doc Documentation string (const char* string with static storage duration, or nullptr)
877 * @sa lass::python::IntEnumDefinition
878 * @ingroup EnumDefinition
879 */
880#define PY_DECLARE_INT_ENUM_NAME_DOC(t_cppEnum, s_name, s_doc) \
881 ::lass::python::IntEnumDefinition<t_cppEnum> lass::python::PyExportTraits<t_cppEnum>::enumDefinition(s_name, s_doc);
882
883/** Defines the enumDefinition for initialization with constructor arguments for `enum.IntEnum`.
884 * Use this with initializer list: PY_DECLARE_INT_ENUM_EX(MyEnum)("MyEnum", "docs", { ... });
885 * @param t_cppEnum C++ enum type
886 * @sa lass::python::IntEnumDefinition
887 * @ingroup EnumDefinition
888 */
889#define PY_DECLARE_INT_ENUM_EX(t_cppEnum) \
890 ::lass::python::IntEnumDefinition<t_cppEnum> lass::python::PyExportTraits<t_cppEnum>::enumDefinition
891
892/** @} */
893
894
895
896/** @addtogroup EnumDefinition
897 * @name Integer Flag Support
898 * Macros for exporting C++ flag enums as Python `enum.IntFlag` types with bitwise operations.
899 * @{
900 */
901
902/** Specializes PyExportTraits for a C++ enum using `enum.IntFlag`.
903 * Use this in header files for bitfield enums, then use PY_DECLARE_INT_FLAG_* in source files.
904 * @param dllInterface Export specification (e.g., LASS_DLL_EXPORT)
905 * @param t_cppEnum C++ enum type (should be a bitfield enum)
906 * @sa lass::python::IntFlagDefinition
907 * @sa lass::python::FlagBoundary
908 * @ingroup EnumDefinition
909 */
910#define PY_SHADOW_INT_FLAG(dllInterface, t_cppEnum)\
911 namespace lass \
912 { \
913 namespace python \
914 { \
915 template <> \
916 struct PyExportTraits<t_cppEnum> \
917 { \
918 using TEnum = t_cppEnum; \
919 using TEnumDefinition = IntFlagDefinition<TEnum>; \
920 static dllInterface TEnumDefinition enumDefinition; \
921 static PyObject* build(TEnum value) { return enumDefinition.build(value); } \
922 static int get(PyObject* obj, TEnum& value) { return enumDefinition.get(obj, value); } \
923 }; \
924 } \
925 } \
926 /**/
927
928/** Defines the enumDefinition with name only for `enum.IntFlag`.
929 * @param t_cppEnum C++ enum type
930 * @param s_name Python enum name (const char* string with static storage duration)
931 * @sa lass::python::IntFlagDefinition
932 * @ingroup EnumDefinition
933 */
934#define PY_DECLARE_INT_FLAG_NAME(t_cppEnum, s_name) \
935 ::lass::python::IntFlagDefinition<t_cppEnum> lass::python::PyExportTraits<t_cppEnum>::enumDefinition(s_name);
936
937/** Defines the enumDefinition with name and docstring for `enum.IntFlag`.
938 * @param t_cppEnum C++ enum type
939 * @param s_name Python enum name (const char* string with static storage duration)
940 * @param s_doc Documentation string (const char* string with static storage duration, or nullptr)
941 * @sa lass::python::IntFlagDefinition
942 * @ingroup EnumDefinition
943 */
944#define PY_DECLARE_INT_FLAG_NAME_DOC(t_cppEnum, s_name, s_doc) \
945 ::lass::python::IntFlagDefinition<t_cppEnum> lass::python::PyExportTraits<t_cppEnum>::enumDefinition(s_name, s_doc);
946
947/** Defines the enumDefinition for initialization with constructor arguments for `enum.IntFlag`.
948 * Use with: PY_DECLARE_INT_FLAG_EX(MyEnum)("MyEnum", "docs", FlagBoundary::Keep, { ... });
949 * @param t_cppEnum C++ enum type
950 * @sa lass::python::IntFlagDefinition
951 * @sa lass::python::FlagBoundary
952 * @ingroup EnumDefinition
953 */
954#define PY_DECLARE_INT_FLAG_EX(t_cppEnum) \
955 ::lass::python::IntFlagDefinition<t_cppEnum> lass::python::PyExportTraits<t_cppEnum>::enumDefinition
956
957/** @} */
958
959
960
961/** @addtogroup EnumDefinition
962 * @name Generic Enum Support
963 * Macros for exporting C++ enums as Python `enum.Enum` types with custom value types.
964 * @{
965 */
966
967/** Specializes PyExportTraits for a C++ enum using generic `enum.Enum`.
968 * Use this in header files for enums with custom value types, then use PY_DECLARE_ENUM_* in source files.
969 * @param dllInterface Export specification (e.g., LASS_DLL_EXPORT)
970 * @param t_cppEnum C++ enum type
971 * @param t_valueType Python value type for enum values
972 * @sa lass::python::EnumDefinition
973 * @ingroup EnumDefinition
974 */
975#define PY_SHADOW_ENUM(dllInterface, t_cppEnum, t_valueType)\
976 namespace lass \
977 { \
978 namespace python \
979 { \
980 template <> \
981 struct PyExportTraits<t_cppEnum> \
982 { \
983 using TEnum = t_cppEnum; \
984 using TEnumDefinition = EnumDefinition<TEnum, t_valueType>; \
985 static dllInterface TEnumDefinition enumDefinition; \
986 static PyObject* build(TEnum value) { return enumDefinition.build(value); } \
987 static int get(PyObject* obj, TEnum& value) { return enumDefinition.get(obj, value); } \
988 }; \
989 } \
990 } \
991 /**/
992
993/** Defines the enumDefinition with name only for generic `enum.Enum`.
994 * @param t_cppEnum C++ enum type
995 * @param t_valueType Python value type
996 * @param s_name Python enum name (const char* string with static storage duration)
997 * @sa lass::python::EnumDefinition
998 * @ingroup EnumDefinition
999 */
1000#define PY_DECLARE_ENUM_NAME(t_cppEnum, t_valueType, s_name) \
1001 ::lass::python::EnumDefinition<t_cppEnum, t_valueType> lass::python::PyExportTraits<t_cppEnum>::enumDefinition(s_name);
1002
1003/** Defines the enumDefinition with name and docstring for generic `enum.Enum`.
1004 * @param t_cppEnum C++ enum type
1005 * @param t_valueType Python value type
1006 * @param s_name Python enum name (const char* string with static storage duration)
1007 * @param s_doc Documentation string (const char* string with static storage duration, or nullptr)
1008 * @sa lass::python::EnumDefinition
1009 * @ingroup EnumDefinition
1010 */
1011#define PY_DECLARE_ENUM_NAME_DOC(t_cppEnum, t_valueType, s_name, s_doc) \
1012 ::lass::python::EnumDefinition<t_cppEnum, t_valueType> lass::python::PyExportTraits<t_cppEnum>::enumDefinition(s_name, s_doc);
1013
1014/** Defines the enumDefinition for initialization with constructor arguments for generic `enum.Enum`.
1015 * Use with: PY_DECLARE_ENUM_EX(MyEnum, std::string)("MyEnum", "docs", { ... });
1016 * @param t_cppEnum C++ enum type
1017 * @param t_valueType Python value type
1018 * @sa lass::python::EnumDefinition
1019 * @ingroup EnumDefinition
1020 */
1021#define PY_DECLARE_ENUM_EX(t_cppEnum, t_valueType) \
1022 ::lass::python::EnumDefinition<t_cppEnum, t_valueType> lass::python::PyExportTraits<t_cppEnum>::enumDefinition
1023
1024/** @} */
1025
1026
1027
1028/** @addtogroup EnumDefinition
1029 * @name String Enum Support
1030 * Macros for exporting C++ enums as Python `enum.StrEnum` types with string values.
1031 * @{
1032 */
1033
1034/** Specializes PyExportTraits for a C++ enum using `enum.StrEnum`.
1035 * Use this in header files for string-based enums, then use PY_DECLARE_STR_ENUM_* in source files.
1036 * @param dllInterface Export specification (e.g., LASS_DLL_EXPORT)
1037 * @param t_cppEnum C++ enum type
1038 * @sa lass::python::StrEnumDefinition
1039 * @ingroup EnumDefinition
1040 */
1041#define PY_SHADOW_STR_ENUM(dllInterface, t_cppEnum)\
1042 namespace lass \
1043 { \
1044 namespace python \
1045 { \
1046 template <> \
1047 struct PyExportTraits<t_cppEnum> \
1048 { \
1049 using TEnum = t_cppEnum; \
1050 using TEnumDefinition = StrEnumDefinition<TEnum>; \
1051 static dllInterface TEnumDefinition enumDefinition; \
1052 static PyObject* build(TEnum value) { return enumDefinition.build(value); } \
1053 static int get(PyObject* obj, TEnum& value) { return enumDefinition.get(obj, value); } \
1054 }; \
1055 } \
1056 }
1057
1058/** Defines the enumDefinition with name only for `enum.StrEnum`.
1059 * @param t_cppEnum C++ enum type
1060 * @param s_name Python enum name (const char* string with static storage duration)
1061 * @sa lass::python::StrEnumDefinition
1062 * @ingroup EnumDefinition
1063 */
1064#define PY_DECLARE_STR_ENUM_NAME(t_cppEnum, s_name) \
1065 ::lass::python::StrEnumDefinition<t_cppEnum> lass::python::PyExportTraits<t_cppEnum>::enumDefinition(s_name);
1066
1067/** Defines the enumDefinition with name and docstring for `enum.StrEnum`.
1068 * @param t_cppEnum C++ enum type
1069 * @param s_name Python enum name (const char* string with static storage duration)
1070 * @param s_doc Documentation string (const char* string with static storage duration, or nullptr)
1071 * @sa lass::python::StrEnumDefinition
1072 * @ingroup EnumDefinition
1073 */
1074#define PY_DECLARE_STR_ENUM_NAME_DOC(t_cppEnum, s_name, s_doc) \
1075 ::lass::python::StrEnumDefinition<t_cppEnum> lass::python::PyExportTraits<t_cppEnum>::enumDefinition(s_name, s_doc);
1076
1077/** Defines the enumDefinition for initialization with constructor arguments for `enum.StrEnum`.
1078 * Use with: PY_DECLARE_STR_ENUM_EX(MyEnum)("MyEnum", "docs", { ... });
1079 * @param t_cppEnum C++ enum type
1080 * @sa lass::python::StrEnumDefinition
1081 * @ingroup EnumDefinition
1082 */
1083#define PY_DECLARE_STR_ENUM_EX(t_cppEnum) \
1084 ::lass::python::StrEnumDefinition<t_cppEnum> lass::python::PyExportTraits<t_cppEnum>::enumDefinition
1085
1086/** @} */
1087
1088
1089
1090/** @addtogroup EnumDefinition
1091 * @name Common Enum Utilities
1092 * Utility macros for adding enum definitions to modules and classes.
1093 * @{
1094 */
1095
1096/** Adds an enum definition to a Python module.
1097 * Use this after declaring the enum with PY_DECLARE_*_ENUM_* macros.
1098 * The enum will be accessible as module.EnumName in Python.
1099 * @param i_module Module variable identifier (must be unscoped identifier for token concatenation)
1100 * @param t_cppEnum C++ enum type
1101 *
1102 * @par Usage Example:
1103 * ```cpp
1104 * // In header:
1105 * PY_SHADOW_INT_ENUM(LASS_DLL_EXPORT, MyEnum);
1106 *
1107 * // In source:
1108 * PY_DECLARE_MODULE_DOC(mymodule, "MyModule documentation");
1109 * PY_MODULE_ENUM(mymodule, MyEnum);
1110 * ```
1111 *
1112 * @note this must be called in the same translation unit (source file) that declares the module
1113 * with `PY_DECLARE_MODULE_*` macros.
1114 *
1115 * @ingroup EnumDefinition
1116 */
1117#define PY_MODULE_ENUM( i_module, t_cppEnum ) \
1118 LASS_EXECUTE_BEFORE_MAIN_EX\
1119 ( LASS_CONCATENATE( lassExecutePyModuleEnum_, i_module ),\
1120 i_module.addEnum( &::lass::python::PyExportTraits<t_cppEnum>::enumDefinition ); \
1121 )
1122
1123/** Adds an enum definition as a nested enum to a Python class.
1124 * Use this after declaring the enum with PY_DECLARE_*_ENUM_* macros.
1125 * The enum will be accessible as ClassName.EnumName in Python.
1126 * @param i_cppClass C++ class identifier (must be unscoped identifier for token concatenation)
1127 * @param t_cppEnum C++ enum type
1128 *
1129 * @par Usage Example:
1130 * ```cpp
1131 * // In header:
1132 * PY_SHADOW_INT_ENUM(LASS_DLL_EXPORT, MyEnum);
1133 *
1134 * // In source:
1135 * PY_DECLARE_CLASS_NAME(MyClass, "MyClass documentation");
1136 * PY_CLASS_ENUM(MyClass, MyEnum);
1137 * ```
1138
1139 * @note this must be called in the same translation unit (source file) that declares the class
1140 * with `PY_DECLARE_CLASS_*` macros.
1141 *
1142 * @ingroup EnumDefinition
1143 */
1144#define PY_CLASS_ENUM( i_cppClass, t_cppEnum ) \
1145 LASS_EXECUTE_BEFORE_MAIN_EX\
1146 ( LASS_CONCATENATE( lassExecutePyClassEnum_, i_cppClass ),\
1147 i_cppClass ::_lassPyClassDef.addInnerEnum( &::lass::python::PyExportTraits<t_cppEnum>::enumDefinition ); \
1148 )
1149
1150/** @} */
EnumDefinitionBase(const char *name)
Construct enum definition with name only.
PyObject * type() const
The Python enum type object, after freezeDefinition() has been called.
const char * doc() const
Optional docstring for the Python enum type.
const char * name() const
The name of the Python enum type.
TPyObjPtr valueObject(PyObject *obj) const
Returns the value of an enum instances as a Python object.
PyObject * freezeDefinition(const char *moduleName, const char *scopeName)
Freeze the enum definition and create the Python enum type.
EnumDefinition(const char *name, const char *doc, std::initializer_list< Enumerator > enumerators)
Construct with name, documentation, and enumerators list.
int get(PyObject *obj, TEnum &value) const
Extracts a C++ enum value from a Python object.
EnumDefinition(const char *name)
Construct with enum name only.
TPyObjPtr freezeEnumerators()
Converts stored enumerators to Python tuple format and builds lookup tables.
PyObject * build(TEnum value) const
Creates a Python enum instance from a C++ enum value.
TPyObjPtr doFreezeDefinition(TPyObjPtr &&kwargs) override
Creates a generic enum.Enum-derived type.
void addEnumerator(std::string name, TEnum enumerator, TValue value)
Add an enumerator to the definition.
EnumDefinition(const char *name, std::initializer_list< Enumerator > enumerators)
Construct with name and enumerators list.
EnumDefinition(const char *name, const char *doc)
Construct with name and documentation.
IntEnumDefinition(const char *name, const char *doc)
Construct with name and documentation.
IntEnumDefinition(const char *name, std::initializer_list< Enumerator > enumerators)
Construct with name and enumerators list.
void addEnumerator(std::string name, TEnum value)
Add an enumerator member to the definition.
TPyObjPtr doFreezeDefinition(TPyObjPtr &&kwargs) override
Creates an enum.IntEnum-derived type.
TPyObjPtr doValueObject(PyObject *obj) const override
Extracts integer values from enum instances or integer objects.
IntEnumDefinition(const char *name, const char *doc, std::initializer_list< Enumerator > enumerators)
Construct with name, documentation, and enumerators list.
PyObject * build(TEnum value) const
Creates a Python enum instance from a C++ enum value.
int get(PyObject *obj, TEnum &value) const
Extracts a C++ enum value from a Python object.
IntEnumDefinition(const char *name)
Construct with enum name only.
virtual TPyObjPtr doMakeEnumType(TPyObjPtr &&enumerators, TPyObjPtr &&kwargs)
Creates the actual enum.IntEnum type object.
IntFlagDefinition(const char *name, const char *doc, FlagBoundary boundary, std::initializer_list< Enumerator > enumerators)
Construct with name, documentation, boundary behavior, and enumerators.
TPyObjPtr doMakeEnumType(TPyObjPtr &&enumerators, TPyObjPtr &&kwargs) override
Creates an enum.IntFlag-derived type with boundary behavior.
acquire the GIL for the current scope.
Definition gil.h:56
Definition of an enum.StrEnum-derived enum type in Python.
TPyObjPtr doValueObject(PyObject *obj) const override
Extracts string values from enum instances or string objects.
TPyObjPtr doFreezeDefinition(TPyObjPtr &&kwargs) override
Creates an enum.StrEnum-derived type.
a map-like container built on a sorted vector (write-rarely, read-many)
Definition vector_map.h:66
TPyObjPtr makeEnumType(const char *name, TPyObjPtr &&enumerators, TPyObjPtr &&kwargs)
Creates a basic enum.Enum type.
TPyObjPtr makeIntEnumType(const char *name, TPyObjPtr &&enumerators, TPyObjPtr &&kwargs)
Creates an enum.IntEnum type.
TPyObjPtr makeIntFlagType(const char *name, TPyObjPtr &&enumerators, TPyObjPtr &&kwargs, FlagBoundary boundary)
Creates an enum.IntFlag type.
FlagBoundary
Defines the boundary behavior for enum.IntFlag-derived enums.
TPyObjPtr makeStrEnumType(const char *name, TPyObjPtr &&enumerators, TPyObjPtr &&kwargs)
Creates an enum.StrEnum type (or equivalent for Python < 3.11).
@ Keep
Allow any integer value (most permissive)
@ Strict
Only allow exact flag combinations.
@ Conform
Mask to defined bits only.
PyObjectPtr< PyObject >::Type TPyObjPtr
PyObjectPtr to a PyObject.
PyObject * fromSharedPtrToNakedCast(const util::SharedPtr< T, PyObjectStorage, PyObjectCounter > &object)
fromSharedPtrToNakedCast.
Comprehensive C++ to Python binding library.
Library for Assembled Shared Sources.
Definition config.h:53
Represents a single enumerator with name, C++ enum value, and Python value.
TEnum enumerator
Corresponding C++ enum value.
std::string name
Python name for the enumerator.
TValue value
Python value for the enumerator.
Represents a single enumerator member with name and C++ enum value.
TEnum enumerator
Corresponding C++ enum value.
std::string name
Python name for the member.