Skip to content

Commit

Permalink
Doc updates (#370)
Browse files Browse the repository at this point in the history
* Make sure beta folder is included in class reference.

* Add type hinting and doc strings for redis_interface.py

* add language field to sphinx conf.py

* fix minor warnings during docs build.
  • Loading branch information
mjrosengrant authored Sep 12, 2023
1 parent c59f16f commit d7adb85
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 37 deletions.
10 changes: 10 additions & 0 deletions doc/source/beta.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
###############
Class reference
###############


.. toctree::
:titlesonly:
:maxdepth: 1

modules
3 changes: 1 addition & 2 deletions doc/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@ def setup(app):
# The full version, including alpha/beta/rc tags
release = ''


# -- General configuration ---------------------------------------------------

# If your documentation needs a minimal Sphinx version, state it here.
Expand Down Expand Up @@ -122,7 +121,7 @@ def setup(app):
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = None
language = 'en'

# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
Expand Down
4 changes: 2 additions & 2 deletions doc/source/workspace.rst
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ Common Operations
*****************

Load PDB/SDF/MMCIF as a Nanome Complex
================================
======================================
.. code-block:: python
from nanome.api.structure import Complex
Expand All @@ -103,7 +103,7 @@ Load PDB/SDF/MMCIF as a Nanome Complex
Export Nanome Complex as PDB/SDF/MMCIF
================================
======================================
.. code-block:: python
from nanome.api.structure import Complex
Expand Down
2 changes: 1 addition & 1 deletion nanome/api/plugin_instance.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ def request_workspace(self, callback=None):

def request_complex_list(self, callback=None):
"""
| Request the list of all complexes in the workspace, in shallow mode
| Request the list of all complexes in the workspace, in shallow mode.
:param callback: Callback to receive list of complexes.
:type callback: Callable[[List[Complex]], None]
Expand Down
102 changes: 74 additions & 28 deletions nanome/beta/redis_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,27 @@
import redis
import time
import uuid

from typing import List, Union
from nanome import PluginInstance
from nanome._internal.enums import Messages
from nanome._internal.network import Packet
from nanome.api.serializers import CommandMessageSerializer
from nanome.api.streams import Stream
from nanome.util import Logs, enums
from nanome.api import shapes, structure, ui, user
from nanome.util import Logs, enums, Vector3, Quaternion
from nanome.util.file import LoadInfoDone

__all__ = ['PluginInstanceRedisInterface']

workspace_struct = Union[
structure.Complex, structure.Molecule, structure.Chain,
structure.Residue, structure.Atom, structure.Bond]

ui_content = Union[
ui.Button, ui.Label, ui.Mesh, ui.Image,
ui.Dropdown, ui.DropdownItem, ui.LoadingBar,
ui.Slider, ui.TextInput
]
NTS_RESPONSE_TIMEOUT = os.environ.get('NTS_RESPONSE_TIMEOUT', 30)


Expand All @@ -41,9 +51,6 @@ def __init__(self, redis_host, redis_port, redis_password, redis_channel=None):
self.session_id = None
self.version_table = None

def set_channel(self, value):
self.channel = value

def connect(self):
"""Ping Redis, and then get data from plugin required for serialization."""
self.redis.ping()
Expand All @@ -52,8 +59,8 @@ def connect(self):
self.session_id = plugin_data['session_id']
self.version_table = plugin_data['version_table']

def create_writing_stream(self, indices_list, stream_type):
"""Return a stream wrapped in the RedisStreamInterface"""
def create_writing_stream(self, indices_list: List[int], stream_type: enums.StreamType) -> Stream:
"""Create a stream allowing the plugin to continuously update properties of many objects."""
message_type = Messages.stream_create
expects_response = True
args = (stream_type, indices_list, enums.StreamDirection.writing)
Expand All @@ -64,34 +71,48 @@ def create_writing_stream(self, indices_list, stream_type):
stream = Stream(None, *stream_args)
return stream

def request_workspace(self):
def request_workspace(self) -> structure.Workspace:
"""Request the entire workspace, in deep mode"""
message_type = Messages.workspace_request
expects_response = True
args = None
response = self._send_message(message_type, args, expects_response)
return response

def request_complexes(self, id_list):
def request_complexes(self, id_list: List[int]) -> List[structure.Complex]:
"""Requests a list of complexes by their indices.
Complexes returned contains the full structure (atom/bond/residue/chain/molecule)
"""
message_type = Messages.complexes_request
expects_response = True
args = id_list
response = self._send_message(message_type, args, expects_response)
return response

def update_structures_shallow(self, structures):
def update_structures_shallow(self, structures: List[workspace_struct]):
"""Update the specific molecular structures in the scene to match the structures in parameter.
Only updates the structure's data, will not update children or other descendents.
"""
message_type = Messages.structures_shallow_update
expects_response = False
args = structures
self._send_message(message_type, args, expects_response)

def update_structures_deep(self, struct_list):
def update_structures_deep(self, struct_list: List[workspace_struct]):
"""Update the specific molecular structures in the scene to match the structures in parameter.
Will also update descendent structures and can be used to remove descendent structures.
"""
message_type = Messages.structures_deep_update
expects_response = True
args = struct_list
response = self._send_message(message_type, args, expects_response)
return response

def request_complex_list(self):
def request_complex_list(self) -> List[structure.Complex]:
"""Request the list of all complexes in the workspace, in shallow mode."""
message_type = Messages.complex_list_request
args = None
expects_response = True
Expand All @@ -107,52 +128,68 @@ def _send_message(self, message_type: Messages, fn_args, expects_response):
response = self._deserialize_payload(serialized_response)
return response

def zoom_on_structures(self, structures):
def zoom_on_structures(self, structures: workspace_struct) -> None:
"""Repositions and resizes the workspace such that the provided structure(s) will be in the
center of the users view.
"""
message_type = Messages.structures_zoom
expects_response = False
args = structures
self._send_message(message_type, args, expects_response)

async def send_notification(self, notification_type: enums.NotificationTypes, message):
async def send_notification(self, notification_type: enums.NotificationTypes, message: str):
"""Send a notification to the user"""
message_type = Messages.notification_send
expects_response = False
args = [notification_type, message]
self._send_message(message_type, args, expects_response)

def center_on_structures(self, structures):
def center_on_structures(self, structures: workspace_struct):
"""Repositions the workspace such that the provided structure(s) will be in the center of the world."""
message_type = Messages.structures_center
expects_response = False
args = structures
self._send_message(message_type, args, expects_response)

def add_to_workspace(self, complex_list):
def add_to_workspace(self, complex_list: List[structure.Complex]):
"""Add a list of complexes to the current workspace."""
message_type = Messages.add_to_workspace
expects_response = True
args = complex_list
response = self._send_message(message_type, args, expects_response)
return response

def open_url(self, url, desktop_browser=False):
def open_url(self, url: str, desktop_browser: bool = False) -> None:
"""Open a URL in the user's browser."""
message_type = Messages.open_url
expects_response = False
args = (url, desktop_browser)
self._send_message(message_type, args, expects_response)

def request_presenter_info(self):
def request_presenter_info(self) -> user.PresenterInfo:
"""Get info about the presenter."""
message_type = Messages.presenter_info_request
expects_response = True
args = None
result = self._send_message(message_type, args, expects_response)
return result

def request_controller_transforms(self):
"""Requests presenter controller info.
(head position, head rotation, left controller position,
left controller rotation, right controller position,
right controller rotation)
"""
message_type = Messages.controller_transforms_request
expects_response = True
args = None
result = self._send_message(message_type, args, expects_response)
return result

def apply_color_scheme(self, color_scheme, target, only_carbons=False):
def apply_color_scheme(self, color_scheme: enums.ColorScheme, target: enums.ColorSchemeTarget, only_carbons: bool = False):
"""Applies a color scheme to selected atoms."""
message_type = Messages.apply_color_scheme
expects_response = False
args = (color_scheme, target, only_carbons)
Expand Down Expand Up @@ -186,7 +223,7 @@ def _rpc_request(self, message, expects_response=False):
message_data = pickle.loads(pickled_message_data)
return message_data

def upload_shapes(self, shape_list):
def upload_shapes(self, shape_list: List[shapes.Shape]):
"""Upload a list of shapes to the server.
:arg: shape_list: List of shapes to upload.
Expand All @@ -200,7 +237,8 @@ def upload_shapes(self, shape_list):
shape._index = shape_index
return shape_list

def get_plugin_data(self):
def get_plugin_data(self) -> dict:
"""Custom function to get data necessary for serialization from the remote plugin."""
function_name = 'get_plugin_data'
expects_response = True
message = self._build_message(function_name, None, None, expects_response)
Expand All @@ -216,32 +254,38 @@ def _build_packet(self, message_type, args=None, expects_response=False):
packet.write(message)
return request_id, packet

def update_content(self, *content):
def update_content(self, *content: ui_content) -> None:
"""Update specific UI elements (button, slider, list...)
"""
message_type = Messages.content_update
expects_response = False
args = list(content)
self._send_message(message_type, args, expects_response)

def update_node(self, *nodes):
def update_node(self, *nodes: List[ui.LayoutNode]) -> None:
"""Updates layout nodes and their children."""
message_type = Messages.node_update
expects_response = False
args = nodes
self._send_message(message_type, args, expects_response)

def set_menu_transform(self, index, position, rotation, scale):
def set_menu_transform(self, index: int, position: Vector3, rotation: Quaternion, scale: Vector3):
"""Update the position, scale, and rotation of the menu."""
message_type = Messages.menu_transform_set
expects_response = False
args = [index, position, rotation, scale]
self._send_message(message_type, args, expects_response)

def request_menu_transform(self, index):
def request_menu_transform(self, index: int):
"""Requests spatial information of the plugin menu (position, rotation, scale)."""
message_type = Messages.menu_transform_request
expects_response = True
args = [index]
response = self._send_message(message_type, args, expects_response)
return response

def update_stream(self, stream, data):
def update_stream(self, stream: Stream, data: List):
"""Feed new data into an existing stream."""
message_type = Messages.stream_feed
expects_response = True

Expand All @@ -252,13 +296,15 @@ def update_stream(self, stream, data):
response = self._send_message(message_type, args, expects_response)
return response

def destroy_stream(self, stream):
def destroy_stream(self, stream: Stream):
"""Delete an existing stream."""
message_type = Messages.stream_destroy
expects_response = False
args = stream.id
self._send_message(message_type, args, expects_response)

def send_files_to_load(self, files_list):
def send_files_to_load(self, files_list: List[str]) -> LoadInfoDone:
"""Send a molecular structure file (PDB, SDF, etc.) to the workspace to render."""
message_type = Messages.load_file
expects_response = True
files_and_data = []
Expand Down
12 changes: 8 additions & 4 deletions nanome/util/logs.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,13 @@ class LogType(IntEnum):
@classmethod
def error(cls, *args, **kwargs):
"""
| Prints an error
| Prints an error.
:param args: Variable length argument list
:type args: Anything printable
:param kwargs: Keyword arguments to pass to python logging module.
For options, see https://github.com/python/cpython/blob/main/Lib/logging/__init__.py#L1604
"""
module = cls.caller_name()
Expand All @@ -36,12 +37,13 @@ def error(cls, *args, **kwargs):
@classmethod
def warning(cls, *args, **kwargs):
"""
| Prints a warning
| Prints a warning.
:param args: Variable length argument list
:type args: Anything printable
:param kwargs: Keyword arguments to pass to python logging module.
For options, see https://github.com/python/cpython/blob/main/Lib/logging/__init__.py#L1604
"""
module = cls.caller_name()
Expand All @@ -52,12 +54,13 @@ def warning(cls, *args, **kwargs):
@classmethod
def message(cls, *args, **kwargs):
"""
| Prints a message
| Prints a message.
:param args: Variable length argument list
:type args: Anything printable
:param kwargs: Keyword arguments to pass to python logging module.
For options, see https://github.com/python/cpython/blob/main/Lib/logging/__init__.py#L1604
"""
module = cls.caller_name()
Expand All @@ -68,13 +71,14 @@ def message(cls, *args, **kwargs):
@classmethod
def debug(cls, *args, **kwargs):
"""
| Prints a debug message
| Prints a debug message.
| Prints only if plugin started in verbose mode (with -v argument)
:param args: Variable length argument list
:type args: Anything printable
:param kwargs: Keyword arguments to pass to python logging module.
For options, see https://github.com/python/cpython/blob/main/Lib/logging/__init__.py#L1604
"""
module = cls.caller_name()
Expand Down

0 comments on commit d7adb85

Please sign in to comment.