diff --git a/doc/source/class_documentation.rst b/doc/source/class_documentation.rst index 4f3f394b2..5528dd066 100644 --- a/doc/source/class_documentation.rst +++ b/doc/source/class_documentation.rst @@ -3,11 +3,10 @@ API reference ************* Ansys Dynamic Reporting contains a low-level API that allows the user to access -a;; the available features and properties in full detail. While this low-level +all the available features and properties in full detail. While this low-level API is very powerful, it can also be quite complex to use and it requires a steep learning curve. For a comprehensive description of this API, see -`External Python API `_ -in the documentation for Ansys Dynamic Reporting. +the section :ref:`Low Level Python API `. The goal of PyDynamicReporting is to provide an easier, more Pythonic way to start or connect to an Ansys Dynamic Reporting service so that you do not need @@ -30,9 +29,14 @@ class to create, query, and modify items. Lastly, you create and use ``Report`` instances to access reports in Ansys Dynamic Reporting. + .. autosummary:: :toctree: _autosummary/ ansys.dynamicreporting.core.Item ansys.dynamicreporting.core.Service ansys.dynamicreporting.core.Report + +.. toctree:: + lowlevelapi/index.rst + diff --git a/doc/source/lowlevelapi/DataItemObject.rst b/doc/source/lowlevelapi/DataItemObject.rst new file mode 100755 index 000000000..ed4511042 --- /dev/null +++ b/doc/source/lowlevelapi/DataItemObject.rst @@ -0,0 +1,365 @@ +Data Item Object +================ + +.. _ItemREST: + +report_objects.ItemREST object +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This object is a Python representation of an Ansys Dynamic +Reporting data item object. When +this object is created, a GUID will automatically be generated for the +object and the date is set to the current time/date. + +Data members +^^^^^^^^^^^^ + +The following attributes are available on an ItemREST object: + +- guid - string GUID. The default is ``str(uuid.uuid1())`` +- tags - The user-defined tags string for this object. Multiple tags + are space-separated. +- sequence - An integer sequence number that can be used for + sorting/indexing in a report +- date - The time & date of the creation of this object. The default + is: ``datetime.datetime.now(pytz.utc)`` +- name - The name of the data object, a string +- source - The source of the data object, a string +- session - string GUID of a SessionREST object that already exists in + the database +- dataset - string GUID of a DatasetREST object that already exists in + the database + + +Methods +^^^^^^^ + +**item.set_tags(tagstring)** + +Set the tags for the item to the passed string. Multiple tags are +space-separated. + +**item.get_tags()** + +Returns the tags string for this object. Multiple tags are +space-separated. + +**item.add_tag(tag, value=None)** + +Adds a tag to the current tag string. If no value is passed, the simple +tag string is added to the tags string. If a value is specified, a +string of the form tag=value will be added to the tag string. + +**item.rem_tag(tag)** + +Remove the tag (and any potential associated value) from the current tag +string. + +**has_file = item.is_file_protocol()** + +This method returns True if the data item refers to an actual file on +the server. Currently the ItemRest.type values of ItemREST.type_img, +ItemREST.type_scn, ItemREST.type_anim and ItemREST.type_file all refer +to files. + +Once all of the metadata attributes listed above are set, an actual data +payload needs to be set for the data item. There are convenience methods +to set the item type and fill in the payload data. + +**content = item.get_payload_content()** + +For Items that have been fetched using the Server object, this method +allows you to get the payload without having to manually decode the +payload data. + +An example of the use of this method is shown below: + +.. code-block:: python + + from ansys.dynamicreporting.core.utils import report_remote_server, report_objects + + serverobj = report_remote_server.Server("http://localhost:8000/", "nexus", "cei") + obj_list = serverobj.get_objects( + objtype=report_objects.ItemREST, query="A|i_type|cont|string;" + ) + + # Previously you had to do this to get the data of an item and then decode it to view human readable content + + # import pickle** + # data = pickle.loads(obj_list[0].payloaddata) + + # This method gives you the human readable content directly (handles decoding internally.) + data = obj_list[0].get_payload_content() + + +Animation Item +'''''''''''''' + +**item.set_payload_animation(mp4_filename)** + +This method sets the item payload to an animation. The "mp4_filename" +argument should be the name of a .mp4 encoded video file. Note: the file +must exist on disk before this call is made and must stay on disk until +the item is pushed to the ADR Nexus server. + +File Item +''''''''' + +**item.set_payload_file(filename)** + +This method sets the item payload to the content of an arbitrary file on +disk. The argument should be the name of a file to be uploaded. Note: +the file must exist on disk before this call is made and must stay on +disk until the item is pushed to the ADR Nexus server. + +HTML Item +''''''''' + +**item.set_payload_html(html_text)** + +This will set the item payload to HTML formatted text. + +Image Item +'''''''''' + +**item.set_payload_image(image)** + +This method sets the item payload to an image. The argument can be one +of three things: the binary representation of a .png file on disk as a +string, a QImage object or an enve.image object. Examples are shown +below: + +- A string which is the binary data representation of the image. Note: + this is the only format supported in a Python interpreter that lacks + the PyQt and enve modules. + + .. code-block:: python + + with open("example.png", "rb") as fp: + img = fp.read() + item.set_payload_image(img) + + +- A Qt QImage object instance + + .. code-block:: python + + from PyQt4 import QtGui + + img = QtGui.QImage("example.png") + item.set_payload_image(img) + + +- An enve image object instance + + .. code-block:: python + + import enve + + img = enve.image() + if img.load("example.png") == 0: + item.set_payload_image(img) + + +None Item +''''''''' + +**item.set_payload_none()** + +By default an item has no payload. This method will reset the item to +that state. It is legal to push an item without a data payload into the +server. + +Scene Item +'''''''''' + +**item.set_payload_scene(filename)** + +This method sets the item payload to the 3D geometry found in the passed +filename. Supported geometry formats include: EnSight CSF, STL, PLY, +SCDOC and AVZ format files. + +String Item +''''''''''' + +**item.set_payload_string(string)** + +This will set the item payload to an ASCII string. + +Table Item +'''''''''' + +**item.set_payload_table(dictionary)** + +This will set the item payload to be a table, the table being specified +in a dictionary. Minimally, the dictionary must contain a single numpy +array with the 'array' key. There are a few restrictions on this array. +First, it must be 2D. Second, the dtype of the array should be +numpy.float32, numpy.double or a string (dtype="\|S20"). + +Other table properties (e.g. row/column labels, text formatting, etc) +can also be set in this dictionary. A simple example: + +.. code-block:: python + + import numpy + + d = dict( + array=numpy.zeros((3, 2), numpy.double), + rowlbls=["Row 1", "Row 2", "Row 3"], + collbls=["Column A", "Column B"], + title="Simple table", + ) + item.set_payload_table(d) + + +If the external Python API is being used from within EnSight, it is also +possible to pass an ENS_PLOTTER object to the set_payload_table() +method. It will capture not only the data in the plots, but many of the +plotter attributes. One example might be: + +.. code-block:: python + + plot = ensight.objs.core.PLOTS[0] # get the first ENS_PLOTTER object + item.set_payload_table(plot) + + +Many more table properties exist and can be set as the default values +for a table by setting same-named keys in the dictionary. The properties +are documented in the item properties section at `this`_ page. + +.. _this: https://nexusdemo.ensight.com/docs/en/html/Nexus.html?TableItem.html + +A short-cut APIs exists for a common case: + +.. code-block:: python + + item.set_payload_table_values(array, rowlbls=None, collbls=None, title=None) + + +This is a shortcut for the following two lines of python: + +.. code-block:: python + + d = dict( + array=numpy.array(array, numpy.double), + rowlbls=rowlbls, + collbls=collbls, + title=title, + ) + item.set_payload_table(d) + + +Note this can be handy for cases like: + +.. code-block:: python + + item.set_payload_table_values([[1, 2, 3], [4, 5, 6]]) + + +where one does not want to work with numpy and prefers to pass lists of +lists. The core API will convert the list of lists into a 2D numpy array +for the caller. + +It is possible to use a table of strings. To create a 2 row, 3 column +array of strings (up to 20 characters), one might use code like this: + +.. code-block:: python + + import numpy + + array = numpy.array([["A", "B", "C"], [1, 2, 3]], dtype="\|S20") + d = dict( + array=array, + rowlbls=["Row 1", "Row 2"], + collbls=["Column A", "Column B", "Column C"], + title="Simple ASCII table", + ) + item.set_payload_table(d) + + +A numpy array of strings contains strings of all the same length. The +maximum length must be specified using the 'dtype=' named argument when +the array is created. + +.. _TreeItemDetails: + + +Tree Item +''''''''' + +**item.set_payload_tree(tree)** + +A tree payload consists of a list of "entities". Each entity is a +dictionary with several required keys and potentially some optional +ones. The required dictionary keys are: + +- 'name' - the text string that will be displayed in the tree view. +- 'key' - a simple text string that can be used to specify the type of + the entity. This value can be used to enforce a schema on the + entities. This value is not displayed. +- 'value' - the data item value for the entity. This can be the None + object or an object of any of the following types: bool, int, float, + str, datetime.datetime, uuid.UUID. + +optional keys include: + +- 'children' - this key can be set to another list of entities. These + entities are 'children' of the entity with this key and their + visibility is controlled by the visible state of this entity. +- 'state' - if present, this key hints the generation engine that this + entity node (or the nodes below it) should be initially displayed + expanded or collapsed. Valid values include the strings: "expanded", + "collapsed", "collapseRecursive" and "expandRecursive". +- 'header' - this key may be set to a boolean and defaults to False. If + it is present and set to True, the rendered row associated with this + item will be displayed as bold text and with an enhanced bottom + border line. + +The following example includes examples of all of the various options: + +.. code-block:: python + + import datetime + import enve + import uuid + + image_item = server.create_item(name="An Image", source="externalAPI", sequence=0) + img = enve.image() + if img.load("example.png") == 0: + image_item.set_payload_image(img) + + leaves = list() + for i in range(10): + leaves.append(dict(key="leaves", name="Leaf {}".format(i), value=i)) + + children = list() + children.append(dict(key="child", name="Boolean example", value=True)) + children.append(dict(key="child", name="Integer example", value=10)) + children.append(dict(key="child", name="Float example", value=99.99)) + children.append(dict(key="child", name="Simple string", value="Hello world!!!")) + children.append( + dict(key="child", name="The current date", value=datetime.datetime.now()) + ) + + # this entity will display the image item (or a link to it) created above + children.append( + dict(key="child", name="A data item guid", value=uuid.UUID(image_item.guid)) + ) + children.append( + dict( + key="child_parent", + name="A child parent", + value="Parents can have values", + children=leaves, + state="expanded", + ) + ) + + tree = list() + tree.append( + dict(key="root", name="Top Level", value=None, children=children, state="collapsed") + ) + item = server.create_item(name="Tree List Example", source="externalAPI", sequence=0) + item.set_payload_tree(tree) + diff --git a/doc/source/lowlevelapi/DatasetandSessionObjects.rst b/doc/source/lowlevelapi/DatasetandSessionObjects.rst new file mode 100755 index 000000000..32cb30265 --- /dev/null +++ b/doc/source/lowlevelapi/DatasetandSessionObjects.rst @@ -0,0 +1,107 @@ +Dataset and Session Objects +=========================== + +.. _DatasetREST: + +report_objects.DatasetREST object +--------------------------------- + +This object is a Python representation of an Ansys +Dynamic Reporting dataset object. When +this object is created, a GUID will automatically be generated for the +object. + +Data members +^^^^^^^^^^^^ + +The following attributes are available on a DatasetREST object: + +- guid - string GUID. The default is str(uuid.uuid1()) +- tags - The user-defined tags string for this object. Multiple tags + are space-separated. +- filename - The filename portion of the dataset local path, a string +- dirname - The directory name portion of the dataset local path, a + string +- format - The format of the dataset, a string +- numparts - The number of parts in the dataset, an integer +- numelements - The total number of elements in the dataset, an integer + (a measure of the size of the dataset) + +Methods +^^^^^^^ + +**dataset.set_tags(tagstring)** + +Set the tags for the dataset to the passed string. Multiple tags are +space-separated. + +**dataset.get_tags()** + +Returns the tags string for this object. Multiple tags are +space-separated. + +**dataset.add_tag(tag, value=None)** + +Adds a tag to the current tag string. If no value is passed, the simple +tag string is added to the tags string. If a value is specified, a +string of the form tag=value will be added to the tag string. + +**dataset.rem_tag(tag)** + +Remove the tag (and any potential associated value) from the current tag +string. + +.. _SessionREST: + +report_objects.SessionREST object +--------------------------------- + +This object is a Python representation of an +Ansys Dynamic Reporting session object. When +this object is created, a GUID will automatically be generated for the +object and the date is set to the current time/date. + + +Data members +^^^^^^^^^^^^ + +The following attributes are available on a SessionREST object: + +- guid - string GUID. The default is ``str(uuid.uuid1())`` +- tags - The user defined tags string for this object. Multiple tags + are space-separated. +- date - The time & date of the creation of this object. The default + is: ``datetime.datetime.now(pytz.utc)`` +- hostname - The name of the host system the session was run on, a + string +- version - The version of the application that was used to generate + this session, a string +- platform - The platform/OS on which the application generated this + session, a string +- application - The name of the application generating this session, a + string + + +Methods +^^^^^^^ + +**session.set_tags(tagstring)** + +Set the tags for the session to the passed string. Multiple tags are +space-separated. + +**session.get_tags()** + +Returns the tags string for this object. Multiple tags are +space-separated. + +**session.add_tag(tag, value=None)** + +Adds a tag to the current tag string. If no value is passed, the simple +tag string is added to the tags string. If a value is specified, a +string of the form tag=value will be added to the tag string. + +**session.rem_tag(tag)** + +Remove the tag (and any potential associated value) from the current tag +string. diff --git a/doc/source/lowlevelapi/GettingStarted.rst b/doc/source/lowlevelapi/GettingStarted.rst new file mode 100755 index 000000000..d1403b1cb --- /dev/null +++ b/doc/source/lowlevelapi/GettingStarted.rst @@ -0,0 +1,352 @@ +Startup +------- + +The following code snippet illustrates how to import the necessary API +modules (technically, **import requests** is not necessary, but some of +the API calls are simpler with that module available): + +.. code-block:: python + + from ansys.dynamicreporting.core.utils import report_remote_server, report_objects + import requests + + +Simple Example +-------------- + +This snippet creates a new database, starts an ADR Nexus server, verifies the +server and shuts it down. It uses the port=None option to allow the +system to find and use a non-conflicting port to run the server on. If +needed, the port is returned as part of the URL returned by: +serverobj.get_URL(). + +.. code-block:: python + + db_dir = "D:/data/example_database" + report_remote_server.create_new_local_database(None, directory=db_dir) + serverobj = report_remote_server.Server() + report_remote_server.launch_local_database_server( + None, port=None, directory=db_dir, connect=serverobj + ) + version_number = serverobj.validate() + serverobj.stop_local_server() + +core.report_remote_server module +-------------------------------- + +This module includes the interfaces needed to manage ADR Nexus servers. + +Module functions +^^^^^^^^^^^^^^^^ + +Many of these functions support Qt integration. The parent option +specifies the Qt widget that should be the parent if they are to display +any GUI elements. If parent is specified as None, no GUI elements will +be presented to the user and the operation will just return an error +status. + +report_remote_server.launch_local_database_server +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: python + + bError = launch_local_database_server( + parent, + directory="", + no_directory_prompt=False, + port=8000, + connect=None, + terminate_on_python_exit=False, + delete_db_on_python_exit=False, + username="nexus", + password="cei", + verbose=True, + return_info=None, + raise_exception=False, + use_system_tray=None, + server_timeout=180.0, + **kwargs + ) + + +This function will try to launch a local ADR Nexus server using the database +found in the specified directory on the specified port. If parent is not +set None, the function will interact with the user via Qt modal dialogs +(parent will be the parent of the dialogs) to select database directory, +ports, username and password. One can bypass the prompt to select the +server directory using the no_directory_prompt keyword argument. + +By default, a launched server will continue to run after the current +Python session stops. There is a server method stop_local_server() that +can be used to stop the launched server. Otherwise, the +terminate_on_python_exit keyword can be set to True to cause the server +to be automatically shut down if the current Python interpreter instance +exits cleanly. + +If the delete_db_on_python_exit argument is also set to True, then once +the server is automatically shut down the database directory it was +connected to will be deleted. + +If the Qt parent is not set to None and the server has not been set to +terminate on exit, then the use_system_tray option can be used to cause +the server to place a menu in the system tray. This menu will allow for +the server to be stopped, the logs to be reviewed and other options. + +When launching a server, this function will try to connect to the +launched server for some time before assuming the launch has failed. The +length of this timeout is specified by the server_timeout keyword. + +By default, the function will return True on success or False on +failure. If raise_exception is True, the function will raise an +exception instead of returning False. + +The username and password for the database should be specified using +those keywords. + +If the connect keyword is specified, it should be an instance of the +report_remote_server.Server class. This object will be populated with +the launched server details when the function returns. It is a handy way +to capture a dynamically selected port. + +The port keyword can be set to the specific port number the ADR Nexus server +should use. The port keyword may also be set to None, in which case the +system will search for an open port on which to start the ADR Nexus server, +starting at 8000. If this option is selected, it is critical that the +'connect' keyword be set, otherwise there will be no mechanism for one +to know the actual port that was used. + +The verbose keyword controls the level of log output generated by the +ADR Nexus server and determines if the user is allowed to modify any +dynamically selected port number. + +In addition to the above mentioned arguments, this method supports all +of the options available to the Ansys Dynamic Reporting Launcher CLI (through ``**kwargs``). + +report_remote_server.create_new_local_database +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: python + + bError = create_new_local_database( + parent, directory="", return_info={}, raise_exception=False + ) + + +This function will create a new, empty database with the default +username and password in the directory specified by the directory +keyword. If parent is None, this function will try to create the +database and return True on success without presenting any GUI elements. +It is very important to set the directory keyword if passing None as the +parent. Otherwise, parent should be a Qt widget object that will serve +as the parent of modal dialog used to select the directory to contain +the new database. The target directory should be empty as this method +will insert a media directory, a db.sqlite3 file and a manage.py file. +The return_info argument is optional. If a dictionary is passed, +information about the created database will be stored in it. + +If raise_exception is True, method will throw an error instead of +returning the error flag. + +report_remote_server.connect_to_server_dialog +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: python + + bError = connect_to_server_dialog(parent, server, title=None) + + +This method presents a dialog to the user with a window title specified +by the title keyword that allows the user to enter all of the +information needed to connect to an ADR Nexus server. It then attempts to +connect to the server and returns True if the connection succeeded. The +server argument should be an instance of the report_remote_server.Server +class which will be initialized with the entered values. This method can +only be called from a PyQt application. You can specify None for the +parent, but it will have the same effect as displaying a modal dialog +with no parent specified. Do not use this method if your application +should not display any GUI. + +:doc:`report_remote_server.Server ` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This class provides an interface to the ADR Nexus server. Most of the core +API can be accessed via an instance of this class. The Server object has +methods for creating instances of data item and template objects. + + +core.report_objects module +-------------------------- + +This module provides the core data items that can be pushed into +an Ansys Dynamic Reporting +database. This includes the session, dataset and item objects. +Generally, these classes should be created using the Server object +methods create_item, create_layout, default_dataset and default_session +or via one of the Server query methods. + +.. _ReportObjectsList: + + +Class hierarchy +^^^^^^^^^^^^^^^ + + +**BaseRESTObject** - Abstract Ansys Dynamic Reporting REST object interface base class + + - :ref:`DatasetREST ` - Dataset + information + + - :ref:`SessionREST ` - Session + information + + - :ref:`ItemREST ` - Core data items + + - :ref:`TemplateREST ` - Abstract base class + for all template (layout and generator) classes + + - :ref:`LayoutREST ` - Abstract base class for + all layout classes + + - :ref:`basicREST ` - Basic column layout class + + - :ref:`panelREST ` - Column layout class with + support for pullouts and headers + + - :ref:`boxREST ` - Explicit child layout class + + - :ref:`tabsREST ` - Layout that organizes + layout children into tabs + + - :ref:`carouselREST ` - Layout that + organizes children into a 'carousel' presentation + + - :ref:`sliderREST ` - Specialized image + layout for interactive image review/comparison + + - :ref:`footerREST ` - Page footer layout + + - :ref:`headerREST ` - Page header layout + + - :ref:`iteratorREST ` - Tag-based layout + replicator + + - :ref:`tagpropsREST ` - Map item/layout + tags into properties + + - :ref:`tocREST ` - Table of contents/figure list + layout + + - :ref:`reportlinkREST ` - Cross layout + linking + + - :ref:`GeneratorREST ` - Abstract base + class for all generator classes + + - :ref:`tablemergeREST ` - Table merge + generator for merging multiple tables into a single table + + - :ref:`tablereduceREST ` - Table + reduction generator that may collapse rows/columns into aggregated + values + + - :ref:`tablerowcolumnfilterREST ` - + Table row/column filter generator for removing/organizing table rows + and columns + + - :ref:`tablevaluefilterREST ` - Table + value filter generator for processing table values + + - :ref:`tablesortfilterREST ` - Table + sort/filter generator for re-organizing tables + + - :ref:`sqlqueriesREST ` - SQL query + generator for pulling data into the report from external SQL databases + + - :ref:`treemergeREST ` - tree merge + generator for merging multiple trees into a single tree + + +Examples +-------- + +A simple example of how this API might be used: + + +.. code-block:: python + + from ansys.dynamicreporting.core.utils import report_remote_server, report_objects + + serverobj = report_remote_server.Server( + url="http://localhost:8000", username="nexus", password="cei" + ) + session = serverobj.get_default_session() + session.application = "My Application" + session.version = "10.2" + item = serverobj.create_item(name="Simple header", source="My Python script") + item.set_payload_html("

An Example Header

") + error = serverobj.put_objects([item]) + + +This would start a new session that connects to an ADR Nexus server already +running on port 8000 of the local system. The server has a default +dataset and a default session object. We change the name and version of +the session application before creating a new data item. The data item +is populated with some HTML source and then pushed to the server. The +put_objects() call will push the item, the session and the dataset +objects all to the ADR Nexus server. + +A more complex example that generates an ASCII table of three columns +representing a username, a version number and a date (as a floating +point value): + +.. code-block:: python + + # core Python modules + from dateutil import parser + import datetime + import random + import requests + import numpy + + # Ansys Dynamic Reporting modules + from ansys.dynamicreporting.core.utils import report_remote_server, report_objects + + # time values can be represented as double precision counts of seconds from a standard time_base + time_base = datetime.datetime(1970, 1, 1) + + + def make_time(s): + dt = parser.parse(s) + return (dt - time_base).total_seconds() + + + # generate a row of random values + def row_gen(start, end): + users = ["bob", "fred", "mary", "jill"] + versions = ["1.1", "2.0", "1.3", "1.0"] + t0 = make_time(start) + t1 = make_time(end) + return [ + users[random.randint(0, 3)], + versions[random.randint(0, 3)], + t0 + (t1 - t0) * random.random(), + ] + + + # connect to the default ADR Nexus server (this assumes the server had been started previously + + s = report_remote_server.Server("http://localhost:8000", "nexus", "cei") + nrows = 40 + ncols = 3 + item = s.create_item(name="Text List Example", source="externalAPI", sequence=0) + array = numpy.zeros((nrows, ncols), dtype="\|S20") + for i in range(nrows): + array[i] = row_gen("1/1/2017", "2/1/2017") + + item.set_payload_table_values( + array, rowlbls=None, collbls=["User", "Version", "Date"], title="January" + ) + item.add_tag("month", "Jan") + item.add_tag("user_version_example") + if s.put_objects(item) == requests.codes.ok: + print("Success") diff --git a/doc/source/lowlevelapi/ServerObject.rst b/doc/source/lowlevelapi/ServerObject.rst new file mode 100755 index 000000000..361b08d2a --- /dev/null +++ b/doc/source/lowlevelapi/ServerObject.rst @@ -0,0 +1,308 @@ +Server Object +============= + +report_remote_server.Server object +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This object serves to wrap the Ansys Dynamic Reporting REST API. +It sets up a connection +to an ADR Nexus server and allows objects to be pulled from and pushed to the +server. + +A new server object can be created with the following: + +**serverobj = report_remote_server.Server(url=None, username=None, password=None)** + +Methods +^^^^^^^ + +**serverobj.set_URL("http://localhost:8000")** +**serverobj.set_username("nexus")** +**serverobj.set_password("cei")** + +Specify the ADR Nexus server (url and authentication information) to which +to connect the Server object to. + +**url = serverobj.get_URL()** +**username = serverobj.get_username()** +**password = serverobj.get_password()** + +Retrieve information about the current Server configuration. + +**server_name = serverobj.get_server_name()** + +Attempts to connect to the database returns the name of the server. For +remote servers, the name is a configuration parameter. For local +servers, it is the name of the directory that contains the SQLite file. +Note: if a connection to the server cannot be made or the server does +not support names, this method returns the URL for the server. + +**server_version_float = serverobj.validate()** + +Attempts to connect to the database and verifies that the server +connection specifications are valid. It returns the version of the +ADR Nexus +server API that the server is using. Note: this method will throw an +exception on encountering an error. + +**has_database_url = serverobj.valid_database()** + +This method checks to see if a database url has been set. It returns +True if a url has been set. It does not verify that the connection and +username, password is valid. + +**serverobj.stop_local_server()** + +This method will stop any local ADR Nexus server accessible via the current +Server object URL, username and password. + +**guid_list = serverobj.get_object_guids(objtype=type_class, query=None)** + +This method will query the server and returns a list of the object GUIDs +that meet the specific query. If the query is +None, all of the GUIDs of the type specified by objtype will be +returned. The objtype keyword specifies the type of database object to +get the list of guids for. Valid values for the objtype keyword include: + +- report_objects.DatasetREST +- report_objects.SessionREST +- report_objects.ItemREST + +**obj_list = serverobj.get_objects(objtype=type_class, query=None)** + +This method is similar to **get_object_guids()** except that it +returns a list of actual instances of the class specified by the +objtype keyword instead of just returning the GUIDs. + +Note that if you want the list of templates, you can either set +**objtype** to **report_objects.TempalteREST** or to +**report.objects.TemplateREST.factory**. In the first case, all the +templates will be returned as objects of the TemplateREST class. In +the second case, all templates will be returned as objects of the +sub-classes of TemplateREST, corresponding to the exact report_type. + +**obj = serverobj.get_object_from_guid(guid, objtype=type_class)** + +This method queries the ADR Nexus server for a single object of the class +specified by objtype with the GUID specified by the guid argument. It +returns an instance of the class specified by objtype or None if the +GUID is not present. + +**status_code = serverobj.put_objects(objects)** + +This method takes a collection of objects of the classes +report_objects.DatasetREST, report_objects.SessionREST and +report_objects.ItemREST and pushes the local contents of the objects to +the server. If objects with the same GUID(s) already exist in the server +database, they will be overwritten. The return value is a status code +from the **requests** Python module (e.g. **requests.codes.ok**). Note: +if an error occurs the method will return the last error, but it will +try to push every object in the input collection. + +**status_code = serverobj.del_objects(objects)** + +This method takes a collection of objects of the classes +report_objects.DatasetREST, report_objects.SessionREST and +report_objects.ItemREST and asks the server to delete them. If objects +with matching GUIDs exist in the server database, they will be removed +from the database. This method only looks at the guid attribute of the +input object collection. The return value is a status code from the +**requests** Python module (e.g. **requests.codes.ok**). Note: if an +error occurs the method will return the last error, but it will try to +delete every object in the input collection. + +**status_code = serverobj.get_file(object, fileobj)** + +In some cases, a report_objects.ItemREST instance will have an +associated file in the Ansys Dynamic Reporting datastore. +Examples include images, +animations and 3D geometry (see report_objects.ItemRest above). The +ItemREST.is_file_protocol() can be used to check for this. This method +will download the file (if any) associated with the (ItemREST instance) +object and write the output into the file object specified by the +fileobj argument. Fileobj should be an open Python file type object that +supports minimally write I/O semantics. Note that the operation is +streaming, so it is possible for a partial file to exist if errors are +encountered. The return value is a status code from the **requests** +Python module (e.g. **requests.codes.ok**). + +**session = serverobj.get_default_session()** +**dataset = serverobj.get_default_dataset()** +**serverobj.set_default_session(session)** +**serverobj.set_default_dataset(dataset)** + +The server object maintains default SessionREST and DatasetREST objects +that are used with the create_item() method to simplify data item +creation. The get_default_session() and get_default_dataset() methods +return the current default session and dataset objects. The +corresponding set_default_session() and set_default_dataset() methods +set these objects to externally generated objects or more commonly, +modified objects returned by the get methods. + +**item = serverobj.create_item(name="Unnamed Item", source="ADR Python +API", sequence=0)** + +This method simplifies the generation of data items. One can create a +new data item by simply instantiating an instance of ItemREST(), but +many of the item attributes would need to be configured properly before +the object can be saved into the database. Most notably, the +item.session and item.dataset attributes need to be set to the GUIDs for +an instance of SessionREST and DatasetREST respectively. The Server +object always maintains a default instance of SessionREST and +DatasetREST objects. The object references can be modified by the user +to customize their metadata. The create_item() method will create a new +instance of the ItemREST class and will automatically fill in the +session and dataset attributes to the objects returned by +get_default_session() and get_default_dataset(). Additionally, if +put_objects() is called on an item whose session or dataset attributes +match the default GUIDs, the put_objects() method will push the session +and/or dataset objects as needed. If the session/dataset objects change +(without changing the GUIDs) the system will detect this any +automatically push them when the next item is pushed that references one +of them. The create_item() method allows the user to specify the name, +source and sequence number for the item during creation. + +**serverobj.export_report_as_html(report_guid, directory_name, +query=None)** + +This method exports the Ansys Dynamic Reporting report with the +GUID specified by the +argument "report_guid". The result will be written into the directory +specified by the argument "directory_name". The method will create the +directory if it does not exist previously. There will be a file named +"index.html" in the directory and a "media" subdirectory containing the +resources needed to display the report. note: if there is an error, this +method will throw an exception. + +Input arguments: + +- report guid (string) - the guid of the report to be downloaded as + HTML. +- directory_name (string) - the name of the directory to save the + downloaded contents. +- query (dictionary) - a dictionary of query parameters to add to the + report URL. + +**serverobj.export_report_as_pdf(report_guid, file_name, delay=5000)** + +Save a PDF rendering of the Ansys Dynamic Reporting report with the GUID specified by the +argument "report_guid". The name of the PDF file is specified by the +argument "file_name". Note: if there is an error, this method will throw +an exception. This is the equivalent of displaying the report with the +query 'print=pdf' included in the report URL. + +Input arguments: + +- report guid (string) - the guid of the report to be saved as PDF. +- file_name (string) - the name of the target PDF file. +- delay (int) - number of milliseconds to wait for the report to load + before downloading it. Default is 5000ms. Optional. + +Various data items and report templates will behave differently when +printing: + +#. Tree data items will be fully expanded and the interactive buttons + for expanding/collapsing will be removed. +#. Animation data items will be rendered as if the 'image_display' + property is set to 1. +#. Table data items will have all of their interactive controls + suppressed (e.g. sorting, searching, scrolling, pagination, etc) +#. Tab layouts will behave as if the 'inline_tabs' property is set to 1. +#. Panel layouts will behave as if the 'panel_template_toggle' property + is set to 0. + +Magic tokens +^^^^^^^^^^^^ + +Magic tokens is a new way for users in the ADR Nexus server +to login without using +their password. Ansys Dynamic Reporting +provides a Python API to generate a per-user +secret token. This token can then be attached to any Ansys Dynamic Reporting web page URL +to bypass login during future access. This is currently restricted to +only the user who starts the server. This can be useful if a URL needs +to be reused within a HTML iframe. + +**serverobj.generate_magic_token(max_age=None)** + +This method generates a magic token with the desired expiry. + +Input arguments: + +- max_age (int) - Expiry of the token in seconds. If this is None, the + server will use its default expiry of 1 day. + +**serverobj.get_url_with_magic_token()** + +This will return a URL to access the ADR Nexus server with a magic token +attached. + +Usage: + +.. code-block:: python + + from ansys.dynamicreporting.core.utils import report_remote_server, report_objects + + server = report_remote_server.Server() + opts = { + "port": 8000, + "directory": "C:\\Users\\Nexus\\db", + "raise_exception": True, + "connect": server, + } + launched = report_remote_server.launch_local_database_server(None, opts) + if launched: + print(server.magic_token) # auto generation.. default expiry of 1day + print(server.get_url_with_magic_token()) + server.magic_token = server.generate_magic_token( + max_age=60 + ) # manual generation, with an expiry of 60 seconds + print(server.get_url_with_magic_token()) + # Prints URL with token. + # Example: http://127.0.0.1:8000?magic_token=eyJ1c2VyX2lkIjozLCJtYXhfYWdlIjo4NjQwMCwidGltZXN0YW1wIjoiMW5QY1B5In0:1nPcPy:c3OZhMCVQQq_fXXzevQ47WHxYfbAZE5TI-GL0yBzIaw + template = serverobj.create_template( + name="New Template", parent=None, report_type="Layout:basic" + ) + + +Method on a report_remote_server.Server() object to create a new +report_object.TemplateREST object. You can pass as input: + +- name (string) - the name of the template +- parent (template objects)- the parent template. If None, the new + template will be a top level one +- report_type (string) - sets the type of template. Each value of + report_type corresponds to a different template type, and will + generate an object from the corresponding template sub-class. See the + table for the accepted values of report_type, the corresponding + template type and Python API sub-class. + +**error_string = serverobj.get_last_error()** + +Several of the server methods return REST error codes: put_objects(), +del_objects(), get_file(), etc. When these methods error, they return +the specific REST error code. If the error in question was generated by +the ADR Nexus server, in addition to the error_code not being equal to +**requests.codes.ok**, the server may return a more detailed error +string. This string can be retrieved using the get_last_error() method. +An example of a data item with an item name exceeding: + +.. code-block:: python + + from ansys.dynamicreporting.core.utils import report_remote_server, report_objects + + serverobj = report_remote_server.Server( + url="http://localhost:8000", username="nexus", password="cei" + ) + invalid_data_item_name = 100 + item = serverobj.create_item(invalid_data_item_name, "command line") + item.set_payload_string("A simple text string") + print(serverobj.put_objects(item)) + print(serverobj.get_last_error()) + + +will output the following (note: **requests.codes.bad_request** == 400) +output noting that the "name" field exceeds the maximum field length: + +**400** +**{"name":["Ensure this field has no more than 80 characters."]}** diff --git a/doc/source/lowlevelapi/TemplateObjects.rst b/doc/source/lowlevelapi/TemplateObjects.rst new file mode 100755 index 000000000..b74d3db1e --- /dev/null +++ b/doc/source/lowlevelapi/TemplateObjects.rst @@ -0,0 +1,1642 @@ +.. _TemplateREST: + +Template Objects +================ + +.. _here: https://nexusdemo.ensight.com/docs/en/html/Nexus.html?LayoutTemplates.html +.. _link: https://nexusdemo.ensight.com/docs/en/html/Nexus.html?QueryExpressions.html +.. _Columns: https://nexusdemo.ensight.com/docs/en/html/Nexus.html?Columns.html +.. _Panel: https://nexusdemo.ensight.com/docs/en/html/Nexus.html?Panel.html +.. _Boxes: https://nexusdemo.ensight.com/docs/en/html/Nexus.html?Boxes.html +.. _Tabs: https://nexusdemo.ensight.com/docs/en/html/Nexus.html?Tabs.html +.. _Carousel: https://nexusdemo.ensight.com/docs/en/html/Nexus.html?Carousel.html +.. _Slider: https://nexusdemo.ensight.com/docs/en/html/Nexus.html?Slider.html +.. _Page Footer: https://nexusdemo.ensight.com/docs/en/html/Nexus.html?PageFooter.html +.. _Page Header: https://nexusdemo.ensight.com/docs/en/html/Nexus.html?PageHeader.html +.. _Iterator: https://nexusdemo.ensight.com/docs/en/html/Nexus.html?Iterator.html +.. _Tag to Properties: https://nexusdemo.ensight.com/docs/en/html/Nexus.html?TagProperties.html +.. _Table of Contents: https://nexusdemo.ensight.com/docs/en/html/Nexus.html?TableofContents.html +.. _Link Report: https://nexusdemo.ensight.com/docs/en/html/Nexus.html?LinkReport.html +.. _Table Merge: https://nexusdemo.ensight.com/docs/en/html/Nexus.html?TableMerge.html +.. _Table Reduction: https://nexusdemo.ensight.com/docs/en/html/Nexus.html?TableReduction.html +.. _Table Row/Column Filter: https://nexusdemo.ensight.com/docs/en/html/Nexus.html?TableRowColumnFilter.html +.. _Table Value Filter: https://nexusdemo.ensight.com/docs/en/html/Nexus.html?TableValueFilter.html +.. _Table Row/Column Sort: https://nexusdemo.ensight.com/docs/en/html/Nexus.html?TableRowColumnSort.html +.. _SQL Query: https://nexusdemo.ensight.com/docs/en/html/Nexus.html?SQLQuery.html +.. _Tree Merge: https://nexusdemo.ensight.com/docs/en/html/Nexus.html?TreeMerge.html +.. _Generator templates: https://nexusdemo.ensight.com/docs/en/html/Nexus.html?GeneratorTemplates.html + + + +report_objects.TemplateREST object +---------------------------------- + +This object is a Python representation of an Ansys +Dynamic Reporting template object. When +this object is created, a GUID will automatically be generated for the +object and the date is set to the current time/date. The +report_objects.TemplateREST class represent features common to all +template types. Two sub-classes, report_objects.LayoutREST and +report_objects.GeneratorREST represent the generic Layout and Generator +templates. From each of these classes, a set of sub-classes representing +the specific template types are inherited. For information specific to +each template type, refer to the :ref:`subclass tree `. + +.. note:: + + TemplateREST objects should always be generated using the + server object :doc:`create_template() ` method. + + +Data members +^^^^^^^^^^^^ + +The following attributes are available on a TemplateREST object: + +- guid - string GUID. The default is **str(uuid.uuid1())** +- tags - The user-defined tags string for this object. Multiple tags + are space-separated. You can also access the tabs via the method + :ref:`get_tags() `. +- date - The time & date of the creation of this object. The default + is: **datetime.datetime.now(pytz.utc)** +- name - The name of the template +- report_type - The type of the report template (e.g. 'Layout:basic'). + The report_type is also set by the sub-class of the object. See + :ref:`this table ` for the + correspondence between report_type and template sub-class +- item_filter - The filter string for this report template. You can + also access the filter via the method + :ref:`get_filter() `. +- params - A Python dictionary of the parameters for this specific + report_type. You can also access the parameters via the method + :ref:`get_params() `. +- children - A list of the child templates of this template +- master - True if the parent data member is None +- parent - The parent template (if any) of this template + +Methods +^^^^^^^ + +.. _template_get_params: + +**template.get_params()** + +Get the parameters of the template. + +The parameter field contains all the fields that can be set via the GUI, +including filters, list of properties, individual settings for the +specific template type. While one can access all the values via this +method, we would suggest using the methods specific to the field you are +interested in for each field for sake of clarity and usability. + +**template.set_params({'param1': 1})** + +Set the parameters of the template. This function takes as input a +dictionary. + +The parameter field contains all the fields that can be set via the GUI, +including filters, list of properties, individual settings for the +specific template type. While one can access all the values via this +method, we would suggest using the methods specific to the field you are +interested in for each field for sake of clarity and usability. + +**template.add_params({'param1': 1})** + +Add the parameters to the existing template parameters. This function +takes as input a dictionary. + +The parameter field contains all the fields that can be set via the GUI, +including filters, list of properties, individual settings for the +specific template type. While one can access all the values via this +method, we would suggest using the methods specific to the field you are +interested in for each field for sake of clarity and usability. + +**template.get_property()** + +Get the properties of the template as a dictionary. A general +description of what properties are for a template can be found +`here`_. + +**template.set_property(property={})** + +Set the properties of the template. Input needs to be a dictionary. A +general description of what properties are for a template can be found +`here`_. + +**template.add_property(property={})** + +Add the properties of the template. Input needs to be a dictionary. A +general description of what properties are for a template can be found +`here`_. + +**template.get_sort_fields()** + +Get the sorting filter of the template. + +**template.set_sort_fields(['+i_date', '-i_name'])** + +Set the sorting filter of the template. This function takes a list as +input. The list is generated with '+' for increasing, '-' for +decreasing, followed by the property to sort by, with the same strings +as reported at this `link`_. Example: setting the sort +fields to be by increasing item date and decreasing by item name +becomes: ['+i_date', '-i_name'] + +**template.add_sort_fields(['+i_date', '-i_name'])** + +Add elements to the sorting filter of the template. This function takes +a list as input. The list is generated with '+' for increasing, '-' for +decreasing, followed by the property to sort by, with the same strings +as reported `link`_. Example: setting the sort +fields to be by increasing item date and decreasing by item name +becomes: ['+i_date', '-i_name'] + +**template.get_sort_selection()** + +Get the sort selection parameter. + +**template.set_sort_selection(value="all")** + +Set the sort selection parameter for the template.This function takes a +string as input, among the following options: + +- 'all' +- 'first' +- 'last' + +**template.set_tags(tagstring)** + +Set the tags for the template to the passed string. Multiple tags are +space-separated. + +.. _template_get_tags: + +**template.get_tags()** + +Returns the tags string for this object. Multiple tags are +space-separated. + +**template.add_tag(tag, value=None)** + +Adds a tag to the current tag string. If no value is passed, the simple +tag string is added to the tags string. If a value is specified, a +string of the form tag=value will be added to the tag string. + +**template.rem_tag(tag)** + +Remove the tag (and any potential associated value) from the current tag +string. + +.. _template_get_filter: + +**template.get_filter()** + +Get the item filter of the template. The item filter is encoded as a +string using the format explained `link`_. + +**template.set_filter(filter_str='')** + +Sets the item filter of the template. Takes as input a string. The item +filter is encoded as a string using the format explained +`link`_. + +**template.add_filter(filter_str='')** + +Add filters to the item filter of the template. Takes as input a string. +The item filter is encoded as a string using the format explained +`link`_. + +**template.get_filter_mode()** + +Returns the filter mode of the template. The possible outputs are: + +- 'items': corresponds to Incoming Items +- 'root_replace': corresponds to Database (replace) +- 'root_append': corresponds to Database (append) + +**template.set_filter_mode(value='items')** + +Sets the filter mode of the template. Takes as input a string. See +get_filter_mode for the accepted values. + +Example of usage. Let's assume you want to create a template like the +one shown in the picture (from the documentation example in the +Ansys Dynamic Reporting installer): + +.. figure:: lib/NewItem306.png + :alt: Image + :align: center + + +Let's also assume you want this template to be a root-level template +(i.e.: that doesn't have a parent template) in the database running +locally on port 8000. These would be the lines of code to create the new +template: + +.. code-block:: python + + from ansys.dynamicreporting.core.utils import report_remote_server, report_objects + + server = report_remote_server.Server("http://localhost:8000", "nexus", "cei") + all_reports = server.get_objects(objtype=report_objects.TemplateREST) + my_template = server.create_template( + name="Example Template", parent=None, report_type="Layout:panel" + ) + my_template.set_filter("A|i_src|cont|build_imagery;A|i_tags|cont|timestep=10;") + my_template.set_property({"width": "50"}) + server.put_objects(my_template) + + +SubClasses +^^^^^^^^^^ + +Each template type is represented by a subclass of the TemplateREST +class. There are two main subclasses: LayoutREST for the Layout template +types and GeneratorREST for the Generator template types. Each of these +subclasses has its own set of subclasses, to represent each specific +template type. + +.. _template_type_table: + +======================= ============================= ======================================== +**Layouts** **Template type** **Template API sub-class** +======================= ============================= ======================================== +basic `Columns`_ :ref:`report_objects.basicREST() + ` + +panel `Panel`_ :ref:`report_objects.panelREST() + ` + +box `Boxes`_ :ref:`report_objects.boxREST() + ` + +tabs `Tabs`_ :ref:`report_objects.tabsREST() + ` + +carousel `Carousel`_ :ref:`report_objects.carouselREST() + ` + +slider `Slider`_ :ref:`report_objects.sliderREST() + ` + +footer `Page Footer`_ :ref:`report_objects.footerREST() + ` + +header `Page Header`_ :ref:`report_objects.headerREST() + ` + +iterator `Iterator`_ :ref:`report_objects.iteratorREST() + ` + +tagprops `Tag to Properties`_ :ref:`report_objects.tagpropsREST() + ` + +toc `Table of Contents`_ :ref:`report_objects.tocREST() + ` + +reportlink `Link Report`_ :ref:`report_objects.reportlinkREST() + ` +======================= ============================= ======================================== + +======================= ============================= ======================================== +**Generators** **Template type** **Template API sub-class** +======================= ============================= ======================================== +tablemerge `Table Merge`_ :ref:`report_objects.tablemergeREST() + ` + +tablereduce `Table Reduction`_ :ref:`report_objects.tablereduceREST() + ` + +tablerowcolumnfilter `Table Row/Column Filter`_ :ref:`report_objects.tablerowcolumnfilterREST() + ` + +tablevaluefilter `Table Value Filter`_ :ref:`report_objects.tablevaluefilterREST() + ` + +tablesortfilter `Table Row/Column Sort`_ :ref:`report_objects.tablesortfilterREST() + ` + +sqlqueries `SQL Query`_ :ref:`report_objects.sqlqueriesREST() + ` + +treemerge `Tree Merge`_ :ref:`report_objects.mergetreeREST() + ` +======================= ============================= ======================================== + + +.. _LayoutREST: + +LayoutREST class +^^^^^^^^^^^^^^^^ + +Inherits from TemplateREST + +Class that groups all the common attributes among Layout templates +(for reference, see `here`_). Its specific methods are: + +**template.get_column_count()** + +Get the number of columns. + +**template.set_column_count(value)** + +Set the number of columns. Takes as input an integer larger than 0. + +**template.get_column_widths()** + +Get the list of the widths of the columns. + +**template.set_column_widths([1.0, 2.0, 1.0])** + +Set the list of the widths of the columns. Takes as input an array where +each number represent the relative width of that column compared to the +other columns. + +**template.get_transpose()** + +Returns the Transpose columns/rows status of the template. It returns 0 +for off, 1 for on. It supports only Layout: template types. + +**template.set_transpose(value=0)** + +Sets the Transpose columns/rows status of the template. value = 0 for +off, value = 1 for on. It supports only Layout: template types. + +**template.get_skip()** + +Returns the Skip if no input items status of the template. It returns 0 +for off, 1 for on. It supports only Layout: template types. + +**template.set_skip(value=0)** + +Sets the Skip if no input items status of the template. value = 0 +(default) for off, value = 1 for on. It supports only Layout: template +types. + +**template.get_html()** + +Returns the HTML of the template. It supports only Layout: template +types + +**template.set_html(value=None)** + +Sets the HTML of the template. Takes as input a string. It supports only +Layout: template types. + +Example of usage. Let's assume you want to create a template like the +one shown in the picture (from the "Slider Example" template in the +documentation example in the Ansys Dynamic Reporting installer): + +.. figure:: lib/NewItem307.png + :alt: Image + :align: center + + +Let's also assume you want this template to be a root-level template +(i.e.: that doesn't have a parent template) in the database running +locally on port 8000. These would be the lines of code to create the new +template: + +.. code-block:: python + + from ansys.dynamicreporting.core.utils import report_remote_server, report_objects + + server = report_remote_server.Server("http://localhost:8000", "nexus", "cei") + all_reports = server.get_objects(objtype=report_objects.TemplateREST) + my_template = server.create_template( + name="Slider Example", parent=None, report_type="Layout:panel" + ) + my_template.set_column_count(2) + my_template.set_column_widths([1.0, 1.0]) + * my_template.set_html("

Example Slider Panels

キャンペー") + server.put_objects(my_template) + + +.. _GeneratorREST: + +GeneratorREST class +^^^^^^^^^^^^^^^^^^^ + +Inherits from TemplateREST + +Class that groups all the common attributes among +`Generator templates`_. Its specific methods are: + +**template.get_generated_items()** + +Get the Generated items flag. Returned values: + +- 'replace': corresponds to Replace +- 'add': corresponds to Append + +**template.set_generated_items(value)** + +Get the Generated items flag. Takes as input a string. See +get_generated_items() for the acceptable strings. + +**template.get_append_tags()** + +Get the value for Append template tags to new items. Returned values are +True for toggled ON, False for toggled OFF + +**template.set_append_tags(value=True)** + +Get the value for Append template tags to new items. The input needs to +be a boolean: True / False + + +.. _basicREST: + +basicREST object +^^^^^^^^^^^^^^^^ + +Inherits from TemplateREST, LayoutREST + +Class that corresponds to the `Columns`_ Layout template +type. No specific methods. + +.. _panelREST: + +panelREST object +^^^^^^^^^^^^^^^^ + +Inherits from TemplateREST, LayoutREST + +Class that corresponds to the `Panel`_ Layout template type. +Its specific methods are: + +**template.get_panel_style()** + +Get the style of the Panel. Possible returned values: + +- 'panel': corresponds to Titled Panel +- 'callout-default': corresponds to Callout +- 'callout-danger': corresponds to Callout Error +- 'callout-warning': corresponds to Callout Warning +- 'callout-success': corresponds to Callout Success +- 'callout-info': corresponds to Callout Info + +**template.set_panel_style(value='panel')** + +Set the style of the Panel. Takes as input strings. For the acceptable +values, see get_panel_style() + +**template.get_items_as_link()** + +Get the Show items as link toggle. 0 corresponds to Off, 1 corresponds +to ON. + +**template.set_items_as_link(value=0)** + +Set the Show items as link toggle. Takes as input an integer. 0 +corresponds to Off, 1 corresponds to ON. + +.. _boxREST: + +boxREST object +^^^^^^^^^^^^^^ + +Inherits from TemplateREST, LayoutREST + +Class that corresponds to the `Boxes`_ Layout template type. +Its specific methods are: + +**template.get_children_layout()** + +Get the children layout. This method returns a dictionary where each +entry is a different child layout. + +For each entry, the key corresponds to the guid of the child template. +The corresponding value is an array that gives:: + + [ X, Y, Width, Height, Clip] + + +where Clip has the following values: + +- 'self': corresponds to Clip: To self +- 'scroll': corresponds to Clip: Scroll +- 'none': corresponds to Clip: None + +**template.set_child_position(guid=None, value=[0,0,10,10])** + +Set the children layout: position and size. The method takes as input +the guid of the child template you want to modify, and an array of 4 +integers that corresponds to [X, Y, Width, Height] that you want to +set. +Remember that if you are setting a new child template (not modifying +an existing one), you will manually need to set that this child +template has the current box template as the parent template. See the +example below for how to do it. + +**template.set_child_clip(guid=None, clip='self')** + +Set the children layout: clip parameter. The method takes as input the +guid of the child template you want to modify, and the clip type as a +string. Only the types enumerated in get_children_layout() are +acceptable values. +Remember that if you are setting the clip type for a new child +template (not modifying an existing one), you will manually need to +set that this child template has the current box template as the +parent template. See the example below for how to do it. + +Example of usage. Let's assume you want to create a template like the +one shown in the picture (from the documentation example in the +Ansys Dynamic Reporting installer): + +.. figure:: lib/NewItem305.png + :alt: Image + :align: center + + +Let's also assume you want this template to be a child template of the +template "Box report test" that already exists in in the database +running locally on port 8000. These would be the lines of code to create +the new template: + +.. code-block:: python + + from ansys.dynamicreporting.core.utils import report_remote_server, report_objects + + server = report_remote_server.Server("http://localhost:8000", "nexus", "cei") + all_reports = server.get_objects(objtype=report_objects.TemplateREST) + my_parent = [x for x in all_reports if x.name == "Box reporttest"][0] + my_template = server.create_template( + name="Box Template", parent=my_parent, report_type="Layout:box" + ) + + first_box = [x for x in all_reports if x.name == "box_images"][0] + my_template.set_child_position(guid=first_box.guid, value=[40, 39, 320, 240]) + first_box.parent = my_template.guid + second_box = [x for x in all_reports if x.name == "box_movies"][0] + my_template.set_child_position(guid=second_box.guid, value=[370, 39, 355, 241]) + my_template.set_child_clip(guid=second_box.guid, clip="scroll") + second_box.parent = my_template.guid + third_box = [x for x in all_reports if x.name == "box_plot"][0] + + my_template.set_child_position(guid=third_box.guid, value=[41, 288, 685, 210]) + my_template.set_child_clip(guid=third_box.guid, clip="none") + third_box.parent = my_template.guid + + server.put_objects([first_box, second_box, third_box]) + server.put_objects(my_template) + server.put_objects(my_parent) + +.. _tabsREST: + +tabsREST object +^^^^^^^^^^^^^^^ + +Inherits from TemplateREST, LayoutREST + +Class that corresponds to the `Tabs`_ Layout template type. No +specific methods for this class. + +.. _carouselREST: + +carouselREST object +^^^^^^^^^^^^^^^^^^^ + +Inherits from TemplateREST, LayoutREST + +Class that corresponds to the `Carousel`_ Layout template +type. Its specific methods are: + +**template.get_animated()** + +Get the Animated value. If the toggle is OFF (default), the method will +return 0. This means that the Carousel doesn't automatically change +displayed image, and the user needs to click to see the next item. + +A non-zero integer value means the Carousel will automatically change +displayed image. The value represents how long each image is displayed +for in ms. + +**template.set_animated(value=0)** + +Set the Animated value. For an explanation of what this parameter +represents, see the get_animated() method above. + +**template.get_slide_dots()** + +Get the Include side dots value. If zero (default), the method returns +1. If the number of side dots is larger than the number of items +displayed on the Carousel, a number of dots corresponding to the number +of items will be displayed. If the number of side dots is smaller than +the number of items displayed on the Carousel, it is ignored an no dots +are displayed. + +**template.set_slide_dots(value=20)** + +Set the Include side dots value. For an explanation of what this +parameter represents, see the get_side_dots() method above. + +.. _sliderREST: + +sliderREST object +^^^^^^^^^^^^^^^^^ + +Inherits from TemplateREST, LayoutREST + +Class that corresponds to the `Slider`_ template +type. Its specific methods are: + +**template.get_map_to_slider()** + +Get the Selected tags and sort to map to sliders. This function returns +a list where each element corresponds to one tag and its sorting order. +The accepted sorted orders are: + +- 'text_up': corresponds to Text sort up +- 'text_down': corresponds to Text sort down +- 'numeric_up': corresponds to Numeric sort up +- 'numeric_down': corresponds to Numeric sort down +- 'none': corresponds to No sorting + +An example of output of this function is: ['tag1|text_up', +'tag2|numeric_down', 'tag3|none'] where the slider is sorted by "tag1" +using the "Text sort up" sorting method, then by "tag2" using the +"Numeric sort down" method and finally by "tag3" using no sorting +method. + +**template.set_map_to_slider(value=[])** + +Set the Selected tags and sort to map to sliders. This function takes as +input a list where each element corresponds to one tag and its sorting +order. See function get_map_to_slider() for the accepted sorting order +values. The input for this function will have form: + +['tag1|text_up', 'tag2|numeric_down', 'tag3|none'] + +**template.add_map_to_slider(value=[])** + +Add new tags and sorting methods to the the Selected tags and sort to +map to sliders. This function takes as input a list where each element +corresponds to one tag and its sorting order. See function +get_map_to_slider() for the accepted sorting order values. The input for +this function will have form: + +['tag1|text_up', 'tag2|numeric_down', 'tag3|none'] + +Example of usage. Let's assume you want to create a template like the +one shown in the picture (from the "Basic Slider" template in the +documentation example in the Ansys Dynamic Reporting installer): + +.. figure:: lib/NewItem308.png + :alt: Image + :align: center + + +Let's also assume you want this template to be a child of the template +"Tabs" in the database running locally on port 8000. These would be the +lines of code to create the new template: + +.. code-block:: python + + from ansys.dynamicreporting.core.utils import report_remote_server, report_objects + + server = report_remote_server.Server("http://localhost:8000", "nexus", "cei") + all_reports = server.get_objects(objtype=report_objects.TemplateREST) + my_parent = [x for x in all_reports if x.name == "Tabs"][0] + my_template = server.create_template( + name="Basic Slider", parent=my_parent, report_type="Layout:slider" + ) + my_template.set_filter("A|s_app|cont|Imagery Session;") + my_template.set_map_to_slider( + ["timestep|numeric_up", "variable|text_up", "mode|text_down"] + ) + server.put_objects(my_template) + server.put_objects(my_parent) + +.. _footerREST: + +footerREST object +^^^^^^^^^^^^^^^^^ + +Inherits from TemplateREST, LayoutREST + +Class that corresponds to the `Page Footer`_ Layout +template type. No specific methods. + +.. _headerREST: + +headerREST object +^^^^^^^^^^^^^^^^^ + +Inherits from TemplateREST, LayoutREST + +Class that corresponds to the `Page Header`_ Layout +template type. No specific methods. + +.. _iteratorREST: + +iteratorREST object +^^^^^^^^^^^^^^^^^^^ + +Inherits from TemplateREST, LayoutREST + +Class that corresponds to the `Iterator`_ template +type. Its specific methods are: + +**template.get_iteration_tags()** + +Get the values for Iteration tag and Secondary sorting tag. The values +are returned as element 0 and 1 of a list. + +**template.set_iteration_tags(value = ['', ''])** + +Set the values for Iteration tag and Secondary sorting tag. The input +values are given as element 0 and 1 of a list, and they need to be +strings + +**template.get_sort_tag()** + +Get the values for Sort items by tag and Reverse the sort as booleans. +The values are returned as element 0 and 1 of a list. + +**template.set_sort_tag(value=[True, False])** + +Set the values for Iteration tag and Secondary sorting tag. The values +are given as a list of booleans. Note that if you set the first element +to False, the second will automatically be set to False as well, +regardless of what the input is. + +.. _tagpropsREST: + +tagpropsREST object +^^^^^^^^^^^^^^^^^^^ + +Inherits from TemplateREST, LayoutREST + +Class that corresponds to the `Tag to Properties`_ +Layout template type. No specific methods. + +.. _tocREST: + +tocREST object +^^^^^^^^^^^^^^ + +Inherits from TemplateREST, LayoutREST + +Class that corresponds to the `Table of Contents`_ +Layout template type. Its specific methods are: + +**template.get_toc()** + +Get the values for Table of Contents, Figure List and Table List. Only +one option can be ON at any given time. The function will return a +string that corresponds to the option that is toggled on: + +- 'toc': corresponds to Table of Contents option +- 'figure': corresponds to the Figure List option +- 'table': corresponds to the Table List option + +If none of these option is ON (default when the template is created), +then the method will return None. + +**template.set_toc(option='toc')** + +Set the values for Table of Contents, Figure List and Table List. Only +one can be ON at any given time. Only the following values for option +are accepted: + +- 'toc': toggles on the Table of Contents option +- 'figure': toggles on the Figure List option +- 'table': toggles on the Table List option + +.. _reportlinkREST: + +reportlinkREST object +^^^^^^^^^^^^^^^^^^^^^ + +Inherits from TemplateREST, LayoutREST + +Class that corresponds to the `Link Report`_ Layout +template type. Its specific methods are: + +**template.get_report_link()** + +Get the guid of the linked report. If no linked report, it will return +None + +**template.set_report_link(link=None)** + +Set the guid of the linked report. It takes as input a valid guid. If +you want to set to link to no report, set the input to None + +.. _tablemergeREST: + +tablemergeREST object +^^^^^^^^^^^^^^^^^^^^^ + +Inherits from TemplateREST, GeneratorREST + +Class that corresponds to the `Table Merge Generator` +template type. Its specific methods are: + +**template.get_merging_param()** + +Get the value of Merging. Possible outputs are: + +- 'row': corresponds to Rows +- 'column': corresponds to Columns + +**template.set_merging_param(value='row')** + +Set the value of Merging. Input needs to be a string: either "row" or +"column". + +**template.get_table_name()** + +Get the value of Resulting table name. + +**template.set_table_name(value = '')** + +Set the value of Resulting table name. Input should be a string. + +**template.get_sources()** + +Get the values of the Select source rows/columns. The output is a list +where each element is a different source. Each element has the following +form: 'row_name|merge_operation' where merge_operation can have one of +the following values: + +- 'duplicate': corresponds to Allow Duplicates +- 'merge': corresponds to Combine Values +- 'rename_tag': corresponds to Rename Using Only Tag +- 'rename_nametag': corresponds to Rename With Name and Tag + +**template.set_sources(value=[])** + +Set the values of the Select source. The input needs to be a list where +each element is a different source, with the form explained in the +get_sources() method section. + +**template.add_sources(value=[])** + +Add some values to the Select source. The input needs to be a list where +each element is a different source, with the form explained in the +get_sources() method section. + +**template.get_rename_tag()** + +Get the value of the Tag to use when renaming field. Output will be a +string. + +**template.set_rename_tag(value='')** + +Set the value of the Tag to use when renaming field. Input should be a +string. + +**template.get_rename_tag()** + +Get the value of the Tag to use when renaming field. Output will be a +string. + +**template.set_rename_tag(value='')** + +Set the value of the Tag to use when renaming field. Input should be a +string. + +**template.get_use_labels()** + +Get the value of the toggle for Use row/column labels as row/column IDs. +Output is 0 for toggled OFF, 1 for toggled ON. + +**template.set_use_labels(value=1)** + +Set the value of the toggle for Use row/column labels as row/column IDs. +Input should be an integer: 0 for toggled OFF, 1 for toggled ON. + +**template.get_use_ids()** + +Get the value for the Row/Column to use as column/row IDs field. + +**template.set_use_ids(value='')** + +Set the value for the Row/Column to use as column/row IDs field. Input +should be a string. This method will not work if get_use_labels() +returns 1. + +**template.get_id_selection()** + +Get the value for the Row/Column ID selection. The possible outputs are: + +- 'all': corresponds to All IDs +- 'intersect': corresponds to Only Common IDs +- 'select': corresponds to Select Specific IDs + +**template.set_id_selection(value='all')** + +Set the value for the Row/Column ID selection. Input should be a string +among the ones listed in the get_id_selection() method. + +**template.get_ids()** + +Get the value for the Select column/row IDs values. If the Column/Row ID +selection is not set to Select Specific IDs, it will return an empty +list. Otherwise, it will return a list where each element is an ID. + +**template.set_ids(value=[])** + +Set the value for the Select column/row IDs values. If the Column/Row ID +selection is not set to Select Specific IDs, the method will bail out. +The input is a list, where each element is an ID as an integer. + +**template.add_ids(value=[])** + +Add IDs to the Select column/row IDs values. If the Column/Row ID +selection is not set to Select Specific IDs, the method will bail out. +The input is a list, where each element is an ID as an integer. + +**template.get_unknown_value()** + +Get the value for Unknown value. It returns a string. Default is 'nan'. + +**template.set_unknown_value(value='nan')** + +Set the value for the Unknown value. Input needs to be a string. + +**template.get_table_transpose()** + +Get the value for Transpose results. Output is an integer: 0 for OFF, 1 +for ON. + +**template.set_table_transpose(value=0)** + +Set the value for Transpose results. Input must be an integer: 0 for +OFF, 1 for ON. + +**template.get_numeric_output()** + +Get the value for Force numeric table output. Output is an integer: 0 +for OFF, 1 for ON. + +**template.set_numeric_output(value=0)** + +Set the value for Force numeric table output. Input must be an integer: +0 for OFF, 1 for ON. + +Example of usage. Let's assume you want to create a template like the +one shown in the picture (from the "Merged Table" template in the +documentation example in the Ansys Dynamic Reporting installer): + +.. figure:: lib/NewItem309.png + :alt: Image + :align: center + + +Let's also assume you want this template to be a child of the template +"Columns" in the database running locally on port 8000. These would be +the lines of code to create the new template: + +.. code-block:: python + + from ansys.dynamicreporting.core.utils import report_remote_server, report_objects + + server = report_remote_server.Server("http://localhost:8000", "nexus", "cei") + all_reports = server.get_objects(objtype=report_objects.TemplateREST) + my_parent = [x for x in all_reports if x.name == "Columns"][0] + my_template = server.create_template( + name="Merged Table", parent=my_parent, report_type="Generator:tablemerge" + ) + my_template.set_generated_items("replace") + my_template.set_table_name("Simple_test") + my_template.set_sources(["temperature|rename_nametag", "Distance|merge"]) + my_template.set_rename_tag("\_index\_") + my_template.set_use_labels(0) + my_template.set_use_ids("Distance") + server.put_objects(my_template) + server.put_objects(my_parent) + +.. _tablereduceREST: + +tablereduceREST object +^^^^^^^^^^^^^^^^^^^^^^ + +Inherits from TemplateREST, GeneratorREST + +Class that corresponds to the `Table Reduction`_ +Generator template type. Its specific methods +are: + +**template.get_reduce_param()** + +Get the value of Reduce. Possible outputs are: + +- 'row': corresponds to Rows +- 'column': corresponds to Columns + +**template.set_reduce_param(value='row')** + +Set the value of Reduce. Input needs to be a string: either "row" or +"column". + +**template.get_table_name()** + +Get the value of Resulting table name. + +**template.set_table_name(value = 'output_table')** + +Set the value of Resulting table name. Input should be a string. + +**template.get_operations()** + +Get the values for the Reduce operations as a list. Each element +corresponds to a different operation. Each element is a dictionary, +where the following keys are presented: + +- 'source_rows': corresponds to the name(s) of the rows/columns used in + the operation +- 'output_rows': corresponds to the Output row/column name +- 'output_rows_from_values': False (OFF) / True (ON) for the Use unique + values from a column/row as column/row names +- 'output_column_select': corresponds to the "Select columns/rows" + field +- 'output_columns': corresponds to the Column/Row name field +- 'output_columns_from_values': False (OFF) / True (ON) for the Use + unique values from a column/row as a new columns/rows toggle +- 'operation': corresponds to the Operation field. Possible values: + + - 'min': Minimum + - 'max': Maximum + - 'count': Count + - 'sum': Sum + - 'diff': Difference + - 'mean': Mean + - 'stdev': Standard deviation + - 'skew': Skew + - 'kurtosis': Kurtosis + +**template.delete_operation(name = [])** + +Method to remove an entire Reduce operation. Takes as input a list with +the name(s) of the source rows/columns used in the operation. So for +example to delete the third Reduce operation from the following panel: + +.. figure:: lib/NewItem293.png + :alt: Image + :align: center + + +use: + +.. code-block:: python + + template.delete_source(name=["temperature", "pressure"]) + + +To delete the first operation, use: + +.. code-block:: python + + template.delete_source(name=["temperature"]) + template.add_operation( + name=["\*"], + unique=False, + output_name="output row", + existing=True, + select_names="\*", + operation="count", + ) + + +Add a new Reduce operation. + +- 'name': corresponds to the name(s) of the rows/columns used in the + operation. Input needs to be a list of strings +- 'unique': corresponds to the Use unique values from a column as row + names toggle. False is OFF, True is ON +- output_name: corresponds to the Output row/column name. +- existing: corresponds to the Use existing columns/rows toggle. False + if OFF, True is ON. +- select_names. If existing is set to True, it is used for the Selected + columns/rows field. If existing is set to False, this field is used + for the Column/Row name. +- operation: corresponds to the operation field. See get_operation() + for the acceptable values. + +For example to create the operation in the following widget: + +.. figure:: lib/NewItem294.png + :alt: Image + :align: center + + +you would run: + +.. code-block:: python + + template.add_operation( + name=["temperature"], + unique=True, + output_name="MinTemp", + existing=False, + select_names="simulationA", + operation="min", + ) + template.get_table_transpose() + + +Get the value for Transpose results. Output is an integer: 0 for OFF, 1 +for ON. + +**template.set_table_transpose(value=0)** + +Set the value for Transpose results. Input must be an integer: 0 for +OFF, 1 for ON. + +**template.get_numeric_output()** + +Get the value for Force numeric table output. Output is an integer: 0 +for OFF, 1 for ON. + +**template.set_numeric_output(value=0)** + +Set the value for Force numeric table output. Input must be an integer: +0 for OFF, 1 for ON. + +Example of usage. Let's assume you want to create a template like the +one shown in the picture (from the "ASCII reduce" template in the +documentation example in the Ansys Dynamic Reporting installer): + +.. figure:: lib/NewItem310.png + :alt: Image + :align: center + + +Let's also assume you want this template to be a child of the template +"Merge reduce example" in the database running locally on port 8000. +These would be the lines of code to create the new template: + +.. code-block:: python + + from ansys.dynamicreporting.core.utils import report_remote_server, report_objects + + server = report_remote_server.Server("http://localhost:8000", "nexus", "cei") + all_reports = server.get_objects(objtype=report_objects.TemplateREST) + my_parent = [x for x in all_reports if x.name == "Merge reduce example"][0] + my_template = server.create_template( + name="ASCII reduce", parent=my_parent, report_type="Generator:tablereduce" + ) + my_template.set_generated_items("replace") + my_template.delete_operation(name=["\*"]) + my_template.add_operation( + name=["\*"], + unique=True, + output_name="User", + existing=False, + select_names="Version", + operation="count", + ) + my_template.add_operation( + name=["\*"], + unique=False, + output_name="Totals", + existing=False, + select_names="Version", + operation="count", + ) + server.put_objects(my_template) + server.put_objects(my_parent) + +.. _tablerowcolumnfilterREST: + +tablerowcolumnfilterREST object +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Inherits from TemplateREST, GeneratorREST + +Class that corresponds to the `Table Row/Column Filter`_ +Generator template type. Its specific +methods are: + +**template.get_table_name()** + +Get the value of New table name. + +**template.set_table_name(value = 'output_table')** + +Set the value of New table name. Input should be a string. + +**template.get_filter_rows()** + +Get the value of Rows... The values are returned as a list of strings, +where each element corresponds to a row value. + +**template.set_filter_rows(value=['\*'])** + +Set the value of Rows... The input value needs to be a list of strings, +where each element corresponds to a different row value. + +**template.add_filter_rows(value=['\*'])** + +Add new values to the value of Rows... The input value needs to be a +list of strings, where each element corresponds to a different row +value. + +**template.get_filter_columns()** + +Get the value of Columns... The values are returned as a list of +strings, where each element corresponds to a column value. + +**template.set_filter_columns(value=['\*'])** + +Set the value of Columns... The input value needs to be a list of +strings, where each element corresponds to a different column value. + +**template.add_filter_columns(value=['\*'])** + +Add new values to the value of Columns... The input value needs to be a +list of strings, where each element corresponds to a different column +value. + +**template.get_invert()** + +Get the value of Select the rows/columns to remove. Returns 0 or False +if it is toggled OFF, 1 or True if it is toggled ON + +**template.set_invert(value=False)** + +Set the value of Select the rows/columns to remove. Set it to 0 or False +to toggle OFF, set to 1 or True to toggle ON + +**template.get_sort()** + +Get the value of Sort rows/columns by selection order. Returns 0 or +False if it is toggled OFF, 1 or True if it is toggled ON + +**template.set_sort(value=False)** + +Set the value of Sort rows/columns by selection order. Set it to 0 or +False to toggle OFF, set to 1 or True to toggle ON. This method works +only if the Select the rows/columns to remove is toggled OFF. + +**template.get_table_transpose()** + +Get the value of Transpose the output table. Returns 0 or False if it is +toggled OFF, 1 or True if it is toggled ON + +**template.set_table_transpose(value=False)** + +Set the value of Transpose the output table. Set it to 0 or False to +toggle OFF, set to 1 or True to toggle ON + +Example of usage. Let's assume you want to create a template like the +one shown in the picture (from the "Filter" template in the +documentation example in the Ansys Dynamic Reporting installer): + +.. figure:: lib/NewItem311.png + :alt: Image + :align: center + + +Let's also assume you want this template to be a child of the template +"RC Filter Generator" in the database running locally on port 8000. +These would be the lines of code to create the new template: + +.. code-block:: python + + from ansys.dynamicreporting.core.utils import report_remote_server, report_objects + + server = report_remote_server.Server("http://localhost:8000", "nexus", "cei") + all_reports = server.get_objects(objtype=report_objects.TemplateREST) + my_parent = [x for x in all_reports if x.name == "RC Filter Generator"][0] + my_template = server.create_template( + name="Filter", parent=my_parent, report_type="Generator:tablerowcolumnfilter" + ) + my_template.set_filter_rows(["0", "fuselage", "\*wing\*"]) + my_template.set_filter_columns(["1", "Tria3", "Tetra\*"]) + my_template.set_table_name("RC_Filtered_Table") + server.put_objects(my_template) + server.put_objects(my_parent) + +.. _tablevaluefilterREST: + +tablevaluefilterREST object +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Inherits from TemplateREST, GeneratorREST + +Class that corresponds to the `Table Value Filter`_ +Generator template type. Its specific methods +are: + +**template.get_table_name()** + +Get the value of New table name. + +**template.set_table_name(value = 'value filtered table')** + +Set the value of New table name. Input should be a string. + +**template.get_filter_by()** + +Get the value of Filter by values in as a list. The first element is +'column' (default) or 'row'. The second element of the list of the +number of row/column set in the following field. + +**template.set_filter_by(value = ['column', '0'])** + +Set the value of Filter by values in as a list. The first element needs +to be 'column' or 'row'. The second element of the list of the number of +row/column set in the following field, and needs to be a string. + +**template.get_filter_value()** + +Get the value of Filter. Each different type of filter will return a +different type of output: + +- 'Range of values': it returns a list of three elements. The first + element is 'range'. The second and third are strings that represent + the min. and max. of the range. +- 'Specific values': it returns a list of two elements. The first + element is "specific". The second element is a list of strings. Each + element in this second list is one entry in the Select specific + values... field +- 'Upper % of values': it returns a list of two elements. The first + element is "top_percent". The second element is a float that + corresponds to the Upper percent of values field. +- 'Upper # of values': it returns a list of two elements. The first + element is "top_count". The second element is an integer that + corresponds to the Upper number of values field. +- 'Lower % of values': it returns a list of two elements. The first + element is "bot_percent". The second element is a float that + corresponds to the Lower percent of values field. +- 'Lower # of values': it returns a list of two elements. The first + element is "bot_count". The second element is an integer that + corresponds to the Lower number of values field. + +**template.set_filter_value(value=['range', '', ''])** + +Set the value of Filter. Each different type needs a different type of +input. See the description of get_filter_value() possible outputs to know the +details of the accepted formats. + +**template.get_invert_filter()** + +Get the value of Invert filter sense. Returns 0 or False if it is +toggled OFF, 1 or True if it is toggled ON + +**template.set_invert_filter(value=False)** + +Set the value of Invert filter sense. Set it to 0 or False to toggle +OFF, set to 1 or True to toggle ON + +**template.get_values_as_dates()** + +Get the value of Treat values as dates. Returns 0 or False if it is +toggled OFF, 1 or True if it is toggled ON + +**template.set_values_as_dates(value=False)** + +Set the value of Treat values as dates. Set it to 0 or False to toggle +OFF, set to 1 or True to toggle ON + +Example of usage. Let's assume you want to create a template like the +one shown in the picture (from the documentation example in the +Ansys Dynamic Reporting installer): + +.. figure:: lib/NewItem304.png + :alt: Image + :align: center + + +Let's also assume you want this template to be a child template of the +template "Value Filter Example" that already exists in in the database +running locally on port 800. These would be the lines of code to create +the new template: + +.. code-block:: python + + from ansys.dynamicreporting.core.utils import report_remote_server, report_objects + + server = report_remote_server.Server("http://localhost:8000", "nexus", "cei") + all_reports = server.get_objects(objtype=report_objects.TemplateREST) + my_parent = [x for x in all_reports if x.name == "Value Filter Example"][0] + my_template = server.create_template( + name="Generator", parent=my_parent, report_type="Generator:tablevaluefilter" + ) + my_template.set_sort_selection(value="first") + my_template.set_table_name("ValueFilteredTable") + my_template.set_filter_by(value=["row", "Quad4"]) + my_template.set_filter_value(value=["range", "100", ""]) + server.put_objects(my_template) + server.put_objects(my_parent) + +.. _tablesortfilterREST: + +tablesortfilterREST object +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Inherits from TemplateREST, GeneratorREST + +Class that corresponds to the `Table Row/Column Sort`_ +Generator template type. Its specific methods +are: + +**template.get_table_name()** + +Get the value of New table name. + +**template.set_table_name(value = 'value filtered table')** + +Set the value of New table name. Input should be a string. + +**template.get_sort_rows()** + +Get the Select columns to sort rows by. This returns a list where each +element is a filter. Each elements start with '+' or '-' to indicate the +direction of the sort, and the string of the row name to sort by. + +**template.set_sort_rows([])** + +Set the Select columns to sort rows by. This function takes a list as +input. The list is generated with '+' for increasing, '-' for +decreasing, followed by the row to sort by. Example: setting the sort +fields to be by increasing row "temperature" and decreasing by row +"pressure" becomes: ['+temperature', '-pressure'] + +**template.add_sort_rows([])** + +Add the Select columns to sort rows by. This function takes a list as +input. See set_sort_rows() for the description on how the list has to be +formatted. + +**template.get_sort_columns()** + +Get the Select rows to sort columns by. This returns a list where each +element is a filter. Each elements start with '+' or '-' to indicate the +direction of the sort, and the string of the column name to sort by. + +**template.set_sort_columns([])** + +Set the Select rows to sort columns by. This function takes a list as +input. See set_sort_rows() for the description on how the list has to be +formatted. + +**template.add_sort_columns([])** + +Add the Select rows to sort columns by. This function takes a list as +input. See set_sort_rows() for the description on how the list has to be +formatted. + +Example of usage. Let's assume you want to create a template like the +one shown in the picture (from the "Sorted" template in the +documentation example in the Ansys Dynamic Reporting installer): + +.. figure:: lib/NewItem312.png + :alt: Image + :align: center + + +.. figure:: lib/NewItem313.png + :alt: Image + :align: center + + +Let's also assume you want this template to be a child of the template +"RC Sort Filter Example" in the database running locally on port 8000. +These would be the lines of code to create the new template: + +.. code-block:: python + + from ansys.dynamicreporting.core.utils import report_remote_server, report_objects + + server = report_remote_server.Server("http://localhost:8000", "nexus", "cei") + all_reports = server.get_objects(objtype=report_objects.TemplateREST) + my_parent = [x for x in all_reports if x.name == "RC Sort Filter Example"][0] + my_template = server.create_template( + name="Sorted", parent=my_parent, report_type="Generator:tablesortfilter" + ) + my_template.set_sort_rows(["+User", "+Version", "+Date"]) + my_template.set_generated_items("replace") + my_template.set_sort_columns(["+Labels"]) + server.put_objects(my_template) + server.put_objects(my_parent) + +.. _sqlqueriesREST: + +sqlqueriesREST object +^^^^^^^^^^^^^^^^^^^^^ + +Inherits from TemplateREST, GeneratorREST + +Class that corresponds to the `SQL Query`_ Generator +template type. Its specific methods are: + +**template.get_db_type()** + +Get the Database type. Possible outputs are: SQLite / PostgreSQL + +**template.set_db_type(value='SQLite')** + +Set the Database type. Input needs to be a string. Only two acceptable +values: 'SQLite' or 'PostgreSQL' + +**template.get_sqlite_name()** + +Get the SQLite filename. + +**template.set_sqlite_name(value='')** + +Set the SQLite filename. Input needs to be a string. The method will not +work if the Database type is set to PostgreSQL + +**template.get_postgre()** + +Get the PostgreSQL parameters. This method returns a dictionary with +five entries, corresponding to: + +- Database name: +- Hostname: +- Port: +- Username: +- Password: + +**template.set_postgre(value = {'database'**: '', +'hostname':'localhost', 'port': '5432', 'username':'nexus', +'password':'cei'}\ **)** + +Set the the PostgreSQL parameters. Input needs to be a dictionary with +the keys: 'database', 'hostname', 'port', 'username', 'password'. Note +that all keys are strings. See get_postgre() method for the description +of each element. The method will not work if the Database type is set to +SQLite + +**template.get_query()** + +Get theSQL query text: field. + +**template.set_query(value='')** + +Set theSQL query text: field. Input needs to be a string. Note that no +check on the validity of the SQL query itself is performed. It is up to +the user to make sure the query is properly formatted. + +**template.validate()** + +Validate the database. This method should be run after all the +parameters for the database connection have been set. The method +returns: + +- Boolean parameter: True is the database can be validated, False + otherwise. +- Error message: If the connection is validated, this will be an empty + string. Otherwise, and error message with more details about the + failure will be returned. + +.. _mergetreeREST: + +mergetreeREST object +^^^^^^^^^^^^^^^^^^^^ + +Inherits from TemplateREST, GeneratorREST + +Class that corresponds to the `Tree Merge`_ Generator +template type. Its specific methods are: + +**template.get_merge_rule()** + +Get the row merging rule. + +**template.set_merge_rule(value='all')** + +Set the row merging rule. Legal values: 'all', 'common', 'first' + +**template.get_match_rule()** + +Get the rule for matching rows. + +**template.set_match_rule(value='both')** + +Set the rule for matching rows. Legal values: 'key', 'name', 'both' + +**template.get_tree_name()** + +Get the name that the generated tree will be given. + +**template.set_tree_name(value='treemerge')** + +Set the name that the generated tree will be given. Input needs to be a +string. + +**template.get_fill_value()** + +Get the value to be used to fill unknown cells. + +**template.set_fill_value(value='')** + +Set the value to be used to fill unknown cells. Input needs to be a +string. + +**template.get_header_tag()** + +Get the name of the tag (if any) to be used to generate an output tree +header. + +**template.set_header_tag(value='')** + +Set the name of the tag to be used to generate an output tree header. +Input needs to be a string. An empty string (the default) specifies that +no tree header be generated. diff --git a/doc/source/lowlevelapi/index.rst b/doc/source/lowlevelapi/index.rst new file mode 100755 index 000000000..61ae9a24a --- /dev/null +++ b/doc/source/lowlevelapi/index.rst @@ -0,0 +1,23 @@ +Low Level Python API +==================== + +.. _Nexus: https://nexusdemo.ensight.com/docs/html/Nexus.html + +.. toctree:: + :maxdepth: 4 + :hidden: + + GettingStarted + DataItemObject + TemplateObjects + ServerObject + DatasetandSessionObjects + +.. _lowlevel: + +The low level Python API for Ansys Dynamic Reporting +allows the user to have full control of all the features +of ADR and the Nexus server. It is a very powerful API, but +at the same time it can be quite complex and requires the end user +to fully understand how ADR works in all its components. For a +full description of ADR as a package, see `Nexus`_ diff --git a/doc/source/lowlevelapi/lib/NewItem293.png b/doc/source/lowlevelapi/lib/NewItem293.png new file mode 100755 index 000000000..0ee0ced00 Binary files /dev/null and b/doc/source/lowlevelapi/lib/NewItem293.png differ diff --git a/doc/source/lowlevelapi/lib/NewItem294.png b/doc/source/lowlevelapi/lib/NewItem294.png new file mode 100755 index 000000000..76c7cb90e Binary files /dev/null and b/doc/source/lowlevelapi/lib/NewItem294.png differ diff --git a/doc/source/lowlevelapi/lib/NewItem304.png b/doc/source/lowlevelapi/lib/NewItem304.png new file mode 100755 index 000000000..85ed434f7 Binary files /dev/null and b/doc/source/lowlevelapi/lib/NewItem304.png differ diff --git a/doc/source/lowlevelapi/lib/NewItem305.png b/doc/source/lowlevelapi/lib/NewItem305.png new file mode 100755 index 000000000..15a8710f0 Binary files /dev/null and b/doc/source/lowlevelapi/lib/NewItem305.png differ diff --git a/doc/source/lowlevelapi/lib/NewItem306.png b/doc/source/lowlevelapi/lib/NewItem306.png new file mode 100755 index 000000000..055205753 Binary files /dev/null and b/doc/source/lowlevelapi/lib/NewItem306.png differ diff --git a/doc/source/lowlevelapi/lib/NewItem307.png b/doc/source/lowlevelapi/lib/NewItem307.png new file mode 100755 index 000000000..7743df27b Binary files /dev/null and b/doc/source/lowlevelapi/lib/NewItem307.png differ diff --git a/doc/source/lowlevelapi/lib/NewItem308.png b/doc/source/lowlevelapi/lib/NewItem308.png new file mode 100755 index 000000000..d7480fbf1 Binary files /dev/null and b/doc/source/lowlevelapi/lib/NewItem308.png differ diff --git a/doc/source/lowlevelapi/lib/NewItem309.png b/doc/source/lowlevelapi/lib/NewItem309.png new file mode 100755 index 000000000..a007160cb Binary files /dev/null and b/doc/source/lowlevelapi/lib/NewItem309.png differ diff --git a/doc/source/lowlevelapi/lib/NewItem310.png b/doc/source/lowlevelapi/lib/NewItem310.png new file mode 100755 index 000000000..ffe8b7935 Binary files /dev/null and b/doc/source/lowlevelapi/lib/NewItem310.png differ diff --git a/doc/source/lowlevelapi/lib/NewItem311.png b/doc/source/lowlevelapi/lib/NewItem311.png new file mode 100755 index 000000000..f4ae21bbb Binary files /dev/null and b/doc/source/lowlevelapi/lib/NewItem311.png differ diff --git a/doc/source/lowlevelapi/lib/NewItem312.png b/doc/source/lowlevelapi/lib/NewItem312.png new file mode 100755 index 000000000..867d42518 Binary files /dev/null and b/doc/source/lowlevelapi/lib/NewItem312.png differ diff --git a/doc/source/lowlevelapi/lib/NewItem313.png b/doc/source/lowlevelapi/lib/NewItem313.png new file mode 100755 index 000000000..cc1e2103e Binary files /dev/null and b/doc/source/lowlevelapi/lib/NewItem313.png differ diff --git a/src/ansys/dynamicreporting/core/utils/report_objects.py b/src/ansys/dynamicreporting/core/utils/report_objects.py index 052282b11..cbbd3daee 100644 --- a/src/ansys/dynamicreporting/core/utils/report_objects.py +++ b/src/ansys/dynamicreporting/core/utils/report_objects.py @@ -1,8 +1,10 @@ import base64 import copy import datetime +import functools import io import json +import logging import os import os.path import pickle @@ -32,6 +34,23 @@ except ImportError: has_numpy = False + +logger = logging.getLogger(__name__) + + +def disable_warn_logging(func): + # Decorator to suppress harmless warning messages + @functools.wraps(func) + def wrapper(*args, **kwargs): + logging.disable(logging.WARNING) + try: + return func(*args, **kwargs) + finally: + logging.disable(logging.NOTSET) + + return wrapper + + """@package report_objects Basic object classes used for server operations """ @@ -2764,7 +2783,7 @@ def set_filter_by(self, value=None): self.params = json.dumps(d) return - def get_filter(self): + def get_filter_value(self): if "filter" in json.loads(self.params): if json.loads(self.params)["filter"] == "range": if "range_min" in json.loads(self.params): @@ -2804,7 +2823,21 @@ def get_filter(self): else: return ["bot_count", 10] - def set_filter(self, value=None): + def set_filter(self, value=None, filter_str=""): + if filter_str != "": + return super().set_filter(filter_str=filter_str) + elif value is not None: + logger.warning( + "WARNING: DEPRECATED METHOD. Use set_filter_value(value) instead. \ + The current method is to be used as set_filter(filter_str) to access \ + high level template filtering. See documentation.\n" + ) + return self.set_filter_value(value=value) + else: + logger.warning("WARNING: value should be passed as input.\n") + return None + + def set_filter_value(self, value=None): if value is None: value = ["range", "", ""] if type(value) is not list: diff --git a/tests/test_report_objects.py b/tests/test_report_objects.py index 1e1048bef..2710b5538 100755 --- a/tests/test_report_objects.py +++ b/tests/test_report_objects.py @@ -1250,6 +1250,16 @@ def test_tablerowcol_transp() -> bool: assert succ and succ_two and succ_three and succ_four +@pytest.mark.ado_test +def test_tablevaluefilter_deprecated() -> bool: + a = ro.tablevaluefilterREST() + a.set_filter(value=["specific", ["a", "b"]]) + succ = a.get_filter_value()[0] == "specific" + a.set_filter(filter_str="A|i_tags|cont|test;") + succ_two = "i_tags|cont|" in a.get_filter() + assert succ and succ_two + + @pytest.mark.ado_test def test_tablevaluefilter() -> bool: a = ro.tablevaluefilterREST() @@ -1293,110 +1303,110 @@ def test_tablevaluefilter() -> bool: @pytest.mark.ado_test def test_tablevaluefilter_filter() -> bool: a = ro.tablevaluefilterREST() - a.get_filter() - a.set_filter() + a.get_filter_value() + a.set_filter_value() succ = False try: - a.set_filter(value="a") + a.set_filter_value(value="a") except ValueError as e: succ = "input should be a list" in str(e) succ_two = False try: - a.set_filter(value=[]) + a.set_filter_value(value=[]) except ValueError as e: succ_two = "list input is too short" in str(e) succ_three = False try: - a.set_filter(value=["range", 1]) + a.set_filter_value(value=["range", 1]) except ValueError as e: succ_three = "input should contain 3 elements" in str(e) succ_four = False try: - a.set_filter(value=["range", 1, 2]) + a.set_filter_value(value=["range", 1, 2]) except ValueError as e: succ_four = "all input elements should be strings" in str(e) - a.set_filter(value=["range", "a", "b"]) - succ_five = a.get_filter()[0] == "range" + a.set_filter_value(value=["range", "a", "b"]) + succ_five = a.get_filter_value()[0] == "range" succ_six = False try: - a.set_filter(value=["specific", "a", "b"]) + a.set_filter_value(value=["specific", "a", "b"]) except ValueError as e: succ_six = "input should contain 2 elements" in str(e) succ_seven = False try: - a.set_filter(value=["specific", "a"]) + a.set_filter_value(value=["specific", "a"]) except ValueError as e: succ_seven = "second input should be a list" in str(e) succ_eight = False try: - a.set_filter(value=["specific", [1, 2]]) + a.set_filter_value(value=["specific", [1, 2]]) except ValueError as e: succ_eight = "specific value(s) should be string" in str(e) - a.set_filter(value=["specific", ["a", "b"]]) - succ_nine = a.get_filter()[0] == "specific" + a.set_filter_value(value=["specific", ["a", "b"]]) + succ_nine = a.get_filter_value()[0] == "specific" succ_ten = False try: - a.set_filter(value=["top_percentage", "a", "b"]) + a.set_filter_value(value=["top_percentage", "a", "b"]) except ValueError as e: succ_ten = "first input is not among the acceptable values" in str(e) succ_eleven = False try: - a.set_filter(value=["top_percent", "a", "b"]) + a.set_filter_value(value=["top_percent", "a", "b"]) except ValueError as e: succ_eleven = "input should contain 2 elements" in str(e) succ_twelve = False try: - a.set_filter(value=["top_percent", "a"]) + a.set_filter_value(value=["top_percent", "a"]) except ValueError as e: succ_twelve = "second input should be a float" in str(e) succ_thirteen = False try: - a.set_filter(value=["top_percent", 110]) + a.set_filter_value(value=["top_percent", 110]) except ValueError as e: succ_thirteen = "percentage should be in the (0,100) range" in str(e) - a.set_filter(value=["top_percent", 10]) - succ_fourteen = a.get_filter()[0] == "top_percent" + a.set_filter_value(value=["top_percent", 10]) + succ_fourteen = a.get_filter_value()[0] == "top_percent" succ_fifteen = False try: - a.set_filter(value=["top_count", 10, 10]) + a.set_filter_value(value=["top_count", 10, 10]) except ValueError as e: succ_fifteen = "input should contain 2 elements" in str(e) succ_sixteen = False try: - a.set_filter(value=["top_count", "a"]) + a.set_filter_value(value=["top_count", "a"]) except ValueError as e: succ_sixteen = "second input should be an int" in str(e) - a.set_filter(value=["top_count", 3]) - succ_seventeen = a.get_filter()[0] == "top_count" + a.set_filter_value(value=["top_count", 3]) + succ_seventeen = a.get_filter_value()[0] == "top_count" succ_eighteen = False try: - a.set_filter(value=["bot_percent", 3, 3]) + a.set_filter_value(value=["bot_percent", 3, 3]) except ValueError as e: succ_eighteen = "input should contain 2 elements" in str(e) succ_nineteen = False try: - a.set_filter(value=["bot_percent", "a"]) + a.set_filter_value(value=["bot_percent", "a"]) except ValueError as e: succ_nineteen = "the second input should be a float" in str(e) succ_twenty = False try: - a.set_filter(value=["bot_percent", 110]) + a.set_filter_value(value=["bot_percent", 110]) except ValueError as e: succ_twenty = "percentage should be in the (0,100) range" in str(e) - a.set_filter(value=["bot_percent", 10]) - succ_twentyone = a.get_filter()[0] == "bot_percent" + a.set_filter_value(value=["bot_percent", 10]) + succ_twentyone = a.get_filter_value()[0] == "bot_percent" succ_twentytwo = False try: - a.set_filter(value=["bot_count", 1, 1]) + a.set_filter_value(value=["bot_count", 1, 1]) except ValueError as e: succ_twentytwo = "input should contain 2 elements" in str(e) succ_twentythree = False try: - a.set_filter(value=["bot_count", "a"]) + a.set_filter_value(value=["bot_count", "a"]) except ValueError as e: succ_twentythree = "second input should be an int" in str(e) - a.set_filter(value=["bot_count", 3]) - succ_twentyfour = a.get_filter()[0] == "bot_count" + a.set_filter_value(value=["bot_count", 3]) + succ_twentyfour = a.get_filter_value()[0] == "bot_count" succ_a = succ + succ_two + succ_three + succ_four + succ_five + succ_six succ_b = succ_seven + succ_eight + succ_nine + succ_ten + succ_eleven succ_c = succ_twelve + succ_thirteen + succ_fourteen + succ_fifteen @@ -1410,17 +1420,17 @@ def test_tablevaluefilter_filter() -> bool: def test_tablevaluefilter_filterparams() -> bool: a = ro.tablevaluefilterREST() a.params = '{"filter": "specific"}' - succ_one = a.get_filter() == ["specific", ["*"]] + succ_one = a.get_filter_value() == ["specific", ["*"]] a.params = '{"filter": "range"}' - succ_two = a.get_filter() == ["range", "", ""] + succ_two = a.get_filter_value() == ["range", "", ""] a.params = '{"filter": "top_percent"}' - succ_three = a.get_filter() == ["top_percent", 10.0] + succ_three = a.get_filter_value() == ["top_percent", 10.0] a.params = '{"filter": "top_count"}' - succ_four = a.get_filter() == ["top_count", 10] + succ_four = a.get_filter_value() == ["top_count", 10] a.params = '{"filter": "bot_percent"}' - succ_five = a.get_filter() == ["bot_percent", 10.0] + succ_five = a.get_filter_value() == ["bot_percent", 10.0] a.params = '{"filter": "bot_count"}' - succ_six = a.get_filter() == ["bot_count", 10] + succ_six = a.get_filter_value() == ["bot_count", 10] assert succ_one and succ_two and succ_three and succ_four and succ_five and succ_six