diff --git a/.buildinfo b/.buildinfo new file mode 100644 index 0000000..9c2a649 --- /dev/null +++ b/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: 6bf4ba22a979f3ac24eaa0aaaba8f590 +tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/LICENSE.html b/LICENSE.html new file mode 100644 index 0000000..f24578c --- /dev/null +++ b/LICENSE.html @@ -0,0 +1,121 @@ + + + + + + + + MIT License — Nasdaq Protocols Python Library 0.0.1 documentation + + + + + + + + + + + +
+
+
+ +
+
+
+ +
+

MIT License

+

Copyright (c) 2024 Nasdaq

+

Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the “Software”), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions:

+

The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software.

+

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.

+
+ + +
+
+
+
+
+ +
+
+
+ + + + + \ No newline at end of file diff --git a/_sources/LICENSE.rst.txt b/_sources/LICENSE.rst.txt new file mode 100644 index 0000000..4626aff --- /dev/null +++ b/_sources/LICENSE.rst.txt @@ -0,0 +1,22 @@ +MIT License +=========== + +Copyright (c) 2024 Nasdaq + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/_sources/api_reference.rst.txt b/_sources/api_reference.rst.txt new file mode 100644 index 0000000..4976463 --- /dev/null +++ b/_sources/api_reference.rst.txt @@ -0,0 +1,11 @@ +API Reference +============= + +.. toctree:: + :maxdepth: 1 + :caption: Contents: + + api_reference_soup + api_reference_itch + api_reference_ouch + api_reference_common \ No newline at end of file diff --git a/_sources/api_reference_common.rst.txt b/_sources/api_reference_common.rst.txt new file mode 100644 index 0000000..8d03e80 --- /dev/null +++ b/_sources/api_reference_common.rst.txt @@ -0,0 +1,12 @@ +Common api reference +==================== + +.. automodule:: nasdaq_protocols.common.message_queue + +.. automodule:: nasdaq_protocols.common.session + +.. automodule:: nasdaq_protocols.common.types + +.. automodule:: nasdaq_protocols.common.utils + +.. automodule:: nasdaq_protocols.common.message.types \ No newline at end of file diff --git a/_sources/api_reference_itch.rst.txt b/_sources/api_reference_itch.rst.txt new file mode 100644 index 0000000..771f8a0 --- /dev/null +++ b/_sources/api_reference_itch.rst.txt @@ -0,0 +1,22 @@ +.. _api-reference-itch: +ITCH API Reference +================== + +Itch +---- +.. automodule:: nasdaq_protocols.itch + + +Itch Session +^^^^^^^^^^^^ +.. autoclass:: nasdaq_protocols.itch.session.ItchSessionId + :show-inheritance: True + +.. autoclass:: nasdaq_protocols.itch.session.ClientSession + :show-inheritance: True + :undoc-members: ['send_heartbeat'] + + +Itch Messages +^^^^^^^^^^^^^ +.. automodule:: nasdaq_protocols.itch.core \ No newline at end of file diff --git a/_sources/api_reference_ouch.rst.txt b/_sources/api_reference_ouch.rst.txt new file mode 100644 index 0000000..c621bf9 --- /dev/null +++ b/_sources/api_reference_ouch.rst.txt @@ -0,0 +1,22 @@ +.. _api-reference-ouch: +OUCH API Reference +================== + +Ouch +---- +.. automodule:: nasdaq_protocols.ouch + + +Ouch Session +^^^^^^^^^^^^ +.. autoclass:: nasdaq_protocols.ouch.session.OuchSessionId + :show-inheritance: True + +.. autoclass:: nasdaq_protocols.ouch.session.ClientSession + :show-inheritance: True + :undoc-members: ['send_heartbeat'] + + +Ouch Messages +^^^^^^^^^^^^^ +.. automodule:: nasdaq_protocols.ouch.core \ No newline at end of file diff --git a/_sources/api_reference_soup.rst.txt b/_sources/api_reference_soup.rst.txt new file mode 100644 index 0000000..6dc367a --- /dev/null +++ b/_sources/api_reference_soup.rst.txt @@ -0,0 +1,25 @@ +.. _api-reference-soup: +SOUP API Reference +================== + +Soup +---- +.. automodule:: nasdaq_protocols.soup + + +Soup Session +^^^^^^^^^^^^ +.. autoclass:: nasdaq_protocols.soup.session.SoupSessionId + :show-inheritance: True + +.. autoclass:: nasdaq_protocols.soup.session.SoupClientSession + :show-inheritance: True + :undoc-members: ['send_heartbeat'] + +.. autoclass:: nasdaq_protocols.soup.session.SoupServerSession + :show-inheritance: True + + +Soup Messages +^^^^^^^^^^^^^ +.. automodule:: nasdaq_protocols.soup.core \ No newline at end of file diff --git a/_sources/developer_guide.rst.txt b/_sources/developer_guide.rst.txt new file mode 100644 index 0000000..7734519 --- /dev/null +++ b/_sources/developer_guide.rst.txt @@ -0,0 +1,39 @@ +Developer's Guide +================= + +This guide is intended for developers who want to contribute to the +development of the `nasdaq-protocols` library. + + +Guidelines +---------- +Before merging to main, please ensure that the following guidelines are met: + +- All existing tests are passing. +- New tests are added when needed. +- Pylint reports no errors, 10/10 +- Code is documented and docstrings are added when needed. +- Documentation is included in the rst files. + + +Building +________ +.. code-block:: console + + $ tox r + +`tox r` will execute all of the following. + +- `tox -e lint` - Runs linter and validates the code +- `tox -e test` - Runs the pytest test cases +- `tox -e build` - Builds the package sdist and wheel +- `tox -e doc` - Builds the documentation + + +FAQ +___ +- **Why is pycharm debugger not stopping at breakpoints?** + Disable the coverage statement from pytest.ini. Refer https://stackoverflow.com/a/56235965/4248850 + +- **Why is the coverage not reported in pycharm?** + Disable the coverage statement from pytest.ini \ No newline at end of file diff --git a/_sources/index.rst.txt b/_sources/index.rst.txt new file mode 100644 index 0000000..421e199 --- /dev/null +++ b/_sources/index.rst.txt @@ -0,0 +1,39 @@ +.. nasdaq-protocols documentation master file, created by + sphinx-quickstart on Thu Jan 4 23:40:15 2024. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to nasdaq-protocols's documentation! +============================================ + +.. automodule:: nasdaq_protocols + +nasdaq-protocols contains client side implementations of the various +publicly available protocols used by Nasdaq ecosystem. + +This package contains only the core implementations of the protocols like message +serialization, deserialization, message validation and session handling. It does not +contain any actual messages that are exchanged between the client and the server. + +The actual messages are application specific and hence has to be defined by the +user of this library. The user has to define the messages as per the protocol specification +by extending the base message class defined in the package. + +Refer to the :ref:`user-guide`. for more information on how to define the messages and use this package. + +.. toctree:: + :maxdepth: 1 + :caption: Contents: + + user_guide + api_reference + developer_guide + LICENSE + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/_sources/install.rst.txt b/_sources/install.rst.txt new file mode 100644 index 0000000..3510a7f --- /dev/null +++ b/_sources/install.rst.txt @@ -0,0 +1,10 @@ +.. _install-guide: + +Installation +============ + +To use nasdaq-protocols, install it using pip: + +.. code-block:: console + + $ pip install nasdaq-protocols \ No newline at end of file diff --git a/_sources/user_guide.rst.txt b/_sources/user_guide.rst.txt new file mode 100644 index 0000000..ce5e354 --- /dev/null +++ b/_sources/user_guide.rst.txt @@ -0,0 +1,14 @@ +.. _user-guide: + +User Guide +========== + +.. toctree:: + :maxdepth: 1 + :caption: User Guides: + + install + user_guide_soup + user_guide_ouch + user_guide_itch + user_guide_create_new_project \ No newline at end of file diff --git a/_sources/user_guide_create_new_project.rst.txt b/_sources/user_guide_create_new_project.rst.txt new file mode 100644 index 0000000..5b3527e --- /dev/null +++ b/_sources/user_guide_create_new_project.rst.txt @@ -0,0 +1,78 @@ +.. _user-guide-create-new-project: + +Create New Project Guide +======================== + +This guide will walk you through creating a new python package that contains the message definitions +of the applications you want to use with the nasdaq-protocols. + +.. note:: + + This guide assumes you have already installed the nasdaq-protocols package. If you have not, please + refer to the :ref:`installation guide `. + + +Steps +----- + +1. Install `tox` if you have not already done so. + + .. code-block:: bash + + bash$ pip install tox + +Refer to the `tox documentation `_ for detailed information. + +2. Create a new python package structure using the `nasdaq-protocols-create-new-project` command line tool. + + .. code-block:: bash + + bash$ nasdaq-protocols-create-new-project --name \ + --application app:proto [--target-dir ] + + Replace `` with the name of your project and `` with the directory where you want to + create the project. + + For example, to create a project named `nasdaq-protocols-messages` in the current directory, with 2 applications `ouch_oe` + and `itch_feed`, you would run the following command: + + .. code-block:: bash + + bash$ nasdaq-protocols-create-new-project --name nasdaq-protocols-messages \ + --application ouch_oe:ouch \ + --application itch_feed:itch + +3. The `nasdaq-protocols-create-new-project` command will create a new python package with the following structure: + + For the above example, the following directory structure will be created. + + .. code-block:: bash + + nasdaq-protocols-messages/ + ├── src/ + | ├── nasdaq_protocols_messages/ + | │ ├── __init__.py + | │ ├── ouch_oe/ + | │ │ └── ouch_oe.xml + | │ └── itch_feed/ + | │ └── itch_feed.xml + ├── pyproject.toml + └── tox.ini + + .. note:: + - **ouch_oe.xml** is the file where you define all the messages for the `ouch_oe` application. + - **itch_feed.xml** is the file where you define all the messages for the `itch_feed` application. + + The XML file contains the format and guidelines on how to define the messages. + +4. Edit the XML files to define the messages for the applications you want to use with the nasdaq-protocols. + +5. Build the package + + .. code-block:: bash + + bash$ cd target-dir/nasdaq-protocols-messages + bash$ tox r + +6. The package will be built and stored in the `dist` directory. This can be uploaded to your PyPI repository or + installed locally. \ No newline at end of file diff --git a/_sources/user_guide_itch.rst.txt b/_sources/user_guide_itch.rst.txt new file mode 100644 index 0000000..246fdb1 --- /dev/null +++ b/_sources/user_guide_itch.rst.txt @@ -0,0 +1,125 @@ +.. _user-guide-itch: + +ITCH User Guide +=============== + +The `nasdaq_protocols.itch` module provides an API to interact with ITCH servers. +Refer :ref:`api-reference-itch`. for more information on the API. + +This package **only** provides the core implementation of the ITCH protocols, like message serialization +deserialization, session handling, etc. It **does not** define any actual ITCH messages. The actual ITCH +messages has to be defined by the user of this package. The first step is to create a new python package +which contains the messages definitions for all the protocols that the user wants to use. + +This package provides a command line utility `nasdaq-protocols-create-new-project` to create a new python package +and all the necessary files. + +Follow the steps in :ref:`user-guide-create-new-project` to create a new python package for application specific +messages. + + +.. note:: + + This rest of the guide assumes that you have built a new python project using the steps mentioned in + :ref:`user-guide-create-new-project`. + + +The generated project will contain a file `itch_.py` which will contain the following + - ITCH message definitions + - ITCH Client Session for this application + +Using the generated code, you can connect to a ITCH server and start receiving messages. + + +The `nasdaq_protocols.itch` module provides an API to interact with ITCH servers. +Refer :ref:`api-reference-itch`. for more information on the API. + + +Connecting to a ITCH Server +--------------------------- +Use the example below to implement a program that will tail itch messages from the server. + +.. code-block:: python + + #!/usr/bin/env python + import asyncio + # from the generated package we import the application we want to use + from nasdaq_protocols_messages import itch_feed + + + stopped = asyncio.Event() + port = 1234 # give the proper itch server port + + + async def itch_output(itch_message): + """ + This function will be called whenever a new ITCH message is received + """ + print('') + print(f'received: {itch_message}') + print('') + + + async def itch_close(): + """ + This function will be called when the ITCH session is closed + """ + stopped.set() + print('') + print('itch session closed, Bye Bye') + print('') + + + async def main(): + # Step1: connect + itch_session = await itch_feed.connect_async( + ('hostname', port), + 'itch username', # itch username, max 6 characters + 'pwdchange', # itch password, max 10 characters + '', # session id + on_msg_coro=itch_output, # function to call when a new message is received + on_close_coro=itch_close, # function to call when the session is closed + sequence=1 # 0 to listen from HEAD, 1 to listen from start, n to listen from n + ) + + print("wait for server to close the session") + await stopped.wait() + + + if __name__ == '__main__': + asyncio.run(main()) + +*A simple itch tail program* + +Slightly modified version where we do not use dispatchers instead explicitly call `receive_message()` method. + +.. code-block:: python + + #!/usr/bin/env python + import asyncio + from nasdaq_protocols_messages import itch_feed + + + port = 1234 # give the proper itch server port + + + async def main(): + # Step1: connect + itch_session = await itch_feed.connect_async( + ('hostname', port), + 'itch username', # itch username, max 6 characters + 'pwdchange', # itch password, max 10 characters + '', # session id + sequence=1 # 0 to listen from HEAD, 1 to listen from start, n to listen from n + ) + + # receive the first message from the server. + itch_message = await itch_session.receive_message() + print(itch_message) + + print("Closing the itch session...") + await itch_session.close() + + + if __name__ == '__main__': + asyncio.run(main()) diff --git a/_sources/user_guide_ouch.rst.txt b/_sources/user_guide_ouch.rst.txt new file mode 100644 index 0000000..9f3f8d9 --- /dev/null +++ b/_sources/user_guide_ouch.rst.txt @@ -0,0 +1,121 @@ +.. _user-guide-ouch: + +OUCH User Guide +=============== + +The `nasdaq_protocols.ouch` module provides an API to interact with OUCH servers. +Refer :ref:`api-reference-ouch`. for more information on the API. + +This package **only** provides the core implementation of the OUCH protocols, like message serialization +deserialization, session handling, etc. It **does not** define any actual OUCH messages. The actual OUCH +messages has to be defined by the user of this package. The first step is to create a new python package +which contains the messages definitions for all the protocols that the user wants to use. + +This package provides a command line utility `nasdaq-protocols-create-new-project` to create a new python package +and all the necessary files. + +Follow the steps in :ref:`user-guide-create-new-project` to create a new python package for application specific +messages. + + +.. note:: + + This rest of the guide assumes that you have built a new python project using the steps mentioned in + :ref:`user-guide-create-new-project`. + + +The generated project will contain a file `ouch_.py` which will contain the following + - OUCH message definitions + - OUCH Client Session for this application + +Using the generated code, you can connect to a OUCH server and start sending/receiving messages. + + +The `nasdaq_protocols.ouch` module provides an API to interact with OUCH servers. +Refer :ref:`api-reference-ouch`. for more information on the API. + + +Sending Message to a OUCH Server +-------------------------------- + +Sample Message Definition +^^^^^^^^^^^^^^^^^^^^^^^^^ +For our test ouch app, lets define our OUCH messages in the file `.xml` as follows, + +.. code-block:: XML + + + + + + + + + + + + + + + + + + + + + + + + + +Sending and Receiving OUCH messages +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +With the above message definition, we can now send the ouch message as follows. + +.. code-block:: python + + #!/usr/bin/env python + import asyncio + # from the generated package we import the application we want to use + from nasdaq_protocols_messages import ouch_oe + + + port = 1234 # give the proper ouch server port + + + async def main(): + # Step1: connect + ouch_session = await ouch_oe.connect_async( + ('hostname', port), + 'ouch username', # ouch username, max 6 characters + 'pwdchange', # ouch password, max 10 characters + '', # session id + sequence=0 # 0 to listen from HEAD, 1 to listen from start, n to listen from n + ) + + # Step2: Prepare a message + enter_order = ouch_oe.EnterOrder() # This is the message we defined in the xml file + enter_order.orderBookId = 1 + enter_order.side = 'B' + enter_order.quantity = 100 + enter_order.price = 20 + + # Step3: Send the message to the server. + ouch_session.send_message(enter_order) + + # Step4: receive the first message from the server. + output = await ouch_session.receive_message() + if isinstance(output, ouch_oe.Accepted): + print("Order accepted") + elif isinstance(output, ouch_oe.Rejected): + print("Order rejected") + + # Step5: Close the session + print("Closing the ouch session...") + await ouch_session.close() + + + if __name__ == '__main__': + asyncio.run(main()) + +*A simple ouch send and receive program* diff --git a/_sources/user_guide_soup.rst.txt b/_sources/user_guide_soup.rst.txt new file mode 100644 index 0000000..e2e5a5b --- /dev/null +++ b/_sources/user_guide_soup.rst.txt @@ -0,0 +1,91 @@ +.. _user-guide-soup: + +SOUP User Guide +=============== + +SoupBinTCP 4.00 is a lightweight point-to-point protocol, built on top of TCP/IP +sockets that allow delivery of a set of sequenced and unsequenced messages from a +server to a client in real-time. SoupBinTCP guarantees that the client receives each +sequenced message generated by the server in the correct order, even across +underlying TCP/IP socket connection failures. + +Refer to the `Official SOUP Documentation `_ for more information +on how SOUP protocol works. + +The `nasdaq_protocols.soup` module provides an API to interact with SOUP servers and clients. +Refer :ref:`api-reference-soup`. for more information on the API. + + +Connect to Soup Server +---------------------- +Example of connecting to a Soup server and receiving messages. + +.. code-block:: python + + #!/usr/bin/env python3 + import asyncio + from nasdaq_protocols import soup + + + stopped = asyncio.Event() + + + async def on_msg(msg): + print(msg) + + + async def on_close(): + stopped.set() + print('closed') + + + async def main(): + port = 1234 # Give the actual port number + session = await soup.connect_async( + ('hostname or ip', port), + 'username', # Soup username, max 6 characters (as per spec) + 'password', # Soup password, max 10 characters (as per spec) + sequence=1, # 0 to listen from HEAD, 1 to listen from start, n to listen from n + on_msg_coro=on_msg, # callback for receiving messages + on_close_coro=on_close # callback for indicating server closed the connection + ) + + # To send a message to the server + # session.send_unseq_data(b'some bytes') + + await stopped.wait() + + + if __name__ == '__main__': + asyncio.run(main()) + +*A simple soup tail program* + + +A slightly modified version of the same example but not using dispatchers for `on_msg` and `on_close` callbacks. + + +.. code-block:: python + + #!/usr/bin/env python3 + import asyncio + from nasdaq_protocols import soup + + + async def main(): + port = 1234 # Give the actual port number + session = await soup.connect_async( + ('hostname or ip', port), 'username', 'password', + sequence=1 + ) + print(await session.receive_msg()) + await session.close() + + # To send a message to the server + # session.send_unseq_data(b'some bytes') + + + if __name__ == '__main__': + asyncio.run(main()) + +*A simple soup tail program without dispatchers* \ No newline at end of file diff --git a/_static/agogo.css b/_static/agogo.css new file mode 100644 index 0000000..cba0199 --- /dev/null +++ b/_static/agogo.css @@ -0,0 +1,555 @@ +/* + * agogo.css_t + * ~~~~~~~~~~~ + * + * Sphinx stylesheet -- agogo theme. + * + * :copyright: Copyright 2007-2024 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +* { + margin: 0px; + padding: 0px; +} + +body { + font-family: "Verdana", Arial, sans-serif; + line-height: 1.4em; + color: black; + background-color: #eeeeec; + + /* fix for background colors breaking at horizontal + scrolling on smaller devices */ + min-width: fit-content; +} + + +/* Page layout */ + +div.header, div.content, div.footer { + width: 70em; + margin-left: auto; + margin-right: auto; +} + +div.header-wrapper { + background: #555573 url(bgtop.png) top left repeat-x; + border-bottom: 3px solid #2e3436; +} + + +/* Default body styles */ +a { + color: #ce5c00; +} + +a:visited { + color: #551a8b; +} + +div.bodywrapper a, div.footer a { + text-decoration: underline; +} + +.clearer { + clear: both; +} + +.left { + float: left; +} + +.right { + float: right; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +h1, h2, h3, h4 { + font-family: "Georgia", "Times New Roman", serif; + font-weight: normal; + color: #3465a4; + margin-bottom: .8em; +} + +h1 { + color: #204a87; +} + +h2 { + padding-bottom: .5em; + border-bottom: 1px solid #3465a4; +} + +a.headerlink { + visibility: hidden; + color: #dddddd; + padding-left: .3em; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +img { + border: 0; +} + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 2px 7px 1px 7px; + border-left: 0.2em solid black; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +dt:target, .highlighted { + background-color: #fbe54e; +} + +/* Header */ + +div.header { + padding: 1em; +} + +div.header .headertitle { + font-family: "Georgia", "Times New Roman", serif; + font-weight: normal; + font-size: 180%; + letter-spacing: .08em; + margin-bottom: .8em; +} + +div.header .headertitle a { + color: white; +} + +div.header div.rel { + margin-top: 1em; +} + +div.header div.rel a { + color: #fcaf3e; + letter-spacing: .1em; + text-transform: uppercase; +} + +p.logo { + float: right; +} + +img.logo { + border: 0; +} + + +/* Content */ +div.content-wrapper { + background-color: white; + padding: 1em; +} + +div.document { + width: 50em; + float: left; +} + +div.body { + padding-right: 2em; + text-align: justify; +} + +div.document h1 { + line-height: 120%; +} + +div.document ul { + margin: 1.5em; + list-style-type: square; +} + +div.document dd { + margin-left: 1.2em; + margin-top: .4em; + margin-bottom: 1em; +} + +div.document .section { + margin-top: 1.7em; +} +div.document .section:first-child { + margin-top: 0px; +} + +div.document div.highlight { + padding: 3px; + border-top: 2px solid #dddddd; + border-bottom: 2px solid #dddddd; + margin-top: .8em; + margin-bottom: .8em; +} + +div.document div.literal-block-wrapper { + margin-top: .8em; + margin-bottom: .8em; +} + +div.document div.literal-block-wrapper div.highlight { + margin: 0; +} + +div.document div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.document div.code-block-caption span.caption-text { +} + +div.document h2 { + margin-top: .7em; +} + +div.document p { + margin-bottom: .5em; +} + +div.document li.toctree-l1 { + margin-bottom: 1em; +} + +div.document .descname { + font-weight: bold; +} + +div.document .sig-paren { + font-size: larger; +} + +div.document .docutils.literal { + background-color: #eeeeec; + padding: 1px; +} + +div.document .docutils.xref.literal { + background-color: transparent; + padding: 0px; +} + +div.document blockquote { + margin: 1em; +} + +div.document ol { + margin: 1.5em; +} + + +/* Sidebar */ + +div.sidebar, +aside.sidebar { + width: 20em; + float: right; + font-size: .9em; +} + +div.sidebar a, aside.sidebar a, div.header a { + text-decoration: none; +} + +div.sidebar a:hover, aside.sidebar a:hover, div.header a:hover { + text-decoration: underline; +} + +div.sidebar h3, +aside.sidebar h3 { + color: #2e3436; + text-transform: uppercase; + font-size: 130%; + letter-spacing: .1em; +} + +div.sidebar ul, +aside.sidebar ul { + list-style-type: none; +} + +div.sidebar li.toctree-l1 a, +aside.sidebar li.toctree-l1 a { + display: block; + padding: 1px; + border: 1px solid #dddddd; + background-color: #eeeeec; + margin-bottom: .4em; + padding-left: 3px; + color: #2e3436; +} + +div.sidebar li.toctree-l2 a, +aside.sidebar li.toctree-l2 a { + background-color: transparent; + border: none; + margin-left: 1em; + border-bottom: 1px solid #dddddd; +} + +div.sidebar li.toctree-l3 a, +aside.sidebar li.toctree-l3 a { + background-color: transparent; + border: none; + margin-left: 2em; + border-bottom: 1px solid #dddddd; +} + +div.sidebar li.toctree-l2:last-child a, +aside.sidebar li.toctree-l2:last-child a { + border-bottom: none; +} + +div.sidebar li.toctree-l1.current a, +aside.sidebar li.toctree-l1.current a { + border-right: 5px solid #fcaf3e; +} + +div.sidebar li.toctree-l1.current li.toctree-l2 a, +aside.sidebar li.toctree-l1.current li.toctree-l2 a { + border-right: none; +} + +div.sidebar input[type="text"], +aside.sidebar input[type="text"] { + width: 170px; +} + +div.sidebar input[type="submit"], +aside.sidebar input[type="submit"] { + width: 30px; +} + + +/* Footer */ + +div.footer-wrapper { + background: url(bgfooter.png) top left repeat-x; + border-top: 4px solid #babdb6; + padding-top: 10px; + padding-bottom: 10px; + min-height: 80px; +} + +div.footer, div.footer a { + color: #888a85; +} + +div.footer .right { + text-align: right; +} + +div.footer .left { + text-transform: uppercase; +} + + +/* Styles copied from basic theme */ + +img.align-left, figure.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, figure.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, figure.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +img.align-default, figure.align-default, .figure.align-default { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-right { + text-align: right; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +div.figure p.caption span.caption-number, +figcaption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text, +figcaption span.caption-text { +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li div.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- viewcode extension ---------------------------------------------------- */ + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family:: "Verdana", Arial, sans-serif; +} + +div.viewcode-block:target { + margin: -1px -3px; + padding: 0 3px; + background-color: #f4debf; + border-top: 1px solid #ac9; + border-bottom: 1px solid #ac9; +} + +div.code-block-caption { + background-color: #ddd; + color: #333; + padding: 2px 5px; + font-size: small; +} + +/* -- math display ---------------------------------------------------------- */ + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} \ No newline at end of file diff --git a/_static/basic.css b/_static/basic.css new file mode 100644 index 0000000..945cab3 --- /dev/null +++ b/_static/basic.css @@ -0,0 +1,925 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2024 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +div.section::after { + display: block; + content: ''; + clear: left; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 20em; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox form.search { + overflow: hidden; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li p.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 360px; + max-width: 800px; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +a:visited { + color: #551A8B; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, figure.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, figure.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, figure.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +img.align-default, figure.align-default, .figure.align-default { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-default { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar, +aside.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px; + background-color: #ffe; + width: 40%; + float: right; + clear: right; + overflow-x: auto; +} + +p.sidebar-title { + font-weight: bold; +} + +nav.contents, +aside.topic, +div.admonition, div.topic, blockquote { + clear: left; +} + +/* -- topics ---------------------------------------------------------------- */ + +nav.contents, +aside.topic, +div.topic { + border: 1px solid #ccc; + padding: 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- content of sidebars/topics/admonitions -------------------------------- */ + +div.sidebar > :last-child, +aside.sidebar > :last-child, +nav.contents > :last-child, +aside.topic > :last-child, +div.topic > :last-child, +div.admonition > :last-child { + margin-bottom: 0; +} + +div.sidebar::after, +aside.sidebar::after, +nav.contents::after, +aside.topic::after, +div.topic::after, +div.admonition::after, +blockquote::after { + display: block; + content: ''; + clear: both; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + margin-top: 10px; + margin-bottom: 10px; + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table.align-default { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +th > :first-child, +td > :first-child { + margin-top: 0px; +} + +th > :last-child, +td > :last-child { + margin-bottom: 0px; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure, figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption, figcaption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number, +figcaption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text, +figcaption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- hlist styles ---------------------------------------------------------- */ + +table.hlist { + margin: 1em 0; +} + +table.hlist td { + vertical-align: top; +} + +/* -- object description styles --------------------------------------------- */ + +.sig { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; +} + +.sig-name, code.descname { + background-color: transparent; + font-weight: bold; +} + +.sig-name { + font-size: 1.1em; +} + +code.descname { + font-size: 1.2em; +} + +.sig-prename, code.descclassname { + background-color: transparent; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.sig-param.n { + font-style: italic; +} + +/* C++ specific styling */ + +.sig-inline.c-texpr, +.sig-inline.cpp-texpr { + font-family: unset; +} + +.sig.c .k, .sig.c .kt, +.sig.cpp .k, .sig.cpp .kt { + color: #0033B3; +} + +.sig.c .m, +.sig.cpp .m { + color: #1750EB; +} + +.sig.c .s, .sig.c .sc, +.sig.cpp .s, .sig.cpp .sc { + color: #067D17; +} + + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +:not(li) > ol > li:first-child > :first-child, +:not(li) > ul > li:first-child > :first-child { + margin-top: 0px; +} + +:not(li) > ol > li:last-child > :last-child, +:not(li) > ul > li:last-child > :last-child { + margin-bottom: 0px; +} + +ol.simple ol p, +ol.simple ul p, +ul.simple ol p, +ul.simple ul p { + margin-top: 0; +} + +ol.simple > li:not(:first-child) > p, +ul.simple > li:not(:first-child) > p { + margin-top: 0; +} + +ol.simple p, +ul.simple p { + margin-bottom: 0; +} + +aside.footnote > span, +div.citation > span { + float: left; +} +aside.footnote > span:last-of-type, +div.citation > span:last-of-type { + padding-right: 0.5em; +} +aside.footnote > p { + margin-left: 2em; +} +div.citation > p { + margin-left: 4em; +} +aside.footnote > p:last-of-type, +div.citation > p:last-of-type { + margin-bottom: 0em; +} +aside.footnote > p:last-of-type:after, +div.citation > p:last-of-type:after { + content: ""; + clear: both; +} + +dl.field-list { + display: grid; + grid-template-columns: fit-content(30%) auto; +} + +dl.field-list > dt { + font-weight: bold; + word-break: break-word; + padding-left: 0.5em; + padding-right: 5px; +} + +dl.field-list > dd { + padding-left: 0.5em; + margin-top: 0em; + margin-left: 0em; + margin-bottom: 0em; +} + +dl { + margin-bottom: 15px; +} + +dd > :first-child { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +.sig dd { + margin-top: 0px; + margin-bottom: 0px; +} + +.sig dl { + margin-top: 0px; + margin-bottom: 0px; +} + +dl > dd:last-child, +dl > dd:last-child > :last-child { + margin-bottom: 0; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +.classifier:before { + font-style: normal; + margin: 0 0.5em; + content: ":"; + display: inline-block; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +.translated { + background-color: rgba(207, 255, 207, 0.2) +} + +.untranslated { + background-color: rgba(255, 207, 207, 0.2) +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +pre, div[class*="highlight-"] { + clear: both; +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; + white-space: nowrap; +} + +div[class*="highlight-"] { + margin: 1em 0; +} + +td.linenos pre { + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + display: block; +} + +table.highlighttable tbody { + display: block; +} + +table.highlighttable tr { + display: flex; +} + +table.highlighttable td { + margin: 0; + padding: 0; +} + +table.highlighttable td.linenos { + padding-right: 0.5em; +} + +table.highlighttable td.code { + flex: 1; + overflow: hidden; +} + +.highlight .hll { + display: block; +} + +div.highlight pre, +table.highlighttable pre { + margin: 0; +} + +div.code-block-caption + div { + margin-top: 0; +} + +div.code-block-caption { + margin-top: 1em; + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +table.highlighttable td.linenos, +span.linenos, +div.highlight span.gp { /* gp: Generic.Prompt */ + user-select: none; + -webkit-user-select: text; /* Safari fallback only */ + -webkit-user-select: none; /* Chrome/Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE10+ */ +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + margin: 1em 0; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: absolute; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/_static/bgfooter.png b/_static/bgfooter.png new file mode 100644 index 0000000..b7c7cad Binary files /dev/null and b/_static/bgfooter.png differ diff --git a/_static/bgtop.png b/_static/bgtop.png new file mode 100644 index 0000000..0574088 Binary files /dev/null and b/_static/bgtop.png differ diff --git a/_static/doctools.js b/_static/doctools.js new file mode 100644 index 0000000..4d67807 --- /dev/null +++ b/_static/doctools.js @@ -0,0 +1,156 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Base JavaScript utilities for all Sphinx HTML documentation. + * + * :copyright: Copyright 2007-2024 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +const BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([ + "TEXTAREA", + "INPUT", + "SELECT", + "BUTTON", +]); + +const _ready = (callback) => { + if (document.readyState !== "loading") { + callback(); + } else { + document.addEventListener("DOMContentLoaded", callback); + } +}; + +/** + * Small JavaScript module for the documentation. + */ +const Documentation = { + init: () => { + Documentation.initDomainIndexTable(); + Documentation.initOnKeyListeners(); + }, + + /** + * i18n support + */ + TRANSLATIONS: {}, + PLURAL_EXPR: (n) => (n === 1 ? 0 : 1), + LOCALE: "unknown", + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext: (string) => { + const translated = Documentation.TRANSLATIONS[string]; + switch (typeof translated) { + case "undefined": + return string; // no translation + case "string": + return translated; // translation exists + default: + return translated[0]; // (singular, plural) translation tuple exists + } + }, + + ngettext: (singular, plural, n) => { + const translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated !== "undefined") + return translated[Documentation.PLURAL_EXPR(n)]; + return n === 1 ? singular : plural; + }, + + addTranslations: (catalog) => { + Object.assign(Documentation.TRANSLATIONS, catalog.messages); + Documentation.PLURAL_EXPR = new Function( + "n", + `return (${catalog.plural_expr})` + ); + Documentation.LOCALE = catalog.locale; + }, + + /** + * helper function to focus on search bar + */ + focusSearchBar: () => { + document.querySelectorAll("input[name=q]")[0]?.focus(); + }, + + /** + * Initialise the domain index toggle buttons + */ + initDomainIndexTable: () => { + const toggler = (el) => { + const idNumber = el.id.substr(7); + const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`); + if (el.src.substr(-9) === "minus.png") { + el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`; + toggledRows.forEach((el) => (el.style.display = "none")); + } else { + el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`; + toggledRows.forEach((el) => (el.style.display = "")); + } + }; + + const togglerElements = document.querySelectorAll("img.toggler"); + togglerElements.forEach((el) => + el.addEventListener("click", (event) => toggler(event.currentTarget)) + ); + togglerElements.forEach((el) => (el.style.display = "")); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler); + }, + + initOnKeyListeners: () => { + // only install a listener if it is really needed + if ( + !DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS && + !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS + ) + return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.altKey || event.ctrlKey || event.metaKey) return; + + if (!event.shiftKey) { + switch (event.key) { + case "ArrowLeft": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const prevLink = document.querySelector('link[rel="prev"]'); + if (prevLink && prevLink.href) { + window.location.href = prevLink.href; + event.preventDefault(); + } + break; + case "ArrowRight": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const nextLink = document.querySelector('link[rel="next"]'); + if (nextLink && nextLink.href) { + window.location.href = nextLink.href; + event.preventDefault(); + } + break; + } + } + + // some keyboard layouts may need Shift to get / + switch (event.key) { + case "/": + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break; + Documentation.focusSearchBar(); + event.preventDefault(); + } + }); + }, +}; + +// quick alias for translations +const _ = Documentation.gettext; + +_ready(Documentation.init); diff --git a/_static/documentation_options.js b/_static/documentation_options.js new file mode 100644 index 0000000..d1f2291 --- /dev/null +++ b/_static/documentation_options.js @@ -0,0 +1,13 @@ +const DOCUMENTATION_OPTIONS = { + VERSION: '0.0.1', + LANGUAGE: 'en', + COLLAPSE_INDEX: false, + BUILDER: 'html', + FILE_SUFFIX: '.html', + LINK_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt', + NAVIGATION_WITH_KEYS: false, + SHOW_SEARCH_SUMMARY: true, + ENABLE_SEARCH_SHORTCUTS: true, +}; \ No newline at end of file diff --git a/_static/file.png b/_static/file.png new file mode 100644 index 0000000..a858a41 Binary files /dev/null and b/_static/file.png differ diff --git a/_static/language_data.js b/_static/language_data.js new file mode 100644 index 0000000..367b8ed --- /dev/null +++ b/_static/language_data.js @@ -0,0 +1,199 @@ +/* + * language_data.js + * ~~~~~~~~~~~~~~~~ + * + * This script contains the language-specific data used by searchtools.js, + * namely the list of stopwords, stemmer, scorer and splitter. + * + * :copyright: Copyright 2007-2024 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +var stopwords = ["a", "and", "are", "as", "at", "be", "but", "by", "for", "if", "in", "into", "is", "it", "near", "no", "not", "of", "on", "or", "such", "that", "the", "their", "then", "there", "these", "they", "this", "to", "was", "will", "with"]; + + +/* Non-minified version is copied as a separate JS file, if available */ + +/** + * Porter Stemmer + */ +var Stemmer = function() { + + var step2list = { + ational: 'ate', + tional: 'tion', + enci: 'ence', + anci: 'ance', + izer: 'ize', + bli: 'ble', + alli: 'al', + entli: 'ent', + eli: 'e', + ousli: 'ous', + ization: 'ize', + ation: 'ate', + ator: 'ate', + alism: 'al', + iveness: 'ive', + fulness: 'ful', + ousness: 'ous', + aliti: 'al', + iviti: 'ive', + biliti: 'ble', + logi: 'log' + }; + + var step3list = { + icate: 'ic', + ative: '', + alize: 'al', + iciti: 'ic', + ical: 'ic', + ful: '', + ness: '' + }; + + var c = "[^aeiou]"; // consonant + var v = "[aeiouy]"; // vowel + var C = c + "[^aeiouy]*"; // consonant sequence + var V = v + "[aeiou]*"; // vowel sequence + + var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0 + var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1 + var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1 + var s_v = "^(" + C + ")?" + v; // vowel in stem + + this.stemWord = function (w) { + var stem; + var suffix; + var firstch; + var origword = w; + + if (w.length < 3) + return w; + + var re; + var re2; + var re3; + var re4; + + firstch = w.substr(0,1); + if (firstch == "y") + w = firstch.toUpperCase() + w.substr(1); + + // Step 1a + re = /^(.+?)(ss|i)es$/; + re2 = /^(.+?)([^s])s$/; + + if (re.test(w)) + w = w.replace(re,"$1$2"); + else if (re2.test(w)) + w = w.replace(re2,"$1$2"); + + // Step 1b + re = /^(.+?)eed$/; + re2 = /^(.+?)(ed|ing)$/; + if (re.test(w)) { + var fp = re.exec(w); + re = new RegExp(mgr0); + if (re.test(fp[1])) { + re = /.$/; + w = w.replace(re,""); + } + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1]; + re2 = new RegExp(s_v); + if (re2.test(stem)) { + w = stem; + re2 = /(at|bl|iz)$/; + re3 = new RegExp("([^aeiouylsz])\\1$"); + re4 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re2.test(w)) + w = w + "e"; + else if (re3.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + else if (re4.test(w)) + w = w + "e"; + } + } + + // Step 1c + re = /^(.+?)y$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(s_v); + if (re.test(stem)) + w = stem + "i"; + } + + // Step 2 + re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step2list[suffix]; + } + + // Step 3 + re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step3list[suffix]; + } + + // Step 4 + re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; + re2 = /^(.+?)(s|t)(ion)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + if (re.test(stem)) + w = stem; + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1] + fp[2]; + re2 = new RegExp(mgr1); + if (re2.test(stem)) + w = stem; + } + + // Step 5 + re = /^(.+?)e$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + re2 = new RegExp(meq1); + re3 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) + w = stem; + } + re = /ll$/; + re2 = new RegExp(mgr1); + if (re.test(w) && re2.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + + // and turn initial Y back to y + if (firstch == "y") + w = firstch.toLowerCase() + w.substr(1); + return w; + } +} + diff --git a/_static/minus.png b/_static/minus.png new file mode 100644 index 0000000..d96755f Binary files /dev/null and b/_static/minus.png differ diff --git a/_static/plus.png b/_static/plus.png new file mode 100644 index 0000000..7107cec Binary files /dev/null and b/_static/plus.png differ diff --git a/_static/pygments.css b/_static/pygments.css new file mode 100644 index 0000000..6110e9f --- /dev/null +++ b/_static/pygments.css @@ -0,0 +1,84 @@ +pre { line-height: 125%; } +td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +.highlight .hll { background-color: #ffffcc } +.highlight { background: #f8f8f8; } +.highlight .c { color: #8f5902; font-style: italic } /* Comment */ +.highlight .err { color: #a40000; border: 1px solid #ef2929 } /* Error */ +.highlight .g { color: #000000 } /* Generic */ +.highlight .k { color: #204a87; font-weight: bold } /* Keyword */ +.highlight .l { color: #000000 } /* Literal */ +.highlight .n { color: #000000 } /* Name */ +.highlight .o { color: #ce5c00; font-weight: bold } /* Operator */ +.highlight .x { color: #000000 } /* Other */ +.highlight .p { color: #000000; font-weight: bold } /* Punctuation */ +.highlight .ch { color: #8f5902; font-style: italic } /* Comment.Hashbang */ +.highlight .cm { color: #8f5902; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #8f5902; font-style: italic } /* Comment.Preproc */ +.highlight .cpf { color: #8f5902; font-style: italic } /* Comment.PreprocFile */ +.highlight .c1 { color: #8f5902; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #8f5902; font-style: italic } /* Comment.Special */ +.highlight .gd { color: #a40000 } /* Generic.Deleted */ +.highlight .ge { color: #000000; font-style: italic } /* Generic.Emph */ +.highlight .ges { color: #000000; font-weight: bold; font-style: italic } /* Generic.EmphStrong */ +.highlight .gr { color: #ef2929 } /* Generic.Error */ +.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.highlight .gi { color: #00A000 } /* Generic.Inserted */ +.highlight .go { color: #000000; font-style: italic } /* Generic.Output */ +.highlight .gp { color: #8f5902 } /* Generic.Prompt */ +.highlight .gs { color: #000000; font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.highlight .gt { color: #a40000; font-weight: bold } /* Generic.Traceback */ +.highlight .kc { color: #204a87; font-weight: bold } /* Keyword.Constant */ +.highlight .kd { color: #204a87; font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { color: #204a87; font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { color: #204a87; font-weight: bold } /* Keyword.Pseudo */ +.highlight .kr { color: #204a87; font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #204a87; font-weight: bold } /* Keyword.Type */ +.highlight .ld { color: #000000 } /* Literal.Date */ +.highlight .m { color: #0000cf; font-weight: bold } /* Literal.Number */ +.highlight .s { color: #4e9a06 } /* Literal.String */ +.highlight .na { color: #c4a000 } /* Name.Attribute */ +.highlight .nb { color: #204a87 } /* Name.Builtin */ +.highlight .nc { color: #000000 } /* Name.Class */ +.highlight .no { color: #000000 } /* Name.Constant */ +.highlight .nd { color: #5c35cc; font-weight: bold } /* Name.Decorator */ +.highlight .ni { color: #ce5c00 } /* Name.Entity */ +.highlight .ne { color: #cc0000; font-weight: bold } /* Name.Exception */ +.highlight .nf { color: #000000 } /* Name.Function */ +.highlight .nl { color: #f57900 } /* Name.Label */ +.highlight .nn { color: #000000 } /* Name.Namespace */ +.highlight .nx { color: #000000 } /* Name.Other */ +.highlight .py { color: #000000 } /* Name.Property */ +.highlight .nt { color: #204a87; font-weight: bold } /* Name.Tag */ +.highlight .nv { color: #000000 } /* Name.Variable */ +.highlight .ow { color: #204a87; font-weight: bold } /* Operator.Word */ +.highlight .pm { color: #000000; font-weight: bold } /* Punctuation.Marker */ +.highlight .w { color: #f8f8f8 } /* Text.Whitespace */ +.highlight .mb { color: #0000cf; font-weight: bold } /* Literal.Number.Bin */ +.highlight .mf { color: #0000cf; font-weight: bold } /* Literal.Number.Float */ +.highlight .mh { color: #0000cf; font-weight: bold } /* Literal.Number.Hex */ +.highlight .mi { color: #0000cf; font-weight: bold } /* Literal.Number.Integer */ +.highlight .mo { color: #0000cf; font-weight: bold } /* Literal.Number.Oct */ +.highlight .sa { color: #4e9a06 } /* Literal.String.Affix */ +.highlight .sb { color: #4e9a06 } /* Literal.String.Backtick */ +.highlight .sc { color: #4e9a06 } /* Literal.String.Char */ +.highlight .dl { color: #4e9a06 } /* Literal.String.Delimiter */ +.highlight .sd { color: #8f5902; font-style: italic } /* Literal.String.Doc */ +.highlight .s2 { color: #4e9a06 } /* Literal.String.Double */ +.highlight .se { color: #4e9a06 } /* Literal.String.Escape */ +.highlight .sh { color: #4e9a06 } /* Literal.String.Heredoc */ +.highlight .si { color: #4e9a06 } /* Literal.String.Interpol */ +.highlight .sx { color: #4e9a06 } /* Literal.String.Other */ +.highlight .sr { color: #4e9a06 } /* Literal.String.Regex */ +.highlight .s1 { color: #4e9a06 } /* Literal.String.Single */ +.highlight .ss { color: #4e9a06 } /* Literal.String.Symbol */ +.highlight .bp { color: #3465a4 } /* Name.Builtin.Pseudo */ +.highlight .fm { color: #000000 } /* Name.Function.Magic */ +.highlight .vc { color: #000000 } /* Name.Variable.Class */ +.highlight .vg { color: #000000 } /* Name.Variable.Global */ +.highlight .vi { color: #000000 } /* Name.Variable.Instance */ +.highlight .vm { color: #000000 } /* Name.Variable.Magic */ +.highlight .il { color: #0000cf; font-weight: bold } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/_static/searchtools.js b/_static/searchtools.js new file mode 100644 index 0000000..b08d58c --- /dev/null +++ b/_static/searchtools.js @@ -0,0 +1,620 @@ +/* + * searchtools.js + * ~~~~~~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for the full-text search. + * + * :copyright: Copyright 2007-2024 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +/** + * Simple result scoring code. + */ +if (typeof Scorer === "undefined") { + var Scorer = { + // Implement the following function to further tweak the score for each result + // The function takes a result array [docname, title, anchor, descr, score, filename] + // and returns the new score. + /* + score: result => { + const [docname, title, anchor, descr, score, filename] = result + return score + }, + */ + + // query matches the full name of an object + objNameMatch: 11, + // or matches in the last dotted part of the object name + objPartialMatch: 6, + // Additive scores depending on the priority of the object + objPrio: { + 0: 15, // used to be importantResults + 1: 5, // used to be objectResults + 2: -5, // used to be unimportantResults + }, + // Used when the priority is not in the mapping. + objPrioDefault: 0, + + // query found in title + title: 15, + partialTitle: 7, + // query found in terms + term: 5, + partialTerm: 2, + }; +} + +const _removeChildren = (element) => { + while (element && element.lastChild) element.removeChild(element.lastChild); +}; + +/** + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping + */ +const _escapeRegExp = (string) => + string.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string + +const _displayItem = (item, searchTerms, highlightTerms) => { + const docBuilder = DOCUMENTATION_OPTIONS.BUILDER; + const docFileSuffix = DOCUMENTATION_OPTIONS.FILE_SUFFIX; + const docLinkSuffix = DOCUMENTATION_OPTIONS.LINK_SUFFIX; + const showSearchSummary = DOCUMENTATION_OPTIONS.SHOW_SEARCH_SUMMARY; + const contentRoot = document.documentElement.dataset.content_root; + + const [docName, title, anchor, descr, score, _filename] = item; + + let listItem = document.createElement("li"); + let requestUrl; + let linkUrl; + if (docBuilder === "dirhtml") { + // dirhtml builder + let dirname = docName + "/"; + if (dirname.match(/\/index\/$/)) + dirname = dirname.substring(0, dirname.length - 6); + else if (dirname === "index/") dirname = ""; + requestUrl = contentRoot + dirname; + linkUrl = requestUrl; + } else { + // normal html builders + requestUrl = contentRoot + docName + docFileSuffix; + linkUrl = docName + docLinkSuffix; + } + let linkEl = listItem.appendChild(document.createElement("a")); + linkEl.href = linkUrl + anchor; + linkEl.dataset.score = score; + linkEl.innerHTML = title; + if (descr) { + listItem.appendChild(document.createElement("span")).innerHTML = + " (" + descr + ")"; + // highlight search terms in the description + if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js + highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted")); + } + else if (showSearchSummary) + fetch(requestUrl) + .then((responseData) => responseData.text()) + .then((data) => { + if (data) + listItem.appendChild( + Search.makeSearchSummary(data, searchTerms, anchor) + ); + // highlight search terms in the summary + if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js + highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted")); + }); + Search.output.appendChild(listItem); +}; +const _finishSearch = (resultCount) => { + Search.stopPulse(); + Search.title.innerText = _("Search Results"); + if (!resultCount) + Search.status.innerText = Documentation.gettext( + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories." + ); + else + Search.status.innerText = _( + "Search finished, found ${resultCount} page(s) matching the search query." + ).replace('${resultCount}', resultCount); +}; +const _displayNextItem = ( + results, + resultCount, + searchTerms, + highlightTerms, +) => { + // results left, load the summary and display it + // this is intended to be dynamic (don't sub resultsCount) + if (results.length) { + _displayItem(results.pop(), searchTerms, highlightTerms); + setTimeout( + () => _displayNextItem(results, resultCount, searchTerms, highlightTerms), + 5 + ); + } + // search finished, update title and status message + else _finishSearch(resultCount); +}; +// Helper function used by query() to order search results. +// Each input is an array of [docname, title, anchor, descr, score, filename]. +// Order the results by score (in opposite order of appearance, since the +// `_displayNextItem` function uses pop() to retrieve items) and then alphabetically. +const _orderResultsByScoreThenName = (a, b) => { + const leftScore = a[4]; + const rightScore = b[4]; + if (leftScore === rightScore) { + // same score: sort alphabetically + const leftTitle = a[1].toLowerCase(); + const rightTitle = b[1].toLowerCase(); + if (leftTitle === rightTitle) return 0; + return leftTitle > rightTitle ? -1 : 1; // inverted is intentional + } + return leftScore > rightScore ? 1 : -1; +}; + +/** + * Default splitQuery function. Can be overridden in ``sphinx.search`` with a + * custom function per language. + * + * The regular expression works by splitting the string on consecutive characters + * that are not Unicode letters, numbers, underscores, or emoji characters. + * This is the same as ``\W+`` in Python, preserving the surrogate pair area. + */ +if (typeof splitQuery === "undefined") { + var splitQuery = (query) => query + .split(/[^\p{Letter}\p{Number}_\p{Emoji_Presentation}]+/gu) + .filter(term => term) // remove remaining empty strings +} + +/** + * Search Module + */ +const Search = { + _index: null, + _queued_query: null, + _pulse_status: -1, + + htmlToText: (htmlString, anchor) => { + const htmlElement = new DOMParser().parseFromString(htmlString, 'text/html'); + for (const removalQuery of [".headerlink", "script", "style"]) { + htmlElement.querySelectorAll(removalQuery).forEach((el) => { el.remove() }); + } + if (anchor) { + const anchorContent = htmlElement.querySelector(`[role="main"] ${anchor}`); + if (anchorContent) return anchorContent.textContent; + + console.warn( + `Anchored content block not found. Sphinx search tries to obtain it via DOM query '[role=main] ${anchor}'. Check your theme or template.` + ); + } + + // if anchor not specified or not found, fall back to main content + const docContent = htmlElement.querySelector('[role="main"]'); + if (docContent) return docContent.textContent; + + console.warn( + "Content block not found. Sphinx search tries to obtain it via DOM query '[role=main]'. Check your theme or template." + ); + return ""; + }, + + init: () => { + const query = new URLSearchParams(window.location.search).get("q"); + document + .querySelectorAll('input[name="q"]') + .forEach((el) => (el.value = query)); + if (query) Search.performSearch(query); + }, + + loadIndex: (url) => + (document.body.appendChild(document.createElement("script")).src = url), + + setIndex: (index) => { + Search._index = index; + if (Search._queued_query !== null) { + const query = Search._queued_query; + Search._queued_query = null; + Search.query(query); + } + }, + + hasIndex: () => Search._index !== null, + + deferQuery: (query) => (Search._queued_query = query), + + stopPulse: () => (Search._pulse_status = -1), + + startPulse: () => { + if (Search._pulse_status >= 0) return; + + const pulse = () => { + Search._pulse_status = (Search._pulse_status + 1) % 4; + Search.dots.innerText = ".".repeat(Search._pulse_status); + if (Search._pulse_status >= 0) window.setTimeout(pulse, 500); + }; + pulse(); + }, + + /** + * perform a search for something (or wait until index is loaded) + */ + performSearch: (query) => { + // create the required interface elements + const searchText = document.createElement("h2"); + searchText.textContent = _("Searching"); + const searchSummary = document.createElement("p"); + searchSummary.classList.add("search-summary"); + searchSummary.innerText = ""; + const searchList = document.createElement("ul"); + searchList.classList.add("search"); + + const out = document.getElementById("search-results"); + Search.title = out.appendChild(searchText); + Search.dots = Search.title.appendChild(document.createElement("span")); + Search.status = out.appendChild(searchSummary); + Search.output = out.appendChild(searchList); + + const searchProgress = document.getElementById("search-progress"); + // Some themes don't use the search progress node + if (searchProgress) { + searchProgress.innerText = _("Preparing search..."); + } + Search.startPulse(); + + // index already loaded, the browser was quick! + if (Search.hasIndex()) Search.query(query); + else Search.deferQuery(query); + }, + + _parseQuery: (query) => { + // stem the search terms and add them to the correct list + const stemmer = new Stemmer(); + const searchTerms = new Set(); + const excludedTerms = new Set(); + const highlightTerms = new Set(); + const objectTerms = new Set(splitQuery(query.toLowerCase().trim())); + splitQuery(query.trim()).forEach((queryTerm) => { + const queryTermLower = queryTerm.toLowerCase(); + + // maybe skip this "word" + // stopwords array is from language_data.js + if ( + stopwords.indexOf(queryTermLower) !== -1 || + queryTerm.match(/^\d+$/) + ) + return; + + // stem the word + let word = stemmer.stemWord(queryTermLower); + // select the correct list + if (word[0] === "-") excludedTerms.add(word.substr(1)); + else { + searchTerms.add(word); + highlightTerms.add(queryTermLower); + } + }); + + if (SPHINX_HIGHLIGHT_ENABLED) { // set in sphinx_highlight.js + localStorage.setItem("sphinx_highlight_terms", [...highlightTerms].join(" ")) + } + + // console.debug("SEARCH: searching for:"); + // console.info("required: ", [...searchTerms]); + // console.info("excluded: ", [...excludedTerms]); + + return [query, searchTerms, excludedTerms, highlightTerms, objectTerms]; + }, + + /** + * execute search (requires search index to be loaded) + */ + _performSearch: (query, searchTerms, excludedTerms, highlightTerms, objectTerms) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + const allTitles = Search._index.alltitles; + const indexEntries = Search._index.indexentries; + + // Collect multiple result groups to be sorted separately and then ordered. + // Each is an array of [docname, title, anchor, descr, score, filename]. + const normalResults = []; + const nonMainIndexResults = []; + + _removeChildren(document.getElementById("search-progress")); + + const queryLower = query.toLowerCase().trim(); + for (const [title, foundTitles] of Object.entries(allTitles)) { + if (title.toLowerCase().trim().includes(queryLower) && (queryLower.length >= title.length/2)) { + for (const [file, id] of foundTitles) { + const score = Math.round(Scorer.title * queryLower.length / title.length); + const boost = titles[file] === title ? 1 : 0; // add a boost for document titles + normalResults.push([ + docNames[file], + titles[file] !== title ? `${titles[file]} > ${title}` : title, + id !== null ? "#" + id : "", + null, + score + boost, + filenames[file], + ]); + } + } + } + + // search for explicit entries in index directives + for (const [entry, foundEntries] of Object.entries(indexEntries)) { + if (entry.includes(queryLower) && (queryLower.length >= entry.length/2)) { + for (const [file, id, isMain] of foundEntries) { + const score = Math.round(100 * queryLower.length / entry.length); + const result = [ + docNames[file], + titles[file], + id ? "#" + id : "", + null, + score, + filenames[file], + ]; + if (isMain) { + normalResults.push(result); + } else { + nonMainIndexResults.push(result); + } + } + } + } + + // lookup as object + objectTerms.forEach((term) => + normalResults.push(...Search.performObjectSearch(term, objectTerms)) + ); + + // lookup as search terms in fulltext + normalResults.push(...Search.performTermsSearch(searchTerms, excludedTerms)); + + // let the scorer override scores with a custom scoring function + if (Scorer.score) { + normalResults.forEach((item) => (item[4] = Scorer.score(item))); + nonMainIndexResults.forEach((item) => (item[4] = Scorer.score(item))); + } + + // Sort each group of results by score and then alphabetically by name. + normalResults.sort(_orderResultsByScoreThenName); + nonMainIndexResults.sort(_orderResultsByScoreThenName); + + // Combine the result groups in (reverse) order. + // Non-main index entries are typically arbitrary cross-references, + // so display them after other results. + let results = [...nonMainIndexResults, ...normalResults]; + + // remove duplicate search results + // note the reversing of results, so that in the case of duplicates, the highest-scoring entry is kept + let seen = new Set(); + results = results.reverse().reduce((acc, result) => { + let resultStr = result.slice(0, 4).concat([result[5]]).map(v => String(v)).join(','); + if (!seen.has(resultStr)) { + acc.push(result); + seen.add(resultStr); + } + return acc; + }, []); + + return results.reverse(); + }, + + query: (query) => { + const [searchQuery, searchTerms, excludedTerms, highlightTerms, objectTerms] = Search._parseQuery(query); + const results = Search._performSearch(searchQuery, searchTerms, excludedTerms, highlightTerms, objectTerms); + + // for debugging + //Search.lastresults = results.slice(); // a copy + // console.info("search results:", Search.lastresults); + + // print the results + _displayNextItem(results, results.length, searchTerms, highlightTerms); + }, + + /** + * search for object names + */ + performObjectSearch: (object, objectTerms) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const objects = Search._index.objects; + const objNames = Search._index.objnames; + const titles = Search._index.titles; + + const results = []; + + const objectSearchCallback = (prefix, match) => { + const name = match[4] + const fullname = (prefix ? prefix + "." : "") + name; + const fullnameLower = fullname.toLowerCase(); + if (fullnameLower.indexOf(object) < 0) return; + + let score = 0; + const parts = fullnameLower.split("."); + + // check for different match types: exact matches of full name or + // "last name" (i.e. last dotted part) + if (fullnameLower === object || parts.slice(-1)[0] === object) + score += Scorer.objNameMatch; + else if (parts.slice(-1)[0].indexOf(object) > -1) + score += Scorer.objPartialMatch; // matches in last name + + const objName = objNames[match[1]][2]; + const title = titles[match[0]]; + + // If more than one term searched for, we require other words to be + // found in the name/title/description + const otherTerms = new Set(objectTerms); + otherTerms.delete(object); + if (otherTerms.size > 0) { + const haystack = `${prefix} ${name} ${objName} ${title}`.toLowerCase(); + if ( + [...otherTerms].some((otherTerm) => haystack.indexOf(otherTerm) < 0) + ) + return; + } + + let anchor = match[3]; + if (anchor === "") anchor = fullname; + else if (anchor === "-") anchor = objNames[match[1]][1] + "-" + fullname; + + const descr = objName + _(", in ") + title; + + // add custom score for some objects according to scorer + if (Scorer.objPrio.hasOwnProperty(match[2])) + score += Scorer.objPrio[match[2]]; + else score += Scorer.objPrioDefault; + + results.push([ + docNames[match[0]], + fullname, + "#" + anchor, + descr, + score, + filenames[match[0]], + ]); + }; + Object.keys(objects).forEach((prefix) => + objects[prefix].forEach((array) => + objectSearchCallback(prefix, array) + ) + ); + return results; + }, + + /** + * search for full-text terms in the index + */ + performTermsSearch: (searchTerms, excludedTerms) => { + // prepare search + const terms = Search._index.terms; + const titleTerms = Search._index.titleterms; + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + + const scoreMap = new Map(); + const fileMap = new Map(); + + // perform the search on the required terms + searchTerms.forEach((word) => { + const files = []; + const arr = [ + { files: terms[word], score: Scorer.term }, + { files: titleTerms[word], score: Scorer.title }, + ]; + // add support for partial matches + if (word.length > 2) { + const escapedWord = _escapeRegExp(word); + if (!terms.hasOwnProperty(word)) { + Object.keys(terms).forEach((term) => { + if (term.match(escapedWord)) + arr.push({ files: terms[term], score: Scorer.partialTerm }); + }); + } + if (!titleTerms.hasOwnProperty(word)) { + Object.keys(titleTerms).forEach((term) => { + if (term.match(escapedWord)) + arr.push({ files: titleTerms[term], score: Scorer.partialTitle }); + }); + } + } + + // no match but word was a required one + if (arr.every((record) => record.files === undefined)) return; + + // found search word in contents + arr.forEach((record) => { + if (record.files === undefined) return; + + let recordFiles = record.files; + if (recordFiles.length === undefined) recordFiles = [recordFiles]; + files.push(...recordFiles); + + // set score for the word in each file + recordFiles.forEach((file) => { + if (!scoreMap.has(file)) scoreMap.set(file, {}); + scoreMap.get(file)[word] = record.score; + }); + }); + + // create the mapping + files.forEach((file) => { + if (!fileMap.has(file)) fileMap.set(file, [word]); + else if (fileMap.get(file).indexOf(word) === -1) fileMap.get(file).push(word); + }); + }); + + // now check if the files don't contain excluded terms + const results = []; + for (const [file, wordList] of fileMap) { + // check if all requirements are matched + + // as search terms with length < 3 are discarded + const filteredTermCount = [...searchTerms].filter( + (term) => term.length > 2 + ).length; + if ( + wordList.length !== searchTerms.size && + wordList.length !== filteredTermCount + ) + continue; + + // ensure that none of the excluded terms is in the search result + if ( + [...excludedTerms].some( + (term) => + terms[term] === file || + titleTerms[term] === file || + (terms[term] || []).includes(file) || + (titleTerms[term] || []).includes(file) + ) + ) + break; + + // select one (max) score for the file. + const score = Math.max(...wordList.map((w) => scoreMap.get(file)[w])); + // add result to the result list + results.push([ + docNames[file], + titles[file], + "", + null, + score, + filenames[file], + ]); + } + return results; + }, + + /** + * helper function to return a node containing the + * search summary for a given text. keywords is a list + * of stemmed words. + */ + makeSearchSummary: (htmlText, keywords, anchor) => { + const text = Search.htmlToText(htmlText, anchor); + if (text === "") return null; + + const textLower = text.toLowerCase(); + const actualStartPosition = [...keywords] + .map((k) => textLower.indexOf(k.toLowerCase())) + .filter((i) => i > -1) + .slice(-1)[0]; + const startWithContext = Math.max(actualStartPosition - 120, 0); + + const top = startWithContext === 0 ? "" : "..."; + const tail = startWithContext + 240 < text.length ? "..." : ""; + + let summary = document.createElement("p"); + summary.classList.add("context"); + summary.textContent = top + text.substr(startWithContext, 240).trim() + tail; + + return summary; + }, +}; + +_ready(Search.init); diff --git a/_static/sphinx_highlight.js b/_static/sphinx_highlight.js new file mode 100644 index 0000000..8a96c69 --- /dev/null +++ b/_static/sphinx_highlight.js @@ -0,0 +1,154 @@ +/* Highlighting utilities for Sphinx HTML documentation. */ +"use strict"; + +const SPHINX_HIGHLIGHT_ENABLED = true + +/** + * highlight a given string on a node by wrapping it in + * span elements with the given class name. + */ +const _highlight = (node, addItems, text, className) => { + if (node.nodeType === Node.TEXT_NODE) { + const val = node.nodeValue; + const parent = node.parentNode; + const pos = val.toLowerCase().indexOf(text); + if ( + pos >= 0 && + !parent.classList.contains(className) && + !parent.classList.contains("nohighlight") + ) { + let span; + + const closestNode = parent.closest("body, svg, foreignObject"); + const isInSVG = closestNode && closestNode.matches("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.classList.add(className); + } + + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + const rest = document.createTextNode(val.substr(pos + text.length)); + parent.insertBefore( + span, + parent.insertBefore( + rest, + node.nextSibling + ) + ); + node.nodeValue = val.substr(0, pos); + /* There may be more occurrences of search term in this node. So call this + * function recursively on the remaining fragment. + */ + _highlight(rest, addItems, text, className); + + if (isInSVG) { + const rect = document.createElementNS( + "http://www.w3.org/2000/svg", + "rect" + ); + const bbox = parent.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute("class", className); + addItems.push({ parent: parent, target: rect }); + } + } + } else if (node.matches && !node.matches("button, select, textarea")) { + node.childNodes.forEach((el) => _highlight(el, addItems, text, className)); + } +}; +const _highlightText = (thisNode, text, className) => { + let addItems = []; + _highlight(thisNode, addItems, text, className); + addItems.forEach((obj) => + obj.parent.insertAdjacentElement("beforebegin", obj.target) + ); +}; + +/** + * Small JavaScript module for the documentation. + */ +const SphinxHighlight = { + + /** + * highlight the search words provided in localstorage in the text + */ + highlightSearchWords: () => { + if (!SPHINX_HIGHLIGHT_ENABLED) return; // bail if no highlight + + // get and clear terms from localstorage + const url = new URL(window.location); + const highlight = + localStorage.getItem("sphinx_highlight_terms") + || url.searchParams.get("highlight") + || ""; + localStorage.removeItem("sphinx_highlight_terms") + url.searchParams.delete("highlight"); + window.history.replaceState({}, "", url); + + // get individual terms from highlight string + const terms = highlight.toLowerCase().split(/\s+/).filter(x => x); + if (terms.length === 0) return; // nothing to do + + // There should never be more than one element matching "div.body" + const divBody = document.querySelectorAll("div.body"); + const body = divBody.length ? divBody[0] : document.querySelector("body"); + window.setTimeout(() => { + terms.forEach((term) => _highlightText(body, term, "highlighted")); + }, 10); + + const searchBox = document.getElementById("searchbox"); + if (searchBox === null) return; + searchBox.appendChild( + document + .createRange() + .createContextualFragment( + '" + ) + ); + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords: () => { + document + .querySelectorAll("#searchbox .highlight-link") + .forEach((el) => el.remove()); + document + .querySelectorAll("span.highlighted") + .forEach((el) => el.classList.remove("highlighted")); + localStorage.removeItem("sphinx_highlight_terms") + }, + + initEscapeListener: () => { + // only install a listener if it is really needed + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.shiftKey || event.altKey || event.ctrlKey || event.metaKey) return; + if (DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS && (event.key === "Escape")) { + SphinxHighlight.hideSearchWords(); + event.preventDefault(); + } + }); + }, +}; + +_ready(() => { + /* Do not call highlightSearchWords() when we are on the search page. + * It will highlight words from the *previous* search query. + */ + if (typeof Search === "undefined") SphinxHighlight.highlightSearchWords(); + SphinxHighlight.initEscapeListener(); +}); diff --git a/api_reference.html b/api_reference.html new file mode 100644 index 0000000..5c9f7cb --- /dev/null +++ b/api_reference.html @@ -0,0 +1,119 @@ + + + + + + + + API Reference — Nasdaq Protocols Python Library 0.0.1 documentation + + + + + + + + + + + + +
+
+
+ +
+
+
+ +
+

API Reference

+ +
+ + +
+
+
+
+
+ +
+
+
+ + + + + \ No newline at end of file diff --git a/api_reference_common.html b/api_reference_common.html new file mode 100644 index 0000000..12057c1 --- /dev/null +++ b/api_reference_common.html @@ -0,0 +1,815 @@ + + + + + + + + Common api reference — Nasdaq Protocols Python Library 0.0.1 documentation + + + + + + + + + + + + +
+
+
+ +
+
+
+ +
+

Common api reference

+
+
+class nasdaq_protocols.common.message_queue.DispatchableMessageQueue(session_id, on_msg_coro=None)
+

Bases: Stoppable

+

A message queue that dispatches messages to a coro.

+
+
Parameters:
+
    +
  • session_id (Any)

  • +
  • on_msg_coro (Callable[[Any], Awaitable[None]])

  • +
+
+
+
+
+async put(msg)
+

put an entry into the queue. +:param msg: Any

+
+
Parameters:
+

msg (Any)

+
+
Return type:
+

None

+
+
+
+ +
+
+async get()
+

get an entry from the queue.

+

if the underlying queue contains entries, the first element is fetched and returned, +if the queue contains no entries, a coro is awaited, which will wait until queue contains +an entry.

+
+
Raises:

StateError - if the dispatcher is already in progress +EndOfQueue - if queue is stopped the underlying queue contains no entries.

+
+
+
+ +
+
+put_nowait(msg)
+

put an entry into the queue. +:param msg: Any

+
+
Parameters:
+

msg (Any)

+
+
+
+ +
+
+get_nowait()
+

get an entry from the queue. This is a non-blocking call. +:return: entry from the queue or None if queue is empty.

+
+
Return type:
+

Any | None

+
+
+
+ +
+
+pause_dispatching()
+

This is a context manager that pauses the dispatcher:

+
queue = DispatchableMessageQueue(session_id, on_msg_coro)
+
+queue.get()  # will raise an exception
+
+async with queue.pause_dispatching():
+     queue.get()  # will not raise an exception
+
+
+
+ +
+
+is_dispatching()
+

Check is message queue is actively dispatching.

+
+
Return type:
+

bool

+
+
+
+ +
+
+start_dispatching(on_msg_coro)
+

Start dispatching messages from the queue to the coro.

+
+
Parameters:
+

on_msg_coro (Callable[[Any], Awaitable[None]])

+
+
Return type:
+

None

+
+
+
+ +
+
+async stop()
+

Stop the queue.

+
+
Return type:
+

None

+
+
+
+ +
+
+is_stopped()
+
+
Returns:
+

True if the queue is stopped.

+
+
Return type:
+

bool

+
+
+
+ +
+ +
+
+class nasdaq_protocols.common.session.HeartbeatMonitor(session_id, interval, on_no_activity_coro, *, stop_when_no_activity=True, tolerate_missed_heartbeats=1, name='monitor')
+

Bases: Stoppable

+

Monitor that trips the on_no_activity_coro if no activity is detected.

+

Currently, activity is externally signalled by calling the ping method.

+
+
Parameters:
+
    +
  • session_id (Any) – The session id.

  • +
  • interval (float) – interval in seconds at which the monitor checks for activity.

  • +
  • on_no_activity_coro (Callable[[], Coroutine]) – coroutine to be called when no activity is detected.

  • +
  • stop_when_no_activity (bool) – If True, the monitor stops when no activity is detected.

  • +
  • tolerate_missed_heartbeats (int) – number of missed heartbeats to tolerate.

  • +
  • name (str)

  • +
+
+
+
+
+ping()
+

Ping the monitor.

+
+
Return type:
+

None

+
+
+
+ +
+
+is_running()
+

Returns True if the monitor is running.

+
+
Return type:
+

bool

+
+
+
+ +
+
+async stop()
+

Stop the monitor.

+
+
Return type:
+

None

+
+
+
+ +
+ +
+
+class nasdaq_protocols.common.session.Reader(session_id, on_msg_coro, on_close_coro)
+

Bases: Stoppable

+

Abstract Base class for readers.

+

A reader is responsible for parsing the received data from the transport +and dispatching it to the on_msg_coro.

+
+
Parameters:
+
    +
  • session_id (Any) – The session id.

  • +
  • on_msg_coro (Callable[[Any], Coroutine]) – coroutine to be called for every message parsed.

  • +
  • on_close_coro (Callable[[], Coroutine]) – coroutine to be called when the reader detects end of session.

  • +
+
+
+
+
+abstract async on_data(data)
+

Called when data is received from the transport.

+
+
Parameters:
+

data (bytes)

+
+
+
+ +
+ +
+
+class nasdaq_protocols.common.session.AsyncSession(*, session_id, reader_factory, on_msg_coro=None, on_close_coro=None, dispatch_on_connect=True)
+

Bases: Protocol, ABC, Generic[T]

+

Abstract base class for async sessions.

+

Once the transport is available, the session creates a new reader using the +reader_factory and starts parsing the incoming bytes.

+

By default, the session starts in a dispatching mode, meaning the incoming messages +are dispatched to the on_msg_coro. This can be changed by setting dispatch_on_connect=False.

+
+
Parameters:
+
    +
  • session_id (SessionId) – The session id.

  • +
  • reader_factory (Callable[[Any, Callable[[Any], Coroutine], Callable[[], Coroutine]], Reader]) – A callable that returns a reader.

  • +
  • on_msg_coro (Callable[[Any], Coroutine]) – coroutine to be called when a message is received.

  • +
  • on_close_coro (Callable[[], Coroutine]) – coroutine to be called when the session is closed.

  • +
  • dispatch_on_connect (bool) – If True, the session starts with dispatching once connected.

  • +
+
+
+
+
+async receive_msg()
+

Receive a message from the peer. This is a blocking call. +This call blocks until a new message is available.

+

If the session is dispatching messages, then this call raises an exception.

+
+
Return Any:
+

The message received.

+
+
Return type:
+

Type[T]

+
+
+
+ +
+
+receive_msg_nowait()
+

Receive a message from the peer. This is a non-blocking call.

+
+
Return Any:
+

The message received.

+
+
Return type:
+

Type[T] | None

+
+
+
+ +
+
+is_active()
+

Returns True if the session is not closed or in closing state.

+
+
Return type:
+

bool

+
+
+
+ +
+
+is_closed()
+

Returns True if the session is closed. +:return:

+
+
Return type:
+

bool

+
+
+
+ +
+
+initiate_close()
+

Initiate close of the session. +An asynchronous task is created which will close the session and all its +associates.

+

Poll is_closed to check if the session is closed or use the +on_close_coro callback to be notified when the session is closed.

+
+
Return type:
+

None

+
+
+
+ +
+
+async close()
+

Close the session, the session cannot be used after this call.

+
+ +
+
+start_heartbeats(local_hb_interval, remote_hb_interval)
+

Starts the heartbeats for the session.

+
    +
  • if the remote failed heartbeats, then the session is closed.

  • +
  • if the local heartbeat timer expires, then send_heartbeat is called.

  • +
+
+
Parameters:
+
    +
  • local_hb_interval (int | float)

  • +
  • remote_hb_interval (int | float)

  • +
+
+
+
+ +
+
+start_dispatching()
+

By default, the session starts with dispatching switched-on.

+

If, the session is created with dispatching-off, then at any point in time +during the lifetime of this session, dispatching can be switched-on by calling +this method.

+
+ +
+
+abstract send_msg(msg)
+

Send a message to the peer. +:param msg: Any message that is serializable.

+
+
Parameters:
+

msg (Serializable[T])

+
+
Return type:
+

None

+
+
+
+ +
+
+abstract async send_heartbeat()
+

Callback to send a heartbeat to the peer. +:meta private:

+
+ +
+ +
+
+class nasdaq_protocols.common.session.SessionId(host='nohost', port=0)
+

Bases: object

+

A basic session id.

+
+
Parameters:
+
    +
  • host (str)

  • +
  • port (int)

  • +
+
+
+
+
+set_transport(transport)
+

Once the transport is available, the host and port are updated.

+
+
Parameters:
+

transport (Transport)

+
+
Return type:
+

None

+
+
+
+ +
+ +
+
+class nasdaq_protocols.common.types.Serializable
+

Bases: ABC, Generic[T]

+

Abstract Base class for serializable objects.

+
+
+abstract to_bytes()
+

pack the object to binary format.

+
+
Return type:
+

tuple[int, bytes]

+
+
+
+ +
+
+abstract classmethod from_bytes(bytes_)
+

unpack the object from binary format.

+
+
Parameters:
+

bytes_ (bytes)

+
+
Return type:
+

tuple[int, Type[T]]

+
+
+
+ +
+ +
+
+class nasdaq_protocols.common.types.Stoppable
+

Bases: ABC

+
+ +
+
+exception nasdaq_protocols.common.types.StateError
+

Bases: RuntimeError

+

Raised when an operation is attempted in an invalid state.

+
+ +
+
+exception nasdaq_protocols.common.types.EndOfQueue
+

Bases: EOFError

+

Raised when the end of the queue is reached.

+
+ +
+
+class nasdaq_protocols.common.types.TypeDefinition
+

Bases: object

+

Class to hold all type definitions

+
+
Parameters:
+
    +
  • to_str (Callable[[Any], str]) – Function to convert value to string

  • +
  • from_str (Callable[[str], Any]) – Function to convert string to value

  • +
  • to_bytes (Callable[[Any], bytes]) – Function to convert value to bytes

  • +
  • from_bytes (Callable[[bytes], Tuple[int, Any]]) – Function to convert bytes to value

  • +
+
+
Returns:
+

str

+
+
Returns:
+

Any

+
+
Returns:
+

Tuple[int, bytes]

+
+
Returns:
+

Tuple[int, Any]

+
+
+
+ +
+
+nasdaq_protocols.common.utils.logable(target)
+

decorator that adds a log object to the class.

+
+ +
+
+async nasdaq_protocols.common.utils.stop_task(tasks)
+

Cancel a task and wait for it to finish

+
+
Parameters:
+

tasks (Task | Stoppable | list[Task | Stoppable])

+
+
Return type:
+

Task | Stoppable | None

+
+
+
+ +
+
+async nasdaq_protocols.common.utils.start_server(remote, session_factory, spin_timeout=0.001, *, name='server:serve', **kwargs)
+

start a socket server and return the server and the task that runs it

+
+
Return type:
+

Tuple[Server, Task]

+
+
+
+ +
+
+class nasdaq_protocols.common.message.types.Boolean
+

Bases: TypeDefinition

+
+
+type_cls
+

alias of bool

+
+ +
+ +
+
+class nasdaq_protocols.common.message.types.Int
+

Bases: TypeDefinition

+
+
+to_str
+

alias of str

+
+ +
+
+from_str
+

alias of int

+
+ +
+
+type_cls
+

alias of int

+
+ +
+ +
+
+class nasdaq_protocols.common.message.types.IntBE
+

Bases: Int

+
+ +
+
+class nasdaq_protocols.common.message.types.UnsignedInt
+

Bases: Int

+
+ +
+
+class nasdaq_protocols.common.message.types.UnsignedIntBE
+

Bases: UnsignedInt

+
+ +
+
+class nasdaq_protocols.common.message.types.Byte
+

Bases: Int

+
+ +
+
+class nasdaq_protocols.common.message.types.Short
+

Bases: Int

+
+ +
+
+class nasdaq_protocols.common.message.types.ShortBE
+

Bases: Int

+
+ +
+
+class nasdaq_protocols.common.message.types.UnsignedShort
+

Bases: Int

+
+ +
+
+class nasdaq_protocols.common.message.types.UnsignedShortBE
+

Bases: Int

+
+ +
+
+class nasdaq_protocols.common.message.types.Long
+

Bases: Int

+
+ +
+
+class nasdaq_protocols.common.message.types.LongBE
+

Bases: Int

+
+ +
+
+class nasdaq_protocols.common.message.types.UnsignedLong
+

Bases: Int

+
+ +
+
+class nasdaq_protocols.common.message.types.UnsignedLongBE
+

Bases: Int

+
+ +
+
+class nasdaq_protocols.common.message.types.CharAscii
+

Bases: TypeDefinition

+
+
+to_str
+

alias of str

+
+ +
+
+from_str
+

alias of str

+
+ +
+
+type_cls
+

alias of str

+
+ +
+ +
+
+class nasdaq_protocols.common.message.types.CharIso8599
+

Bases: CharAscii

+
+ +
+
+class nasdaq_protocols.common.message.types.AsciiString
+

Bases: CharAscii

+
+
Parameters:
+
    +
  • to_bytes (Callable[[str], Tuple[int, bytes]]) – encodes the string to bytes and prepends the 2 digit size of the string

  • +
  • from_bytes (Callable[[bytes], Tuple[int, str]]) – decodes the bytes to string and returns the size of the string and the string

  • +
+
+
+
+ +
+
+class nasdaq_protocols.common.message.types.Iso8859String
+

Bases: CharAscii

+
+ +
+
+class nasdaq_protocols.common.message.types.FixedAsciiString(length, right_justified=False)
+

Bases: TypeDefinition

+
+
+to_str
+

alias of str

+
+ +
+
+from_str
+

alias of str

+
+ +
+
+type_cls
+

alias of str

+
+ +
+ +
+
+class nasdaq_protocols.common.message.types.FixedIsoString(length, right_justified=False)
+

Bases: TypeDefinition

+
+
+to_str
+

alias of str

+
+ +
+
+from_str
+

alias of str

+
+ +
+
+type_cls
+

alias of str

+
+ +
+ +
+ + +
+
+
+
+
+ +
+
+
+ + + + + \ No newline at end of file diff --git a/api_reference_itch.html b/api_reference_itch.html new file mode 100644 index 0000000..d9a7448 --- /dev/null +++ b/api_reference_itch.html @@ -0,0 +1,323 @@ + + + + + + + + ITCH API Reference — Nasdaq Protocols Python Library 0.0.1 documentation + + + + + + + + + + + + +
+
+
+ +
+
+
+ +
+

ITCH API Reference

+
+

Itch

+
+
+class nasdaq_protocols.itch.ItchMessageId(indicator)
+

Bases: Serializable

+
+
Parameters:
+

indicator (int)

+
+
+
+
+classmethod from_bytes(bytes_)
+

unpack the object from binary format.

+
+
Parameters:
+

bytes_ (bytes)

+
+
Return type:
+

tuple[int, ItchMessageId]

+
+
+
+ +
+
+to_bytes()
+

pack the object to binary format.

+
+
Return type:
+

tuple[int, bytes]

+
+
+
+ +
+ +
+
+class nasdaq_protocols.itch.Message(record=None)
+

Bases: CommonMessage

+
+
+
+
+MsgIdClass
+

alias of ItchMessageId

+
+ +
+ +
+
+async nasdaq_protocols.itch.connect_async(remote, user, passwd, session_id, sequence=0, session_factory=None, on_msg_coro=None, on_close_coro=None, client_heartbeat_interval=10, server_heartbeat_interval=10)
+

Connect to the ITCH server.

+
+
Parameters:
+
    +
  • remote (tuple[str, int]) – tuple of host and port

  • +
  • user (str) – Username to login

  • +
  • passwd (str) – Password to login

  • +
  • session_id – Name of the session to join [Default=’’] .

  • +
  • sequence (int) – The sequence number. [Default=1]

  • +
  • session_factory (Callable[[SoupClientSession], ClientSession] | None) – Factory to create a SoupClientSession.

  • +
  • on_msg_coro (Callable[[Type[Message]], Awaitable[None]] | None) – callback, message from server.

  • +
  • on_close_coro (Callable[[], Awaitable[None]] | None) – callback, connection closed .

  • +
  • client_heartbeat_interval (int) – seconds between client heartbeats.

  • +
  • server_heartbeat_interval (int) – seconds between server heartbeats.

  • +
+
+
Returns:
+

SoupClientSession

+
+
+
+ +
+

Itch Session

+
+
+class nasdaq_protocols.itch.session.ItchSessionId(soup_session_id=None)
+

Bases: object

+
+
Parameters:
+

soup_session_id (SoupSessionId)

+
+
+
+ +
+
+class nasdaq_protocols.itch.session.ClientSession(soup_session, on_msg_coro=None, on_close_coro=None, closed=False, session_id=None, close_event=None, message_queue=None)
+

Bases: object

+
+
Parameters:
+
+
+
+
+
+soup_session: SoupClientSession
+
+ +
+
+on_msg_coro: Callable[[Type[Message]], Awaitable[None]]
+
+ +
+
+on_close_coro: Callable[[], Awaitable[None]]
+
+ +
+
+closed: bool
+
+ +
+
+async receive_message()
+

Asynchronously receive a message from the itch session.

+

This method blocks until a message is received by the session.

+
+ +
+
+async close()
+

Asynchronously close the itch session.

+
+ +
+
+classmethod decode(bytes_)
+

Decode the given bytes into an itch message.

+
+
Parameters:
+

bytes_ (bytes)

+
+
+
+ +
+
+log = <Logger ClientSession (WARNING)>
+
+ +
+ +
+
+

Itch Messages

+
+
+class nasdaq_protocols.itch.core.ItchMessageId(indicator)
+

Bases: Serializable

+
+
Parameters:
+

indicator (int)

+
+
+
+
+classmethod from_bytes(bytes_)
+

unpack the object from binary format.

+
+
Parameters:
+

bytes_ (bytes)

+
+
Return type:
+

tuple[int, ItchMessageId]

+
+
+
+ +
+
+to_bytes()
+

pack the object to binary format.

+
+
Return type:
+

tuple[int, bytes]

+
+
+
+ +
+ +
+
+class nasdaq_protocols.itch.core.Message(record=None)
+

Bases: CommonMessage

+
+
+
+
+MsgIdClass
+

alias of ItchMessageId

+
+ +
+ +
+
+
+ + +
+
+
+
+
+ +
+
+
+ + + + + \ No newline at end of file diff --git a/api_reference_ouch.html b/api_reference_ouch.html new file mode 100644 index 0000000..d9597b5 --- /dev/null +++ b/api_reference_ouch.html @@ -0,0 +1,340 @@ + + + + + + + + OUCH API Reference — Nasdaq Protocols Python Library 0.0.1 documentation + + + + + + + + + + + + +
+
+
+ +
+
+
+ +
+

OUCH API Reference

+
+

Ouch

+
+
+class nasdaq_protocols.ouch.OuchMessageId(indicator, direction='outgoing')
+

Bases: Serializable

+
+
Parameters:
+
    +
  • indicator (int)

  • +
  • direction (str)

  • +
+
+
+
+
+classmethod from_bytes(bytes_)
+

unpack the object from binary format.

+
+
Parameters:
+

bytes_ (bytes)

+
+
Return type:
+

tuple[int, OuchMessageId]

+
+
+
+ +
+
+to_bytes()
+

pack the object to binary format.

+
+
Return type:
+

tuple[int, bytes]

+
+
+
+ +
+ +
+
+class nasdaq_protocols.ouch.Message(record=None)
+

Bases: CommonMessage

+
+
+
+
+MsgIdClass
+

alias of OuchMessageId

+
+ +
+ +
+
+async nasdaq_protocols.ouch.connect_async(remote, user, passwd, session_id, sequence=0, session_factory=None, on_msg_coro=None, on_close_coro=None, client_heartbeat_interval=10, server_heartbeat_interval=10)
+

Connect to the OUCH server.

+
+
Parameters:
+
    +
  • remote (tuple[str, int]) – tuple of host and port

  • +
  • user (str) – Username to login

  • +
  • passwd (str) – Password to login

  • +
  • session_id – Name of the session to join [Default=’’] .

  • +
  • sequence (int) – The sequence number. [Default=1]

  • +
  • session_factory (Callable[[SoupClientSession], ClientSession] | None) – Factory to create a SoupClientSession.

  • +
  • on_msg_coro (Callable[[Type[Message]], Awaitable[None]] | None) – callback, message from server.

  • +
  • on_close_coro (Callable[[], Awaitable[None]] | None) – callback, connection closed .

  • +
  • client_heartbeat_interval (int) – seconds between client heartbeats.

  • +
  • server_heartbeat_interval (int) – seconds between server heartbeats.

  • +
+
+
Returns:
+

SoupClientSession

+
+
+
+ +
+

Ouch Session

+
+
+class nasdaq_protocols.ouch.session.OuchSessionId(soup_session_id=None)
+

Bases: object

+
+
Parameters:
+

soup_session_id (SoupSessionId)

+
+
+
+ +
+
+class nasdaq_protocols.ouch.session.ClientSession(soup_session, on_msg_coro=None, on_close_coro=None, closed=False, session_id=None, close_event=None, message_queue=None)
+

Bases: object

+
+
Parameters:
+
+
+
+
+
+soup_session: SoupClientSession
+
+ +
+
+on_msg_coro: Callable[[Type[Message]], Awaitable[None]]
+
+ +
+
+on_close_coro: Callable[[], Awaitable[None]]
+
+ +
+
+closed: bool
+
+ +
+
+async receive_message()
+

Asynchronously receive a message from the ouch session.

+

This method blocks until a message is received by the session.

+
+ +
+
+send_message(msg)
+

Send a message to the Ouch Server.

+
+
Parameters:
+

msg (Message)

+
+
+
+ +
+
+async close()
+

Asynchronously close the ouch session.

+
+ +
+
+decode(bytes_)
+

Decode the given bytes into an itch message.

+
+
Parameters:
+

bytes_ (bytes)

+
+
+
+ +
+
+log = <Logger ClientSession (WARNING)>
+
+ +
+ +
+
+

Ouch Messages

+
+
+class nasdaq_protocols.ouch.core.OuchMessageId(indicator, direction='outgoing')
+

Bases: Serializable

+
+
Parameters:
+
    +
  • indicator (int)

  • +
  • direction (str)

  • +
+
+
+
+
+classmethod from_bytes(bytes_)
+

unpack the object from binary format.

+
+
Parameters:
+

bytes_ (bytes)

+
+
Return type:
+

tuple[int, OuchMessageId]

+
+
+
+ +
+
+to_bytes()
+

pack the object to binary format.

+
+
Return type:
+

tuple[int, bytes]

+
+
+
+ +
+ +
+
+class nasdaq_protocols.ouch.core.Message(record=None)
+

Bases: CommonMessage

+
+
+
+
+MsgIdClass
+

alias of OuchMessageId

+
+ +
+ +
+
+
+ + +
+
+
+
+
+ +
+
+
+ + + + + \ No newline at end of file diff --git a/api_reference_soup.html b/api_reference_soup.html new file mode 100644 index 0000000..8641ea4 --- /dev/null +++ b/api_reference_soup.html @@ -0,0 +1,1100 @@ + + + + + + + + SOUP API Reference — Nasdaq Protocols Python Library 0.0.1 documentation + + + + + + + + + + + + +
+
+
+ +
+
+
+ +
+

SOUP API Reference

+
+

Soup

+

The SoupBinTCP protocol is a simple, lightweight, and fast protocol that +provides reliable, ordered, and error-checked delivery of messages between +client and server. It is designed for high-performance market data and order +entry applications. The protocol is based on the TCP/IP protocol suite and +uses TCP as its transport protocol.

+

This module provides a SoupBinTCP client implementation that can be used to +connect to the SoupBinTCP servers.

+

Though SoupBinTCP is meant for latency sensitive applications, there are +numerous times when the client application is not latency sensitive and +would like to talk to the soup server, Say in testing or writing a monitoring tool.

+

In such cases, the client application can use the SoupBinTCP client provided by this module.

+
+
+exception nasdaq_protocols.soup.InvalidSoupMessage
+

Bases: ValueError

+

Raised when an invalid soup message is received.

+
+ +
+
+class nasdaq_protocols.soup.LoginRejectReason(value)
+

Bases: Enum

+

Login Reject Reason sent from server in case of login failure.

+
+
+classmethod get(reason)
+

Get the LoginRejectReason enum value from the given reason.

+
+
Parameters:
+

reason (str)

+
+
+
+ +
+ +
+
+class nasdaq_protocols.soup.SoupMessage
+

Bases: Serializable[SoupMessage]

+

Base class for all soup messages.

+

Given raw bytes use this class to unpack the bytes to the corresponding soup message:

+
input_bytes = b'Atest      2                   '
+len, soup_msg = SoupMessage.from_bytes(input_bytes)
+type(soup_msg)
+
+
+to_bytes()
+

Pack the soup message to binary format

+
+
Returns:
+

tuple of length and bytes

+
+
Return type:
+

tuple[int, bytes]

+
+
+
+ +
+
+classmethod from_bytes(bytes_)
+

unpacks the bytes to the corresponding soup message

+
+
Parameters:
+

bytes – bytes to unpack

+
+
Returns:
+

tuple of length and soup message

+
+
Return type:
+

tuple[int, Type[SoupMessage]]

+
+
+
+ +
+ +
+
+class nasdaq_protocols.soup.LoginRequest(user, password, session, sequence)
+

Bases: SoupMessage

+

SoupBinTCP Login Request Message.

+
+
Parameters:
+
    +
  • user (str) – Username to login

  • +
  • password (str) – Password to login

  • +
  • session (str) – Name of the session to join [Default=’’] .

  • +
  • sequence (str) – The sequence number. [Default=1]

  • +
+
+
+
+
+to_bytes()
+

Pack the soup message to binary format

+
+
Returns:
+

+
+
Return type:
+

tuple[int, bytes]

+
+
+
+ +
+ +
+
+class nasdaq_protocols.soup.LoginAccepted(session_id, sequence)
+

Bases: SoupMessage

+

SoupBinTCP Login Accepted Message.

+
+
Parameters:
+
    +
  • session_id (str) – Name of the session joined [Default=’’] .

  • +
  • sequence (int) – The next sequence number.

  • +
+
+
+
+
+to_bytes()
+

Pack the soup message to binary format +:return: bytes

+
+
Return type:
+

tuple[int, bytes]

+
+
+
+ +
+ +
+
+class nasdaq_protocols.soup.LoginRejected(reason)
+

Bases: SoupMessage

+

SoupBinTCP Login Rejected Message.

+
+
Parameters:
+

reason (LoginRejectReason) – Reason for login failure. Refer LoginRejectReason

+
+
+
+
+to_bytes()
+

Pack the soup message to binary format +:return: bytes

+
+
Return type:
+

tuple[int, bytes]

+
+
+
+ +
+ +
+
+class nasdaq_protocols.soup.SequencedData(data)
+

Bases: SoupMessage

+

SoupBinTCP Sequenced Data Message.

+
+
Parameters:
+

data (bytes) – The application payload sent by the server.

+
+
+
+
+to_bytes()
+

Pack the soup message to binary format +:return: bytes

+
+
Return type:
+

tuple[int, bytes]

+
+
+
+ +
+ +
+
+class nasdaq_protocols.soup.UnSequencedData(data)
+

Bases: SoupMessage

+

SoupBinTCP Unsequenced Data Message.

+
+
Parameters:
+

data (bytes) – The application payload to be sent to server.

+
+
+
+
+to_bytes()
+

Pack the soup message to binary format +:return: bytes

+
+
Return type:
+

tuple[int, bytes]

+
+
+
+ +
+ +
+
+class nasdaq_protocols.soup.Debug(msg)
+

Bases: SoupMessage

+

SoupBinTCP Debug Message.

+
+
Parameters:
+

msg (str) – The debug message.

+
+
+
+
+to_bytes()
+

Pack the soup message to binary format +:return: bytes

+
+
Return type:
+

tuple[int, bytes]

+
+
+
+ +
+ +
+
+class nasdaq_protocols.soup.ClientHeartbeat
+

Bases: SoupMessage

+

SoupBinTCP Client Heartbeat Message.

+
+
+
+ +
+
+class nasdaq_protocols.soup.ServerHeartbeat
+

Bases: SoupMessage

+

SoupBinTCP Server Heartbeat Message.

+
+
+
+ +
+
+class nasdaq_protocols.soup.EndOfSession
+

Bases: SoupMessage

+

SoupBinTCP End of Session Message.

+

This message is sent from server to indicate the soup stream is now closed.

+
+
+
+ +
+
+class nasdaq_protocols.soup.LogoutRequest
+

Bases: SoupMessage

+

SoupBinTCP Logout Request Message.

+

This message is initiated by the client to sever for graceful session logoff.

+
+
+
+ +
+
+class nasdaq_protocols.soup.SoupSessionId(host='nohost', port=0, session_type='norole', user='nouser', session='nosession')
+

Bases: SessionId

+

Identifier for a soup session.

+
+
Parameters:
+
    +
  • session_type (str) – The type of the session, either ‘client’ or ‘server’.

  • +
  • user (str) – The username.

  • +
  • session (str) – The session id.

  • +
  • host (str)

  • +
  • port (int)

  • +
+
+
+
+
+update(msg, transport=None)
+

Update the session id with the more information as and when it is available.

+
+
Parameters:
+
    +
  • msg (LoginRequest | LoginAccepted) – LoginRequest or LoginAccepted message.

  • +
  • transport (Transport | None) – asyncio.Transport object.

  • +
+
+
Returns:
+

self

+
+
+
+ +
+ +
+
+class nasdaq_protocols.soup.SoupSession(on_msg_coro=None, on_close_coro=None, session_id=NOTHING, *, dispatch_on_connect=True, sequence=1, client_heartbeat_interval=10, server_heartbeat_interval=10)
+

Bases: AsyncSession, ABC

+

Base class for SoupBinTCP[server, client] session.

+
+
Parameters:
+
    +
  • on_msg_coro (Callable[[Any], Awaitable[None]]) – Coroutine to be called when a message is received.

  • +
  • on_close_coro (Callable[[], Coroutine]) – Coroutine to be called when the session is closed.

  • +
  • sequence (int) – The sequence number. [Default=1]

  • +
  • client_heartbeat_interval (int) – The client heartbeat interval in seconds. [Default=10]

  • +
  • server_heartbeat_interval (int) – The server heartbeat interval in seconds. [Default=10]

  • +
  • session_id (SoupSessionId) – The session id.

  • +
  • dispatch_on_connect (bool)

  • +
+
+
+
+
+send_msg(msg)
+

Send a soup message to the server.

+
+
Parameters:
+

msg (SoupMessage) – SoupMessage object.

+
+
Return type:
+

None

+
+
+
+ +
+
+send_debug(text)
+

Send a debug message to the peer.

+
+
Parameters:
+

text (str) – debug text

+
+
Return type:
+

None

+
+
+
+ +
+
+logout()
+

Logout.

+

The session is closed after sending the logout request. +:return:

+
+
Return type:
+

None

+
+
+
+ +
+ +
+
+class nasdaq_protocols.soup.SoupClientSession(on_msg_coro=None, on_close_coro=None, session_id=NOTHING, dispatch_on_connect=False, *, sequence=1, client_heartbeat_interval=10, server_heartbeat_interval=10)
+

Bases: SoupSession

+

SoupBinTCP client session.

+

Upon successful connecting to the soup server, the client session is instantiated.

+
+
Parameters:
+
    +
  • on_msg_coro (Callable[[Any], Awaitable[None]])

  • +
  • on_close_coro (Callable[[], Coroutine])

  • +
  • session_id (SoupSessionId)

  • +
  • dispatch_on_connect (bool)

  • +
  • sequence (int)

  • +
  • client_heartbeat_interval (int)

  • +
  • server_heartbeat_interval (int)

  • +
+
+
+
+
+async login(msg)
+

Login to the soup server.

+

This is supposed to be the first message to be sent to server upon connection successful.

+
+
Parameters:
+

msg (LoginRequest) – LoginRequest message.

+
+
Returns:
+

self

+
+
Raises:
+

ConnectionRefusedError – If the server rejects the login request.

+
+
+
+ +
+
+send_unseq_data(data)
+

Send unsequenced data to the server. +:param data: application payload

+
+
Parameters:
+

data (bytes)

+
+
+
+ +
+ +
+
+class nasdaq_protocols.soup.SoupServerSession(on_close_coro=None, session_id=NOTHING, *, dispatch_on_connect=True, sequence=1, client_heartbeat_interval=10, server_heartbeat_interval=10)
+

Bases: SoupSession

+

Base class for all soup server sessions.

+

Any class that implements a soup server session must inherit from this class. +and implement the following methods:

+
    +
  • on_login

  • +
  • on_unsequenced

  • +
+
+
Parameters:
+
    +
  • on_close_coro (Callable[[], Coroutine])

  • +
  • session_id (SoupSessionId)

  • +
  • dispatch_on_connect (bool)

  • +
  • sequence (int)

  • +
  • client_heartbeat_interval (int)

  • +
  • server_heartbeat_interval (int)

  • +
+
+
+
+
+abstract async on_login(msg)
+

Handle the login request from the client.

+
+
Parameters:
+

msg (LoginRequest) – LoginRequest message.

+
+
Returns:
+

LoginAccepted or LoginRejected message.

+
+
Return type:
+

LoginAccepted | LoginRejected

+
+
+
+ +
+
+abstract async on_unsequenced(msg)
+

Handle the unsequenced data from the client.

+
+
Parameters:
+

msg (UnSequencedData) – UnSequencedData message.

+
+
Return type:
+

None

+
+
+
+ +
+
+send_seq_msg(data)
+

Send sequenced data to the client.

+
+
Parameters:
+

data (bytes | SequencedData) – application payload

+
+
Return type:
+

None

+
+
+
+ +
+
+end_session()
+

End the session.

+
+ +
+
+async send_heartbeat()
+

Send heartbeat to the client.

+

This is called automatically by the session when the heartbeat interval expires. +:meta private:

+
+ +
+ +
+
+async nasdaq_protocols.soup.connect_async(remote, user, passwd, session_id='', sequence=1, on_msg_coro=None, on_close_coro=None, session_factory=None, client_heartbeat_interval=10, server_heartbeat_interval=10)
+

Connect to the SoupBinTCP server and login.

+

Using :param sequence the client can specify the sequence number of the next +message it expects to receive. The server will then send all messages with sequence +numbers greater than the specified sequence number.

+

To connect to the start of the stream, specify sequence=1, which is the default. +To connect to the end of the stream, specify sequence=0, new messages will be received. +To connect to a specific message, specify the sequence number of the message.

+
+
Parameters:
+
    +
  • remote (tuple[str, int]) – tuple of host and port

  • +
  • user (str) – Username to login

  • +
  • passwd (str) – Password to login

  • +
  • session_id (str) – Name of the session to join [Default=’’] .

  • +
  • sequence (int) – The sequence number. [Default=1]

  • +
  • on_msg_coro (Callable[[Any], Awaitable[None]] | None) – callback, message from server.

  • +
  • on_close_coro (Callable[[], Coroutine] | None) – callback, connection closed .

  • +
  • session_factory (Callable[[], SoupClientSession] | None) – Factory to create a SoupClientSession.

  • +
  • client_heartbeat_interval (int) – seconds between client heartbeats.

  • +
  • server_heartbeat_interval (int) – seconds between server heartbeats.

  • +
+
+
Returns:
+

SoupClientSession

+
+
Return type:
+

SoupClientSession

+
+
+
+ +
+

Soup Session

+
+
+class nasdaq_protocols.soup.session.SoupSessionId(host='nohost', port=0, session_type='norole', user='nouser', session='nosession')
+

Bases: SessionId

+

Identifier for a soup session.

+
+
Parameters:
+
    +
  • session_type (str) – The type of the session, either ‘client’ or ‘server’.

  • +
  • user (str) – The username.

  • +
  • session (str) – The session id.

  • +
  • host (str)

  • +
  • port (int)

  • +
+
+
+
+
+update(msg, transport=None)
+

Update the session id with the more information as and when it is available.

+
+
Parameters:
+
    +
  • msg (LoginRequest | LoginAccepted) – LoginRequest or LoginAccepted message.

  • +
  • transport (Transport | None) – asyncio.Transport object.

  • +
+
+
Returns:
+

self

+
+
+
+ +
+ +
+
+class nasdaq_protocols.soup.session.SoupClientSession(on_msg_coro=None, on_close_coro=None, session_id=NOTHING, dispatch_on_connect=False, *, sequence=1, client_heartbeat_interval=10, server_heartbeat_interval=10)
+

Bases: SoupSession

+

SoupBinTCP client session.

+

Upon successful connecting to the soup server, the client session is instantiated.

+
+
Parameters:
+
    +
  • on_msg_coro (Callable[[Any], Awaitable[None]])

  • +
  • on_close_coro (Callable[[], Coroutine])

  • +
  • session_id (SoupSessionId)

  • +
  • dispatch_on_connect (bool)

  • +
  • sequence (int)

  • +
  • client_heartbeat_interval (int)

  • +
  • server_heartbeat_interval (int)

  • +
+
+
+
+
+dispatch_on_connect: bool
+
+ +
+
+async login(msg)
+

Login to the soup server.

+

This is supposed to be the first message to be sent to server upon connection successful.

+
+
Parameters:
+

msg (LoginRequest) – LoginRequest message.

+
+
Returns:
+

self

+
+
Raises:
+

ConnectionRefusedError – If the server rejects the login request.

+
+
+
+ +
+
+send_unseq_data(data)
+

Send unsequenced data to the server. +:param data: application payload

+
+
Parameters:
+

data (bytes)

+
+
+
+ +
+
+SessionType: ClassVar[str] = 'client'
+
+ +
+
+log = <Logger SoupClientSession (WARNING)>
+
+ +
+ +
+
+class nasdaq_protocols.soup.session.SoupServerSession(on_close_coro=None, session_id=NOTHING, *, dispatch_on_connect=True, sequence=1, client_heartbeat_interval=10, server_heartbeat_interval=10)
+

Bases: SoupSession

+

Base class for all soup server sessions.

+

Any class that implements a soup server session must inherit from this class. +and implement the following methods:

+
    +
  • on_login

  • +
  • on_unsequenced

  • +
+
+
Parameters:
+
    +
  • on_close_coro (Callable[[], Coroutine])

  • +
  • session_id (SoupSessionId)

  • +
  • dispatch_on_connect (bool)

  • +
  • sequence (int)

  • +
  • client_heartbeat_interval (int)

  • +
  • server_heartbeat_interval (int)

  • +
+
+
+
+
+abstract async on_login(msg)
+

Handle the login request from the client.

+
+
Parameters:
+

msg (LoginRequest) – LoginRequest message.

+
+
Returns:
+

LoginAccepted or LoginRejected message.

+
+
Return type:
+

LoginAccepted | LoginRejected

+
+
+
+ +
+
+abstract async on_unsequenced(msg)
+

Handle the unsequenced data from the client.

+
+
Parameters:
+

msg (UnSequencedData) – UnSequencedData message.

+
+
Return type:
+

None

+
+
+
+ +
+
+send_seq_msg(data)
+

Send sequenced data to the client.

+
+
Parameters:
+

data (bytes | SequencedData) – application payload

+
+
Return type:
+

None

+
+
+
+ +
+
+end_session()
+

End the session.

+
+ +
+
+async send_heartbeat()
+

Send heartbeat to the client.

+

This is called automatically by the session when the heartbeat interval expires. +:meta private:

+
+ +
+ +
+
+

Soup Messages

+

nasdaq_protocols.soup.core module contains the implementation of the +soup messages.

+
+
+exception nasdaq_protocols.soup.core.InvalidSoupMessage
+

Bases: ValueError

+

Raised when an invalid soup message is received.

+
+ +
+
+class nasdaq_protocols.soup.core.LoginRejectReason(value)
+

Bases: Enum

+

Login Reject Reason sent from server in case of login failure.

+
+
+classmethod get(reason)
+

Get the LoginRejectReason enum value from the given reason.

+
+
Parameters:
+

reason (str)

+
+
+
+ +
+ +
+
+class nasdaq_protocols.soup.core.SoupMessage
+

Bases: Serializable[SoupMessage]

+

Base class for all soup messages.

+

Given raw bytes use this class to unpack the bytes to the corresponding soup message:

+
input_bytes = b'Atest      2                   '
+len, soup_msg = SoupMessage.from_bytes(input_bytes)
+type(soup_msg)
+
+
+to_bytes()
+

Pack the soup message to binary format

+
+
Returns:
+

tuple of length and bytes

+
+
Return type:
+

tuple[int, bytes]

+
+
+
+ +
+
+classmethod from_bytes(bytes_)
+

unpacks the bytes to the corresponding soup message

+
+
Parameters:
+

bytes – bytes to unpack

+
+
Returns:
+

tuple of length and soup message

+
+
Return type:
+

tuple[int, Type[SoupMessage]]

+
+
+
+ +
+ +
+
+class nasdaq_protocols.soup.core.LoginRequest(user, password, session, sequence)
+

Bases: SoupMessage

+

SoupBinTCP Login Request Message.

+
+
Parameters:
+
    +
  • user (str) – Username to login

  • +
  • password (str) – Password to login

  • +
  • session (str) – Name of the session to join [Default=’’] .

  • +
  • sequence (str) – The sequence number. [Default=1]

  • +
+
+
+
+
+to_bytes()
+

Pack the soup message to binary format

+
+
Returns:
+

+
+
Return type:
+

tuple[int, bytes]

+
+
+
+ +
+ +
+
+class nasdaq_protocols.soup.core.LoginAccepted(session_id, sequence)
+

Bases: SoupMessage

+

SoupBinTCP Login Accepted Message.

+
+
Parameters:
+
    +
  • session_id (str) – Name of the session joined [Default=’’] .

  • +
  • sequence (int) – The next sequence number.

  • +
+
+
+
+
+to_bytes()
+

Pack the soup message to binary format +:return: bytes

+
+
Return type:
+

tuple[int, bytes]

+
+
+
+ +
+ +
+
+class nasdaq_protocols.soup.core.LoginRejected(reason)
+

Bases: SoupMessage

+

SoupBinTCP Login Rejected Message.

+
+
Parameters:
+

reason (LoginRejectReason) – Reason for login failure. Refer LoginRejectReason

+
+
+
+
+to_bytes()
+

Pack the soup message to binary format +:return: bytes

+
+
Return type:
+

tuple[int, bytes]

+
+
+
+ +
+ +
+
+class nasdaq_protocols.soup.core.SequencedData(data)
+

Bases: SoupMessage

+

SoupBinTCP Sequenced Data Message.

+
+
Parameters:
+

data (bytes) – The application payload sent by the server.

+
+
+
+
+to_bytes()
+

Pack the soup message to binary format +:return: bytes

+
+
Return type:
+

tuple[int, bytes]

+
+
+
+ +
+ +
+
+class nasdaq_protocols.soup.core.UnSequencedData(data)
+

Bases: SoupMessage

+

SoupBinTCP Unsequenced Data Message.

+
+
Parameters:
+

data (bytes) – The application payload to be sent to server.

+
+
+
+
+to_bytes()
+

Pack the soup message to binary format +:return: bytes

+
+
Return type:
+

tuple[int, bytes]

+
+
+
+ +
+ +
+
+class nasdaq_protocols.soup.core.Debug(msg)
+

Bases: SoupMessage

+

SoupBinTCP Debug Message.

+
+
Parameters:
+

msg (str) – The debug message.

+
+
+
+
+to_bytes()
+

Pack the soup message to binary format +:return: bytes

+
+
Return type:
+

tuple[int, bytes]

+
+
+
+ +
+ +
+
+class nasdaq_protocols.soup.core.ClientHeartbeat
+

Bases: SoupMessage

+

SoupBinTCP Client Heartbeat Message.

+
+
+
+ +
+
+class nasdaq_protocols.soup.core.ServerHeartbeat
+

Bases: SoupMessage

+

SoupBinTCP Server Heartbeat Message.

+
+
+
+ +
+
+class nasdaq_protocols.soup.core.EndOfSession
+

Bases: SoupMessage

+

SoupBinTCP End of Session Message.

+

This message is sent from server to indicate the soup stream is now closed.

+
+
+
+ +
+
+class nasdaq_protocols.soup.core.LogoutRequest
+

Bases: SoupMessage

+

SoupBinTCP Logout Request Message.

+

This message is initiated by the client to sever for graceful session logoff.

+
+
+
+ +
+
+
+ + +
+
+
+
+
+ +
+
+
+ + + + + \ No newline at end of file diff --git a/developer_guide.html b/developer_guide.html new file mode 100644 index 0000000..8c59b16 --- /dev/null +++ b/developer_guide.html @@ -0,0 +1,145 @@ + + + + + + + + Developer’s Guide — Nasdaq Protocols Python Library 0.0.1 documentation + + + + + + + + + + + + +
+
+
+ +
+
+
+ +
+

Developer’s Guide

+

This guide is intended for developers who want to contribute to the +development of the nasdaq-protocols library.

+
+

Guidelines

+

Before merging to main, please ensure that the following guidelines are met:

+
    +
  • All existing tests are passing.

  • +
  • New tests are added when needed.

  • +
  • Pylint reports no errors, 10/10

  • +
  • Code is documented and docstrings are added when needed.

  • +
  • Documentation is included in the rst files.

  • +
+
+

Building

+
$ tox r
+
+
+

tox r will execute all of the following.

+
    +
  • tox -e lint - Runs linter and validates the code

  • +
  • tox -e test - Runs the pytest test cases

  • +
  • tox -e build - Builds the package sdist and wheel

  • +
  • tox -e doc - Builds the documentation

  • +
+
+
+

FAQ

+
    +
  • Why is pycharm debugger not stopping at breakpoints? +Disable the coverage statement from pytest.ini. Refer https://stackoverflow.com/a/56235965/4248850

  • +
  • Why is the coverage not reported in pycharm? +Disable the coverage statement from pytest.ini

  • +
+
+
+
+ + +
+
+
+
+
+ +
+
+
+ + + + + \ No newline at end of file diff --git a/genindex.html b/genindex.html new file mode 100644 index 0000000..2fd7497 --- /dev/null +++ b/genindex.html @@ -0,0 +1,840 @@ + + + + + + + Index — Nasdaq Protocols Python Library 0.0.1 documentation + + + + + + + + + + +
+
+
+ +
+
+
+ + +

Index

+ +
+ A + | B + | C + | D + | E + | F + | G + | H + | I + | L + | M + | N + | O + | P + | R + | S + | T + | U + +
+

A

+ + + +
+ +

B

+ + + +
+ +

C

+ + + +
+ +

D

+ + + +
+ +

E

+ + + +
+ +

F

+ + + +
+ +

G

+ + + +
+ +

H

+ + +
+ +

I

+ + + +
+ +

L

+ + + +
+ +

M

+ + + +
+ +

N

+ + + +
    +
  • + nasdaq_protocols + +
  • +
  • + nasdaq_protocols.common.message.types + +
  • +
  • + nasdaq_protocols.common.message_queue + +
  • +
  • + nasdaq_protocols.common.session + +
  • +
  • + nasdaq_protocols.common.types + +
  • +
  • + nasdaq_protocols.common.utils + +
  • +
    +
  • + nasdaq_protocols.itch + +
  • +
  • + nasdaq_protocols.itch.core + +
  • +
  • + nasdaq_protocols.ouch + +
  • +
  • + nasdaq_protocols.ouch.core + +
  • +
  • + nasdaq_protocols.soup + +
  • +
  • + nasdaq_protocols.soup.core + +
  • +
+ +

O

+ + + +
+ +

P

+ + + +
+ +

R

+ + + +
+ +

S

+ + + +
+ +

T

+ + + +
+ +

U

+ + + +
+ + + +
+
+
+
+
+ +
+
+
+ + + + + \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..b0bc3d6 --- /dev/null +++ b/index.html @@ -0,0 +1,131 @@ + + + + + + + + Welcome to nasdaq-protocols’s documentation! — Nasdaq Protocols Python Library 0.0.1 documentation + + + + + + + + + + + +
+
+
+ +
+
+
+ +
+

Welcome to nasdaq-protocols’s documentation!

+

nasdaq-protocols contains client side implementations of the various +publicly available protocols used by Nasdaq ecosystem.

+

This package contains only the core implementations of the protocols like message +serialization, deserialization, message validation and session handling. It does not +contain any actual messages that are exchanged between the client and the server.

+

The actual messages are application specific and hence has to be defined by the +user of this library. The user has to define the messages as per the protocol specification +by extending the base message class defined in the package.

+

Refer to the User Guide. for more information on how to define the messages and use this package.

+ +
+
+

Indices and tables

+ +
+ + +
+
+
+
+
+ +
+
+
+ + + + + \ No newline at end of file diff --git a/install.html b/install.html new file mode 100644 index 0000000..59f16fa --- /dev/null +++ b/install.html @@ -0,0 +1,114 @@ + + + + + + + + Installation — Nasdaq Protocols Python Library 0.0.1 documentation + + + + + + + + + + + + +
+
+
+ +
+
+
+ +
+

Installation

+

To use nasdaq-protocols, install it using pip:

+
$ pip install nasdaq-protocols
+
+
+
+ + +
+
+
+
+
+ +
+
+
+ + + + + \ No newline at end of file diff --git a/objects.inv b/objects.inv new file mode 100644 index 0000000..21fde36 Binary files /dev/null and b/objects.inv differ diff --git a/py-modindex.html b/py-modindex.html new file mode 100644 index 0000000..aaca855 --- /dev/null +++ b/py-modindex.html @@ -0,0 +1,169 @@ + + + + + + + Python Module Index — Nasdaq Protocols Python Library 0.0.1 documentation + + + + + + + + + + + + + +
+
+
+ +
+
+
+ + +

Python Module Index

+ +
+ n +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
 
+ n
+ nasdaq_protocols +
    + nasdaq_protocols.common.message.types +
    + nasdaq_protocols.common.message_queue +
    + nasdaq_protocols.common.session +
    + nasdaq_protocols.common.types +
    + nasdaq_protocols.common.utils +
    + nasdaq_protocols.itch +
    + nasdaq_protocols.itch.core +
    + nasdaq_protocols.ouch +
    + nasdaq_protocols.ouch.core +
    + nasdaq_protocols.soup +
    + nasdaq_protocols.soup.core +
+ + +
+
+
+
+
+ +
+
+
+ + + + + \ No newline at end of file diff --git a/search.html b/search.html new file mode 100644 index 0000000..3f19c15 --- /dev/null +++ b/search.html @@ -0,0 +1,126 @@ + + + + + + + Search — Nasdaq Protocols Python Library 0.0.1 documentation + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
+ +

Search

+ + + + +

+ Searching for multiple words only shows matches that contain + all words. +

+ + +
+ + + +
+ + +
+ + +
+
+
+
+
+ +
+
+
+ + + + + \ No newline at end of file diff --git a/searchindex.js b/searchindex.js new file mode 100644 index 0000000..a198931 --- /dev/null +++ b/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({"alltitles": {"API Reference": [[1, null]], "Building": [[6, "building"]], "Common api reference": [[2, null]], "Connect to Soup Server": [[13, "connect-to-soup-server"]], "Connecting to a ITCH Server": [[11, "connecting-to-a-itch-server"]], "Contents:": [[1, null], [7, null]], "Create New Project Guide": [[10, null]], "Developer\u2019s Guide": [[6, null]], "FAQ": [[6, "faq"]], "Guidelines": [[6, "guidelines"]], "ITCH API Reference": [[3, null]], "ITCH User Guide": [[11, null]], "Indices and tables": [[7, "indices-and-tables"]], "Installation": [[8, null]], "Itch": [[3, "module-nasdaq_protocols.itch"]], "Itch Messages": [[3, "module-nasdaq_protocols.itch.core"]], "Itch Session": [[3, "itch-session"]], "MIT License": [[0, null]], "OUCH API Reference": [[4, null]], "OUCH User Guide": [[12, null]], "Ouch": [[4, "module-nasdaq_protocols.ouch"]], "Ouch Messages": [[4, "module-nasdaq_protocols.ouch.core"]], "Ouch Session": [[4, "ouch-session"]], "SOUP API Reference": [[5, null]], "SOUP User Guide": [[13, null]], "Sample Message Definition": [[12, "sample-message-definition"]], "Sending Message to a OUCH Server": [[12, "sending-message-to-a-ouch-server"]], "Sending and Receiving OUCH messages": [[12, "sending-and-receiving-ouch-messages"]], "Soup": [[5, "module-nasdaq_protocols.soup"]], "Soup Messages": [[5, "module-nasdaq_protocols.soup.core"]], "Soup Session": [[5, "soup-session"]], "Steps": [[10, "steps"]], "User Guide": [[9, null]], "User Guides:": [[9, null]], "Welcome to nasdaq-protocols\u2019s documentation!": [[7, null]]}, "docnames": ["LICENSE", "api_reference", "api_reference_common", "api_reference_itch", "api_reference_ouch", "api_reference_soup", "developer_guide", "index", "install", "user_guide", "user_guide_create_new_project", "user_guide_itch", "user_guide_ouch", "user_guide_soup"], "envversion": {"sphinx": 63, "sphinx.domains.c": 3, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 9, "sphinx.domains.index": 1, "sphinx.domains.javascript": 3, "sphinx.domains.math": 2, "sphinx.domains.python": 4, "sphinx.domains.rst": 2, "sphinx.domains.std": 2}, "filenames": ["LICENSE.rst", "api_reference.rst", "api_reference_common.rst", "api_reference_itch.rst", "api_reference_ouch.rst", "api_reference_soup.rst", "developer_guide.rst", "index.rst", "install.rst", "user_guide.rst", "user_guide_create_new_project.rst", "user_guide_itch.rst", "user_guide_ouch.rst", "user_guide_soup.rst"], "indexentries": {"asciistring (class in nasdaq_protocols.common.message.types)": [[2, "nasdaq_protocols.common.message.types.AsciiString", false]], "asyncsession (class in nasdaq_protocols.common.session)": [[2, "nasdaq_protocols.common.session.AsyncSession", false]], "boolean (class in nasdaq_protocols.common.message.types)": [[2, "nasdaq_protocols.common.message.types.Boolean", false]], "byte (class in nasdaq_protocols.common.message.types)": [[2, "nasdaq_protocols.common.message.types.Byte", false]], "charascii (class in nasdaq_protocols.common.message.types)": [[2, "nasdaq_protocols.common.message.types.CharAscii", false]], "chariso8599 (class in nasdaq_protocols.common.message.types)": [[2, "nasdaq_protocols.common.message.types.CharIso8599", false]], "clientheartbeat (class in nasdaq_protocols.soup)": [[5, "nasdaq_protocols.soup.ClientHeartbeat", false]], "clientheartbeat (class in nasdaq_protocols.soup.core)": [[5, "nasdaq_protocols.soup.core.ClientHeartbeat", false]], "clientsession (class in nasdaq_protocols.itch.session)": [[3, "nasdaq_protocols.itch.session.ClientSession", false]], "clientsession (class in nasdaq_protocols.ouch.session)": [[4, "nasdaq_protocols.ouch.session.ClientSession", false]], "close() (nasdaq_protocols.common.session.asyncsession method)": [[2, "nasdaq_protocols.common.session.AsyncSession.close", false]], "close() (nasdaq_protocols.itch.session.clientsession method)": [[3, "nasdaq_protocols.itch.session.ClientSession.close", false]], "close() (nasdaq_protocols.ouch.session.clientsession method)": [[4, "nasdaq_protocols.ouch.session.ClientSession.close", false]], "closed (nasdaq_protocols.itch.session.clientsession attribute)": [[3, "nasdaq_protocols.itch.session.ClientSession.closed", false]], "closed (nasdaq_protocols.ouch.session.clientsession attribute)": [[4, "nasdaq_protocols.ouch.session.ClientSession.closed", false]], "connect_async() (in module nasdaq_protocols.itch)": [[3, "nasdaq_protocols.itch.connect_async", false]], "connect_async() (in module nasdaq_protocols.ouch)": [[4, "nasdaq_protocols.ouch.connect_async", false]], "connect_async() (in module nasdaq_protocols.soup)": [[5, "nasdaq_protocols.soup.connect_async", false]], "debug (class in nasdaq_protocols.soup)": [[5, "nasdaq_protocols.soup.Debug", false]], "debug (class in nasdaq_protocols.soup.core)": [[5, "nasdaq_protocols.soup.core.Debug", false]], "decode() (nasdaq_protocols.itch.session.clientsession class method)": [[3, "nasdaq_protocols.itch.session.ClientSession.decode", false]], "decode() (nasdaq_protocols.ouch.session.clientsession method)": [[4, "nasdaq_protocols.ouch.session.ClientSession.decode", false]], "dispatch_on_connect (nasdaq_protocols.soup.session.soupclientsession attribute)": [[5, "nasdaq_protocols.soup.session.SoupClientSession.dispatch_on_connect", false]], "dispatchablemessagequeue (class in nasdaq_protocols.common.message_queue)": [[2, "nasdaq_protocols.common.message_queue.DispatchableMessageQueue", false]], "end_session() (nasdaq_protocols.soup.session.soupserversession method)": [[5, "nasdaq_protocols.soup.session.SoupServerSession.end_session", false]], "end_session() (nasdaq_protocols.soup.soupserversession method)": [[5, "nasdaq_protocols.soup.SoupServerSession.end_session", false]], "endofqueue": [[2, "nasdaq_protocols.common.types.EndOfQueue", false]], "endofsession (class in nasdaq_protocols.soup)": [[5, "nasdaq_protocols.soup.EndOfSession", false]], "endofsession (class in nasdaq_protocols.soup.core)": [[5, "nasdaq_protocols.soup.core.EndOfSession", false]], "fixedasciistring (class in nasdaq_protocols.common.message.types)": [[2, "nasdaq_protocols.common.message.types.FixedAsciiString", false]], "fixedisostring (class in nasdaq_protocols.common.message.types)": [[2, "nasdaq_protocols.common.message.types.FixedIsoString", false]], "from_bytes() (nasdaq_protocols.common.types.serializable class method)": [[2, "nasdaq_protocols.common.types.Serializable.from_bytes", false]], "from_bytes() (nasdaq_protocols.itch.core.itchmessageid class method)": [[3, "nasdaq_protocols.itch.core.ItchMessageId.from_bytes", false]], "from_bytes() (nasdaq_protocols.itch.itchmessageid class method)": [[3, "nasdaq_protocols.itch.ItchMessageId.from_bytes", false]], "from_bytes() (nasdaq_protocols.ouch.core.ouchmessageid class method)": [[4, "nasdaq_protocols.ouch.core.OuchMessageId.from_bytes", false]], "from_bytes() (nasdaq_protocols.ouch.ouchmessageid class method)": [[4, "nasdaq_protocols.ouch.OuchMessageId.from_bytes", false]], "from_bytes() (nasdaq_protocols.soup.core.soupmessage class method)": [[5, "nasdaq_protocols.soup.core.SoupMessage.from_bytes", false]], "from_bytes() (nasdaq_protocols.soup.soupmessage class method)": [[5, "nasdaq_protocols.soup.SoupMessage.from_bytes", false]], "from_str (nasdaq_protocols.common.message.types.charascii attribute)": [[2, "nasdaq_protocols.common.message.types.CharAscii.from_str", false]], "from_str (nasdaq_protocols.common.message.types.fixedasciistring attribute)": [[2, "nasdaq_protocols.common.message.types.FixedAsciiString.from_str", false]], "from_str (nasdaq_protocols.common.message.types.fixedisostring attribute)": [[2, "nasdaq_protocols.common.message.types.FixedIsoString.from_str", false]], "from_str (nasdaq_protocols.common.message.types.int attribute)": [[2, "nasdaq_protocols.common.message.types.Int.from_str", false]], "get() (nasdaq_protocols.common.message_queue.dispatchablemessagequeue method)": [[2, "nasdaq_protocols.common.message_queue.DispatchableMessageQueue.get", false]], "get() (nasdaq_protocols.soup.core.loginrejectreason class method)": [[5, "nasdaq_protocols.soup.core.LoginRejectReason.get", false]], "get() (nasdaq_protocols.soup.loginrejectreason class method)": [[5, "nasdaq_protocols.soup.LoginRejectReason.get", false]], "get_nowait() (nasdaq_protocols.common.message_queue.dispatchablemessagequeue method)": [[2, "nasdaq_protocols.common.message_queue.DispatchableMessageQueue.get_nowait", false]], "heartbeatmonitor (class in nasdaq_protocols.common.session)": [[2, "nasdaq_protocols.common.session.HeartbeatMonitor", false]], "initiate_close() (nasdaq_protocols.common.session.asyncsession method)": [[2, "nasdaq_protocols.common.session.AsyncSession.initiate_close", false]], "int (class in nasdaq_protocols.common.message.types)": [[2, "nasdaq_protocols.common.message.types.Int", false]], "intbe (class in nasdaq_protocols.common.message.types)": [[2, "nasdaq_protocols.common.message.types.IntBE", false]], "invalidsoupmessage": [[5, "nasdaq_protocols.soup.InvalidSoupMessage", false], [5, "nasdaq_protocols.soup.core.InvalidSoupMessage", false]], "is_active() (nasdaq_protocols.common.session.asyncsession method)": [[2, "nasdaq_protocols.common.session.AsyncSession.is_active", false]], "is_closed() (nasdaq_protocols.common.session.asyncsession method)": [[2, "nasdaq_protocols.common.session.AsyncSession.is_closed", false]], "is_dispatching() (nasdaq_protocols.common.message_queue.dispatchablemessagequeue method)": [[2, "nasdaq_protocols.common.message_queue.DispatchableMessageQueue.is_dispatching", false]], "is_running() (nasdaq_protocols.common.session.heartbeatmonitor method)": [[2, "nasdaq_protocols.common.session.HeartbeatMonitor.is_running", false]], "is_stopped() (nasdaq_protocols.common.message_queue.dispatchablemessagequeue method)": [[2, "nasdaq_protocols.common.message_queue.DispatchableMessageQueue.is_stopped", false]], "iso8859string (class in nasdaq_protocols.common.message.types)": [[2, "nasdaq_protocols.common.message.types.Iso8859String", false]], "itchmessageid (class in nasdaq_protocols.itch)": [[3, "nasdaq_protocols.itch.ItchMessageId", false]], "itchmessageid (class in nasdaq_protocols.itch.core)": [[3, "nasdaq_protocols.itch.core.ItchMessageId", false]], "itchsessionid (class in nasdaq_protocols.itch.session)": [[3, "nasdaq_protocols.itch.session.ItchSessionId", false]], "log (nasdaq_protocols.itch.session.clientsession attribute)": [[3, "nasdaq_protocols.itch.session.ClientSession.log", false]], "log (nasdaq_protocols.ouch.session.clientsession attribute)": [[4, "nasdaq_protocols.ouch.session.ClientSession.log", false]], "log (nasdaq_protocols.soup.session.soupclientsession attribute)": [[5, "nasdaq_protocols.soup.session.SoupClientSession.log", false]], "logable() (in module nasdaq_protocols.common.utils)": [[2, "nasdaq_protocols.common.utils.logable", false]], "login() (nasdaq_protocols.soup.session.soupclientsession method)": [[5, "nasdaq_protocols.soup.session.SoupClientSession.login", false]], "login() (nasdaq_protocols.soup.soupclientsession method)": [[5, "nasdaq_protocols.soup.SoupClientSession.login", false]], "loginaccepted (class in nasdaq_protocols.soup)": [[5, "nasdaq_protocols.soup.LoginAccepted", false]], "loginaccepted (class in nasdaq_protocols.soup.core)": [[5, "nasdaq_protocols.soup.core.LoginAccepted", false]], "loginrejected (class in nasdaq_protocols.soup)": [[5, "nasdaq_protocols.soup.LoginRejected", false]], "loginrejected (class in nasdaq_protocols.soup.core)": [[5, "nasdaq_protocols.soup.core.LoginRejected", false]], "loginrejectreason (class in nasdaq_protocols.soup)": [[5, "nasdaq_protocols.soup.LoginRejectReason", false]], "loginrejectreason (class in nasdaq_protocols.soup.core)": [[5, "nasdaq_protocols.soup.core.LoginRejectReason", false]], "loginrequest (class in nasdaq_protocols.soup)": [[5, "nasdaq_protocols.soup.LoginRequest", false]], "loginrequest (class in nasdaq_protocols.soup.core)": [[5, "nasdaq_protocols.soup.core.LoginRequest", false]], "logout() (nasdaq_protocols.soup.soupsession method)": [[5, "nasdaq_protocols.soup.SoupSession.logout", false]], "logoutrequest (class in nasdaq_protocols.soup)": [[5, "nasdaq_protocols.soup.LogoutRequest", false]], "logoutrequest (class in nasdaq_protocols.soup.core)": [[5, "nasdaq_protocols.soup.core.LogoutRequest", false]], "long (class in nasdaq_protocols.common.message.types)": [[2, "nasdaq_protocols.common.message.types.Long", false]], "longbe (class in nasdaq_protocols.common.message.types)": [[2, "nasdaq_protocols.common.message.types.LongBE", false]], "message (class in nasdaq_protocols.itch)": [[3, "nasdaq_protocols.itch.Message", false]], "message (class in nasdaq_protocols.itch.core)": [[3, "nasdaq_protocols.itch.core.Message", false]], "message (class in nasdaq_protocols.ouch)": [[4, "nasdaq_protocols.ouch.Message", false]], "message (class in nasdaq_protocols.ouch.core)": [[4, "nasdaq_protocols.ouch.core.Message", false]], "module": [[2, "module-nasdaq_protocols.common.message.types", false], [2, "module-nasdaq_protocols.common.message_queue", false], [2, "module-nasdaq_protocols.common.session", false], [2, "module-nasdaq_protocols.common.types", false], [2, "module-nasdaq_protocols.common.utils", false], [3, "module-nasdaq_protocols.itch", false], [3, "module-nasdaq_protocols.itch.core", false], [4, "module-nasdaq_protocols.ouch", false], [4, "module-nasdaq_protocols.ouch.core", false], [5, "module-nasdaq_protocols.soup", false], [5, "module-nasdaq_protocols.soup.core", false], [7, "module-nasdaq_protocols", false]], "msgidclass (nasdaq_protocols.itch.core.message attribute)": [[3, "nasdaq_protocols.itch.core.Message.MsgIdClass", false]], "msgidclass (nasdaq_protocols.itch.message attribute)": [[3, "nasdaq_protocols.itch.Message.MsgIdClass", false]], "msgidclass (nasdaq_protocols.ouch.core.message attribute)": [[4, "nasdaq_protocols.ouch.core.Message.MsgIdClass", false]], "msgidclass (nasdaq_protocols.ouch.message attribute)": [[4, "nasdaq_protocols.ouch.Message.MsgIdClass", false]], "nasdaq_protocols": [[7, "module-nasdaq_protocols", false]], "nasdaq_protocols.common.message.types": [[2, "module-nasdaq_protocols.common.message.types", false]], "nasdaq_protocols.common.message_queue": [[2, "module-nasdaq_protocols.common.message_queue", false]], "nasdaq_protocols.common.session": [[2, "module-nasdaq_protocols.common.session", false]], "nasdaq_protocols.common.types": [[2, "module-nasdaq_protocols.common.types", false]], "nasdaq_protocols.common.utils": [[2, "module-nasdaq_protocols.common.utils", false]], "nasdaq_protocols.itch": [[3, "module-nasdaq_protocols.itch", false]], "nasdaq_protocols.itch.core": [[3, "module-nasdaq_protocols.itch.core", false]], "nasdaq_protocols.ouch": [[4, "module-nasdaq_protocols.ouch", false]], "nasdaq_protocols.ouch.core": [[4, "module-nasdaq_protocols.ouch.core", false]], "nasdaq_protocols.soup": [[5, "module-nasdaq_protocols.soup", false]], "nasdaq_protocols.soup.core": [[5, "module-nasdaq_protocols.soup.core", false]], "on_close_coro (nasdaq_protocols.itch.session.clientsession attribute)": [[3, "nasdaq_protocols.itch.session.ClientSession.on_close_coro", false]], "on_close_coro (nasdaq_protocols.ouch.session.clientsession attribute)": [[4, "nasdaq_protocols.ouch.session.ClientSession.on_close_coro", false]], "on_data() (nasdaq_protocols.common.session.reader method)": [[2, "nasdaq_protocols.common.session.Reader.on_data", false]], "on_login() (nasdaq_protocols.soup.session.soupserversession method)": [[5, "nasdaq_protocols.soup.session.SoupServerSession.on_login", false]], "on_login() (nasdaq_protocols.soup.soupserversession method)": [[5, "nasdaq_protocols.soup.SoupServerSession.on_login", false]], "on_msg_coro (nasdaq_protocols.itch.session.clientsession attribute)": [[3, "nasdaq_protocols.itch.session.ClientSession.on_msg_coro", false]], "on_msg_coro (nasdaq_protocols.ouch.session.clientsession attribute)": [[4, "nasdaq_protocols.ouch.session.ClientSession.on_msg_coro", false]], "on_unsequenced() (nasdaq_protocols.soup.session.soupserversession method)": [[5, "nasdaq_protocols.soup.session.SoupServerSession.on_unsequenced", false]], "on_unsequenced() (nasdaq_protocols.soup.soupserversession method)": [[5, "nasdaq_protocols.soup.SoupServerSession.on_unsequenced", false]], "ouchmessageid (class in nasdaq_protocols.ouch)": [[4, "nasdaq_protocols.ouch.OuchMessageId", false]], "ouchmessageid (class in nasdaq_protocols.ouch.core)": [[4, "nasdaq_protocols.ouch.core.OuchMessageId", false]], "ouchsessionid (class in nasdaq_protocols.ouch.session)": [[4, "nasdaq_protocols.ouch.session.OuchSessionId", false]], "pause_dispatching() (nasdaq_protocols.common.message_queue.dispatchablemessagequeue method)": [[2, "nasdaq_protocols.common.message_queue.DispatchableMessageQueue.pause_dispatching", false]], "ping() (nasdaq_protocols.common.session.heartbeatmonitor method)": [[2, "nasdaq_protocols.common.session.HeartbeatMonitor.ping", false]], "put() (nasdaq_protocols.common.message_queue.dispatchablemessagequeue method)": [[2, "nasdaq_protocols.common.message_queue.DispatchableMessageQueue.put", false]], "put_nowait() (nasdaq_protocols.common.message_queue.dispatchablemessagequeue method)": [[2, "nasdaq_protocols.common.message_queue.DispatchableMessageQueue.put_nowait", false]], "reader (class in nasdaq_protocols.common.session)": [[2, "nasdaq_protocols.common.session.Reader", false]], "receive_message() (nasdaq_protocols.itch.session.clientsession method)": [[3, "nasdaq_protocols.itch.session.ClientSession.receive_message", false]], "receive_message() (nasdaq_protocols.ouch.session.clientsession method)": [[4, "nasdaq_protocols.ouch.session.ClientSession.receive_message", false]], "receive_msg() (nasdaq_protocols.common.session.asyncsession method)": [[2, "nasdaq_protocols.common.session.AsyncSession.receive_msg", false]], "receive_msg_nowait() (nasdaq_protocols.common.session.asyncsession method)": [[2, "nasdaq_protocols.common.session.AsyncSession.receive_msg_nowait", false]], "send_debug() (nasdaq_protocols.soup.soupsession method)": [[5, "nasdaq_protocols.soup.SoupSession.send_debug", false]], "send_heartbeat() (nasdaq_protocols.common.session.asyncsession method)": [[2, "nasdaq_protocols.common.session.AsyncSession.send_heartbeat", false]], "send_heartbeat() (nasdaq_protocols.soup.session.soupserversession method)": [[5, "nasdaq_protocols.soup.session.SoupServerSession.send_heartbeat", false]], "send_heartbeat() (nasdaq_protocols.soup.soupserversession method)": [[5, "nasdaq_protocols.soup.SoupServerSession.send_heartbeat", false]], "send_message() (nasdaq_protocols.ouch.session.clientsession method)": [[4, "nasdaq_protocols.ouch.session.ClientSession.send_message", false]], "send_msg() (nasdaq_protocols.common.session.asyncsession method)": [[2, "nasdaq_protocols.common.session.AsyncSession.send_msg", false]], "send_msg() (nasdaq_protocols.soup.soupsession method)": [[5, "nasdaq_protocols.soup.SoupSession.send_msg", false]], "send_seq_msg() (nasdaq_protocols.soup.session.soupserversession method)": [[5, "nasdaq_protocols.soup.session.SoupServerSession.send_seq_msg", false]], "send_seq_msg() (nasdaq_protocols.soup.soupserversession method)": [[5, "nasdaq_protocols.soup.SoupServerSession.send_seq_msg", false]], "send_unseq_data() (nasdaq_protocols.soup.session.soupclientsession method)": [[5, "nasdaq_protocols.soup.session.SoupClientSession.send_unseq_data", false]], "send_unseq_data() (nasdaq_protocols.soup.soupclientsession method)": [[5, "nasdaq_protocols.soup.SoupClientSession.send_unseq_data", false]], "sequenceddata (class in nasdaq_protocols.soup)": [[5, "nasdaq_protocols.soup.SequencedData", false]], "sequenceddata (class in nasdaq_protocols.soup.core)": [[5, "nasdaq_protocols.soup.core.SequencedData", false]], "serializable (class in nasdaq_protocols.common.types)": [[2, "nasdaq_protocols.common.types.Serializable", false]], "serverheartbeat (class in nasdaq_protocols.soup)": [[5, "nasdaq_protocols.soup.ServerHeartbeat", false]], "serverheartbeat (class in nasdaq_protocols.soup.core)": [[5, "nasdaq_protocols.soup.core.ServerHeartbeat", false]], "sessionid (class in nasdaq_protocols.common.session)": [[2, "nasdaq_protocols.common.session.SessionId", false]], "sessiontype (nasdaq_protocols.soup.session.soupclientsession attribute)": [[5, "nasdaq_protocols.soup.session.SoupClientSession.SessionType", false]], "set_transport() (nasdaq_protocols.common.session.sessionid method)": [[2, "nasdaq_protocols.common.session.SessionId.set_transport", false]], "short (class in nasdaq_protocols.common.message.types)": [[2, "nasdaq_protocols.common.message.types.Short", false]], "shortbe (class in nasdaq_protocols.common.message.types)": [[2, "nasdaq_protocols.common.message.types.ShortBE", false]], "soup_session (nasdaq_protocols.itch.session.clientsession attribute)": [[3, "nasdaq_protocols.itch.session.ClientSession.soup_session", false]], "soup_session (nasdaq_protocols.ouch.session.clientsession attribute)": [[4, "nasdaq_protocols.ouch.session.ClientSession.soup_session", false]], "soupclientsession (class in nasdaq_protocols.soup)": [[5, "nasdaq_protocols.soup.SoupClientSession", false]], "soupclientsession (class in nasdaq_protocols.soup.session)": [[5, "nasdaq_protocols.soup.session.SoupClientSession", false]], "soupmessage (class in nasdaq_protocols.soup)": [[5, "nasdaq_protocols.soup.SoupMessage", false]], "soupmessage (class in nasdaq_protocols.soup.core)": [[5, "nasdaq_protocols.soup.core.SoupMessage", false]], "soupserversession (class in nasdaq_protocols.soup)": [[5, "nasdaq_protocols.soup.SoupServerSession", false]], "soupserversession (class in nasdaq_protocols.soup.session)": [[5, "nasdaq_protocols.soup.session.SoupServerSession", false]], "soupsession (class in nasdaq_protocols.soup)": [[5, "nasdaq_protocols.soup.SoupSession", false]], "soupsessionid (class in nasdaq_protocols.soup)": [[5, "nasdaq_protocols.soup.SoupSessionId", false]], "soupsessionid (class in nasdaq_protocols.soup.session)": [[5, "nasdaq_protocols.soup.session.SoupSessionId", false]], "start_dispatching() (nasdaq_protocols.common.message_queue.dispatchablemessagequeue method)": [[2, "nasdaq_protocols.common.message_queue.DispatchableMessageQueue.start_dispatching", false]], "start_dispatching() (nasdaq_protocols.common.session.asyncsession method)": [[2, "nasdaq_protocols.common.session.AsyncSession.start_dispatching", false]], "start_heartbeats() (nasdaq_protocols.common.session.asyncsession method)": [[2, "nasdaq_protocols.common.session.AsyncSession.start_heartbeats", false]], "start_server() (in module nasdaq_protocols.common.utils)": [[2, "nasdaq_protocols.common.utils.start_server", false]], "stateerror": [[2, "nasdaq_protocols.common.types.StateError", false]], "stop() (nasdaq_protocols.common.message_queue.dispatchablemessagequeue method)": [[2, "nasdaq_protocols.common.message_queue.DispatchableMessageQueue.stop", false]], "stop() (nasdaq_protocols.common.session.heartbeatmonitor method)": [[2, "nasdaq_protocols.common.session.HeartbeatMonitor.stop", false]], "stop_task() (in module nasdaq_protocols.common.utils)": [[2, "nasdaq_protocols.common.utils.stop_task", false]], "stoppable (class in nasdaq_protocols.common.types)": [[2, "nasdaq_protocols.common.types.Stoppable", false]], "to_bytes() (nasdaq_protocols.common.types.serializable method)": [[2, "nasdaq_protocols.common.types.Serializable.to_bytes", false]], "to_bytes() (nasdaq_protocols.itch.core.itchmessageid method)": [[3, "nasdaq_protocols.itch.core.ItchMessageId.to_bytes", false]], "to_bytes() (nasdaq_protocols.itch.itchmessageid method)": [[3, "nasdaq_protocols.itch.ItchMessageId.to_bytes", false]], "to_bytes() (nasdaq_protocols.ouch.core.ouchmessageid method)": [[4, "nasdaq_protocols.ouch.core.OuchMessageId.to_bytes", false]], "to_bytes() (nasdaq_protocols.ouch.ouchmessageid method)": [[4, "nasdaq_protocols.ouch.OuchMessageId.to_bytes", false]], "to_bytes() (nasdaq_protocols.soup.core.debug method)": [[5, "nasdaq_protocols.soup.core.Debug.to_bytes", false]], "to_bytes() (nasdaq_protocols.soup.core.loginaccepted method)": [[5, "nasdaq_protocols.soup.core.LoginAccepted.to_bytes", false]], "to_bytes() (nasdaq_protocols.soup.core.loginrejected method)": [[5, "nasdaq_protocols.soup.core.LoginRejected.to_bytes", false]], "to_bytes() (nasdaq_protocols.soup.core.loginrequest method)": [[5, "nasdaq_protocols.soup.core.LoginRequest.to_bytes", false]], "to_bytes() (nasdaq_protocols.soup.core.sequenceddata method)": [[5, "nasdaq_protocols.soup.core.SequencedData.to_bytes", false]], "to_bytes() (nasdaq_protocols.soup.core.soupmessage method)": [[5, "nasdaq_protocols.soup.core.SoupMessage.to_bytes", false]], "to_bytes() (nasdaq_protocols.soup.core.unsequenceddata method)": [[5, "nasdaq_protocols.soup.core.UnSequencedData.to_bytes", false]], "to_bytes() (nasdaq_protocols.soup.debug method)": [[5, "nasdaq_protocols.soup.Debug.to_bytes", false]], "to_bytes() (nasdaq_protocols.soup.loginaccepted method)": [[5, "nasdaq_protocols.soup.LoginAccepted.to_bytes", false]], "to_bytes() (nasdaq_protocols.soup.loginrejected method)": [[5, "nasdaq_protocols.soup.LoginRejected.to_bytes", false]], "to_bytes() (nasdaq_protocols.soup.loginrequest method)": [[5, "nasdaq_protocols.soup.LoginRequest.to_bytes", false]], "to_bytes() (nasdaq_protocols.soup.sequenceddata method)": [[5, "nasdaq_protocols.soup.SequencedData.to_bytes", false]], "to_bytes() (nasdaq_protocols.soup.soupmessage method)": [[5, "nasdaq_protocols.soup.SoupMessage.to_bytes", false]], "to_bytes() (nasdaq_protocols.soup.unsequenceddata method)": [[5, "nasdaq_protocols.soup.UnSequencedData.to_bytes", false]], "to_str (nasdaq_protocols.common.message.types.charascii attribute)": [[2, "nasdaq_protocols.common.message.types.CharAscii.to_str", false]], "to_str (nasdaq_protocols.common.message.types.fixedasciistring attribute)": [[2, "nasdaq_protocols.common.message.types.FixedAsciiString.to_str", false]], "to_str (nasdaq_protocols.common.message.types.fixedisostring attribute)": [[2, "nasdaq_protocols.common.message.types.FixedIsoString.to_str", false]], "to_str (nasdaq_protocols.common.message.types.int attribute)": [[2, "nasdaq_protocols.common.message.types.Int.to_str", false]], "type_cls (nasdaq_protocols.common.message.types.boolean attribute)": [[2, "nasdaq_protocols.common.message.types.Boolean.type_cls", false]], "type_cls (nasdaq_protocols.common.message.types.charascii attribute)": [[2, "nasdaq_protocols.common.message.types.CharAscii.type_cls", false]], "type_cls (nasdaq_protocols.common.message.types.fixedasciistring attribute)": [[2, "nasdaq_protocols.common.message.types.FixedAsciiString.type_cls", false]], "type_cls (nasdaq_protocols.common.message.types.fixedisostring attribute)": [[2, "nasdaq_protocols.common.message.types.FixedIsoString.type_cls", false]], "type_cls (nasdaq_protocols.common.message.types.int attribute)": [[2, "nasdaq_protocols.common.message.types.Int.type_cls", false]], "typedefinition (class in nasdaq_protocols.common.types)": [[2, "nasdaq_protocols.common.types.TypeDefinition", false]], "unsequenceddata (class in nasdaq_protocols.soup)": [[5, "nasdaq_protocols.soup.UnSequencedData", false]], "unsequenceddata (class in nasdaq_protocols.soup.core)": [[5, "nasdaq_protocols.soup.core.UnSequencedData", false]], "unsignedint (class in nasdaq_protocols.common.message.types)": [[2, "nasdaq_protocols.common.message.types.UnsignedInt", false]], "unsignedintbe (class in nasdaq_protocols.common.message.types)": [[2, "nasdaq_protocols.common.message.types.UnsignedIntBE", false]], "unsignedlong (class in nasdaq_protocols.common.message.types)": [[2, "nasdaq_protocols.common.message.types.UnsignedLong", false]], "unsignedlongbe (class in nasdaq_protocols.common.message.types)": [[2, "nasdaq_protocols.common.message.types.UnsignedLongBE", false]], "unsignedshort (class in nasdaq_protocols.common.message.types)": [[2, "nasdaq_protocols.common.message.types.UnsignedShort", false]], "unsignedshortbe (class in nasdaq_protocols.common.message.types)": [[2, "nasdaq_protocols.common.message.types.UnsignedShortBE", false]], "update() (nasdaq_protocols.soup.session.soupsessionid method)": [[5, "nasdaq_protocols.soup.session.SoupSessionId.update", false]], "update() (nasdaq_protocols.soup.soupsessionid method)": [[5, "nasdaq_protocols.soup.SoupSessionId.update", false]]}, "objects": {"": [[7, 0, 0, "-", "nasdaq_protocols"]], "nasdaq_protocols": [[3, 0, 0, "-", "itch"], [4, 0, 0, "-", "ouch"], [5, 0, 0, "-", "soup"]], "nasdaq_protocols.common": [[2, 0, 0, "-", "message_queue"], [2, 0, 0, "-", "session"], [2, 0, 0, "-", "types"], [2, 0, 0, "-", "utils"]], "nasdaq_protocols.common.message": [[2, 0, 0, "-", "types"]], "nasdaq_protocols.common.message.types": [[2, 1, 1, "", "AsciiString"], [2, 1, 1, "", "Boolean"], [2, 1, 1, "", "Byte"], [2, 1, 1, "", "CharAscii"], [2, 1, 1, "", "CharIso8599"], [2, 1, 1, "", "FixedAsciiString"], [2, 1, 1, "", "FixedIsoString"], [2, 1, 1, "", "Int"], [2, 1, 1, "", "IntBE"], [2, 1, 1, "", "Iso8859String"], [2, 1, 1, "", "Long"], [2, 1, 1, "", "LongBE"], [2, 1, 1, "", "Short"], [2, 1, 1, "", "ShortBE"], [2, 1, 1, "", "UnsignedInt"], [2, 1, 1, "", "UnsignedIntBE"], [2, 1, 1, "", "UnsignedLong"], [2, 1, 1, "", "UnsignedLongBE"], [2, 1, 1, "", "UnsignedShort"], [2, 1, 1, "", "UnsignedShortBE"]], "nasdaq_protocols.common.message.types.Boolean": [[2, 2, 1, "", "type_cls"]], "nasdaq_protocols.common.message.types.CharAscii": [[2, 2, 1, "", "from_str"], [2, 2, 1, "", "to_str"], [2, 2, 1, "", "type_cls"]], "nasdaq_protocols.common.message.types.FixedAsciiString": [[2, 2, 1, "", "from_str"], [2, 2, 1, "", "to_str"], [2, 2, 1, "", "type_cls"]], "nasdaq_protocols.common.message.types.FixedIsoString": [[2, 2, 1, "", "from_str"], [2, 2, 1, "", "to_str"], [2, 2, 1, "", "type_cls"]], "nasdaq_protocols.common.message.types.Int": [[2, 2, 1, "", "from_str"], [2, 2, 1, "", "to_str"], [2, 2, 1, "", "type_cls"]], "nasdaq_protocols.common.message_queue": [[2, 1, 1, "", "DispatchableMessageQueue"]], "nasdaq_protocols.common.message_queue.DispatchableMessageQueue": [[2, 3, 1, "", "get"], [2, 3, 1, "", "get_nowait"], [2, 3, 1, "", "is_dispatching"], [2, 3, 1, "", "is_stopped"], [2, 3, 1, "", "pause_dispatching"], [2, 3, 1, "", "put"], [2, 3, 1, "", "put_nowait"], [2, 3, 1, "", "start_dispatching"], [2, 3, 1, "", "stop"]], "nasdaq_protocols.common.session": [[2, 1, 1, "", "AsyncSession"], [2, 1, 1, "", "HeartbeatMonitor"], [2, 1, 1, "", "Reader"], [2, 1, 1, "", "SessionId"]], "nasdaq_protocols.common.session.AsyncSession": [[2, 3, 1, "", "close"], [2, 3, 1, "", "initiate_close"], [2, 3, 1, "", "is_active"], [2, 3, 1, "", "is_closed"], [2, 3, 1, "", "receive_msg"], [2, 3, 1, "", "receive_msg_nowait"], [2, 3, 1, "", "send_heartbeat"], [2, 3, 1, "", "send_msg"], [2, 3, 1, "", "start_dispatching"], [2, 3, 1, "", "start_heartbeats"]], "nasdaq_protocols.common.session.HeartbeatMonitor": [[2, 3, 1, "", "is_running"], [2, 3, 1, "", "ping"], [2, 3, 1, "", "stop"]], "nasdaq_protocols.common.session.Reader": [[2, 3, 1, "", "on_data"]], "nasdaq_protocols.common.session.SessionId": [[2, 3, 1, "", "set_transport"]], "nasdaq_protocols.common.types": [[2, 4, 1, "", "EndOfQueue"], [2, 1, 1, "", "Serializable"], [2, 4, 1, "", "StateError"], [2, 1, 1, "", "Stoppable"], [2, 1, 1, "", "TypeDefinition"]], "nasdaq_protocols.common.types.Serializable": [[2, 3, 1, "", "from_bytes"], [2, 3, 1, "", "to_bytes"]], "nasdaq_protocols.common.utils": [[2, 5, 1, "", "logable"], [2, 5, 1, "", "start_server"], [2, 5, 1, "", "stop_task"]], "nasdaq_protocols.itch": [[3, 1, 1, "", "ItchMessageId"], [3, 1, 1, "", "Message"], [3, 5, 1, "", "connect_async"], [3, 0, 0, "-", "core"]], "nasdaq_protocols.itch.ItchMessageId": [[3, 3, 1, "", "from_bytes"], [3, 3, 1, "", "to_bytes"]], "nasdaq_protocols.itch.Message": [[3, 2, 1, "", "MsgIdClass"]], "nasdaq_protocols.itch.core": [[3, 1, 1, "", "ItchMessageId"], [3, 1, 1, "", "Message"]], "nasdaq_protocols.itch.core.ItchMessageId": [[3, 3, 1, "", "from_bytes"], [3, 3, 1, "", "to_bytes"]], "nasdaq_protocols.itch.core.Message": [[3, 2, 1, "", "MsgIdClass"]], "nasdaq_protocols.itch.session": [[3, 1, 1, "", "ClientSession"], [3, 1, 1, "", "ItchSessionId"]], "nasdaq_protocols.itch.session.ClientSession": [[3, 3, 1, "", "close"], [3, 2, 1, "", "closed"], [3, 3, 1, "", "decode"], [3, 2, 1, "", "log"], [3, 2, 1, "", "on_close_coro"], [3, 2, 1, "", "on_msg_coro"], [3, 3, 1, "", "receive_message"], [3, 2, 1, "", "soup_session"]], "nasdaq_protocols.ouch": [[4, 1, 1, "", "Message"], [4, 1, 1, "", "OuchMessageId"], [4, 5, 1, "", "connect_async"], [4, 0, 0, "-", "core"]], "nasdaq_protocols.ouch.Message": [[4, 2, 1, "", "MsgIdClass"]], "nasdaq_protocols.ouch.OuchMessageId": [[4, 3, 1, "", "from_bytes"], [4, 3, 1, "", "to_bytes"]], "nasdaq_protocols.ouch.core": [[4, 1, 1, "", "Message"], [4, 1, 1, "", "OuchMessageId"]], "nasdaq_protocols.ouch.core.Message": [[4, 2, 1, "", "MsgIdClass"]], "nasdaq_protocols.ouch.core.OuchMessageId": [[4, 3, 1, "", "from_bytes"], [4, 3, 1, "", "to_bytes"]], "nasdaq_protocols.ouch.session": [[4, 1, 1, "", "ClientSession"], [4, 1, 1, "", "OuchSessionId"]], "nasdaq_protocols.ouch.session.ClientSession": [[4, 3, 1, "", "close"], [4, 2, 1, "", "closed"], [4, 3, 1, "", "decode"], [4, 2, 1, "", "log"], [4, 2, 1, "", "on_close_coro"], [4, 2, 1, "", "on_msg_coro"], [4, 3, 1, "", "receive_message"], [4, 3, 1, "", "send_message"], [4, 2, 1, "", "soup_session"]], "nasdaq_protocols.soup": [[5, 1, 1, "", "ClientHeartbeat"], [5, 1, 1, "", "Debug"], [5, 1, 1, "", "EndOfSession"], [5, 4, 1, "", "InvalidSoupMessage"], [5, 1, 1, "", "LoginAccepted"], [5, 1, 1, "", "LoginRejectReason"], [5, 1, 1, "", "LoginRejected"], [5, 1, 1, "", "LoginRequest"], [5, 1, 1, "", "LogoutRequest"], [5, 1, 1, "", "SequencedData"], [5, 1, 1, "", "ServerHeartbeat"], [5, 1, 1, "", "SoupClientSession"], [5, 1, 1, "", "SoupMessage"], [5, 1, 1, "", "SoupServerSession"], [5, 1, 1, "", "SoupSession"], [5, 1, 1, "", "SoupSessionId"], [5, 1, 1, "", "UnSequencedData"], [5, 5, 1, "", "connect_async"], [5, 0, 0, "-", "core"]], "nasdaq_protocols.soup.Debug": [[5, 3, 1, "", "to_bytes"]], "nasdaq_protocols.soup.LoginAccepted": [[5, 3, 1, "", "to_bytes"]], "nasdaq_protocols.soup.LoginRejectReason": [[5, 3, 1, "", "get"]], "nasdaq_protocols.soup.LoginRejected": [[5, 3, 1, "", "to_bytes"]], "nasdaq_protocols.soup.LoginRequest": [[5, 3, 1, "", "to_bytes"]], "nasdaq_protocols.soup.SequencedData": [[5, 3, 1, "", "to_bytes"]], "nasdaq_protocols.soup.SoupClientSession": [[5, 3, 1, "", "login"], [5, 3, 1, "", "send_unseq_data"]], "nasdaq_protocols.soup.SoupMessage": [[5, 3, 1, "", "from_bytes"], [5, 3, 1, "", "to_bytes"]], "nasdaq_protocols.soup.SoupServerSession": [[5, 3, 1, "", "end_session"], [5, 3, 1, "", "on_login"], [5, 3, 1, "", "on_unsequenced"], [5, 3, 1, "", "send_heartbeat"], [5, 3, 1, "", "send_seq_msg"]], "nasdaq_protocols.soup.SoupSession": [[5, 3, 1, "", "logout"], [5, 3, 1, "", "send_debug"], [5, 3, 1, "", "send_msg"]], "nasdaq_protocols.soup.SoupSessionId": [[5, 3, 1, "", "update"]], "nasdaq_protocols.soup.UnSequencedData": [[5, 3, 1, "", "to_bytes"]], "nasdaq_protocols.soup.core": [[5, 1, 1, "", "ClientHeartbeat"], [5, 1, 1, "", "Debug"], [5, 1, 1, "", "EndOfSession"], [5, 4, 1, "", "InvalidSoupMessage"], [5, 1, 1, "", "LoginAccepted"], [5, 1, 1, "", "LoginRejectReason"], [5, 1, 1, "", "LoginRejected"], [5, 1, 1, "", "LoginRequest"], [5, 1, 1, "", "LogoutRequest"], [5, 1, 1, "", "SequencedData"], [5, 1, 1, "", "ServerHeartbeat"], [5, 1, 1, "", "SoupMessage"], [5, 1, 1, "", "UnSequencedData"]], "nasdaq_protocols.soup.core.Debug": [[5, 3, 1, "", "to_bytes"]], "nasdaq_protocols.soup.core.LoginAccepted": [[5, 3, 1, "", "to_bytes"]], "nasdaq_protocols.soup.core.LoginRejectReason": [[5, 3, 1, "", "get"]], "nasdaq_protocols.soup.core.LoginRejected": [[5, 3, 1, "", "to_bytes"]], "nasdaq_protocols.soup.core.LoginRequest": [[5, 3, 1, "", "to_bytes"]], "nasdaq_protocols.soup.core.SequencedData": [[5, 3, 1, "", "to_bytes"]], "nasdaq_protocols.soup.core.SoupMessage": [[5, 3, 1, "", "from_bytes"], [5, 3, 1, "", "to_bytes"]], "nasdaq_protocols.soup.core.UnSequencedData": [[5, 3, 1, "", "to_bytes"]], "nasdaq_protocols.soup.session": [[5, 1, 1, "", "SoupClientSession"], [5, 1, 1, "", "SoupServerSession"], [5, 1, 1, "", "SoupSessionId"]], "nasdaq_protocols.soup.session.SoupClientSession": [[5, 2, 1, "", "SessionType"], [5, 2, 1, "", "dispatch_on_connect"], [5, 2, 1, "", "log"], [5, 3, 1, "", "login"], [5, 3, 1, "", "send_unseq_data"]], "nasdaq_protocols.soup.session.SoupServerSession": [[5, 3, 1, "", "end_session"], [5, 3, 1, "", "on_login"], [5, 3, 1, "", "on_unsequenced"], [5, 3, 1, "", "send_heartbeat"], [5, 3, 1, "", "send_seq_msg"]], "nasdaq_protocols.soup.session.SoupSessionId": [[5, 3, 1, "", "update"]]}, "objnames": {"0": ["py", "module", "Python module"], "1": ["py", "class", "Python class"], "2": ["py", "attribute", "Python attribute"], "3": ["py", "method", "Python method"], "4": ["py", "exception", "Python exception"], "5": ["py", "function", "Python function"]}, "objtypes": {"0": "py:module", "1": "py:class", "2": "py:attribute", "3": "py:method", "4": "py:exception", "5": "py:function"}, "terms": {"0": [2, 3, 4, 5, 11, 12, 13], "00": 13, "001": 2, "1": [2, 3, 4, 5, 11, 12, 13], "10": [3, 4, 5, 6, 11, 12, 13], "100": 12, "1234": [11, 12, 13], "2": [2, 5, 10], "20": 12, "2024": 0, "4": 13, "4248850": 6, "56235965": 6, "6": [11, 12, 13], "65": 12, "75": 12, "85": 12, "8859": 12, "A": [0, 2, 11, 12, 13], "AND": 0, "AS": 0, "BE": 0, "BUT": 0, "By": 2, "FOR": 0, "For": [10, 12], "IN": 0, "If": [2, 5, 10], "In": 5, "It": [5, 7, 11, 12], "NO": 0, "NOT": 0, "OF": 0, "OR": 0, "THE": 0, "TO": 0, "The": [0, 2, 3, 4, 5, 7, 10, 11, 12, 13], "To": [5, 8, 13], "WITH": 0, "With": 12, "__init__": 10, "__main__": [11, 12, 13], "__name__": [11, 12, 13], "abc": [2, 5], "abov": [0, 10, 12], "abstract": [2, 5], "accept": [5, 12], "across": 13, "action": 0, "activ": 2, "actual": [7, 11, 12, 13], "ad": 6, "add": 2, "after": [2, 5], "alia": [2, 3, 4], "all": [0, 2, 5, 6, 10, 11, 12], "allow": 13, "alreadi": [2, 10], "an": [0, 2, 3, 4, 5, 11, 12, 13], "ani": [0, 2, 5, 7, 11, 12], "api": [7, 11, 12, 13], "app": [10, 12], "app_nam": [11, 12], "applic": [5, 7, 10, 11, 12], "ar": [2, 5, 6, 7], "aris": 0, "asciistr": 2, "associ": [0, 2], "assum": [10, 11, 12], "async": [2, 3, 4, 5, 11, 12, 13], "asynchron": [2, 3, 4], "asyncio": [5, 11, 12, 13], "asyncsess": [2, 5], "atest": 5, "attempt": 2, "author": 0, "automat": 5, "avail": [2, 5, 7], "await": [2, 3, 4, 5, 11, 12, 13], "b": [5, 12, 13], "base": [2, 3, 4, 5, 7], "bash": 10, "basic": 2, "befor": 6, "below": 11, "between": [3, 4, 5, 7], "bin": [11, 12, 13], "binari": [2, 3, 4, 5], "block": [2, 3, 4], "bool": [2, 3, 4, 5], "boolean": 2, "breakpoint": 6, "build": 10, "built": [10, 11, 12, 13], "bye": 11, "byte": [2, 3, 4, 5, 13], "bytes_": [2, 3, 4, 5], "c": 0, "call": [2, 5, 11], "callabl": [2, 3, 4, 5], "callback": [2, 3, 4, 5, 13], "can": [2, 5, 10, 11, 12], "cancel": 2, "cannot": 2, "case": [5, 6], "cd": 10, "chang": 2, "char_iso": 12, "charact": [11, 12, 13], "charascii": 2, "charg": 0, "chariso8599": 2, "check": [2, 5], "claim": 0, "class": [2, 3, 4, 5, 7], "classmethod": [2, 3, 4, 5], "classvar": 5, "client": [3, 4, 5, 7, 11, 12, 13], "client_heartbeat_interv": [3, 4, 5], "clientheartbeat": 5, "clientsess": [3, 4], "close": [2, 3, 4, 5, 11, 12, 13], "close_ev": [3, 4], "code": [6, 11, 12], "com": 6, "command": [10, 11, 12], "common": 1, "commonmessag": [3, 4], "condit": 0, "connect": [0, 2, 3, 4, 5, 12], "connect_async": [3, 4, 5, 11, 12, 13], "connectionrefusederror": 5, "contain": [2, 5, 7, 10, 11, 12], "context": 2, "contract": 0, "contribut": 6, "convert": 2, "copi": 0, "copyright": 0, "core": [3, 4, 5, 7, 11, 12], "coro": 2, "coroutin": [2, 5], "correct": 13, "correspond": 5, "coverag": 6, "creat": [2, 3, 4, 5, 9, 11, 12], "current": [2, 10], "damag": 0, "data": [2, 5], "deal": 0, "debug": 5, "debugg": 6, "decod": [2, 3, 4], "decor": 2, "def": [11, 12, 13], "default": [2, 3, 4, 5], "defin": [7, 10, 11, 12], "definit": [2, 10, 11], "deliveri": [5, 13], "deseri": [7, 11, 12], "design": 5, "detail": 10, "detect": 2, "develop": 7, "digit": 2, "dir": 10, "direct": [4, 12], "directori": 10, "disabl": 6, "dispatch": [2, 11, 13], "dispatch_on_connect": [2, 5], "dispatchablemessagequeu": [2, 3, 4], "dist": 10, "distribut": 0, "do": [0, 11], "doc": 6, "docstr": 6, "document": [0, 6, 10, 13], "doe": [7, 11, 12], "done": 10, "dure": 2, "e": 6, "each": 13, "ecosystem": 7, "edit": 10, "either": 5, "element": 2, "elif": 12, "empti": 2, "encod": 2, "end": [2, 5], "end_sess": 5, "endofqueu": 2, "endofsess": 5, "ensur": 6, "enter_ord": 12, "enterord": 12, "entri": [2, 5], "enum": 5, "env": [11, 12, 13], "eoferror": 2, "error": [5, 6], "etc": [11, 12], "even": 13, "event": [0, 3, 4, 11, 13], "everi": 2, "exampl": [10, 11, 13], "except": [2, 5], "exchang": 7, "execut": 6, "exist": 6, "expect": 5, "expir": [2, 5], "explicitli": 11, "express": 0, "extend": 7, "extern": 2, "f": 11, "factori": [3, 4, 5], "fail": 2, "failur": [5, 13], "fals": [2, 3, 4, 5], "fast": 5, "fetch": 2, "field": 12, "file": [0, 6, 10, 11, 12], "finish": 2, "first": [2, 5, 11, 12], "fit": 0, "fixedasciistr": 2, "fixedisostr": 2, "float": 2, "follow": [0, 5, 6, 10, 11, 12], "format": [2, 3, 4, 5, 10], "free": 0, "from": [0, 2, 3, 4, 5, 6, 11, 12, 13], "from_byt": [2, 3, 4, 5], "from_str": 2, "function": [2, 11], "furnish": 0, "gener": [2, 11, 12, 13], "get": [2, 5], "get_nowait": 2, "give": [11, 12, 13], "given": [3, 4, 5], "grace": 5, "grant": 0, "greater": 5, "guarante": 13, "guid": 7, "guidelin": 10, "ha": [7, 11, 12], "handl": [5, 7, 11, 12], "have": [10, 11, 12], "head": [11, 12, 13], "heartbeat": [2, 3, 4, 5], "heartbeatmonitor": 2, "henc": 7, "herebi": 0, "high": 5, "hold": 2, "holder": 0, "host": [2, 3, 4, 5], "hostnam": [11, 12, 13], "how": [7, 10, 13], "http": 6, "i": [0, 2, 3, 4, 5, 6, 10, 11, 12, 13], "id": [2, 5, 11, 12], "identifi": 5, "implement": [5, 7, 11, 12], "impli": 0, "import": [11, 12, 13], "includ": [0, 6], "incom": [2, 12], "index": 7, "indic": [3, 4, 5, 13], "inform": [5, 7, 10, 11, 12, 13], "inherit": 5, "ini": [6, 10], "initi": [2, 5], "initiate_clos": 2, "input_byt": 5, "instal": [9, 10], "instanti": 5, "instead": 11, "int": [2, 3, 4, 5], "int_2_b": 12, "int_4_b": 12, "int_8_b": 12, "intb": 2, "intend": 6, "interact": [11, 12, 13], "interv": [2, 5], "invalid": [2, 5], "invalidsoupmessag": 5, "ip": [5, 13], "is_act": 2, "is_clos": 2, "is_dispatch": 2, "is_run": 2, "is_stop": 2, "isinst": 12, "iso8859str": 2, "itch": [1, 4, 9, 10], "itch_": 11, "itch_clos": 11, "itch_fe": [10, 11], "itch_messag": 11, "itch_output": 11, "itch_sess": 11, "itchmessageid": 3, "itchsessionid": 3, "its": [2, 5], "join": [3, 4, 5], "kind": 0, "kwarg": 2, "latenc": 5, "len": 5, "length": [2, 5], "let": 12, "liabil": 0, "liabl": 0, "librari": [6, 7], "licens": 7, "lifetim": 2, "lightweight": [5, 13], "like": [5, 7, 11, 12], "limit": 0, "line": [10, 11, 12], "lint": 6, "linter": 6, "list": 2, "listen": [11, 12, 13], "local": [2, 10], "local_hb_interv": 2, "log": [2, 3, 4, 5], "logabl": 2, "logger": [3, 4, 5], "login": [3, 4, 5], "loginaccept": 5, "loginreject": 5, "loginrejectreason": 5, "loginrequest": 5, "logoff": 5, "logout": 5, "logoutrequest": 5, "long": 2, "longb": 2, "main": [6, 11, 12, 13], "manag": 2, "market": 5, "max": [11, 12, 13], "mean": 2, "meant": 5, "mention": [11, 12], "merchant": 0, "merg": [0, 6], "messag": [2, 7, 10, 11, 13], "message_queu": [2, 3, 4], "met": 6, "meta": [2, 5], "method": [2, 3, 4, 5, 11], "miss": 2, "mit": 7, "mode": 2, "modifi": [0, 11, 13], "modul": [5, 7, 11, 12, 13], "monitor": [2, 5], "more": [5, 7, 11, 12, 13], "msg": [2, 4, 5, 13], "msgidclass": [3, 4], "must": 5, "n": [11, 12, 13], "name": [2, 3, 4, 5, 10, 12], "nasdaq": [0, 6, 8, 10, 11, 12], "nasdaq_protocol": [2, 3, 4, 5, 11, 12, 13], "nasdaq_protocols_messag": [10, 11, 12], "necessari": [11, 12], "need": 6, "new": [2, 5, 6, 9, 11, 12], "next": 5, "nohost": [2, 5], "non": 2, "none": [2, 3, 4, 5], "noninfring": 0, "norol": 5, "nosess": 5, "noth": 5, "notic": 0, "notifi": 2, "nouser": 5, "now": [5, 12], "number": [2, 3, 4, 5, 13], "numer": 5, "object": [2, 3, 4, 5], "obtain": 0, "off": 2, "offici": 13, "on_clos": 13, "on_close_coro": [2, 3, 4, 5, 11, 13], "on_data": 2, "on_login": 5, "on_msg": 13, "on_msg_coro": [2, 3, 4, 5, 11, 13], "on_no_activity_coro": 2, "on_unsequenc": 5, "onc": 2, "onli": [7, 11, 12], "oper": 2, "order": [5, 12, 13], "orderbookid": 12, "orderid": 12, "other": 0, "otherwis": 0, "ouch": [1, 9, 10], "ouch_": 12, "ouch_o": [10, 12], "ouch_sess": 12, "ouchmessageid": 4, "ouchsessionid": 4, "our": 12, "out": 0, "outgo": [4, 12], "output": 12, "pack": [2, 3, 4, 5], "packag": [6, 7, 10, 11, 12], "page": 7, "param": [2, 5], "paramet": [2, 3, 4, 5], "pars": 2, "particular": 0, "pass": 6, "passwd": [3, 4, 5], "password": [3, 4, 5, 11, 12, 13], "paus": 2, "pause_dispatch": 2, "payload": 5, "peer": [2, 5], "per": [7, 13], "perform": 5, "permiss": 0, "permit": 0, "person": 0, "ping": 2, "pip": [8, 10], "pleas": [6, 10], "point": [2, 13], "poll": 2, "port": [2, 3, 4, 5, 11, 12, 13], "portion": 0, "prepar": 12, "prepend": 2, "price": 12, "print": [11, 12, 13], "privat": [2, 5], "program": [11, 12, 13], "progress": 2, "project": [9, 11, 12], "proper": [11, 12], "proto": 10, "protocol": [2, 5, 6, 8, 10, 11, 12, 13], "provid": [0, 5, 11, 12, 13], "publicli": 7, "publish": 0, "purpos": 0, "put": 2, "put_nowait": 2, "pwdchang": [11, 12], "py": [10, 11, 12], "pycharm": 6, "pylint": 6, "pypi": 10, "pyproject": 10, "pytest": 6, "python": [10, 11, 12], "python3": 13, "quantiti": 12, "queue": 2, "r": [6, 10], "rais": [2, 5], "raw": 5, "reach": 2, "reader": 2, "reader_factori": 2, "real": 13, "reason": [5, 12], "receiv": [2, 3, 4, 5, 11, 13], "receive_messag": [3, 4, 11, 12], "receive_msg": [2, 13], "receive_msg_nowait": 2, "record": [3, 4], "refer": [6, 7, 10, 11, 12, 13], "reject": [5, 12], "reliabl": 5, "remot": [2, 3, 4, 5], "remote_hb_interv": 2, "replac": 10, "report": 6, "repositori": 10, "request": 5, "respons": 2, "rest": [11, 12], "restrict": 0, "return": [2, 3, 4, 5], "right": 0, "right_justifi": 2, "root": 12, "rst": 6, "run": [2, 6, 10, 11, 12, 13], "runtimeerror": 2, "sai": 5, "same": 13, "sdist": 6, "search": 7, "second": [2, 3, 4, 5], "self": 5, "sell": 0, "send": [2, 4, 5, 13], "send_debug": 5, "send_heartbeat": [2, 5], "send_messag": [4, 12], "send_msg": [2, 5], "send_seq_msg": 5, "send_unseq_data": [5, 13], "sensit": 5, "sent": 5, "sequenc": [3, 4, 5, 11, 12, 13], "sequenceddata": 5, "serial": [7, 11, 12], "serializ": [2, 3, 4, 5], "serv": 2, "server": [2, 3, 4, 5, 7], "server_heartbeat_interv": [3, 4, 5], "serverheartbeat": 5, "session": [2, 7, 11, 12, 13], "session_factori": [2, 3, 4, 5], "session_id": [2, 3, 4, 5], "session_typ": 5, "sessionid": [2, 5], "sessiontyp": 5, "set": [2, 11, 13], "set_transport": 2, "sever": 5, "shall": 0, "short": 2, "shortb": 2, "side": [7, 12], "signal": 2, "simpl": [5, 11, 12, 13], "size": 2, "slightli": [11, 13], "so": [0, 10], "socket": [2, 13], "softwar": 0, "some": 13, "soup": [1, 9], "soup_msg": 5, "soup_sess": [3, 4], "soup_session_id": [3, 4], "soupbintcp": [5, 13], "soupclientsess": [3, 4, 5], "soupmessag": 5, "soupserversess": 5, "soupsess": 5, "soupsessionid": [3, 4, 5], "spec": 13, "specif": [5, 7, 11, 12], "specifi": 5, "spin_timeout": 2, "src": 10, "stackoverflow": 6, "start": [2, 5, 11, 12, 13], "start_dispatch": 2, "start_heartbeat": 2, "start_serv": 2, "state": 2, "stateerror": 2, "statement": 6, "step": [11, 12], "step1": [11, 12], "step2": 12, "step3": 12, "step4": 12, "step5": 12, "stop": [2, 6, 11, 13], "stop_task": 2, "stop_when_no_act": 2, "stoppabl": 2, "store": 10, "str": [2, 3, 4, 5], "stream": 5, "string": 2, "structur": 10, "subject": 0, "sublicens": 0, "substanti": 0, "success": 5, "suit": 5, "suppos": 5, "switch": 2, "t": 2, "tail": [11, 13], "talk": 5, "target": [2, 10], "task": 2, "tcp": [5, 13], "test": [5, 6, 12], "text": 5, "than": 5, "thi": [0, 2, 3, 4, 5, 6, 7, 10, 11, 12], "though": 5, "through": 10, "time": [2, 5, 13], "timer": 2, "to_byt": [2, 3, 4, 5], "to_str": 2, "toler": 2, "tolerate_missed_heartbeat": 2, "toml": 10, "tool": [5, 10], "top": 13, "tort": 0, "tox": [6, 10], "transport": [2, 5], "trip": 2, "true": [2, 5], "tupl": [2, 3, 4, 5], "type": [2, 3, 4, 5, 12], "type_cl": 2, "typedefinit": 2, "underli": [2, 13], "unpack": [2, 3, 4, 5], "unsequenc": [5, 13], "unsequenceddata": 5, "unsignedint": 2, "unsignedintb": 2, "unsignedlong": 2, "unsignedlongb": 2, "unsignedshort": 2, "unsignedshortb": 2, "until": [2, 3, 4], "updat": [2, 5], "upload": 10, "upon": 5, "us": [0, 2, 5, 7, 8, 10, 11, 12, 13], "user": [3, 4, 5, 7], "usernam": [3, 4, 5, 11, 12, 13], "usr": [11, 12, 13], "util": [2, 11, 12], "valid": [6, 7], "valu": [2, 5], "valueerror": 5, "variou": 7, "version": [11, 13], "wait": [2, 11, 13], "walk": 10, "want": [6, 10, 11, 12], "warn": [3, 4, 5], "warranti": 0, "we": [11, 12], "wheel": 6, "when": [2, 5, 6, 11], "whenev": 11, "where": [10, 11], "whether": 0, "which": [2, 5, 11, 12], "who": 6, "whom": 0, "why": 6, "without": [0, 13], "work": 13, "would": [5, 10], "write": 5, "xml": [10, 12], "you": [10, 11, 12], "your": 10}, "titles": ["MIT License", "API Reference", "Common api reference", "ITCH API Reference", "OUCH API Reference", "SOUP API Reference", "Developer\u2019s Guide", "Welcome to nasdaq-protocols\u2019s documentation!", "Installation", "User Guide", "Create New Project Guide", "ITCH User Guide", "OUCH User Guide", "SOUP User Guide"], "titleterms": {"": [6, 7], "api": [1, 2, 3, 4, 5], "build": 6, "common": 2, "connect": [11, 13], "content": [1, 7], "creat": 10, "definit": 12, "develop": 6, "document": 7, "faq": 6, "guid": [6, 9, 10, 11, 12, 13], "guidelin": 6, "indic": 7, "instal": 8, "itch": [3, 11], "licens": 0, "messag": [3, 4, 5, 12], "mit": 0, "nasdaq": 7, "new": 10, "ouch": [4, 12], "project": 10, "protocol": 7, "receiv": 12, "refer": [1, 2, 3, 4, 5], "sampl": 12, "send": 12, "server": [11, 12, 13], "session": [3, 4, 5], "soup": [5, 13], "step": 10, "tabl": 7, "user": [9, 11, 12, 13], "welcom": 7}}) \ No newline at end of file diff --git a/user_guide.html b/user_guide.html new file mode 100644 index 0000000..f263e9d --- /dev/null +++ b/user_guide.html @@ -0,0 +1,120 @@ + + + + + + + + User Guide — Nasdaq Protocols Python Library 0.0.1 documentation + + + + + + + + + + + + +
+
+
+ +
+
+
+ +
+

User Guide

+ +
+ + +
+
+
+
+
+ +
+
+
+ + + + + \ No newline at end of file diff --git a/user_guide_create_new_project.html b/user_guide_create_new_project.html new file mode 100644 index 0000000..051c312 --- /dev/null +++ b/user_guide_create_new_project.html @@ -0,0 +1,185 @@ + + + + + + + + Create New Project Guide — Nasdaq Protocols Python Library 0.0.1 documentation + + + + + + + + + + + + +
+
+
+ +
+
+
+ +
+

Create New Project Guide

+

This guide will walk you through creating a new python package that contains the message definitions +of the applications you want to use with the nasdaq-protocols.

+
+

Note

+

This guide assumes you have already installed the nasdaq-protocols package. If you have not, please +refer to the installation guide.

+
+
+

Steps

+
    +
  1. Install tox if you have not already done so.

    +
    +
    bash$ pip install tox
    +
    +
    +
    +
  2. +
+

Refer to the tox documentation for detailed information.

+
    +
  1. Create a new python package structure using the nasdaq-protocols-create-new-project command line tool.

    +
    +
    bash$ nasdaq-protocols-create-new-project --name <project-name> \
    +         --application app:proto [--target-dir <target-dir>]
    +
    +
    +

    Replace <project-name> with the name of your project and <target-dir> with the directory where you want to +create the project.

    +

    For example, to create a project named nasdaq-protocols-messages in the current directory, with 2 applications ouch_oe +and itch_feed, you would run the following command:

    +
    bash$ nasdaq-protocols-create-new-project --name nasdaq-protocols-messages \
    +        --application ouch_oe:ouch \
    +        --application itch_feed:itch
    +
    +
    +
    +
  2. +
  3. The nasdaq-protocols-create-new-project command will create a new python package with the following structure:

    +
    +

    For the above example, the following directory structure will be created.

    +
    nasdaq-protocols-messages/
    +├── src/
    +|    ├── nasdaq_protocols_messages/
    +|       ├── __init__.py
    +|       ├── ouch_oe/
    +|          └── ouch_oe.xml
    +|       └── itch_feed/
    +|           └── itch_feed.xml
    +├── pyproject.toml
    +└── tox.ini
    +
    +
    +
    +

    Note

    +
      +
    • ouch_oe.xml is the file where you define all the messages for the ouch_oe application.

    • +
    • itch_feed.xml is the file where you define all the messages for the itch_feed application.

    • +
    +

    The XML file contains the format and guidelines on how to define the messages.

    +
    +
    +
  4. +
  5. Edit the XML files to define the messages for the applications you want to use with the nasdaq-protocols.

  6. +
  7. Build the package

    +
    +
    bash$ cd target-dir/nasdaq-protocols-messages
    +bash$ tox r
    +
    +
    +
    +
  8. +
  9. The package will be built and stored in the dist directory. This can be uploaded to your PyPI repository or +installed locally.

  10. +
+
+
+ + +
+
+
+
+
+ +
+
+
+ + + + + \ No newline at end of file diff --git a/user_guide_itch.html b/user_guide_itch.html new file mode 100644 index 0000000..67cb071 --- /dev/null +++ b/user_guide_itch.html @@ -0,0 +1,220 @@ + + + + + + + + ITCH User Guide — Nasdaq Protocols Python Library 0.0.1 documentation + + + + + + + + + + + + +
+
+
+ +
+
+
+ +
+

ITCH User Guide

+

The nasdaq_protocols.itch module provides an API to interact with ITCH servers. +Refer ITCH API Reference. for more information on the API.

+

This package only provides the core implementation of the ITCH protocols, like message serialization +deserialization, session handling, etc. It does not define any actual ITCH messages. The actual ITCH +messages has to be defined by the user of this package. The first step is to create a new python package +which contains the messages definitions for all the protocols that the user wants to use.

+

This package provides a command line utility nasdaq-protocols-create-new-project to create a new python package +and all the necessary files.

+

Follow the steps in Create New Project Guide to create a new python package for application specific +messages.

+
+

Note

+

This rest of the guide assumes that you have built a new python project using the steps mentioned in +Create New Project Guide.

+
+
+
The generated project will contain a file itch_<app_name>.py which will contain the following
    +
  • ITCH message definitions

  • +
  • ITCH Client Session for this application

  • +
+
+
+

Using the generated code, you can connect to a ITCH server and start receiving messages.

+

The nasdaq_protocols.itch module provides an API to interact with ITCH servers. +Refer ITCH API Reference. for more information on the API.

+
+

Connecting to a ITCH Server

+

Use the example below to implement a program that will tail itch messages from the server.

+
#!/usr/bin/env python
+import asyncio
+# from the generated package we import the application we want to use
+from nasdaq_protocols_messages import itch_feed
+
+
+stopped = asyncio.Event()
+port = 1234  # give the proper itch server port
+
+
+async def itch_output(itch_message):
+    """
+    This function will be called whenever a new ITCH message is received
+    """
+    print('')
+    print(f'received: {itch_message}')
+    print('')
+
+
+async def itch_close():
+    """
+    This function will be called when the ITCH session is closed
+    """
+    stopped.set()
+    print('')
+    print('itch session closed, Bye Bye')
+    print('')
+
+
+async def main():
+    # Step1: connect
+    itch_session = await itch_feed.connect_async(
+        ('hostname', port),
+        'itch username',  # itch username, max 6 characters
+        'pwdchange', # itch password, max 10 characters
+        '', # session id
+        on_msg_coro=itch_output,  # function to call when a new message is received
+        on_close_coro=itch_close, # function to call when the session is closed
+        sequence=1  # 0 to listen from HEAD, 1 to listen from start, n to listen from n
+    )
+
+    print("wait for server to close the session")
+    await stopped.wait()
+
+
+if __name__ == '__main__':
+    asyncio.run(main())
+
+
+

A simple itch tail program

+

Slightly modified version where we do not use dispatchers instead explicitly call receive_message() method.

+
#!/usr/bin/env python
+import asyncio
+from nasdaq_protocols_messages import itch_feed
+
+
+port = 1234  # give the proper itch server port
+
+
+async def main():
+    # Step1: connect
+    itch_session = await itch_feed.connect_async(
+        ('hostname', port),
+        'itch username',  # itch username, max 6 characters
+        'pwdchange', # itch password, max 10 characters
+        '', # session id
+        sequence=1  # 0 to listen from HEAD, 1 to listen from start, n to listen from n
+    )
+
+    # receive the first message from the server.
+    itch_message = await itch_session.receive_message()
+    print(itch_message)
+
+    print("Closing the itch session...")
+    await itch_session.close()
+
+
+if __name__ == '__main__':
+    asyncio.run(main())
+
+
+
+
+ + +
+
+
+
+
+ +
+
+
+ + + + + \ No newline at end of file diff --git a/user_guide_ouch.html b/user_guide_ouch.html new file mode 100644 index 0000000..256301b --- /dev/null +++ b/user_guide_ouch.html @@ -0,0 +1,216 @@ + + + + + + + + OUCH User Guide — Nasdaq Protocols Python Library 0.0.1 documentation + + + + + + + + + + + + +
+
+
+ +
+
+
+ +
+

OUCH User Guide

+

The nasdaq_protocols.ouch module provides an API to interact with OUCH servers. +Refer OUCH API Reference. for more information on the API.

+

This package only provides the core implementation of the OUCH protocols, like message serialization +deserialization, session handling, etc. It does not define any actual OUCH messages. The actual OUCH +messages has to be defined by the user of this package. The first step is to create a new python package +which contains the messages definitions for all the protocols that the user wants to use.

+

This package provides a command line utility nasdaq-protocols-create-new-project to create a new python package +and all the necessary files.

+

Follow the steps in Create New Project Guide to create a new python package for application specific +messages.

+
+

Note

+

This rest of the guide assumes that you have built a new python project using the steps mentioned in +Create New Project Guide.

+
+
+
The generated project will contain a file ouch_<app_name>.py which will contain the following
    +
  • OUCH message definitions

  • +
  • OUCH Client Session for this application

  • +
+
+
+

Using the generated code, you can connect to a OUCH server and start sending/receiving messages.

+

The nasdaq_protocols.ouch module provides an API to interact with OUCH servers. +Refer OUCH API Reference. for more information on the API.

+
+

Sending Message to a OUCH Server

+
+

Sample Message Definition

+

For our test ouch app, lets define our OUCH messages in the file <app_name>.xml as follows,

+
<root>
+    <messages-root>
+        <message id="EnterOrder" message-id="65" direction="incoming">
+            <fields>
+                <field name="orderBookId" type="int_4_be"/>
+                <field name="side" type="char_iso-8859-1"/>
+                <field name="quantity" type="int_8_be"/>
+                <field name="price" type="int_8_be"/>
+            </fields>
+        </message>
+        <message id="Accepted" message-id="75" direction="outgoing">
+            <fields>
+                <field name="orderId" type="int_8_be"/>
+            </fields>
+        </message>
+        <message id="Rejected" message-id="85" direction="outgoing">
+            <fields>
+                <field name="reason" type="int_2_be"/>
+            </fields>
+        </message>
+    </messages-root>
+</root>
+
+
+
+
+

Sending and Receiving OUCH messages

+

With the above message definition, we can now send the ouch message as follows.

+
#!/usr/bin/env python
+import asyncio
+# from the generated package we import the application we want to use
+from nasdaq_protocols_messages import ouch_oe
+
+
+port = 1234  # give the proper ouch server port
+
+
+async def main():
+    # Step1: connect
+    ouch_session = await ouch_oe.connect_async(
+        ('hostname', port),
+        'ouch username',  # ouch username, max 6 characters
+        'pwdchange', # ouch password, max 10 characters
+        '', # session id
+        sequence=0  # 0 to listen from HEAD, 1 to listen from start, n to listen from n
+    )
+
+    # Step2: Prepare a message
+    enter_order = ouch_oe.EnterOrder()  # This is the message we defined in the xml file
+    enter_order.orderBookId = 1
+    enter_order.side = 'B'
+    enter_order.quantity = 100
+    enter_order.price = 20
+
+    # Step3: Send the message to the server.
+    ouch_session.send_message(enter_order)
+
+    # Step4: receive the first message from the server.
+    output = await ouch_session.receive_message()
+    if isinstance(output, ouch_oe.Accepted):
+        print("Order accepted")
+    elif isinstance(output, ouch_oe.Rejected):
+        print("Order rejected")
+
+    # Step5: Close the session
+    print("Closing the ouch session...")
+    await ouch_session.close()
+
+
+if __name__ == '__main__':
+    asyncio.run(main())
+
+
+

A simple ouch send and receive program

+
+
+
+ + +
+
+
+
+
+ +
+
+
+ + + + + \ No newline at end of file diff --git a/user_guide_soup.html b/user_guide_soup.html new file mode 100644 index 0000000..5005093 --- /dev/null +++ b/user_guide_soup.html @@ -0,0 +1,186 @@ + + + + + + + + SOUP User Guide — Nasdaq Protocols Python Library 0.0.1 documentation + + + + + + + + + + + + +
+
+
+ +
+
+
+ +
+

SOUP User Guide

+

SoupBinTCP 4.00 is a lightweight point-to-point protocol, built on top of TCP/IP +sockets that allow delivery of a set of sequenced and unsequenced messages from a +server to a client in real-time. SoupBinTCP guarantees that the client receives each +sequenced message generated by the server in the correct order, even across +underlying TCP/IP socket connection failures.

+

Refer to the Official SOUP Documentation for more information +on how SOUP protocol works.

+

The nasdaq_protocols.soup module provides an API to interact with SOUP servers and clients. +Refer SOUP API Reference. for more information on the API.

+
+

Connect to Soup Server

+

Example of connecting to a Soup server and receiving messages.

+
#!/usr/bin/env python3
+import asyncio
+from nasdaq_protocols import soup
+
+
+stopped = asyncio.Event()
+
+
+async def on_msg(msg):
+    print(msg)
+
+
+async def on_close():
+    stopped.set()
+    print('closed')
+
+
+async def main():
+    port = 1234  # Give the actual port number
+    session = await soup.connect_async(
+        ('hostname or ip', port),
+        'username', # Soup username, max 6 characters (as per spec)
+        'password', # Soup password, max 10 characters (as per spec)
+        sequence=1, # 0 to listen from HEAD, 1 to listen from start, n to listen from n
+        on_msg_coro=on_msg, # callback for receiving messages
+        on_close_coro=on_close # callback for indicating server closed the connection
+    )
+
+    # To send a message to the server
+    # session.send_unseq_data(b'some bytes')
+
+    await stopped.wait()
+
+
+if __name__ == '__main__':
+    asyncio.run(main())
+
+
+

A simple soup tail program

+

A slightly modified version of the same example but not using dispatchers for on_msg and on_close callbacks.

+
#!/usr/bin/env python3
+import asyncio
+from nasdaq_protocols import soup
+
+
+async def main():
+    port = 1234  # Give the actual port number
+    session = await soup.connect_async(
+        ('hostname or ip', port), 'username', 'password',
+        sequence=1
+    )
+    print(await session.receive_msg())
+    await session.close()
+
+    # To send a message to the server
+    # session.send_unseq_data(b'some bytes')
+
+
+if __name__ == '__main__':
+    asyncio.run(main())
+
+
+

A simple soup tail program without dispatchers

+
+
+ + +
+
+
+
+
+ +
+
+
+ + + + + \ No newline at end of file