# &python; Scripting

®ina; contains inbuilt scripting, which offers you fine control over ®ina;'s mathematical engine and enables you to automate large amounts of processing. You can write and run scripts from directly within ®ina;, or you can use the separate command-line tool `regina-python`.

The user interface will stay in sync with any changes that you make through a script, which means you can happily modify a data file via scripts while you have it open.

All scripts in ®ina; use the &python; programming language (). The specific &python; version must be chosen at build time. If you download a ready-made package then the packager has already chosen the &python; version for you; the ready-made packages on the ®ina; website will always use the default version of &python; on each system where possible.

®ina;'s &python; interface typically assumes you know what you are doing, and so the onus is on you to follow the rules. All constraints, preconditions and so on are thoroughly documented in the &api; documentation. Probably the easiest way to crash ®ina; is to bring up a &python; console and do something “illegal” (like gluing together two tetrahedra that belong to different triangulations).

## Starting a &python; Session

There are several ways of starting a &python; session to work with ®ina;:

### Graphical &python; Consoles

You can open a graphical &python; console by selecting Tools Python Console from the menu (or by pressing the corresponding toolbar button).

A new console window will open as illustrated below, with an input area down the bottom (see the red arrow) and a full history of the session in the main part of the window. You can save this history by selecting Console Save Session .

When you start the &python; session, ®ina; will set some special variables for you:

`item`

If you have a packet selected in the tree when you start the &python; session, the variable `item` will refer to this packet (see the figure above for an example of this).

Note that, if you later change your selection in the packet tree, the `item` variable will not change as a result.

`root`

The variable `root` will refer to the hidden root at the top of your packet tree (this root is not visible in the user interface, but its top-level children are).

You are welcome to use these variables to change packets in your data file (or even add, remove or rename packets): the graphical user interface will always stay in sync with any changes that you make via &python;.

### Command-Line Sessions

You can run the command-line program `regina-python` without a graphical user interface at all. This will use the standard &python; interpreter. Since this is a text-based interface, you can also redirect input and output in the usual way (using < and > in your command shell).

&macosx; users will find `regina-python` inside ®ina;'s application bundle. See the FAQ entry for details.

&windows; users do not have the command-line `regina-python` at all, though they can still use graphical &python; consoles and script packets.

### Script Packets

You can create a new script packet in your data file. Script packets allow you to save &python; scripts along with your data, and they give your scripts easy access to the packets inside your file.

When you open a script packet, you will see your &python; code in the lower part of the script editor, and a table of variables up the top.

You can add your own variables to this table, and set them to arbitrary packets within your data file. ®ina; will always set these variables to the corresponding packets before running your script.

At the top of the script editor you will find buttons to compile and run your script. Compiling is optional: it merely gives you a chance to spot syntax errors as you go. When you press Run, ®ina; will run your script in a new graphical &python; console. The console will be left open in case you wish to experiment further.

Again, you are welcome to change packets in your data file via scripts (or even add, remove or rename packets): the graphical user interface will always stay in sync with any changes that your scripts make.

## Accessing ®ina; from &python;

All of ®ina;'s objects, classes and methods belong to the module called `regina`. For instance, the main 3-manifold triangulation class is `regina.Triangulation3`, the main knot/link class is `regina.Link`, and the main routine to read a data file is `regina.open`.

### Automatic Imports

Whenever ®ina; gives you access to &python; (either through a graphical console, a script packet, or a `regina-python` command-line session), it will automatically import the `regina` module (i.e., “`import regina`”), and it will import all of ®ina;'s objects, classes and methods into the current namespace (i.e., “`from regina import *`”). As a single exception, it will not import `regina.open`, so as to not hide &python;'s own `open()` function.

This means, for instance, that you can create a new triangulation by just calling `Triangulation3()`, but to read a data file you should still call `regina.open(filename)`. For command-line sessions, if you wish to avoid the heavy-handed “`from regina import *`”, you can pass the option `--noautoimport` to `regina-python` (in which case you will need to use fully qualified names such as `regina.Triangulation3()`).

## &api; Documentation

®ina; includes a complete &api; reference for its calculation engine, which describes in detail the objects, classes and methods that are available through &python;. To read this documentation, you can:

- read the locally installed documentation by selecting Help Python &api; Reference ;
- read it online through the ®ina; website;
- read it inline from within &python; (see below).

Be aware that this &api; documentation is primarily written for &cpp; (the main language that ®ina; is written in). This means:

- The documentation uses &cpp; notation and &cpp; types, though these are all translated in the natural way to &python; (e.g., `std::string` becomes a &python; string, and `std::vector` becomes a &python; list).
- Some functions differ in how they are called from &cpp; versus &python;. In such cases you will see the &cpp; description, but there will also be a “&python;” paragraph explaining how things differ in &python;.

There are more issues that &python; users should be aware of; please do read the summary page in the &api; documentation that outlines the main differences.

### Inline Documentation

Since version; 7.2, ®ina; now provides &python; docstrings for all of its classes and functions. This means that you can get help directly from the &python; prompt, as illustrated below.

Be aware, however, that this documentation is extracted automatically from the hand-written &cpp; &api; documentation discussed above. Although great attention has been paid to making this extraction as useful and natural as possible, it is still automated. Therefore you will find:

- The documentation still uses some &cpp; terminology (e.g., `std::string`, pointers and references, move semantics, etc.).
- Function arguments are often not named in the synopsis at the beginning of the docstring (you will see them called `arg0`, `arg1`, etc.). However, they are named in the detailed descriptions of the arguments that follow.
- Some functions differ in how they are called from &cpp; versus &python; (e.g., `Tetrahedron3.face()`, or `Link.rewrite()`). In these cases, the detailed hand-written argument descriptions will follow the &cpp; variant, but the initial synopsis will be written for &python;. For clarity, here the arguments in the &python; synopsis will be named. Look also for a “&python;” paragraph that explains exactly how the &cpp; and &python; versions differ.
- Some parts of the documentation are not accessible at all through &python;, since they do not correspond to entities that hold docstrings (e.g., class constants such as `Perm4::nPerms`, or standalone pages such as the discussion on Seifert fibred space notation).

Ultimately, it is the &cpp; documentation that is authoritative, not the inline &python; documentation. Again, remember that you can always read the &cpp; documentation online.

An example of docstrings for member functions:

    &docstring1;

An example of docstrings for classes:

    &docstring2;

## Talking with &snappy;

Since ®ina; 4.95, a default installation of ®ina; can talk directly with a default installation of &snappy; on many platforms. This includes &macosx; 10.7 or greater (if you installed the &snappy; app bundle in the usual `Applications` folder), and &linux; (if your &snappy; uses the default system &python; installation).

Simply type `import snappy` from within any of ®ina;'s &python; environments. To send information back and forth between ®ina; and &snappy;:

- ®ina;'s triangulation classes `Triangulation3` and `SnapPeaTriangulation` both have a `snapPea()` function, which gives a string that you can pass to &snappy;'s `Manifold` constructor.

- &snappy;'s `Manifold` class has a `_to_string()` function, which gives a string that you can pass to ®ina;'s `Triangulation3` or `SnapPeaTriangulation` constructor.

Regarding fillings and peripheral curves: ®ina; does not store fillings or peripheral curves for its own native triangulation packets, as represented by the `Triangulation3` class. However, it does store fillings and peripheral curves for its hybrid &snappea; triangulation packets, as represented by the `SnapPeaTriangulation` class. The trade-off is that the native `Triangulation3` class offers ®ina;'s full fine-grained control over the triangulation, whereas the hybrid `SnapPeaTriangulation` class has a more limited (largely read-only) interface.

- When sending data from ®ina; to &snappy;, if your triangulation is of the class `Triangulation3`, then `Triangulation3.snapPea()` will create a &snappy; manifold in which all fillings and peripheral curves are marked as unknown. If your triangulation is of the class `SnapPeaTriangulation`, and if you already have fillings and peripheral curves stored on each cusp, then `SnapPeaTriangulation.snapPea()` will create a &snappy; manifold that preserves these.

- Conversely, when sending data from &snappy; to ®ina;, you can choose to instantiate a triangulation using either the `Triangulation3` class or the `SnapPeaTriangulation` class. If you use the `Triangulation3` class then all fillings and peripheral curves will be lost. If you use the `SnapPeaTriangulation` class then fillings and peripheral curves will be preserved (but your interface will be more restricted).

If you wish to send the complement of a native ®ina; `Link` to &snappy;, you can pass your link directly to the `SnapPeaTriangulation` constructor, which will preserve the peripheral curves from the link diagram; then you can pass this to &snappy; via `SnapPeaTriangulation.snapPea()` as above.

Regarding the interface: the `SnapPeaTriangulation` class inherits from `Triangulation3`, and so you can use it anywhere that a read-only triangulation is expected (in particular, you can use it for enumerating vertex normal surfaces or angle structures). However, because `SnapPeaTriangulation` must maintain two synchronised copies of the triangulation (®ina;'s and &snappea;'s), it is essentially read-only: any attempt to modify the triangulation using ®ina;'s native routines (e.g., `pachner()` or `barycentricSubdivision()`) will cause the &snappea; triangulation to delete itself and become a “null triangulation” instead.

At present, &snappy; (version 2.0.3) is not compatible with multiple &python; interpreters. If you import &snappy; into more than one &python; console in the graphical user interface, &snappy; may stop working. See this troubleshooting entry for details.

The following &python; session illustrates several of the concepts discussed above.

    bab@ember:~$ regina-python
    Regina 7.2
    Software for low-dimensional topology
    Copyright (c) 1999-2022, The Regina development team
    >>> import snappy
    >>> m = snappy.Manifold('m001')
    >>> t = SnapPeaTriangulation(m._to_string())
    >>> print t.detail()
    Size of the skeleton:
      Tetrahedra: 2
      Triangles: 4
      Edges: 2
      Vertices: 1

    Tetrahedron gluing:
      Tet  |  glued to:      (012)      (013)      (023)      (123)
      -----+-------------------------------------------------------
        0  |               1 (103)    1 (320)    1 (210)    1 (132)
        1  |               0 (320)    0 (102)    0 (310)    0 (132)

    Vertices:
      Tet  |  vertex:    0   1   2   3
      -----+--------------------------
        0  |             0   0   0   0
        1  |             0   0   0   0

    Edges:
      Tet  |  edge:   01  02  03  12  13  23
      -----+--------------------------------
        0  |           0   1   1   1   1   0
        1  |           0   1   1   1   1   0

    Triangles:
      Tet  |  face:  012 013 023 123
      -----+------------------------
        0  |           0   1   2   3
        1  |           2   0   1   3

    Tetrahedron shapes:
      0: ( -1.60812e-16, 1 )
      1: ( -1.60812e-16, 1 )

    Cusps:
      0: Vertex 0, complete

    >>> print t.hasStrictAngleStructure()
    True
    >>> print AngleStructures(t).detail()
    4 vertex angle structures (no restrictions):
    0 1 0 ; 1 0 0
    0 0 1 ; 1 0 0
    1 0 0 ; 0 1 0
    1 0 0 ; 0 0 1

    >>> t2 = Example3.figureEight()
    >>> m2 = snappy.Manifold(t2.snapPea())
    >>> print m2.volume()
    2.02988321282
    >>>

## Sample &python; Sessions

Several sample &python; sessions are reproduced below. Each session was started by running `regina-python` from the command line.

### Working with a triangulation

    &sessiontriangulation;

### Working with a packet tree

    &sessiontree;

### Reporting progress of long operations

    &sessionprogress;