Skip to content

Commit

Permalink
Merge pull request #10 from iluvcapra/doc
Browse files Browse the repository at this point in the history
Doc
  • Loading branch information
iluvcapra authored Jun 21, 2023
2 parents accfc60 + 223e721 commit cb13f18
Show file tree
Hide file tree
Showing 7 changed files with 93 additions and 40 deletions.
8 changes: 7 additions & 1 deletion INSTALLING.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
## Installing
# Installing

## Minimum Requirements

py-ptsl requires Python 3.11.

## Steps

py-ptsl can be installed by cloning the repository from Github, and then
installing the package with `pip`.
Expand Down
5 changes: 2 additions & 3 deletions doc/source/engine.rst
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
.. currentmodule:: ptsl

Engine Class
============

.. currentmodule:: ptsl

.. automethod:: engine.open_engine

.. autoclass:: Engine
:members:
:member-order: bysource
:special-members: __init__
1 change: 1 addition & 0 deletions doc/source/ptsl_versions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ PTSL Versions/Pro Tools Versions
+==============+====================+
| 1 | 2022.12 |
| | 2023.3 |
| | 2023.6 |
+--------------+--------------------+
8 changes: 7 additions & 1 deletion ptsl/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
"""
py-ptsl: Native Python client for the Pro Tools scripting RPC interface
Native Python PTSL (Pro Tools Scripting Language) RPC interface
This project is a work of Pro Tools enthusiasts and users and is not
affiliated with Avid.
For more information on this package see the github repository at
https://github.com/iluvcapra/py-ptsl/
"""

from .client import Client
Expand Down
34 changes: 29 additions & 5 deletions ptsl/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def open_client(*args, **kwargs):
class Auditor:
"""
The Auditor is used by the client for reporting-out the status of requests
as the are run.
as they are run.
"""

def __init__(self, enabled: bool) -> None:
Expand Down Expand Up @@ -75,7 +75,7 @@ def run_returning(self):

class Client:
"""
The Client class
The Client class:
- maintains the grpc stub and channel
- holds PTSL server session data
- manages the connection's registration
Expand Down Expand Up @@ -131,13 +131,16 @@ def __init__(self,

raise grpc_error

def run(self, operation: Operation):
def run(self, operation: Operation) -> None:
"""
Run an operation on the client.
:raises: `CommandError` if the server returns an error
"""

self.auditor.run_called(operation.command_id())

# convert the request body into JSON
request_body_json = self._prepare_operation_request_json(operation)
response = self._send_sync_request(operation.command_id(),
request_body_json)
Expand All @@ -162,6 +165,10 @@ def run(self, operation: Operation):
self.auditor.run_returning()

def _prepare_operation_request_json(self, operation):
"""
Convert the request body into a JSON string (or an empty string if
there is no request body.
"""
if operation.request is None:
request_body_json = ""
else:
Expand All @@ -176,6 +183,13 @@ def _prepare_operation_request_json(self, operation):
return request_body_json

def _response_error_json_cleanup(self, json_in: str) -> str:
"""
This is a shim that will take a `command_error_type` value
from the response error json and convert it into a PT_UnknownError
if the `command_error_type` value is mis-formatted by the server
(for instance, if the server returns a symbold name or numeric string
value, as it sometimes has done in the past. (See `errata`).
"""
error_dict = json.loads(json_in)
old_val = error_dict['command_error_type']
if isinstance(old_val, str):
Expand All @@ -190,6 +204,14 @@ def _response_error_json_cleanup(self, json_in: str) -> str:
return json.dumps(error_dict)

def _handle_completed_response(self, operation, response):
"""
Accept the response message from the server, parse
the response body JSON if present, and hand the results
to the operation.
If the operation provides a cleanup function, this is run on
the response body JSON prior to parsing.
"""
p = operation.__class__.response_body()
if len(response.response_body_json) > 0 and p is not None:
self.auditor.response_json_before_cleanup(
Expand All @@ -206,7 +228,9 @@ def _handle_completed_response(self, operation, response):

def _send_sync_request(self, command_id,
request_body_json, task_id="") -> pt.Response:

"""
Send a synchronous request to the server.
"""
request = pt.Request(
header=pt.RequestHeader(
task_id=task_id,
Expand Down
71 changes: 44 additions & 27 deletions ptsl/engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,26 @@ def open_engine(*args, **kwargs):


class Engine:
"""
A callable interface for PTSL.
The Engine exposes PTSL commands as methods, translating call
arguments into corresponding requests, and then translating
responses into return objects. So, instead of creating a request,
dispatching a command to the client with the request object,
receving a response (or error) and processing it, you can simply
call a method on the Engine with parameters, and that method returns
a value.
One of the goals of the engine class is to hide as many redundant
value classes from the PTSL protocol as possible, so where the PTSL
client may return an enumeration value for the session sample rate,
the Engine returns a simple integer. Entity types, like :class:`Track`
or :class:`MemoryLocation` objects are retained.
The `Engine` initializes a new :class:`Client` object by passing its
initialization parameters to :meth:`~ptsl.Client.__init__`
"""

client: ptsl.Client

Expand All @@ -43,20 +63,7 @@ def __init__(self,
application_name: Optional[str] = None,
certificate_path: Optional[str] = None,
address='localhost:31416'):
"""
Open the engine.

:param company_name: Company name
:param application_name: Application name
:param certificate_path: Path to a developer certificate
:param address: server:port to connect the engine to.
.. note:: If `certificate_path` is given, the legacy
AuthorizeConnection method will be used for setting up the
connection session. If it is `None`, then `company_name` and
`application_name` will be used with the RegisterConnection
method (available since Pro Tools 2023.3).
"""
self.client = ptsl.Client(certificate_path=certificate_path,
company_name=company_name,
application_name=application_name,
Expand Down Expand Up @@ -100,8 +107,8 @@ def create_session(self,
"""
Create a new Pro Tools session.
:param name: Session Name
:param path: Path to the new session
:param str name: Session Name
:param str path: Path to the new session
:param SessionAudioFormat file_type: file type, defaults to
:attr:`~ptsl.PTSL_pb2.SessionAudioFormat.SAF_WAVE`
:param SampleRate sample_rate: sample rate, defaults to
Expand All @@ -110,7 +117,7 @@ def create_session(self,
:attr:`~ptsl.PTSL_pb2.BitDepth.Bit24`
:param IOSettings io_setting: The IO Setting to use,
defaults to :attr:`~ptsl.PTSL_pb2.IOSettings.IO_Last`
:param is_interelaved: Interleaved state
:param bool is_interelaved: Interleaved state
"""

op = ops.CreateSession(
Expand Down Expand Up @@ -151,7 +158,7 @@ def create_session_from_template(
:attr:`~ptsl.PTSL_pb2.BitDepth.Bit24`
:param IOSettings io_setting: The IO Setting to use,
defaults to :attr:`~ptsl.PTSL_pb2.IOSettings.IO_Last`
:param is_interelaved: Interleaved state
:param bool is_interelaved: Interleaved state
"""

op = ops.CreateSession(
Expand Down Expand Up @@ -193,7 +200,7 @@ def create_session_from_aaf(
:attr:`~ptsl.PTSL_pb2.BitDepth.Bit24`
:param IOSettings io_setting: The IO Setting to use,
defaults to :attr:`~ptsl.PTSL_pb2.IOSettings.IO_Last`
:param is_interelaved: Interleaved state
:param bool is_interelaved: Interleaved state
"""

op = ops.CreateSession(
Expand Down Expand Up @@ -235,8 +242,8 @@ def save_session_as(self, path: str, name: str):
"""
Save the currently-open session as a new name to a different path.
:param path: Path to the new session
:param name: New name for the session
:param str path: Path to the new session
:param str name: New name for the session
"""
op = ops.SaveSessionAs(session_name=name, session_location=path)
self.client.run(op)
Expand Down Expand Up @@ -413,6 +420,16 @@ def edit_memory_location(self, location_number: int,
comments: str):
"""
Edit a memory location.
:param int location_number: Location number to edit (if location does not
exist, this will create a new location in 2023.6)
:param str name: Location name
:param str start_time: Start time
:param str end_time: End time
:param TimeProperties time_properties: Time properties, either this is a range or a marker
:param MemoryLocationReference reference: Reference
:param MemoryLocationProperties general_properties: Location properties
:param str comments: Comment field
"""
op = ops.EditMemoryLocation(
number=location_number,
Expand Down Expand Up @@ -517,13 +534,13 @@ def export_mix(
.. note:: This method runs synchronously and will not return until the
bounce has completed.
:param file_type: Export file type
:param sources: Busses to bounce
:param audio_info: Audio options
:param video_info: Video options
:param location_info: Output folder settings
:param dolby_atmos_info: Dolby Atmos output settings
:param offline_bounce: Bounce offline option
:param EM_FileType file_type: Export file type
:param List[EM_SourceInfo] sources: Busses to bounce
:param EM_AudioInfo audio_info: Audio options
:param EM_VideoInfo video_info: Video options
:param EM_LocationInfo location_info: Output folder settings
:param EM_DolbyAtmosInfo dolby_atmos_info: Dolby Atmos output settings
:param bool offline_bounce: Bounce offline option
"""
op = ops.ExportMix(
file_name=base_name,
Expand Down
6 changes: 3 additions & 3 deletions tests/test_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ class TestEngine(TestCase):
"""
The :class:`TestEngine` test case exercises the :class:`Engine` interface. The client
is fully mocked. These tests are here mostly to make sure the engine is translating
the auto-generated *Request classes from call arguments, and *Response classes into
return values correctly.
the *Request classes from call arguments, and *Response classes into return values,
correctly.
If these fail, it probably means a breaking change has ocurred in `PTSL.proto` or the
engine's interface has changed.
engine's interface.
"""

MARKER_LOCATION_FIXTURE = [
Expand Down

0 comments on commit cb13f18

Please sign in to comment.