Skip to content

Delegates

penne.Delegate

Bases: NoodleObject

Parent class for all delegates

Defines general methods that should be available for all delegates. In this context, a delegate refers to an object in a NOODLES scene that can be subclassed and extended by the user. For example, a user can create an implementation for a table that specifically suits their needs. The server's job is essentially to manage the state of all delegates, and to call the appropriate methods on them when necessary. Most methods defined by the user will also be to manipulate the state of the delegates.

Attributes:

Name Type Description
client Client

Client delegate is attached to

id ID

Unique identifier for delegate

name str

Name of delegate

signals dict

Signals that can be called on delegate, method name to callable

penne.InjectedMethod

InjectedMethod(method_obj)

Bases: object

Class for representing injected method in delegate

The context is automatically set when invoked. This object is callable and is what is actually called when the injected method is called.

Attributes:

Name Type Description
method Callable

method to be called

injected bool

attribute marking method as injected, useful for clearing out old injected methods

Source code in penne/delegates.py
29
30
31
def __init__(self, method_obj) -> None:
    self.method = method_obj
    self.injected = True

penne.inject_methods

inject_methods(delegate, methods)

Inject methods into a delegate class

Idea is to inject a method that is from the server to put into a delegate. Now it looks like the delegate has an instance method that actually calls what is on the server. Context, is automatically taken care of. This should mostly be called on_new or on_update for delegates that have methods. This method clears out any old injected methods if present.

Parameters:

Name Type Description Default
delegate Delegate

identifier for delegate to be modified

required
methods list

list of method id's to inject

required
Source code in penne/delegates.py
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
def inject_methods(delegate: Delegate, methods: List[MethodID]):
    """Inject methods into a delegate class

    Idea is to inject a method that is from the server to put into a delegate.
    Now it looks like the delegate has an instance method that actually calls what
    is on the server. Context, is automatically taken care of. This should mostly be
    called on_new or on_update for delegates that have methods. This method clears out any
    old injected methods if present.

    Args:
        delegate (Delegate):
            identifier for delegate to be modified
        methods (list):
            list of method id's to inject
    """

    # Clear out old injected methods
    to_remove = []
    for field, value in delegate:
        if hasattr(value, "injected"):
            logging.debug(f"Deleting: {field} in inject methods")
            to_remove.append(field)
    for field in to_remove:
        delattr(delegate, field)

    for method_id in methods:

        # Get method delegate and manipulate name to exclude noo::
        method = delegate.client.get_delegate(method_id)
        if "noo::" in method.name:
            name = method.name[5:]
        else:
            name = method.name

        # Create injected by linking delegates, and creating call method
        linked = LinkedMethod(delegate, method)
        injected = InjectedMethod(linked.__call__)

        setattr(delegate, name, injected)

penne.inject_signals

inject_signals(delegate, signals)

Method to inject signals into delegate

Idea is to inject a signal that is from the server to put into a delegate. These signals are stored in a dict that can be used to map the signal name to a callable response that handles the signal and its args.

Parameters:

Name Type Description Default
delegate Delegate

delegate object to be injected

required
signals list

list of signal id's to be injected

required
Source code in penne/delegates.py
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
def inject_signals(delegate: Delegate, signals: List[SignalID]):
    """Method to inject signals into delegate

    Idea is to inject a signal that is from the server to put into a delegate. These signals are stored in a dict
    that can be used to map the signal name to a callable response that handles the signal and its args.

    Args:
        delegate (Delegate):
            delegate object to be injected
        signals (list):
            list of signal id's to be injected
    """

    for signal_id in signals:
        signal = delegate.client.state[signal_id]  # refactored state
        delegate.signals[signal.name] = None

penne.get_context

get_context(delegate)

Helper to get context from delegate

Parameters:

Name Type Description Default
delegate Delegate

delegate to get context for, can be Entity, Table, or Plot

required

Returns:

Name Type Description
context dict

context for delegate, None if not found indicating document

Source code in penne/delegates.py
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
def get_context(delegate: Delegate):
    """Helper to get context from delegate

    Args:
        delegate (Delegate): delegate to get context for, can be Entity, Table, or Plot

    Returns:
        context (dict): context for delegate, None if not found indicating document

    """

    if isinstance(delegate, Entity):
        return {"entity": delegate.id}
    elif isinstance(delegate, Table):
        return {"table": delegate.id}
    elif isinstance(delegate, Plot):
        return {"plot": delegate.id}
    else:
        return None

penne.Method

Bases: Delegate

A method that clients can request the server to call.

Attributes:

Name Type Description
id MethodID

ID for the method

name str

Name of the method

doc Optional[str]

Documentation for the method

return_doc Optional[str]

Documentation for the return value

arg_doc List[MethodArg]

Documentation for the arguments

invoke

invoke(on_delegate, args=None, callback=None)

Invoke this delegate's method

Parameters:

Name Type Description Default
on_delegate Delegate

delegate method is being invoked on used to get context

required
args list

args for the method

None
callback function

function to be called when complete

None

Raises:

Type Description
ValueError

Invalid delegate context

Source code in penne/delegates.py
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
def invoke(self, on_delegate: Delegate, args=None, callback=None):
    """Invoke this delegate's method

    Args:
        on_delegate (Delegate):
            delegate method is being invoked on 
            used to get context
        args (list, optional):
            args for the method
        callback (function):
            function to be called when complete

    Raises:
        ValueError: Invalid delegate context
    """

    if isinstance(on_delegate, Table):
        kind = "table"
    elif isinstance(on_delegate, Plot):
        kind = "plot"
    elif isinstance(on_delegate, Entity):
        kind = "entity"
    else:
        raise ValueError("Invalid delegate context")

    context = {kind: on_delegate.id}
    self.client.invoke_method(self.id, args, context=context, callback=callback)

penne.Signal

Bases: Delegate

A signal that the server can send to update clients.

Attributes:

Name Type Description
id SignalID

ID for the signal

name str

Name of the signal

doc Optional[str]

Documentation for the signal

arg_doc List[MethodArg]

Documentation for the arguments

penne.Entity

Bases: Delegate

Container for other entities, possibly renderable, has associated methods and signals

Can reference other entities, geometry, plots, and lights. It can be rendered, if it has a render rep. It may have associated methods and signals. The transform is relative to the parent entity. In other contexts it may be called a node.

Attributes:

Name Type Description
id EntityID

ID for the entity

name Optional[str]

Name of the entity

parent Optional[EntityID]

Parent entity

transform Optional[Mat4]

Local transform for the entity

text_rep Optional[TextRepresentation]

Text representation for the entity

web_rep Optional[WebRepresentation]

Web representation for the entity

render_rep Optional[RenderRepresentation]

Render representation for the entity

lights Optional[List[LightID]]

List of lights attached to the entity

tables Optional[List[TableID]]

List of tables attached to the entity

plots Optional[List[PlotID]]

List of plots attached to the entity

tags Optional[List[str]]

List of tags for the entity

methods_list Optional[List[MethodID]]

List of methods attached to the entity

signals_list Optional[List[SignalID]]

List of signals attached to the entity

influence Optional[BoundingBox]

Bounding box for the entity

request_set_position

request_set_position(position)

Request to set the position of the entity

Parameters:

Name Type Description Default
position Vec3

Position to set

required
Source code in penne/delegates.py
846
847
848
849
850
851
852
def request_set_position(self, position: Vec3):
    """Request to set the position of the entity

    Args:
        position (Vec3): Position to set
    """
    self.set_position(position)

request_set_rotation

request_set_rotation(rotation)

Request to set the rotation of the entity

Parameters:

Name Type Description Default
rotation Vec4

Rotation to set

required
Source code in penne/delegates.py
854
855
856
857
858
859
860
def request_set_rotation(self, rotation: Vec4):
    """Request to set the rotation of the entity

    Args:
        rotation (Vec4): Rotation to set
    """
    self.set_rotation(rotation)

request_set_scale

request_set_scale(scale)

Request to set the scale of the entity

Parameters:

Name Type Description Default
scale Vec3

Scale to set

required
Source code in penne/delegates.py
862
863
864
865
866
867
868
def request_set_scale(self, scale: Vec3):
    """Request to set the scale of the entity

    Args:
        scale (Vec3): Scale to set
    """
    self.set_scale(scale)

show_methods

show_methods()

Show methods available on the entity

Source code in penne/delegates.py
870
871
872
873
874
875
876
877
878
879
880
881
882
def show_methods(self):
    """Show methods available on the entity"""

    if self.methods_list is None:
        message = "No methods available"
    else:
        message = f"-- Methods on {self.name} --\n--------------------------------------\n"
        for method_id in self.methods_list:
            method = self.client.get_delegate(method_id)
            message += f">> {method}"

    print(message)
    return message

penne.Plot

Bases: Delegate

An abstract plot object.

Attributes:

Name Type Description
id PlotID

ID for the plot

name Optional[str]

Name of the plot

table Optional[TableID]

Table to plot

simple_plot Optional[str]

Simple plot to render

url_plot Optional[str]

URL for plot to render

methods_list Optional[List[MethodID]]

List of methods attached to the plot

signals_list Optional[List[SignalID]]

List of signals attached to the plot

show_methods

show_methods()

Show methods available on the entity

Source code in penne/delegates.py
915
916
917
918
919
920
921
922
923
924
925
926
927
def show_methods(self):
    """Show methods available on the entity"""

    if self.methods_list is None:
        message = "No methods available"
    else:
        message = f"-- Methods on {self.name} --\n--------------------------------------\n"
        for method_id in self.methods_list:
            method = self.client.get_delegate(method_id)
            message += f">> {method}"

    print(message)
    return message

penne.Buffer

Bases: Delegate

A buffer of bytes containing data for an image or a mesh.

Bytes can be stored directly in the buffer with inline_bytes, or they can be stored in a URI with uri_bytes. The server should create a separate server to host the bytes, and there is support for this in the ByteServer class. To obtain these bytes, clients would have to make an HTTP request to the URI.

A buffer could store a single attribute, or it could store multiple attributes interleaved together. This is where buffer views specify how to interpret the buffer.

Attributes:

Name Type Description
id BufferID

ID for the buffer

name Optional[str]

Name of the buffer

size int

Size of the buffer in bytes

inline_bytes Optional[bytes]

Bytes of the buffer

uri_bytes Optional[str]

URI for the bytes

penne.BufferView

Bases: Delegate

A view into a buffer, specifying a subset of the buffer and how to interpret it.

Attributes:

Name Type Description
id BufferViewID

ID for the buffer view

name Optional[str]

Name of the buffer view

source_buffer BufferID

Buffer that the view is referring to

type BufferType

Type of the buffer view

offset int

Offset into the buffer in bytes

length int

Length of the buffer view in bytes

penne.Material

Bases: Delegate

A material that can be applied to a mesh.

The material is a collection of textures and factors that are used to render the mesh.

Attributes:

Name Type Description
id MaterialID

ID for the material

name Optional[str]

Name of the material

pbr_info Optional[PBRInfo]

Information for physically based rendering

normal_texture Optional[TextureRef]

Texture for normals

occlusion_texture Optional[TextureRef]

Texture for occlusion

occlusion_texture_factor Optional[float]

Factor for occlusion

emissive_texture Optional[TextureRef]

Texture for emissive

emissive_factor Optional[Vec3]

Factor for emissive

use_alpha Optional[bool]

Whether to use alpha

alpha_cutoff Optional[float]

Alpha cutoff

double_sided Optional[bool]

Whether the material is double-sided

penne.Image

Bases: Delegate

An image, can be used for a texture

Like a buffer, an image can be stored in a URI to reduce the size of messages. To obtain the bytes, you would have to make an HTTP request to the URI.

Attributes:

Name Type Description
id ImageID

ID for the image

name Optional[str]

Name of the image

buffer_source Optional[BufferID]

Buffer that the image is stored in

uri_source Optional[str]

URI for the bytes if they are hosted externally

penne.Texture

Bases: Delegate

A texture, can be used for a material

This is like a wrapping paper that is applied to a mesh. The image specifies the pattern, and the sampler specifies which part of the image should be applied to each part of the mesh.

Attributes:

Name Type Description
id TextureID

ID for the texture

name Optional[str]

Name of the texture

image ImageID

Image to use for the texture

sampler Optional[SamplerID]

Sampler to use for the texture

penne.Sampler

Bases: Delegate

A sampler to use for a texture

A sampler specifies how to take portions of an image and apply them to a mesh.

Attributes:

Name Type Description
id SamplerID

ID for the sampler

name Optional[str]

Name of the sampler

mag_filter Optional[MagFilterTypes]

Magnification filter

min_filter Optional[MinFilterTypes]

Minification filter

wrap_s Optional[SamplerMode]

Wrap mode for S

wrap_t Optional[SamplerMode]

Wrap mode for T

penne.Light

Bases: Delegate

Represents a light in the scene

For these purposes, a light is just a couple of properties like color, intensity, and light type. The entity that stores the light will dictate position and direction with its transform. The client application is then responsible for using this information to render the light. The light is either a point light, a spotlight, or a directional light.

Attributes:

Name Type Description
id LightID

ID for the light

name Optional[str]

Name of the light

color Optional[Color]

Color of the light

intensity Optional[float]

Intensity of the light

point Optional[PointLight]

Point light information

spot Optional[SpotLight]

Spotlight information

directional Optional[DirectionalLight]

Directional light information

penne.Geometry

Bases: Delegate

Represents geometry in the scene and can be used for meshes

This is more of a collection of patches, but each patch will contain the geometry information to render a mesh. The patch references buffer views and buffers for each attribute, and a material to use for rendering. Instances are stored in a separate buffer that is referenced at the entity level.

Attributes:

Name Type Description
id GeometryID

ID for the geometry

name Optional[str]

Name of the geometry

patches List[GeometryPatch]

Patches that make up the geometry

penne.Table

Table(**kwargs)

Bases: Delegate

Object to store tabular data.

Note that this delegate doesn't store any actual data. Delegates are meant to subclass and add functionality to this class. For the client to receive the actual data, they must subscribe to the table. The client will have access to certain injected methods that allow them to insert, update, delete, and clear the table. This class provides some abstract methods that can be overridden to handle these events.

Attributes:

Name Type Description
id TableID

ID for the table

name Optional[str]

Name of the table

meta Optional[str]

Metadata for the table

methods_list Optional[List[MethodID]]

List of methods for the table

signals_list Optional[List[SignalID]]

List of signals for the table

tbl_subscribe Optional[InjectedMethod]

Injected method to subscribe to the table

tbl_insert Optional[InjectedMethod]

Injected method to insert rows into the table

tbl_update Optional[InjectedMethod]

Injected method to update rows in the table

tbl_remove Optional[InjectedMethod]

Injected method to remove rows from the table

tbl_clear Optional[InjectedMethod]

Injected method to clear the table

tbl_update_selection Optional[InjectedMethod]

Injected method to update the selection

Source code in penne/delegates.py
1198
1199
1200
1201
1202
1203
1204
1205
1206
def __init__(self, **kwargs):
    """Override init to link default values with methods"""
    super().__init__(**kwargs)
    self.signals = {
        "noo::tbl_reset": self._reset_table,
        "noo::tbl_rows_removed": self._remove_rows,
        "noo::tbl_updated": self._update_rows,
        "noo::tbl_selection_updated": self._update_selection
    }

on_new

on_new(message)

Handler when create message is received

Parameters:

Name Type Description Default
message Message

create message with the table's info

required
Source code in penne/delegates.py
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
def on_new(self, message: dict):
    """Handler when create message is received

    Args:
        message (Message): create message with the table's info
    """

    # Check contents
    methods = self.methods_list
    signals = self.signals_list

    # Inject methods and signals if applicable
    if methods:
        inject_methods(self, methods)
    if signals:
        inject_signals(self, signals)

    # Reset
    self._reset_table()
    self.relink_signals()

on_update

on_update(message)

Handler when update message is received

Parameters:

Name Type Description Default
message Message

update message with the new table's info

required
Source code in penne/delegates.py
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
def on_update(self, message: dict):
    """Handler when update message is received

    Args:
        message (Message): update message with the new table's info
    """

    # Inject methods and signals if applicable
    if self.methods_list:
        inject_methods(self, self.methods_list)
    if self.signals_list:
        inject_signals(self, self.signals_list)
    self.relink_signals()
relink_signals()

Relink the signals for built-in methods

Injecting signals adds them as keys which map to None. The signals must be relinked after injecting. These should always be linked, along with whatever is injected.

Source code in penne/delegates.py
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
def relink_signals(self):
    """Relink the signals for built-in methods

    Injecting signals adds them as keys which map to None. The signals must be relinked after injecting.
    These should always be linked, along with whatever is injected.
    """

    self.signals["noo::tbl_reset"] = self._reset_table
    self.signals["noo::tbl_rows_removed"] = self._remove_rows
    self.signals["noo::tbl_updated"] = self._update_rows
    self.signals["noo::tbl_selection_updated"] = self._update_selection

request_clear

request_clear(callback=None)

Clear the table

User endpoint for interacting with table and invoking method

Parameters:

Name Type Description Default
callback function

callback function called when complete

None
Source code in penne/delegates.py
1385
1386
1387
1388
1389
1390
1391
1392
1393
def request_clear(self, callback=None):
    """Clear the table

    User endpoint for interacting with table and invoking method

    Args:
        callback (function, optional): callback function called when complete
    """
    self.tbl_clear(callback=callback)

request_insert

request_insert(row_list, callback=None)

Add rows to end of table

User endpoint for interacting with table and invoking method For input, row list is list of rows. Also note that tables have nine columns by default (x, y, z, r, g, b, sx, sy, sz). x, y, z -> coordinates r, g, b -> color values [0, 1] sx, sy, sz -> scaling factors, default size is 1 meter

Row_list: [[1, 2, 3, 4, 5, 6, 7, 8, 9]]

Parameters:

Name Type Description Default
row_list list

add rows using list of rows

required
callback function

callback function

None
Source code in penne/delegates.py
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
def request_insert(self, row_list: List[List[int]], callback=None):
    """Add rows to end of table

    User endpoint for interacting with table and invoking method
    For input, row list is list of rows. Also note that tables have
    nine columns by default (x, y, z, r, g, b, sx, sy, sz).
    x, y, z -> coordinates
    r, g, b -> color values [0, 1]
    sx, sy, sz -> scaling factors, default size is 1 meter

    Row_list: [[1, 2, 3, 4, 5, 6, 7, 8, 9]]

    Args:
        row_list (list, optional): add rows using list of rows
        callback (function, optional): callback function
    """

    self.tbl_insert(row_list, callback=callback)

request_remove

request_remove(keys, callback=None)

Remove rows from table by their keys

User endpoint for interacting with table and invoking method

Parameters:

Name Type Description Default
keys list

list of keys for rows to be removed

required
callback function

callback function called when complete

None
Source code in penne/delegates.py
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
def request_remove(self, keys: List[int], callback=None):
    """Remove rows from table by their keys

    User endpoint for interacting with table and invoking method

    Args:
        keys (list):
            list of keys for rows to be removed
        callback (function, optional):
            callback function called when complete
    """

    self.tbl_remove(keys, callback=callback)

request_update

request_update(keys, rows, callback=None)

Update the table using a DataFrame

User endpoint for interacting with table and invoking method

Parameters:

Name Type Description Default
keys list[int]

list of keys to update

required
rows list[list[int]]

list of new rows to update with

required
callback function

callback function called when complete

None
Source code in penne/delegates.py
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
def request_update(self, keys: List[int], rows: List[List[int]], callback=None):
    """Update the table using a DataFrame

    User endpoint for interacting with table and invoking method

    Args:
        keys (list[int]):
            list of keys to update
        rows (list[list[int]]):
            list of new rows to update with
        callback (function, optional):
            callback function called when complete
    """

    self.tbl_update(keys, rows, callback=callback)

request_update_selection

request_update_selection(name, keys, callback=None)

Update a selection object in the table

User endpoint for interacting with table and invoking method

Parameters:

Name Type Description Default
name str

name of the selection object to be updated

required
keys list

list of keys to be in new selection

required
callback function

callback function called when complete

None
Source code in penne/delegates.py
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
def request_update_selection(self, name: str, keys: List[int], callback=None):
    """Update a selection object in the table

    User endpoint for interacting with table and invoking method

    Args:
        name (str):
            name of the selection object to be updated
        keys (list):
            list of keys to be in new selection
        callback (function, optional):
            callback function called when complete
    """
    selection = Selection(name=name, rows=keys)
    self.tbl_update_selection(selection.model_dump(), callback=callback)

show_methods

show_methods()

Show methods available on the table

Source code in penne/delegates.py
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
def show_methods(self):
    """Show methods available on the table"""

    if self.methods_list is None:
        message = "No methods available"
    else:
        message = f"-- Methods on {self.name} --\n--------------------------------------\n"
        for method_id in self.methods_list:
            method = self.client.get_delegate(method_id)
            message += f">> {method}"

    print(message)
    return message

subscribe

subscribe(callback=None)

Subscribe to this delegate's table

Calls on_table_init as callback

Parameters:

Name Type Description Default
callback Callable

function to be called after table is subscribed to and initialized

None

Raises:

Type Description
Exception

Could not subscribe to table

Source code in penne/delegates.py
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
def subscribe(self, callback: Callable = None):
    """Subscribe to this delegate's table

    Calls on_table_init as callback

    Args:
          callback (Callable): function to be called after table is subscribed to and initialized

    Raises:
        Exception: Could not subscribe to table
    """

    try:
        # Allow for callback after table init
        self.tbl_subscribe(callback=lambda data: self._on_table_init(data, callback))
    except Exception as e:
        raise Exception(f"Could not subscribe to table {self.id}...{e}")

penne.Document

Bases: Delegate

Delegate for document

Attributes:

Name Type Description
name str

name will be "Document"

methods_list list[MethodID]

list of methods available on the document

signals_list list[SignalID]

list of signals available on the document

on_update

on_update(message)

Handler when update message is received

Should update methods_list and signals_list

Parameters:

Name Type Description Default
message Message

update message with the new document's info

required
Source code in penne/delegates.py
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
def on_update(self, message: dict):
    """Handler when update message is received

    Should update methods_list and signals_list

    Args:
        message (Message): update message with the new document's info
    """
    if "methods_list" in message:
        self.methods_list = [MethodID(*element) for element in message["methods_list"]]
        inject_methods(self, self.methods_list)
    if "signals_list" in message:
        self.signals_list = [SignalID(*element) for element in message["signals_list"]]

reset

reset()

Reset the document

Called when document reset message is received. Will reset state, and clear methods and signals on document

Source code in penne/delegates.py
1456
1457
1458
1459
1460
1461
1462
1463
def reset(self):
    """Reset the document

    Called when document reset message is received. Will reset state, and clear methods and signals on document
    """
    self.client.state = {"document": self}
    self.methods_list = []
    self.signals_list = []

show_methods

show_methods()

Show methods available on the document

Source code in penne/delegates.py
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
def show_methods(self):
    """Show methods available on the document"""

    if not self.methods_list:
        message = "No methods available"
    else:
        message = f"-- Methods on Document --\n--------------------------------------\n"
        for method_id in self.methods_list:
            method = self.client.get_delegate(method_id)
            message += f">> {method}"

    print(message)
    return message

update_client_view

update_client_view(direction, angle)

Notify the server of an area of interest for the client

Source code in penne/delegates.py
1465
1466
1467
1468
def update_client_view(self, direction: Vec3, angle: float):
    """Notify the server of an area of interest for the client"""

    self.client_view(direction, angle)

penne.Reply

Bases: NoodleObject

Reply message sent from server in response to method invocation

Will either contain resulting data, or an exception

Attributes:

Name Type Description
invoke_id str

id of the invoke message that this is a reply to

result Any

result of the method invocation

method_exception MethodException

exception raised when invoking method