.. _Introduction: Introduction ******************************************************************************* This is the documentation for the priint:comet Python API. Python is an open-source, object-oriented scripting language which can be used to drive customization and logic of **priint:comet InDesign®**, **priint:comet_pdf** and **priint:comet Illustrator®**. The content of this documentation provides the complete API reference to the comet Python extension and highlights use-cases and differences between the native CScript scripting language and Python itself. Prerequisites =============================================================================== .. container:: priint-block **Python knowledge** This documentation is intended as an API reference and technical documentation. It is not a user manual for priint comet or a manual for developing with Python. We therefore assume basic knowledge of Python and object oriented programming for this documentation. .. container:: priint-block **Host software** The priint:comet Python API is available for the following products - henceforth called 'host software': .. container:: priint-block |indd| priint:comet InDesign® .. container:: priint-block |comet-pdf| priint:comet_pdf .. container:: priint-block |illu| priint:comet Illustrator® Throughout this documentation you will find sections marked with the above icons. Whenever you encounter such a section it means that the described paragraphs only apply to the equivalent host software(s). In the :doc:`APIReference` you will also find these symbols next to function documentation with special meaning. See :ref:`introduction.functionAvailability` .. include:: Installation.inc How to read this documentation =============================================================================== .. _introduction.functionAvailability: Function availability ------------------------------------------------------------------------------- There are several functions and modules which are not implemented in one software or the other since they either fulfill special tasks or are not feasible to implement. e.g. the :py:mod:`comet.batch` module is only implemented for priint:comet for Illustrator. Below each function documentation, you'll find a legend indicating in which host software this function is available: .. container:: priint-block |indd| Available in priint:comet InDesign® .. container:: priint-block |comet-pdf| Available in priint:comet_pdf .. container:: priint-block |illu| Available in priint:comet Illustrator® Functions which are not available will output a log message to the logfile and always return :py:data:`None`, most likely resulting in the script failing if this case is not handled. Function & parameter specialization ------------------------------------------------------------------------------- Several functions behave differently between host softwares - e.g. while the function :py:meth:`.CTable.getFrame` gets the containing frame in **InDesign®** and **comet_pdf**, it gets the table frame itself for **Illustrator®** These differing behaviors are usually described in the general function documentation. There are also functions which are implemented for multiple host softwares even though not every function parameter has a meaning. In these function parameters you will specialization sections for each parameter which behaves differently between host softwares. It is also possible that parameters are ignored entirely by a certain host software. In this case you usually need to provide a dummy parameter to retain argument count and order. Usually this dummy parameter should be the equivalent to an empty type for this data type, e.g. :py:data:`None`, **0**, **0.0** or **''** Context filtering ------------------------------------------------------------------------------- When developing Python scripts you likely will not develop your scripts for all available host applications at once. Due to the sheer amount of available functions, you may be overwhelmed in finding the functions you need and are available for your host software. For this purpose we added buttons for each host software at the very top right of each documentation page. Pressing these buttons shows or hides any function depending on the active host software. e.g. When you are developing scripts for **Illustrator®**, you can hide all functions only available to **InDesign®** and **comet_pdf** Getting started =============================================================================== Development environment ------------------------------------------------------------------------------- The print:comet Python API is based on Python 3.10. The print:comet Python API is implemented directly into the host software as C code. This means that while it can be introspected at runtime, there is no actual Python code distributed with comet. Instead we provide a comet package which does contain function stubs which are used to generate this documentation. While there is no actual code inside these files, the hierarchy and function/variable definitions are present. Setting your development environment up to finding this package, you can at least get some auto completion. The comet package is distributed together with this documentation in the *comet* subfolder. Building the first script ------------------------------------------------------------------------------- Lets start by writing our first Python script. There is always some boilerplate code every Python script inside comet needs to be able to execute. As there are several languages like CScript or XMLQuery we can execute in most situations, we first need to tell comet that the content of the script is indeed Python. .. container:: priint-block-important All Python scripts must start with this line: .. code-block:: python #!py This tells comet to treat the following script as Python instead of CScript or other builtin languages. Afterwards, we need to import the :py:mod:`comet` module (technically this is not necessary, but no comet functionality can be accessed without it): .. code-block:: python import comet And lastly, every script which is called needs an entry point function called '**main**' which takes no arguments. Optionally, this function can return an int indicating whether the script succeeded (0) or failed (other value or omitted): .. code-block:: python def main(): return 0 This gives us the minimum base script which can be used as a base for future scripts: .. code-block:: python #!py import comet def main(): return 0 .. _INTR-HelloWorld: Hello world! ------------------------------------------------------------------------------- The first task when learning a programming language is usually showing the message 'Hello world' on screen. There are two main methods of quickly displaying information: Showing message boxes and outputting messages to the logfile. Both are accessible through script functions owned by the :py:mod:`comet` module. Message boxes can be shown by using :py:meth:`comet.showMessage`, log file messages can be written by using :py:meth:`comet.wlog` (of course only if logfile writing is enabled). Please note that logfile writing must be enabled manually in the host software. Here is a small script displaying 'Hello World': .. code-block:: python #!py import comet def main(): message = 'Hello World!' comet.showMessage(message) comet.wlog(message) #wlog automatically adds a line break unless specified otherwise return 0 Running this script displays a message box (run in Illustrator): .. figure:: images/image_helloWorld.png And displays a message in the logfile: .. figure:: images/image_helloWorld2.png Of course, for *comet_pdf* there are no message boxes, but the text content gets output to the console instead. API Structure =============================================================================== The priint:comet Python API is structured into two main areas: :doc:`modules` and :doc:`classes` **Modules** provide static and utility functionality and often act as factories or fetching facilities for class-based objects. **Constants** are part of the :py:mod:`comet` module for universal access. Constants usually define integral or string values and are used for several function parameters to improve code readability. **Classes** are either instantiated as objects by the module functions (either through query methods like :py:func:`.document.getFront`, or by factory functions) or are provided by the script environment itself. It is usually not possible to instantiate a class directly. API Conventions =============================================================================== The priint:comet Python API has strongly defined semantic and syntactic conventions: .. container:: priint-block **Class names are written in uppercase** .. container:: priint-block **Module names are written in lowercase** .. container:: priint-block **Default and named parameters** All function parameters are considered named parameters. Consider the method :py:meth:`comet.CFrame.link` with the following parameters: .. code-block:: python recordID, start=0, length=-1, autoLoad=False, applyRules=False, changeStaticLinks=False Any default parameter is indicated by having a value behind the '=' sign. These parameters are also named parameters. That means the function can be called in the following ways: .. code-block:: python #All default parameters get their default value comet.gFrame.link(myID) #Only change the value of the parameter autoLoad comet.gFrame.link(myID, autoLoad = True) #Since all parameters are named, #their order in the call can be changed this way comet.gFrame.link(myID, changeStaticLinks = True, autoLoad = True) .. container:: priint-block **No public members** No class or module in has public variable members except for constant values which cannot be changed. These constant values are usually used as parameters or return values. Another exception is the :py:mod:`comet` module which exposes submodules as members. Any object of a comet class therefore has getters and setters for attributes which prevent invalid access. e.g. Even though the :py:class:`comet.CRect` class is a simple container for numeric values, it does not provide direct access to internal data. Data can be accessed by e.g. using :py:meth:`comet.CRect.getLeft` or :py:meth:`comet.CRect.setLeft` Note that getter functions always return copies of values instead of references. The following code snippet **does not** change the left side of the rectangle: .. code-block:: python rect = comet.gFrame.getBBox() left = rect.getLeft() left = 20.0 #this does not change the value stored in the rect This can be applied in a transitive manner: .. code-block:: python id = link.getRecordID() #link is of type comet.CLink #This line does not change the value of the ID for subsequent calls to #link.getRecordID(), nor does it relink anything in the document: id.setID(123) .. container:: priint-block **Document size and position units are in pt unless stated otherwise** .. container:: priint-block **Indices for pages are - contrary to CScript - 0-based unless stated otherwise** Safety & Error handling =============================================================================== | One of the most common pitfalls with our native scripting language CScript is how prone it is to user- and unhandled errors. | One can cause the host software to crash when forgetting to check a return value of a function which might fail, providing a wrong data type to a function parameter or not properly checking string buffer boundaries. | | For these reasons we introduce several safety mechanisms in the priint:comet Python API. | :priint-important:`These rules apply to each and every function` .. container:: priint-block **Type safety** | Every function of the priint:comet Python API checks the provided parameter types and provides no implicit conversion unless explicitly stated. | e.g. Providing an int parameter when a str is expected. | | A failed type check will result in the raise of a :py:class:`TypeError`. | | Some functions however accept multiple data types for a single parameter. This is explicitly stated in the parameter description in this case. | In this case all data types are checked against. .. container:: priint-block **Value safety** Whenever a function expects a parameter which can potentially have invalid values, the value is checked against the possible values. e.g. The function :py:func:`.batch.setStart` only accepts int values in range(0, 24) for the *hours* parameter. A failed value check will result in the raise of a :py:class:`ValueError`. .. container:: priint-block **Additional errors** | When a function is called with valid parameters, errors still may occur internally (e.g. when trying to load a placeholder with a failing data connection). | In this case most functions raise :py:class:`.CometError` which inherits from :py:class:`BaseException` and can be caught like any other Python exception. | | This exception class provides an error message and an error code which can be used for support purposes. .. include:: Availability.inc