Skip to content
Draft

V18 #1314

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
39756d1
wip
BenPinet Jun 8, 2026
1b18385
wip
BenPinet Jun 9, 2026
df8dc99
wip
BenPinet Jun 12, 2026
cc237e7
wip
BenPinet Jun 12, 2026
c7ecbe2
wip
BenPinet Jun 16, 2026
20de5b0
Merge branch 'next' into feat/add_uuid_to_attribute
BenPinet Jun 16, 2026
6882d5b
wip
BenPinet Jun 16, 2026
6ec0e96
wip
BenPinet Jun 17, 2026
be288e0
wip
BenPinet Jun 19, 2026
88722b2
Merge branch 'next' into feat/add_uuid_to_attribute
BenPinet Jun 19, 2026
19297f1
wip
BenPinet Jun 19, 2026
3f59771
clean
BenPinet Jun 19, 2026
f549b73
fix python
BenPinet Jun 19, 2026
a9482f0
fix tests
BenPinet Jun 19, 2026
23cfdf1
feat(Attributes): add uuid to identify attributes and remove find or …
BenPinet Jun 22, 2026
3194d1b
feat(Attribute): attribute are now identified with uuid.
BenPinet Jun 22, 2026
4a07b92
fixes for geosciences
BenPinet Jun 23, 2026
d174e81
python fixes
BenPinet Jun 23, 2026
740b3e5
fix copy
BenPinet Jun 24, 2026
fe21d43
fix vertices identifier
BenPinet Jun 25, 2026
c794ab8
fix load vertex identifier
BenPinet Jun 26, 2026
bb19da1
opengeode fixes for background
BenPinet Jun 29, 2026
8999c5e
Merge branch 'next' into feat/add_uuid_to_attribute
BenPinet Jun 30, 2026
759e9e0
Merge branch 'next' into feat/add_uuid_to_attribute
BenPinet Jul 8, 2026
d17100b
add id to scalar function
BenPinet Jul 16, 2026
a0660c1
fix compilation
BenPinet Jul 16, 2026
ca65cfd
remove uuid
BenPinet Jul 16, 2026
f33bbb3
Merge branch 'next' into feat/add_uuid_to_attribute
BenPinet Jul 16, 2026
01b9bd7
add python function
BenPinet Jul 16, 2026
d34cbee
fixes
BenPinet Jul 22, 2026
177ca3e
Merge pull request #1290 from Geode-solutions/feat/add_uuid_to_attribute
BotellaA Jul 23, 2026
aaca805
feat(Attributes): add no-value property support
BenPinet Jul 29, 2026
76633bc
add ways to save vtk files with no data value
BenPinet Jul 30, 2026
93cc080
Merge branch 'next' into v18
BenPinet Jul 31, 2026
473c5d7
Merge branch 'v18' into feat/add_no_value_property_to_attribute
BenPinet Jul 31, 2026
2852353
Merge pull request #1310 from Geode-solutions/feat/add_no_value_prope…
BotellaA Jul 31, 2026
f2ae8f8
fix(Logger): replace warn with warning
BenPinet Aug 3, 2026
e2a5918
fix(SIGN): rename signe struct
BenPinet Aug 3, 2026
e2fd4c6
Merge pull request #1312 from Geode-solutions/feat/replace_replace_wa…
BotellaA Aug 3, 2026
d869749
feat(Passkey): add explicit to passkey constructor
BenPinet Aug 4, 2026
3156d65
Merge pull request #1313 from Geode-solutions/feat/put_sign_struct_in…
BotellaA Aug 4, 2026
7ea4265
Merge branch 'v18' into feat/add_explicit_to_passkey_constructor
BenPinet Aug 5, 2026
0947b1a
Merge pull request #1315 from Geode-solutions/feat/add_explicit_to_pa…
BotellaA Aug 5, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 28 additions & 4 deletions bindings/python/src/basic/attribute.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
namespace geode
{
template < typename type >
void python_attribute_class(

Check warning on line 34 in bindings/python/src/basic/attribute.cpp

View workflow job for this annotation

GitHub Actions / test / tidy

bindings/python/src/basic/attribute.cpp:34:10 [misc-use-internal-linkage]

function 'python_attribute_class' can be made static or moved into an anonymous namespace to enforce internal linkage
pybind11::module& module, const std::string& typestr )
{
const auto read_name = absl::StrCat( "ReadOnlyAttribute", typestr );
Expand All @@ -53,23 +53,47 @@
std::shared_ptr< VariableAttribute< type > > >(
module, variable_name.c_str() )
.def( "set_value", &VariableAttribute< type >::set_value )
.def( "default_value", &VariableAttribute< type >::default_value );
.def(
"default_values", &VariableAttribute< type >::default_values );
const auto sparse_name = absl::StrCat( "SparseAttribute", typestr );
pybind11::class_< SparseAttribute< type >, ReadOnlyAttribute< type >,
std::shared_ptr< SparseAttribute< type > > >(
module, sparse_name.c_str() )
.def( "set_value", &SparseAttribute< type >::set_value )
.def( "default_value", &SparseAttribute< type >::default_value );
.def( "default_values", &SparseAttribute< type >::default_values );
}

template < typename type >
void python_attribute_values_class(

Check warning on line 67 in bindings/python/src/basic/attribute.cpp

View workflow job for this annotation

GitHub Actions / test / tidy

bindings/python/src/basic/attribute.cpp:67:10 [misc-use-internal-linkage]

function 'python_attribute_values_class' can be made static or moved into an anonymous namespace to enforce internal linkage
pybind11::module& module, const std::string& typestr )
{
const auto values_name = absl::StrCat( "AttributeValues", typestr );
pybind11::class_< AttributeValues< type > >(
module, values_name.c_str() )
.def( pybind11::init<>() )
.def_readwrite(
"default_value", &AttributeValues< type >::default_value )
.def_readwrite( "no_value", &AttributeValues< type >::no_value );
}

void define_attributes( pybind11::module& module )

Check warning on line 79 in bindings/python/src/basic/attribute.cpp

View workflow job for this annotation

GitHub Actions / test / tidy

bindings/python/src/basic/attribute.cpp:79:10 [misc-use-internal-linkage]

function 'define_attributes' can be made static or moved into an anonymous namespace to enforce internal linkage
{
pybind11::class_< AttributeProperties >( module, "AttributeProperties" )
.def( pybind11::init<>() )
.def( pybind11::init< bool, bool >() )
.def_readwrite( "assignable", &AttributeProperties::assignable )
.def_readwrite( "interpolable", &AttributeProperties::interpolable )
.def_readwrite(
"interpolable", &AttributeProperties::interpolable );
"transferable", &AttributeProperties::transferable );

python_attribute_values_class< bool >( module, "Bool" );
python_attribute_values_class< int >( module, "Int" );
python_attribute_values_class< unsigned int >( module, "UInt" );
python_attribute_values_class< float >( module, "Float" );
python_attribute_values_class< double >( module, "Double" );
python_attribute_values_class< std::array< double, 2 > >(
module, "ArrayDouble2" );
python_attribute_values_class< std::array< double, 3 > >(
module, "ArrayDouble3" );

pybind11::class_< AttributeBase, std::shared_ptr< AttributeBase > >(
module, "AttributeBase" )
Expand Down
80 changes: 59 additions & 21 deletions bindings/python/src/basic/attribute_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,43 +33,79 @@
namespace geode
{
template < typename type >
void python_attribute_class( pybind11::class_< AttributeManager >& manager,

Check warning on line 36 in bindings/python/src/basic/attribute_manager.cpp

View workflow job for this annotation

GitHub Actions / test / tidy

bindings/python/src/basic/attribute_manager.cpp:36:10 [misc-use-internal-linkage]

variable 'python_attribute_class' can be made static or moved into an anonymous namespace to enforce internal linkage

Check warning on line 36 in bindings/python/src/basic/attribute_manager.cpp

View workflow job for this annotation

GitHub Actions / test / tidy

bindings/python/src/basic/attribute_manager.cpp:36:10 [cppcoreguidelines-avoid-non-const-global-variables]

variable 'python_attribute_class' is non-const and globally accessible, consider making it const
const std::string& suffix )
{
const auto read_suffix = absl::StrCat( "find_attribute_", suffix );
manager.def(
read_suffix.c_str(), &AttributeManager::find_attribute< type > );
const auto constant_suffix =
absl::StrCat( "find_or_create_attribute_constant_", suffix );
manager.def( constant_suffix.c_str(),
const auto read_suffix =
absl::StrCat( "find_read_only_attribute_", suffix );
manager.def( read_suffix.c_str(),
&AttributeManager::find_read_only_attribute< type > );
const auto create_constant_suffix =
absl::StrCat( "create_attribute_constant_", suffix );
manager.def( create_constant_suffix.c_str(),
static_cast< geode::uuid ( AttributeManager::* )( std::string_view,
AttributeValues< type >, AttributeProperties ) >(
&AttributeManager::create_attribute< ConstantAttribute,
type > ) );
manager.def( create_constant_suffix.c_str(),
static_cast< void ( AttributeManager::* )( std::string_view,
const uuid&, AttributeValues< type >, AttributeProperties ) >(
&AttributeManager::create_attribute< ConstantAttribute,
type > ) );
const auto find_constant_suffix =
absl::StrCat( "find_attribute_constant_", suffix );
manager.def( find_constant_suffix.c_str(),
static_cast< std::shared_ptr< ConstantAttribute< type > > (
AttributeManager::* )( std::string_view, type ) >(
&AttributeManager::find_or_create_attribute< ConstantAttribute,
AttributeManager::* )( const geode::uuid& ) >(
&AttributeManager::find_attribute< ConstantAttribute,
type > ) );
const auto create_variable_suffix =
absl::StrCat( "create_attribute_variable_", suffix );
manager.def( create_variable_suffix.c_str(),
static_cast< geode::uuid ( AttributeManager::* )( std::string_view,
AttributeValues< type >, AttributeProperties ) >(
&AttributeManager::create_attribute< VariableAttribute,
type > ) );
manager.def( create_variable_suffix.c_str(),
static_cast< void ( AttributeManager::* )( std::string_view,
const uuid&, AttributeValues< type >, AttributeProperties ) >(
&AttributeManager::create_attribute< VariableAttribute,
type > ) );
const auto variable_suffix =
absl::StrCat( "find_or_create_attribute_variable_", suffix );
manager.def( variable_suffix.c_str(),
const auto find_variable_suffix =
absl::StrCat( "find_attribute_variable_", suffix );
manager.def( find_variable_suffix.c_str(),
static_cast< std::shared_ptr< VariableAttribute< type > > (
AttributeManager::* )( std::string_view, type ) >(
&AttributeManager::find_or_create_attribute< VariableAttribute,
AttributeManager::* )( const geode::uuid& ) >(
&AttributeManager::find_attribute< VariableAttribute,
type > ) );
const auto sparse_suffix =
absl::StrCat( "find_or_create_attribute_sparse_", suffix );
manager.def( sparse_suffix.c_str(),
static_cast< std::shared_ptr< SparseAttribute< type > > (
AttributeManager::* )( std::string_view, type ) >(
&AttributeManager::find_or_create_attribute< SparseAttribute,
const auto create_sparse_suffix =
absl::StrCat( "create_attribute_sparse_", suffix );
manager.def( create_sparse_suffix.c_str(),
static_cast< geode::uuid ( AttributeManager::* )( std::string_view,
AttributeValues< type >, AttributeProperties ) >(
&AttributeManager::create_attribute< SparseAttribute,
type > ) );
manager.def( create_sparse_suffix.c_str(),
static_cast< void ( AttributeManager::* )( std::string_view,
const uuid&, AttributeValues< type >, AttributeProperties ) >(
&AttributeManager::create_attribute< SparseAttribute,
type > ) );
const auto find_sparse_suffix =
absl::StrCat( "find_attribute_sparse_", suffix );
manager.def( find_sparse_suffix.c_str(),
static_cast< std::shared_ptr< SparseAttribute< type > > (
AttributeManager::* )( const geode::uuid& ) >(
&AttributeManager::find_attribute< SparseAttribute, type > ) );
}

void define_attribute_manager( pybind11::module& module )

Check warning on line 101 in bindings/python/src/basic/attribute_manager.cpp

View workflow job for this annotation

GitHub Actions / test / tidy

bindings/python/src/basic/attribute_manager.cpp:101:10 [misc-use-internal-linkage]

function 'define_attribute_manager' can be made static or moved into an anonymous namespace to enforce internal linkage
{
pybind11::class_< AttributeManager > manager(
module, "AttributeManager" );
manager.def( pybind11::init<>() )
.def( "find_generic_attribute",
&AttributeManager::find_generic_attribute )
.def( "attribute_names", &AttributeManager::attribute_names )
.def( "attribute_ids", &AttributeManager::attribute_ids )
.def( "attribute_type", &AttributeManager::attribute_type )
.def( "attribute_exists", &AttributeManager::attribute_exists )
.def( "nb_elements", &AttributeManager::nb_elements )
Expand All @@ -80,7 +116,9 @@
.def( "delete_attribute", &AttributeManager::delete_attribute )
.def( "set_attribute_properties",
&AttributeManager::set_attribute_properties )
.def( "delete_elements", &AttributeManager::delete_elements );
.def( "delete_elements", &AttributeManager::delete_elements )
.def( "attribute_ids_matching_name",
&AttributeManager::attribute_ids_matching_name );
python_attribute_class< bool >( manager, "bool" );
python_attribute_class< int >( manager, "int" );
python_attribute_class< unsigned int >( manager, "uint" );
Expand Down
4 changes: 2 additions & 2 deletions bindings/python/src/geometry/sign.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,14 @@

namespace geode
{
void define_sign( pybind11::module& module )

Check warning on line 33 in bindings/python/src/geometry/sign.cpp

View workflow job for this annotation

GitHub Actions / test / tidy

bindings/python/src/geometry/sign.cpp:33:10 [misc-use-internal-linkage]

function 'define_sign' can be made static or moved into an anonymous namespace to enforce internal linkage
{
module.def( "tetrahedron_volume_sign", &tetrahedron_volume_sign );
module.def( "triangle_area_sign2D",
static_cast< Sign ( * )( const Triangle2D& ) >(
static_cast< SIGN ( * )( const Triangle2D& ) >(
&triangle_area_sign ) );
module.def( "triangle_area_sign3D",
static_cast< Sign ( * )( const Triangle3D&, local_index_t ) >(
static_cast< SIGN ( * )( const Triangle3D&, local_index_t ) >(
&triangle_area_sign ) );
}
} // namespace geode
99 changes: 73 additions & 26 deletions bindings/python/tests/basic/test-py-attribute.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,61 +30,108 @@


def test_constant_attribute(manager):
constant_attribute = manager.find_or_create_attribute_constant_bool(
"bool", True)

attribute = manager.find_attribute_bool("bool")

properties = basic.AttributeProperties()
properties.assignable = False
properties.interpolable = False
properties.transferable = True
values = basic.AttributeValuesBool()
values.default_value = True
values.no_value = False
constant_attribute_id = manager.create_attribute_constant_bool(
"bool", values, properties)
constant_attribute = manager.find_attribute_constant_bool(constant_attribute_id)
attribute = manager.find_read_only_attribute_bool(constant_attribute_id)
if not attribute.value(0):
raise ValueError("[Test] Should be equal to True")

constant_attribute.set_value(False)
if attribute.value(12):
raise ValueError("[Test] Should be equal to False")
return constant_attribute_id


def test_int_variable_attribute(manager):
variable_attribute = manager.find_or_create_attribute_variable_int(
"int", 12)

properties = basic.AttributeProperties()
properties.assignable = False
properties.interpolable = False
properties.transferable = True
values = basic.AttributeValuesInt()
values.default_value = 12
values.no_value = 12
variable_attribute_id = manager.create_attribute_variable_int(
"int", values, properties)
variable_attribute = manager.find_attribute_variable_int(variable_attribute_id)
variable_attribute.set_value(3, 3)
if not variable_attribute.is_genericable():
raise ValueError("[Test] Should be genericable")

new_properties = basic.AttributeProperties()
new_properties.assignable = True
new_properties.interpolable = True
properties.transferable = True
manager.set_attribute_properties(variable_attribute_id,new_properties)

manager.set_attribute_properties("int",basic.AttributeProperties(True,True))
if not variable_attribute.properties().assignable or not variable_attribute.properties().interpolable :
raise ValueError("[Test] Should be assignable and interpolable")

attribute = manager.find_attribute_int("int")
if attribute.value(3) != 3:
find_read_only_attribute = manager.find_read_only_attribute_int(variable_attribute_id)
if variable_attribute.value(3) != 3:
raise ValueError("[Test] Should be equal to 3")
if attribute.value(6) != 12:
if variable_attribute.value(6) != 12:
raise ValueError("[Test] Should be equal to 12")
if find_read_only_attribute.value(3) != 3:
raise ValueError("[Test] Should be equal to 3")
if find_read_only_attribute.value(6) != 12:
raise ValueError("[Test] Should be equal to 12")

variable_attribute.set_value(3, 5)
if attribute.value(3) != 5:
if variable_attribute.value(3) != 5:
raise ValueError("[Test] Should be equal to 5")
if find_read_only_attribute.value(3) != 5:
raise ValueError("[Test] Should be equal to 5")


def test_double_sparse_attribute(manager):
sparse_attribute = manager.find_or_create_attribute_sparse_double(
"double", 12)
sparse_attribute.set_value(3, 3)
sparse_attribute.set_value(7, 7)

attribute = manager.find_attribute_double("double")
properties = basic.AttributeProperties()
properties.assignable = False
properties.interpolable = False
properties.transferable = True
values = basic.AttributeValuesDouble()
values.default_value = 12
values.no_value = 12
sparse_attribute_id = manager.create_attribute_sparse_double(
"double", values,properties)
attribute = manager.find_attribute_sparse_double(sparse_attribute_id)
attribute.set_value(3, 3)
attribute.set_value(7, 7)

find_read_only_attribute = manager.find_read_only_attribute_double(sparse_attribute_id)
if attribute.value(3) != 3:
raise ValueError("[Test] Should be equal to 3")
if attribute.value(6) != 12:
raise ValueError("[Test] Should be equal to 12")
if attribute.value(7) != 7:
raise ValueError("[Test] Should be equal to 7")
if find_read_only_attribute.value(3) != 3:
raise ValueError("[Test] Should be equal to 3")
if find_read_only_attribute.value(6) != 12:
raise ValueError("[Test] Should be equal to 12")
if find_read_only_attribute.value(7) != 7:
raise ValueError("[Test] Should be equal to 7")

sparse_attribute.set_value(3, 5)
attribute.set_value(3, 5)
if attribute.value(3) != 5:
raise ValueError("[Test] Should be equal to 5")
if find_read_only_attribute.value(3) != 5:
raise ValueError("[Test] Should be equal to 5")
return sparse_attribute_id


def test_number_of_attributes(manager, nb):
if len(manager.attribute_names()) != nb:
if len(manager.attribute_ids()) != nb:
raise ValueError(
"[Test] Not the correct number of attributes in the manager")

Expand All @@ -99,8 +146,8 @@ def test_delete_attribute_elements(manager):
"[Test] Two attribute elements should have been removed")


def test_sparse_attribute_after_element_deletion(manager):
sparse_attribute = manager.find_attribute_double("double")
def test_sparse_attribute_after_element_deletion(manager, double_attribute_id):
sparse_attribute = manager.find_read_only_attribute_double(double_attribute_id)
if sparse_attribute.value(0) != 12:
raise ValueError("Element 0 of sparse attribute should be 12 ")
if sparse_attribute.value(5) != 7:
Expand All @@ -114,17 +161,17 @@ def test_sparse_attribute_after_element_deletion(manager):
manager.resize(10)
if manager.nb_elements() != 10:
raise ValueError("[Test] Manager should have 10 elements")
test_constant_attribute(manager)
bool_attribute_id = test_constant_attribute(manager)
test_int_variable_attribute(manager)
test_double_sparse_attribute(manager)
test_double_sparse_attribute(manager)
double_attribute_id = test_double_sparse_attribute(manager)
test_delete_attribute_elements(manager)
test_sparse_attribute_after_element_deletion(manager)
test_sparse_attribute_after_element_deletion(manager,double_attribute_id)
test_number_of_attributes(manager, 4)
manager.delete_attribute(bool_attribute_id)
test_number_of_attributes(manager, 3)
manager.delete_attribute("bool")
test_number_of_attributes(manager, 2)
manager.clear_attributes()
test_number_of_attributes(manager, 2)
test_number_of_attributes(manager, 3)
manager.resize(10)
if manager.nb_elements() != 10:
raise ValueError("[Test] Manager should have 10 elements")
Expand Down
16 changes: 13 additions & 3 deletions bindings/python/tests/mesh/test-py-edged-curve.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,18 @@ def test_edge_requests(edged_curve, builder):


def test_clone(edged_curve):
attribute = edged_curve.edge_attribute_manager(
).find_or_create_attribute_variable_int("test", 0)

properties = opengeode_py_basic.AttributeProperties()
properties.assignable = False
properties.interpolable = False
properties.transferable = True
values = opengeode_py_basic.AttributeValuesInt()
values.default_value = 0
values.no_value = 0
attribute_id = edged_curve.edge_attribute_manager(
).create_attribute_variable_int("test", values,properties)

attribute = edged_curve.edge_attribute_manager().find_attribute_variable_int(attribute_id)
attribute.set_value(0, 42)

edged_curve2 = edged_curve.clone()
Expand All @@ -133,7 +143,7 @@ def test_clone(edged_curve):
if edged_curve2.nb_edges() != 3:
raise ValueError("[Test] EdgedCurve2 should have 3 edge")

attribute2 = edged_curve2.edge_attribute_manager().find_attribute_int("test")
attribute2 = edged_curve2.edge_attribute_manager().find_read_only_attribute_int(attribute_id)
if attribute2.value(0) != 42:
raise ValueError("[Test] EdgedCurve2 attribute should be 42")

Expand Down
Loading
Loading