Skip to content

Attribute

Helper for a named attribute stored on a geometry.

Attribute complements the standard named-attribute methods exposed by geometries and domains. It keeps the attribute name, domain, data type and geometry together, and lets the attribute be used much like a socket in an expression.

An instance is normally created with Domain.get or Geometry.get, rather than by calling this constructor directly.

Typical usage

Create a face attribute of type Vector and store a value:

    mesh = Mesh()
    attr = mesh.faces.get("My Vector", Vector)
    attr.set((0, 0, 1))

The same operation can be written through the value property. Reading the property creates a Named Attribute node; assigning it creates a Store Named Attribute node:

    attr = mesh.faces.get("My Vector", Vector)

    vector_field = attr.value
    attr.value = vector_field.normalize()

Read an existing integer attribute, build an expression and store its cached result:

    attr = mesh.faces.get("My Integer", Integer)
    attr = attr ** 2
    attr = attr + 1
    attr.set()

Attributes can be combined with sockets, constants, or other attributes. The resulting field remains cached until set() is called:

    weight = mesh.points.get("Weight", Float)
    factor = mesh.points.get("Factor", Float)

    weight = weight * factor + 0.25
    weight.set()

Non-in-place operators cache their result on the helper. Calling set without a value stores that cached result. In-place operators write their result to the geometry immediately:

    attr += 1
    attr *= 2

Named attributes can also be removed or renamed:

    attr.rename("My Renamed Integer")
    attr.remove()

Parameters:

Name Type Description Default
name str

Name of the attribute.

required
data_type type | str | value

Socket type used to read and store the attribute. For example, Float, Integer or Vector.

None
domain str | Domain | Geometry

Attribute domain, optionally carrying the geometry on which the attribute is stored. The default domain is Point.

None
Notes

Attribute represents Geometry Nodes fields; it does not read or modify Blender mesh attribute data directly from Python.

Source code in core/attributes.py
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
class Attribute:
    """Helper for a named attribute stored on a geometry.

    ``Attribute`` complements the standard named-attribute methods exposed by
    geometries and domains. It keeps the attribute name, domain, data type and
    geometry together, and lets the attribute be used much like a socket in an
    expression.

    An instance is normally created with ``Domain.get`` or ``Geometry.get``,
    rather than by calling this constructor directly.

    Typical usage
    -------------
    Create a face attribute of type ``Vector`` and store a value:

    ``` python
        mesh = Mesh()
        attr = mesh.faces.get("My Vector", Vector)
        attr.set((0, 0, 1))
    ```

    The same operation can be written through the ``value`` property. Reading
    the property creates a Named Attribute node; assigning it creates a Store
    Named Attribute node:

    ``` python
        attr = mesh.faces.get("My Vector", Vector)

        vector_field = attr.value
        attr.value = vector_field.normalize()
    ```

    Read an existing integer attribute, build an expression and store its
    cached result:

    ``` python
        attr = mesh.faces.get("My Integer", Integer)
        attr = attr ** 2
        attr = attr + 1
        attr.set()
    ```

    Attributes can be combined with sockets, constants, or other attributes.
    The resulting field remains cached until ``set()`` is called:

    ``` python
        weight = mesh.points.get("Weight", Float)
        factor = mesh.points.get("Factor", Float)

        weight = weight * factor + 0.25
        weight.set()
    ```

    Non-in-place operators cache their result on the helper. Calling
    ``set`` without a value stores that cached result. In-place operators
    write their result to the geometry immediately:

    ``` python
        attr += 1
        attr *= 2
    ```

    Named attributes can also be removed or renamed:

    ``` python
        attr.rename("My Renamed Integer")
        attr.remove()
    ```

    Parameters
    ----------
    name : str
        Name of the attribute.
    data_type : type | str | value, optional
        Socket type used to read and store the attribute. For example,
        ``Float``, ``Integer`` or ``Vector``.
    domain : str | Domain | Geometry, optional
        Attribute domain, optionally carrying the geometry on which the
        attribute is stored. The default domain is ``Point``.

    Notes
    -----
    ``Attribute`` represents Geometry Nodes fields; it does not read or modify
    Blender mesh attribute data directly from Python.
    """

    DOMAINS = {
        'Point'     : 'POINT', 
        'Edge'      : 'EDGE', 
        'Face'      : 'FACE', 
        'Corner'    : 'CORNER', 
        'Spline'    : 'CURVE', 
        'Instance'  : 'INSTANCE', 
        'Layer'     : 'LAYER'}

    DT_SET = {
        'Float'         : 'FLOAT',
        'Integer'       : 'INT',
        'Boolean'       : 'BOOLEAN',
        'Vector'        : 'FLOAT_VECTOR', 
        'Color'         : 'FLOAT_COLOR', 
        'Quaternion'    : 'QUATERNION', 
        '4x4 Matrix'    : 'FLOAT4X4', 
        '8Bit Integer'  : 'INT8', 
        '2D Vector'     : 'FLOAT2', 
        '4D Vector'     : 'FLOAT4',
        'Byte Color'    : 'BYTE_COLOR',
        }
    DT_GET = {
        'Float'         : 'FLOAT',
        'Integer'       : 'INT',
        'Boolean'       : 'BOOLEAN',
        'Vector'        : 'FLOAT_VECTOR', 
        'Color'         : 'FLOAT_COLOR', 
        'Quaternion'    : 'QUATERNION', 
        '4x4 Matrix'    : 'FLOAT4X4', 
        '8Bit Integer'  : 'INT',            #'INT8', 
        '2D Vector'     : 'FLOAT_VECTOR',   #'FLOAT2', 
        '4D Vector'     : 'FLOAT_VECTOR',   #'FLOAT4',
        'Byte Color'    : 'COLOR',          #'BYTE_COLOR',
        }

    def __init__(self, name, data_type=None, domain=None):
        """Create a named geometry-attribute helper.

        Parameters
        ----------
        name : str | String
            Name of the attribute.
        data_type : type | str | value, optional
            Socket type used to read and store the attribute.
        domain : str | Domain | Geometry, optional
            Attribute domain and, when supplied by a domain or geometry
            instance, the geometry on which the attribute is stored.
        """

        self._value = None

        # Name
        self.name = name

        # Geometry and domain

        self.geometry     = None
        self._domain_name = None
        self.domain       = domain

        # data type

        self._data_type = None
        self.data_type = data_type

    # ----------------------------------------------------------------------------------------------------
    # str
    # ----------------------------------------------------------------------------------------------------

    def __str__(self):
        return f"<Attribute: {self.geometry}.{str(self.name)}, domain: {self.domain_name}, type: {self.data_type}>"

    # ----------------------------------------------------------------------------------------------------
    # Error if geometry is not defined
    # ----------------------------------------------------------------------------------------------------

    def _check_geometry(self, message):
        if self.geometry is None:
            raise NodeError(f"Attribute.geometry is None, {message}")

    # ----------------------------------------------------------------------------------------------------
    # Geometry and domain
    # ----------------------------------------------------------------------------------------------------

    @classmethod
    def _get_geo_domain(cls, value):

        from .geometry_class import Geometry
        from .domain_class import Domain

        geometry = None
        domain_name = None

        if value is None:
            return None, None

        elif isinstance(value, Domain):
            geometry = value._geo
            domain_name = value.DOMAIN_NAME.title()

        elif isinstance(value, Geometry):
            geometry = value

        elif isinstance(value, str):
            domain_name = value

        else:
            raise NodeError(f"Value <{value}> is not a valid domain for named Attribute.")

        if domain_name is None:
            return geometry, None

        # Domain name

        if domain_name == 'Face Corner':
            domain_name = 'Corner'
        elif domain_name == 'Curve':
            domain_name = 'Spline'

        if domain_name not in Attribute.DOMAINS:
            raise ValueError(f"Attribute.domain name error: '{domain_name}' not in {Attribute.DOMAINS}")

        return geometry, domain_name

    @property
    def domain_name(self):
        if self._domain_name is None:
            return 'Point'
        else:
            return self._domain_name

    @domain_name.setter
    def domain_name(self, value):
        _, domain_name = self._get_geo_domain(value)
        self._domain_name = domain_name

    @property
    def domain(self):
        if self.domain_name is None:
            return None

        prop_name = "insts" if self.domain_name == 'Instance' else self.domain_name.lower() + "s"
        try:
            return getattr(self.geometry, prop_name)
        except:
            pass

        raise AttributeError(f"Attribute error: {self} geometry {self.geometry} doesn't have a domain '{self.domain_name}'")

    @domain.setter
    def domain(self, value):

        geometry, domain_name = self._get_geo_domain(value)
        if geometry is not None:
            self.geometry = geometry
        if domain_name is not None:
            self.domain_name = domain_name

    # ----------------------------------------------------------------------------------------------------
    # Data type
    # ----------------------------------------------------------------------------------------------------

    @classmethod
    def _get_data_type(cls, value):

        from .sockettype import SocketType

        if value is None:
            return None

        dt = SocketType.get_data_type_for_node(value, 'GeometryNodeStoreNamedAttribute')

        for i, data_type in enumerate(list(Attribute.DT_SET.values())):
            if data_type == dt:
                return list(Attribute.DT_SET.keys())[i]

        return None

    @property
    def data_type(self):
        if self._data_type is None:
            self._data_type = 'Float'
        return self._data_type

    @data_type.setter
    def data_type(self, value):
        self._data_type = self._get_data_type(value)

    # ====================================================================================================
    # Setting and getting
    # ====================================================================================================

    # ----------------------------------------------------------------------------------------------------
    # Getting
    # ----------------------------------------------------------------------------------------------------

    def get(self):
        """Return the attribute as a Geometry Nodes field socket.

        > Node Named Attribute

        The Named Attribute node is created lazily. Its output is cached until
        ``set`` writes a value and clears the cache.

        Returns
        -------
        Socket
            Field socket containing the named attribute value.
        """

        from .nodeclass import Node

        if self._value is None:
            self._value = Node('Named Attribute', 
            {'Name': self.name}, 
            data_type = Attribute.DT_SET[self.data_type],
            )._out

        return self._value

    # ----------------------------------------------------------------------------------------------------
    # Setting
    # ----------------------------------------------------------------------------------------------------

    def set(self, value=None, domain=None):
        """Store a value in the named attribute.

        > Node Store Named Attribute

        If ``value`` is omitted, the result cached by the latest non-in-place
        operation is stored. In-place operators such as ``+=`` call this method
        automatically.

        Parameters
        ----------
        value : value | Socket, optional
            Value or field to store. When omitted, use the cached value.
        domain : str | Domain | Geometry, optional
            Override the geometry or domain configured on this helper. Passing
            a ``Domain`` also applies that domain's selection.

        Returns
        -------
        Attribute
            This helper, with its cached value cleared.
        """

        from .nodeclass import Node

        # ---------------------------------------------------------------------------
        # Value and data_type
        # ---------------------------------------------------------------------------

        if value is None:
            value = self._value
        if self.data_type is None:
            self.data_type = self._get_data_type(value)

        # ---------------------------------------------------------------------------
        # Domain argument overrides properties
        # ---------------------------------------------------------------------------

        selection = None

        # Geometry and domain name from domain argument
        geo, dn = self._get_geo_domain(domain)

        # Not None, overrides attributes
        if geo is not None:
            self.geometry = geo
            #selection = domain.get_selection()
        if dn is not None:
            self.domain_name = dn

        # ---------------------------------------------------------------------------
        # Selection
        # ---------------------------------------------------------------------------

        dom = self.domain
        if dom is None:
            selection = self.geometry.get_selection()
        else:
            selection = dom.get_selection()

        # ---------------------------------------------------------------------------
        # Create the node
        # ---------------------------------------------------------------------------

        socket = Node('Store Named Attribute', {
            'Geometry': self.geometry,
            'Selection': selection,
            'Name': self.name,
            'Value': value},
            domain = self.domain_name,
            data_type = Attribute.DT_SET[self.data_type],
            )._out

        if self.geometry is not None:
            self.geometry._jump(socket)

        self._value = None

        return self

    @property
    def value(self):
        """Read or store the named attribute value.

        Getter
        ------
        > Node Named Attribute

        Reading ``value`` calls ``get()``. It creates a Named Attribute node
        when the field is not already cached, then returns its output socket:

        ``` python
            field = attr.value
        ```

        Setter
        ------
        > Node Store Named Attribute

        Assigning ``value`` calls ``set()``. It creates a Store Named Attribute
        node and updates the geometry attached to this helper:

        ``` python
            attr.value = field
        ```

        Returns
        -------
        Socket
            The Named Attribute field socket when the property is read.
        """
        return self.get()

    @value.setter
    def value(self, value):
        self.set(value)

    # ====================================================================================================
    # Remove
    # ====================================================================================================

    def remove(self, wildcard=None):
        """Remove the named attribute from the geometry.

        > Node Remove Named Attribute

        Parameters
        ----------
        wildcard : str | String, default=None
            wild card string

        Raises
        ------
        NodeError
            If no geometry is attached to the helper.
        """
        self._check_geometry(f"Impossible to remove named attribute '{str(self.name)}'")

        if wildcard is None:
            self.geometry.remove_named_attribute(pattern_mode='Exact', name=self.name)
        else:
            self.geometry.remove_named_attribute(pattern_mode='Wildcard', name=wildcard)

    # ====================================================================================================
    # Rename
    # ====================================================================================================

    def rename(self, name, overwrite=None):
        """Rename the attribute on the geometry.

        > Node Rename Attribute

        Parameters
        ----------
        name : str
            New attribute name.
        overwrite : bool, optional
            Value passed to the Rename Attribute node's overwrite input.

        Raises
        ------
        NodeError
            If no geometry is attached to the helper.
        """
        self._check_geometry(f"Impossible to rename attribute '{str(self.name)}'")

        new_name = name
        self.geometry.rename_attribute(mode='Single', old=self.name, new=new_name, overwrite=overwrite)
        self.name = name

    # ====================================================================================================
    # Operations
    # ====================================================================================================

    def _set_value(self, value):
        self._value = value
        return self

    @classmethod
    def _aget(cls, other):
        if isinstance(other, Attribute):
            return other.get()
        else:
            return other

    # ----- Neg

    def __neg__(self):
        return self._set_value(self.get().multiply(-1))

    # ----- Abs

    def __abs__(self):
        return self._set_value(self.get().abs())

    # ----- Addition

    def __add__(self, other):
        return self._set_value(self.get() + self._aget(other))

    def __radd__(self, other):
        return self._set_value(self._aget(other) + self.get())

    def __iadd__(self, other):
        return self.set(self.get() + self._aget(other))

    # ----- Subtraction

    def __sub__(self, other):
        return self._set_value(self.get() - self._aget(other))

    def __rsub__(self, other):
        return self._set_value(self._aget(other) - self.get())

    def __isub__(self, other):
        return self.set(self.get() - self._aget(other))

    # ----- Multiplication

    def __mul__(self, other):
        return self._set_value(self.get() * self._aget(other))

    def __rmul__(self, other):
        return self._set_value(self._aget(other) * self.get())

    def __imul__(self, other):
        return self.set(self.get() * self._aget(other))

    # ----- Division

    def __truediv__(self, other):
        return self._set_value(self.get() / self._aget(other))

    def __rtruediv__(self, other):
        return self._set_value(self._aget(other) / self.get())

    def __itruediv__(self, other):
        return self.set(self.get() / self._aget(other))

    # ----- Modulo

    def __mod__(self, other):
        return self._set_value(self.get() % self._aget(other))

    def _rmod__(self, other):
        return self._set_value(self._aget(other) % self.get())

    def __imod__(self, other):
        return self.set(self.get() % self._aget(other))

    # ----- Power

    def __pow__(self, other):
        return self._set_value(self.get() ** self._aget(other))

    def __rpow__(self, other):
        return self._set_value(self._aget(other) ** self.get())

    def __ipow__(self, other):
        return self.set(self.get() ** self._aget(other))

    # ----- Operations

    def __round__(self):
        return self._set_value(self.get().round())

    def __trunc__(self):
        return self._set_value(self.get().trunc())

    def __floor__(self):
        return self._set_value(self.get().floor())

    def __ceil__(self):
        return self._set_value(self.get().ceil())

    # =============================================================================================================================
    # Comparison
    # __eq__ __ne__ __lt__ __gt__ __le__ __ge__

    def __ge__(self, other):
        return self._set_value(self.get().greater_equal(self._aget(other)))

    def __gt__(self, other):
        return self._set_value(self.get().greater_than(self._aget(other)))

    def __le__(self, other):
        return self._set_value(self.get().less_equal(self._aget(other)))

    def __lt__(self, other):
        return self._set_value(self.get().less_than(self._aget(other)))

    def __eq__(self, other):
        return self._set_value(self.get().equal(self._aget(other)))

    def __ne__(self, other):
        return self._set_value(self.get().not_equal(self._aget(other)))

    # =============================================================================================================================
    # Boolean specific

    def __or__(self, other):
        return self._set_value(self.get().bor(self._aget(other)))

    def __ror__(self, other):
        return self._set_value(self.get().bor(self._aget(other)))

    def __and__(self, other):
        return self._set_value(self.get().band(self._aget(other)))

    def __rand__(self, other):
        return self._set_value(self.get().band(self._aget(other)))

    def __xor__(self, other):
        return self.get()._set_value(self.get().xor(self._aget(other)))

    def __rxor__(self, other):
        return self._set_value(self.get().xor(self._aget(other)))

    # To avoid user errors

    def __bool__(self):
        raise NodeError(f"Attribute is not a python bool : {self}")

    # ====================================================================================================
    # Class test
    # ====================================================================================================

    @classmethod
    def _class_test(cls):

        from geonodes import GeoNodes, Mesh, Layout, Float, Integer, Vector

        with GeoNodes("Attribute Test"):

            mesh = Mesh()

            # Create attributes and store explicit values.
            with Layout("Create and set"):
                direction = mesh.faces.get("My Vector", Vector)
                direction.set((0, 0, 1))

                weight = mesh.points.get("Weight", Float)
                weight.value = 0.5

            # Read an attribute as a field, cache operations, then store the
            # cached result with set().
            with Layout("Cached operations"):
                counter = mesh.faces.get("My Integer", Integer)
                counter = counter**2
                counter = counter + 1
                counter.set()

            # In-place operations store their result immediately.
            with Layout("In-place operations"):
                counter += 1
                counter *= 2

            # Attribute helpers can be created from Geometry as well as Domain.
            with Layout("Geometry helper"):
                factor = mesh.get("Factor", Float, domain="Face")
                factor.set(direction.value.length())

            # Rename and remove attributes from the geometry.
            with Layout("Rename and remove"):
                temporary = mesh.points.get("Temporary", Float)
                temporary.set(1.0)
                temporary.rename("Renamed")
                temporary.remove()

            # Get Attribute Names with both domain and data-type filters.
            names = mesh.faces.get_attribute_names(Vector)

            mesh.out()
            names.out("Face Vector Attributes")

value property writable

Read or store the named attribute value.

Getter

Node Named Attribute

Reading value calls get(). It creates a Named Attribute node when the field is not already cached, then returns its output socket:

    field = attr.value
Setter

Node Store Named Attribute

Assigning value calls set(). It creates a Store Named Attribute node and updates the geometry attached to this helper:

    attr.value = field

Returns:

Type Description
Socket

The Named Attribute field socket when the property is read.

__init__(name, data_type=None, domain=None)

Create a named geometry-attribute helper.

Parameters:

Name Type Description Default
name str | String

Name of the attribute.

required
data_type type | str | value

Socket type used to read and store the attribute.

None
domain str | Domain | Geometry

Attribute domain and, when supplied by a domain or geometry instance, the geometry on which the attribute is stored.

None
Source code in core/attributes.py
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
def __init__(self, name, data_type=None, domain=None):
    """Create a named geometry-attribute helper.

    Parameters
    ----------
    name : str | String
        Name of the attribute.
    data_type : type | str | value, optional
        Socket type used to read and store the attribute.
    domain : str | Domain | Geometry, optional
        Attribute domain and, when supplied by a domain or geometry
        instance, the geometry on which the attribute is stored.
    """

    self._value = None

    # Name
    self.name = name

    # Geometry and domain

    self.geometry     = None
    self._domain_name = None
    self.domain       = domain

    # data type

    self._data_type = None
    self.data_type = data_type

get()

Return the attribute as a Geometry Nodes field socket.

Node Named Attribute

The Named Attribute node is created lazily. Its output is cached until set writes a value and clears the cache.

Returns:

Type Description
Socket

Field socket containing the named attribute value.

Source code in core/attributes.py
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
def get(self):
    """Return the attribute as a Geometry Nodes field socket.

    > Node Named Attribute

    The Named Attribute node is created lazily. Its output is cached until
    ``set`` writes a value and clears the cache.

    Returns
    -------
    Socket
        Field socket containing the named attribute value.
    """

    from .nodeclass import Node

    if self._value is None:
        self._value = Node('Named Attribute', 
        {'Name': self.name}, 
        data_type = Attribute.DT_SET[self.data_type],
        )._out

    return self._value

remove(wildcard=None)

Remove the named attribute from the geometry.

Node Remove Named Attribute

Parameters:

Name Type Description Default
wildcard str | String

wild card string

None

Raises:

Type Description
NodeError

If no geometry is attached to the helper.

Source code in core/attributes.py
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
def remove(self, wildcard=None):
    """Remove the named attribute from the geometry.

    > Node Remove Named Attribute

    Parameters
    ----------
    wildcard : str | String, default=None
        wild card string

    Raises
    ------
    NodeError
        If no geometry is attached to the helper.
    """
    self._check_geometry(f"Impossible to remove named attribute '{str(self.name)}'")

    if wildcard is None:
        self.geometry.remove_named_attribute(pattern_mode='Exact', name=self.name)
    else:
        self.geometry.remove_named_attribute(pattern_mode='Wildcard', name=wildcard)

rename(name, overwrite=None)

Rename the attribute on the geometry.

Node Rename Attribute

Parameters:

Name Type Description Default
name str

New attribute name.

required
overwrite bool

Value passed to the Rename Attribute node's overwrite input.

None

Raises:

Type Description
NodeError

If no geometry is attached to the helper.

Source code in core/attributes.py
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
def rename(self, name, overwrite=None):
    """Rename the attribute on the geometry.

    > Node Rename Attribute

    Parameters
    ----------
    name : str
        New attribute name.
    overwrite : bool, optional
        Value passed to the Rename Attribute node's overwrite input.

    Raises
    ------
    NodeError
        If no geometry is attached to the helper.
    """
    self._check_geometry(f"Impossible to rename attribute '{str(self.name)}'")

    new_name = name
    self.geometry.rename_attribute(mode='Single', old=self.name, new=new_name, overwrite=overwrite)
    self.name = name

set(value=None, domain=None)

Store a value in the named attribute.

Node Store Named Attribute

If value is omitted, the result cached by the latest non-in-place operation is stored. In-place operators such as += call this method automatically.

Parameters:

Name Type Description Default
value value | Socket

Value or field to store. When omitted, use the cached value.

None
domain str | Domain | Geometry

Override the geometry or domain configured on this helper. Passing a Domain also applies that domain's selection.

None

Returns:

Type Description
Attribute

This helper, with its cached value cleared.

Source code in core/attributes.py
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
def set(self, value=None, domain=None):
    """Store a value in the named attribute.

    > Node Store Named Attribute

    If ``value`` is omitted, the result cached by the latest non-in-place
    operation is stored. In-place operators such as ``+=`` call this method
    automatically.

    Parameters
    ----------
    value : value | Socket, optional
        Value or field to store. When omitted, use the cached value.
    domain : str | Domain | Geometry, optional
        Override the geometry or domain configured on this helper. Passing
        a ``Domain`` also applies that domain's selection.

    Returns
    -------
    Attribute
        This helper, with its cached value cleared.
    """

    from .nodeclass import Node

    # ---------------------------------------------------------------------------
    # Value and data_type
    # ---------------------------------------------------------------------------

    if value is None:
        value = self._value
    if self.data_type is None:
        self.data_type = self._get_data_type(value)

    # ---------------------------------------------------------------------------
    # Domain argument overrides properties
    # ---------------------------------------------------------------------------

    selection = None

    # Geometry and domain name from domain argument
    geo, dn = self._get_geo_domain(domain)

    # Not None, overrides attributes
    if geo is not None:
        self.geometry = geo
        #selection = domain.get_selection()
    if dn is not None:
        self.domain_name = dn

    # ---------------------------------------------------------------------------
    # Selection
    # ---------------------------------------------------------------------------

    dom = self.domain
    if dom is None:
        selection = self.geometry.get_selection()
    else:
        selection = dom.get_selection()

    # ---------------------------------------------------------------------------
    # Create the node
    # ---------------------------------------------------------------------------

    socket = Node('Store Named Attribute', {
        'Geometry': self.geometry,
        'Selection': selection,
        'Name': self.name,
        'Value': value},
        domain = self.domain_name,
        data_type = Attribute.DT_SET[self.data_type],
        )._out

    if self.geometry is not None:
        self.geometry._jump(socket)

    self._value = None

    return self