diff --git a/.github/workflows/ci-test-dependecies.yaml b/.github/workflows/ci-test-dependecies.yaml new file mode 100644 index 00000000..c0469415 --- /dev/null +++ b/.github/workflows/ci-test-dependecies.yaml @@ -0,0 +1,24 @@ +name: CI Dependencies Test + +on: + pull_request: + branches: + - master + - release_* + +jobs: + test: + strategy: + matrix: +# providers: [ rdp, rdp5, rdp6, lwdp, lwdp1 ] + providers: [ lwdp, lwdp1 ] + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v2 + - name: Install dependencies + run: | + pip install th2-data-services[${{ matrix.providers }}] + - name: Test dependencies + run: | + pip install pytest -q + pytest tests/tests_unit/test_dependencies/ --provider=${{ matrix.providers }} diff --git a/.github/workflows/ci-test-dev-dependecies.yaml b/.github/workflows/ci-test-dev-dependecies.yaml new file mode 100644 index 00000000..1bb4a858 --- /dev/null +++ b/.github/workflows/ci-test-dev-dependecies.yaml @@ -0,0 +1,27 @@ +name: CI Dev Dependencies Test + +on: + pull_request: + branches: + - dev_* + - TH2-* + - th2-* + - pypi_* + +jobs: + test: + strategy: + matrix: +# providers: [ rdp, rdp5, rdp6, lwdp, lwdp1 ] + providers: [ lwdp, lwdp1 ] + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v2 + - name: Install dependencies + run: | + # Install Package From Local Directory + pip install --pre -e .[${{ matrix.providers }}] + - name: Test dependencies + run: | + pip install pytest -q + pytest tests/tests_unit/test_dependencies/ --provider=${{ matrix.providers }} diff --git a/.github/workflows/ci-tests-py310.yml b/.github/workflows/ci-tests-py310.yml new file mode 100644 index 00000000..fe8884d7 --- /dev/null +++ b/.github/workflows/ci-tests-py310.yml @@ -0,0 +1,36 @@ +name: CI tests Py 3.10 (for master only) + +on: + push: + branches: + - master + +jobs: + test: + name: Run tests + runs-on: ubuntu-20.04 + + strategy: + matrix: + py_version: [ '3.10' ] + + steps: + - uses: actions/checkout@v2 + + - name: Set up Python ${{ matrix.py_version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.py_version }} + architecture: x64 + + - name: Install dependencies + run: | + pip install -r requirements.txt + pip install pytest + pip install pytest-xdist + pip install th2-data-services-lwdp==2.0.2.0 # To test utils. Utils imports resolvers + + - name: Test with pytest + run: | + export PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=python + bash run_unit_tests.sh diff --git a/.github/workflows/ci-tests.yml b/.github/workflows/ci-tests.yml index d9979741..18137c7c 100644 --- a/.github/workflows/ci-tests.yml +++ b/.github/workflows/ci-tests.yml @@ -1,24 +1,38 @@ name: CI tests on: - pull_request: +# pull_request: # It duplicates push in PRs + push: jobs: test: - runs-on: ubuntu-20.04 + name: Run tests + + strategy: + matrix: + py_version: [ '3.8', '3.9' ] + os: [ ubuntu-20.04, windows-latest ] + + runs-on: ${{ matrix.os }} + steps: - uses: actions/checkout@v2 - - name: Set up Python 3.7 - uses: actions/setup-python@v1 + + - name: Set up Python ${{ matrix.py_version }} + uses: actions/setup-python@v4 with: - python-version: 3.7 + python-version: ${{ matrix.py_version }} + architecture: x64 + - name: Install dependencies run: | - pip install -r requirements.txt - pip install importlib importlib-metadata - - name: Test with pytest - run: | + pip install --pre -e . -q pip install pytest - cd tests - python unittestV5.py - python unittestV6.py + pip install pytest-xdist + pip install th2-data-services-lwdp==2.0.3.0 # To test utils. Utils imports resolvers + + - name: unit tests + run: | + + pip list + pytest tests/tests_unit -n auto --ignore tests/tests_unit/test_dependencies/ diff --git a/.github/workflows/ci-unwelcome-words.yml b/.github/workflows/ci-unwelcome-words.yml index d31b366d..8a12fbab 100644 --- a/.github/workflows/ci-unwelcome-words.yml +++ b/.github/workflows/ci-unwelcome-words.yml @@ -1,23 +1,23 @@ name: CI Unwelcome words on: - pull_request: + push: jobs: test: runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v2 - with: - ref: ${{ github.sha }} - - name: Checkout tool - uses: actions/checkout@v2 - with: - repository: exactpro-th2/ci-github-action - ref: master - token: ${{ secrets.PAT_CI_ACTION }} - path: ci-github-action - - name: Run CI action - uses: ./ci-github-action - with: - ref: ${{ github.sha }} + - uses: actions/checkout@v4 + with: + ref: ${{ github.sha }} + - name: Checkout tool + uses: actions/checkout@v4 + with: + repository: exactpro-th2/ci-github-action + ref: master + token: ${{ secrets.PAT_CI_ACTION }} + path: ci-github-action + - name: Run CI action + uses: ./ci-github-action + with: + ref: ${{ github.sha }} diff --git a/.github/workflows/dev-build-to-pypi.yml b/.github/workflows/dev-build-to-pypi.yml deleted file mode 100644 index 72dbbebc..00000000 --- a/.github/workflows/dev-build-to-pypi.yml +++ /dev/null @@ -1,57 +0,0 @@ -name: Dev build and publish Python distributions to PyPI - -on: - push: - branches: - - dev_* - - pypi_* - -jobs: - build-n-publish: - name: Dev build and Python distributions to PyPI - runs-on: ubuntu-20.04 - steps: - - uses: actions/checkout@v2 - # Prepare custom build version - - name: Get package version - id: pack_ver - uses: notiz-dev/github-action-json-property@release - with: - path: package_info.json - prop_path: package_version - - name: Build custom package version - id: release_ver - run: echo ::set-output name=value::"${{ steps.pack_ver.outputs.prop }}.dev${{ github.run_id }}" - - name: Show package version - run: echo ${{ steps.release_ver.outputs.value }} - - name: Set version for current build in package_info.json - uses: MerthinTechnologies/edit-json-action@v1 - with: - filename: './package_info.json' - key: 'package_version' - value: ${{ steps.release_ver.outputs.value }} - # Build and publish - - name: Set up Python 3.7 - uses: actions/setup-python@v1 - with: - python-version: 3.7 - - name: Install dependencies - run: | - pip install -r requirements.txt - pip install importlib importlib-metadata - - name: Test with pytest - run: | - pip install pytest - cd tests - python unittestV5.py - python unittestV6.py - cd .. - - name: Build package - run: | - python setup.py sdist - - name: Publish distribution to PyPI - uses: pypa/gh-action-pypi-publish@master - with: - user: __token__ - password: ${{ secrets.PYPI_PASSWORD }} - repository_url: https://upload.pypi.org/legacy/ diff --git a/.github/workflows/publish-release-candidate.yml b/.github/workflows/publish-release-candidate.yml new file mode 100644 index 00000000..bf494bb7 --- /dev/null +++ b/.github/workflows/publish-release-candidate.yml @@ -0,0 +1,20 @@ +name: check and publish release candidate Python tarball to PyPi + +on: workflow_dispatch + +jobs: + build-job: + name: Check and publish snapshot tarball to PyPi + uses: th2-net/.github/.github/workflows/compound-python.yml@main + with: + release-type: release-candidate + style-check-enabled: false + strict-style-check: false + python-check-versions: "['3.8', '3.9', '3.10', '3.11', '3.12']" + test-dir: tests/tests_unit + test-ignore-dir: tests/tests_unit/test_dependencies/ + test-requirements-files: requirements_dev.txt, requirements.txt + create-tag: true + + secrets: + pypi-password: ${{ secrets.PYPI_PASSWORD }} diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml new file mode 100644 index 00000000..91927188 --- /dev/null +++ b/.github/workflows/publish-release.yml @@ -0,0 +1,20 @@ +name: check and publish release Python tarball to PyPi + +on: workflow_dispatch + +jobs: + build-job: + name: Check and publish snapshot tarball to PyPi + uses: th2-net/.github/.github/workflows/compound-python.yml@main + with: + release-type: release + style-check-enabled: false + strict-style-check: false + python-check-versions: "['3.8', '3.9', '3.10', '3.11', '3.12']" + test-dir: tests/tests_unit + test-ignore-dir: tests/tests_unit/test_dependencies/ + test-requirements-files: requirements_dev.txt, requirements.txt + create-tag: true + + secrets: + pypi-password: ${{ secrets.PYPI_PASSWORD }} diff --git a/.github/workflows/publish-snapshot.yml b/.github/workflows/publish-snapshot.yml new file mode 100644 index 00000000..580849e0 --- /dev/null +++ b/.github/workflows/publish-snapshot.yml @@ -0,0 +1,25 @@ +name: check and publish snapshot Python tarball to PyPi + +on: + push: + branches: + - dev_* + - pypi_* + paths-ignore: + - README.md + +jobs: + build-job: + name: Check and publish snapshot tarball to PyPi + uses: th2-net/.github/.github/workflows/compound-python.yml@main + with: + release-type: development + style-check-enabled: false + strict-style-check: false + python-check-versions: "['3.8', '3.9', '3.10', '3.11', '3.12']" + test-dir: tests/tests_unit + test-ignore-dir: tests/tests_unit/test_dependencies/ + test-requirements-files: requirements_dev.txt, requirements.txt + + secrets: + pypi-password: ${{ secrets.PYPI_PASSWORD }} diff --git a/.github/workflows/pypi-publish.yaml b/.github/workflows/pypi-publish.yaml deleted file mode 100644 index 5a7b234a..00000000 --- a/.github/workflows/pypi-publish.yaml +++ /dev/null @@ -1,37 +0,0 @@ -name: Build and publish Python distributions to PyPI - -on: - push: - branches: - - master - -jobs: - build-n-publish: - name: Build and Python distributions to PyPI - runs-on: ubuntu-20.04 - steps: - - uses: actions/checkout@v2 - - name: Set up Python 3.7 - uses: actions/setup-python@v1 - with: - python-version: 3.7 - - name: Install dependencies - run: | - pip install -r requirements.txt - pip install importlib importlib-metadata - - name: Test with pytest - run: | - pip install pytest - cd tests - python unittestV5.py - python unittestV6.py - cd .. - - name: Build package - run: | - python setup.py sdist - - name: Publish distribution to PyPI - uses: pypa/gh-action-pypi-publish@master - with: - user: __token__ - password: ${{ secrets.PYPI_PASSWORD }} - repository_url: https://upload.pypi.org/legacy/ diff --git a/.gitignore b/.gitignore index 27ed2160..22d17eb7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +th2/data_services/utils/__init__.py +th2/data_services/utils/json.py + # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] diff --git a/.pre-commit-config-windows.yaml b/.pre-commit-config-windows.yaml new file mode 100644 index 00000000..49558e27 --- /dev/null +++ b/.pre-commit-config-windows.yaml @@ -0,0 +1,83 @@ +fail_fast: true # pre-commit will stop running hooks after the first failure. +default_stages: [ commit, push ] + +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v2.3.0 + hooks: + - id: check-merge-conflict + - id: end-of-file-fixer + # confilict with documentation generation +# - id: trailing-whitespace +# args: [--markdown-linebreak-ext=md] + - id: check-case-conflict + - id: requirements-txt-fixer + + - repo: https://github.com/psf/black + rev: 22.10.0 + hooks: + - id: black + name: black + entry: black + types: [ python ] + args: [ --line-length=100 ] + + - repo: https://github.com/PyCQA/autoflake + rev: v1.7.7 + hooks: + - id: autoflake + name: autoflake + args: [ --in-place, --remove-all-unused-imports, --ignore-init-module-imports ] + + - repo: https://github.com/pycqa/pydocstyle + rev: 6.3.0 # pick a git hash / tag to point to + hooks: + - id: pydocstyle + files: th2_data_services + args: + - --convention=google + - --add-ignore=D100,D101,D104,D105,D403, D102, # http://www.pydocstyle.org/en/stable/error_codes.html + + - repo: local + hooks: +# - id: docgen +# name: docgen +# language: script +# entry: doc_gen.sh +# require_serial: true # https://github.com/pre-commit/pre-commit/issues/1466 +# +# # Working incorrectly +# # - id: update_readme_toc +# # name: update_readme_toc +# # language: script +# # entry: update_readme_toc.sh +# # require_serial: true # https://github.com/pre-commit/pre-commit/issues/1466 +# +# - id: update_get_started_example_in_readme +# name: update_get_started_example_in_readme +# language: script +# entry: attach_file_to.sh +# args: +# - get_started_example.py +# - README.md +# require_serial: true # https://github.com/pre-commit/pre-commit/issues/1466 + + - id: unit_tests + name: unit_tests +# stages: [ push ] # Don't work in my PyCharm for some reason. + stages: [ commit ] + entry: python -m pytest tests --ignore tests/tests_unit/test_dependencies/ + language: python + pass_filenames: false + always_run: true + # Don't know how to solve the libs problem other way. + additional_dependencies: [pytest, treelib, flatdict, + orjson, th2-data-services-lwdp==2.0.3.0, ciso8601] + + - id: check_copyright + name: check_copyright + stages: [ commit ] + entry: python check_copyright.py copyright.txt ./th2_data_services + language: python + pass_filenames: false + always_run: true diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 82f895ed..019262e9 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -6,28 +6,31 @@ repos: rev: v2.3.0 hooks: - id: check-merge-conflict + - id: end-of-file-fixer + # confilict with documentation generation +# - id: trailing-whitespace +# args: [--markdown-linebreak-ext=md] + - id: check-case-conflict + - id: requirements-txt-fixer - repo: https://github.com/psf/black - rev: 21.8b0 + rev: 22.10.0 hooks: - id: black name: black entry: black types: [ python ] - args: [ --line-length=120 ] + args: [ --line-length=100 ] - - repo: https://github.com/myint/autoflake - rev: v1.4 + - repo: https://github.com/PyCQA/autoflake + rev: v1.7.7 hooks: - id: autoflake name: autoflake - entry: autoflake - language: system - types: [ python ] args: [ --in-place, --remove-all-unused-imports, --ignore-init-module-imports ] - repo: https://github.com/pycqa/pydocstyle - rev: 6.1.1 # pick a git hash / tag to point to + rev: 6.3.0 # pick a git hash / tag to point to hooks: - id: pydocstyle files: th2_data_services @@ -43,6 +46,13 @@ repos: entry: doc_gen.sh require_serial: true # https://github.com/pre-commit/pre-commit/issues/1466 + # Working incorrectly + # - id: update_readme_toc + # name: update_readme_toc + # language: script + # entry: update_readme_toc.sh + # require_serial: true # https://github.com/pre-commit/pre-commit/issues/1466 + - id: update_get_started_example_in_readme name: update_get_started_example_in_readme language: script @@ -50,12 +60,24 @@ repos: args: - get_started_example.py - README.md - require_serial: true - -# - id: unit_tests -# name: unit_tests -# stages: [ push ] -# entry: pytest -n auto -# language: system -# pass_filenames: false -# always_run: true \ No newline at end of file + require_serial: true # https://github.com/pre-commit/pre-commit/issues/1466 + + - id: unit_tests + name: unit_tests +# stages: [ push ] # Don't work in my PyCharm for some reason. + stages: [ commit ] + entry: python -m pytest tests --ignore tests/tests_unit/test_dependencies/ -vv + language: python + pass_filenames: false + always_run: true + # Don't know how to solve the libs problem other way. + additional_dependencies: [pytest, treelib, flatdict, + orjson, th2-data-services-lwdp==2.0.3.0, ciso8601] + + - id: check_copyright + name: check_copyright + stages: [ commit ] + entry: python check_copyright.py copyright.txt ./th2_data_services + language: python + pass_filenames: false + always_run: true diff --git a/MANIFEST.in b/MANIFEST.in index 79917ab2..b2f1ae77 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,3 +1,3 @@ include README.md include requirements.txt -include package_info.json \ No newline at end of file +include package_info.json diff --git a/README.md b/README.md index cbf7bd10..7ea5a3da 100644 --- a/README.md +++ b/README.md @@ -11,10 +11,8 @@ Table of Contents * [1. Introduction](#1-introduction) * [2. Getting started](#2-getting-started) * [2.1. Installation](#21-installation) - * [GRPC provider warning](#grpc-provider-warning) - * [Reasons for the restriction](#reasons-for-the-restriction) - * [Switch to another interface](#switch-to-another-interface) - * [Versions compatibility table](#versions-compatibility-table) + * [Core](#core) + * [Data sources (providers)](#data-sources-providers) * [2.2. Example](#22-example) * [2.3. Short theory](#23-short-theory) * [Terms](#terms) @@ -23,32 +21,31 @@ Table of Contents * [Pipelining](#pipelining) * [Internal iteration](#internal-iteration) * [Data caching](#data-caching) - * [EventsTree and collections](#eventstree-and-collections) - * [EventsTree](#eventstree) + * [Forced caching](#forced-caching) + * [EventTree and collections](#eventtree-and-collections) + * [EventTree](#eventtree) * [Collections](#collections) * [Hints](#hints) + * [FieldsResolver](#fieldsresolver) * [2.4. Links](#24-links) -* [3. API](#3-api) -* [4. Examples](#4-examples) - * [4.1. Notebooks](#41-notebooks) - * [4.2. *.py](#42-py) +* [3. Best practices](#3-best-practices) +* [4. Official DataSource implementations](#4-official-datasource-implementations) +* [5. API](#5-api) +* [6. Examples](#6-examples) # 1. Introduction This repository is a library for creating th2-data-services applications. +Data Services allows you to manipulate the stream data processing workflow using pipelining. -The library used to analyze stream data using _aggregate operations_ mainly from -the ["Report Data Provider"](https://github.com/th2-net/th2-rpt-data-provider). Data Services allows you to manipulate -the stream data processing workflow using _pipelining_. +The library's features: -The library allows you: - -- Natively connect to ["Report Data Provider"](https://github.com/th2-net/th2-rpt-data-provider) via - `ProviderDataSource` class and extract TH2 Events/Messages via _commands_ +- Provides core interface for developing data source implementations - Work with iterable objects (list, tuple, etc including files) via _Data object_ using its features - Manipulate the workflow to make some analysis by _Data object_ methods -- Build Event Trees (`EventsTreeCollection` class) +- Use timestamp converter implementations or use base class to create custom converters +- Build Event Trees (EventTree, EventTreeCollection and ParentEventTreeCollection classes) Workflow manipulation tools allows you: @@ -65,7 +62,9 @@ There is also another part of _data services_ ## 2.1. Installation -- From PyPI (pip) +### Core + +- From PyPI (pip) This package can be found on [PyPI](https://pypi.org/project/th2-data-services/ "th2-data-services"). ``` pip install th2-data-services @@ -77,253 +76,410 @@ There is also another part of _data services_ pip install th2-data-services/ ``` -### GRPC provider warning -This library has ability to interact with several versions of grpc providers, but it's limited by installed version of -`th2_grpc_data_provider` package version. You can use only appropriate version of provider api, which is compatible with -installed version of `th2_grpc_data_provider`. - -By default, `th2_data_services` uses the latest available version of provider api version. - -#### Reasons for the restriction -1. Two different versions of `th2_grpc_data_provider` can't be installed in the same virtual environment; -2. Two different versions of package `th2_grpc_data_provider` may depend on different versions of packages `th2_grpc_common`; -3. In the case of using another package in the process of using `th2_data_services` (for example `th2_common`), -which also depends on `th2_grpc_common`, a version conflict may occur (both at the Python level and at the Protobuf level). +### Data sources (providers) +Since `v1.3.0`, the library doesn't provide data source dependencies. -#### Switch to another interface -The transition to another version of the interface is carried out by installing another version of the -`th2_grpc_data_provider` package by running this command (in case you are using pip): - - pip install th2_grpc_data_provider== +You should provide it manually during installation. +You just need to add square brackets after library name and put dependency name. -For example, if you want to use v5 provider api, then you should run this command: - - pip install th2_grpc_data_provider==0.1.6 +``` +pip install th2-data-services[dependency_name] +``` +**Dependencies list** -#### Versions compatibility table +| dependency name | provider version | +|:-----------------:|---------------------------------------| +| lwdp | latest version of lwdp | +| lwdp2 | latest version of lwdp v2 | +| lwdp3 | latest version of lwdp v3 | +| utils-rpt-viewer | latest version of utils-rpt-viewer | +| utils-rpt-viewer5 | latest version of utils-rpt-viewer v5 | +| utils-advanced | latest version of ds-utils | -| Provider api | th2_grpc_data_provider version | -|:------------:|:------------------------------:| -| v5 | 0.1.6 | -| v6 | 1.1.0 | +**Example** +``` +pip install th2-data-services[lwdp1] +``` ## 2.2. Example A good, short example is worth a thousand words. -This example works with **Events**, but you also can do the same actions with **Messages**. +This example shows basic usage of library's features. [The following example as a file](examples/get_started_example.py). -```python -from collections import Generator -from typing import Tuple, List, Optional + +from typing import Tuple, List, Optional, Generator from datetime import datetime -from th2_data_services import Data -from th2_data_services.events_tree import EventsTree -from th2_data_services.provider.v5.data_source.http import HTTPProvider5DataSource -from th2_data_services.provider.v5.commands import http as commands -from th2_data_services.provider.v5.events_tree import EventsTreeCollectionProvider5, ParentEventsTreeCollectionProvider5 -from th2_data_services.provider.v5.filters.event_filters import NameFilter, TypeFilter, FailedStatusFilter -from th2_data_services.provider.v5.filters.message_filters import BodyFilter +from th2_data_services.data import Data +from th2_data_services.dummy import DummyDataSource +from th2_data_services.event_tree import ( + EventTree, + EventTreeCollection, + ParentEventTreeCollection, + IETCDriver, +) +from th2_data_services.interfaces import IDataSource +from th2_data_services.utils.converters import ( + DatetimeConverter, + DatetimeStringConverter, + ProtobufTimestampConverter, + Th2TimestampConverter, +) +###################################### # [0] Lib configuration +###################################### + # [0.1] Interactive or Script mode # If you use the lib in interactive mode (jupyter, ipython) it's recommended to set the special # global parameter to True. It'll keep cache files if something went wrong. -import th2_data_services - -th2_data_services.INTERACTIVE_MODE = True - -# [0.2] Logging -# Import helper function to setup logging. -from th2_data_services import add_stderr_logger, add_file_logger - -add_stderr_logger() # Just execute it to activate DS lib logging. Debug level by default. -# or if you want to put logs to the file -add_file_logger() - -# [1] Create DataSource object to connect to rpt-data-provider. -DEMO_HOST = "10.100.66.66" # th2-kube-demo Host port where rpt-data-provider is located. -DEMO_PORT = "30999" # Node port of rpt-data-provider. -data_source = HTTPProvider5DataSource(f"http://{DEMO_HOST}:{DEMO_PORT}") - -START_TIME = datetime( - year=2021, month=6, day=17, hour=9, minute=44, second=41, microsecond=692724 -) # Datetime in utc format. -END_TIME = datetime(year=2021, month=6, day=17, hour=12, minute=45, second=50) - -# [2] Get events or messages from START_TIME to END_TIME. -# [2.1] Get events. -events: Data = data_source.command( - commands.GetEvents( - start_timestamp=START_TIME, - end_timestamp=END_TIME, - attached_messages=True, - # Use Filter class to apply rpt-data-provider filters. - # Do not use multiple classes of the same type. - filters=[ - TypeFilter("Send message"), - NameFilter(["ExecutionReport", "NewOrderSingle"]), # You can use multiple values. - FailedStatusFilter(), - ], - ) +from th2_data_services.config import options + +options.INTERACTIVE_MODE = True + +# Some example data +events = Data( + [ + { + "eventId": "demo_book_1:th2-scope:20230105135705560873000:d61e930a-8d00-11ed-aa1a-d34a6155152d_1", + "batchId": None, + "isBatched": False, + "eventName": "Set of auto-generated events for ds lib testing", + "eventType": "ds-lib-test-event", + "endTimestamp": {"epochSecond": 1672927025, "nano": 561751000}, + "startTimestamp": {"epochSecond": 1672927025, "nano": 560873000}, + "parentEventId": None, + "successful": True, + "bookId": "demo_book_1", + "scope": "th2-scope", + "attachedMessageIds": [], + "body": [], + }, + { + "eventId": "demo_book_1:th2-scope:20230105135705563522000:9adbb3e0-5f8b-4c28-a2ac-7361e8fa704c>demo_book_1:th2-scope:20230105135705563522000:d61e930a-8d00-11ed-aa1a-d34a6155152d_2", + "batchId": "demo_book_1:th2-scope:20230105135705563522000:9adbb3e0-5f8b-4c28-a2ac-7361e8fa704c", + "isBatched": True, + "eventName": "Plain event 1", + "eventType": "ds-lib-test-event", + "endTimestamp": {"epochSecond": 1672927025, "nano": 563640000}, + "startTimestamp": {"epochSecond": 1672927025, "nano": 563522000}, + "parentEventId": "demo_book_1:th2-scope:20230105135705560873000:d61e930a-8d00-11ed-aa1a-d34a6155152d_1", + "successful": True, + "bookId": "demo_book_1", + "scope": "th2-scope", + "attachedMessageIds": [], + "body": {"type": "message", "data": "ds-lib test body"}, + }, + { + "eventId": "demo_book_1:th2-scope:20230105135705563522000:9adbb3e0-5f8b-4c28-a2ac-7361e8fa704c>demo_book_1:th2-scope:20230105135705563757000:d61e930a-8d00-11ed-aa1a-d34a6155152d_3", + "batchId": "demo_book_1:th2-scope:20230105135705563522000:9adbb3e0-5f8b-4c28-a2ac-7361e8fa704c", + "isBatched": True, + "eventName": "Plain event 2", + "eventType": "ds-lib-test-event", + "endTimestamp": {"epochSecond": 1672927025, "nano": 563791000}, + "startTimestamp": {"epochSecond": 1672927025, "nano": 563757000}, + "parentEventId": "demo_book_1:th2-scope:20230105135705560873000:d61e930a-8d00-11ed-aa1a-d34a6155152d_1", + "successful": True, + "bookId": "demo_book_1", + "scope": "th2-scope", + "attachedMessageIds": [], + "body": {"type": "message", "data": "ds-lib test body"}, + }, + { + "eventId": "fake-eventId", + "batchId": "fake-batchId", + "isBatched": True, + "eventName": "Fake event", + "eventType": "ds-lib-test-event", + "endTimestamp": {"epochSecond": 1672927035, "nano": 563791000}, + "startTimestamp": {"epochSecond": 1672927325, "nano": 563757000}, + "parentEventId": "not_exists_in_the_events_stream", + "successful": False, + "bookId": "demo_book_1", + "scope": "th2-scope", + "attachedMessageIds": [], + "body": {"type": "message", "data": "ds-lib test body"}, + }, + ] ) -# [2.2] Get messages. -messages: Data = data_source.command( - commands.GetMessages( - start_timestamp=START_TIME, - end_timestamp=END_TIME, - attached_events=True, - stream=["demo-conn2"], - filters=BodyFilter("195"), # Filter message if there is a substring '195' in the body. - ) -) +###################################### +# [1] Working with a Data object. +###################################### -# [3] Work with a Data object. -# [3.1] Filter. +# [1.1] Filter. filtered_events: Data = events.filter(lambda e: e["body"] != []) # Filter events with empty body. -# [3.2] Map. +# [1.2] Map. def transform_function(record): return {"eventName": record["eventName"], "successful": record["successful"]} filtered_and_mapped_events = filtered_events.map(transform_function) -# [3.3] Data pipeline. +# [1.3] Data pipeline. # Instead of doing data transformations step by step you can do it in one line. -filtered_and_mapped_events_by_pipeline = events.filter(lambda e: e["body"] != []).map(transform_function) - +filtered_and_mapped_events_by_pipeline = events.filter(lambda e: e["body"] != []).map( + transform_function +) # Content of these two Data objects should be equal. assert list(filtered_and_mapped_events) == list(filtered_and_mapped_events_by_pipeline) -# [3.4] Sift. Skip the first few items or limit them. -events_from_11_to_end: Generator = events.sift(skip=10) -only_first_10_events: Generator = events.sift(limit=10) +# [1.4] Sift. Skip the first few items or limit them. +data = Data([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]) +items_from_11_to_end: Generator = data.sift(skip=10) +only_first_10_items: Generator = data.sift(limit=10) -# [3.5] Changing cache status. +# [1.5] Changing cache status. events.use_cache(True) # or just -events.use_cache() - -# [3.6] Walk through data. +events.use_cache() # If you want to activate cache. +# [1.6] Walk through data. for event in events: # Do something with event (event is a dict). print(event) # After first iteration the events has a cache file. -# Now they will be used the cache in following iteration. +# Now they will be used in the cache in the next iteration. -# [3.7] Get number of the elements in the Data object. +# [1.7] Get number of the elements in the Data object. number_of_events = events.len -# [3.8] Check that Data object isn't empty. +# [1.8] Check that Data object isn't empty. # The data source should be not empty. assert events.is_empty is False -# [3.9] Convert Data object to the list of elements(events or messages). +# [1.9] Convert Data object to the list of elements(events or messages). # Be careful, this can take too much memory. events_list = list(events) -# [3.10] Get event/message by id. -desired_event = "9ce8a2ff-d600-4366-9aba-2082cfc69901:ef1d722e-cf5e-11eb-bcd0-ced60009573f" -desired_events = [ - "deea079b-4235-4421-abf6-6a3ac1d04c76:ef1d3a20-cf5e-11eb-bcd0-ced60009573f", - "a34e3cb4-c635-4a90-8f42-37dd984209cb:ef1c5cea-cf5e-11eb-bcd0-ced60009573f", -] -desired_message = "demo-conn1:first:1619506157132265837" -desired_messages = [ - "demo-conn1:first:1619506157132265836", - "demo-conn1:first:1619506157132265833", -] - -data_source.command(commands.GetEventById(desired_event)) # Returns 1 event (dict). -data_source.command(commands.GetEventsById(desired_events)) # Returns 2 events list(dict). - -data_source.command(commands.GetMessageById(desired_message)) # Returns 1 message (dict). -data_source.command(commands.GetMessagesById(desired_messages)) # Returns 2 messages list(dict). - -# [3.11] The cache inheritance. +# [1.10] The cache inheritance. # Creates a new Data object that will use cache from the events Data object. -events_with_batch = events.filter(lambda record: record.get("batchId")) +events_filtered: Data = events.filter(lambda record: record.get("batchId")) # New Data objects don't use their own cache by default but use the cache of the parent Data object. -# Use use_cache method to activate caching. After that, the Data object will create its own cache file. -events_with_batch.use_cache(True) +# Use use_cache method to activate caching. +# After that, the Data object will create its own cache file. +events_filtered.use_cache() -list(events_with_batch) +list(events_filtered) # Just to iterate Data object (cache file will be created). -events_types_with_batch = events_with_batch.map(lambda record: {"eventType": record.get("eventType")}) +filtered_events_types = events_filtered.map(lambda record: {"eventType": record.get("eventType")}) -events_without_types_with_batch = events_types_with_batch.filter(lambda record: not record.get("eventType")) -events_without_types_with_batch.use_cache(True) +events_without_types_with_batch = filtered_events_types.filter( + lambda record: not record.get("eventType") +) +events_without_types_with_batch.use_cache() -# [3.12] Data objects joining. +# [1.11] Data objects joining. # You have the following 3 Data objects. d1 = Data([1, 2, 3]) d2 = Data(["a", {"id": 123}, "c"]) d3 = Data([7, 8, 9]) # You can join Data objects in following ways. +# Please note, new Data object will have cache status == False. data_via_init = Data([d1, d2, d3]) data_via_add = d1 + d2 + d3 data_with_non_data_obj_via_init = Data([d1, ["a", {"id": 123}, "c"], d3]) data_with_non_data_obj_via_add = d1 + ["a", {"id": 123}, "c"] + d3 +# You can join current Data object on place using +=. +# It will keep cache status. +d1 += d3 # d1 will become Data([1,2,3,7,8,9]) + +# [1.12] Build and read Data object cache files. +events.build_cache("cache_filename_or_path") +data_obj_from_cache = Data.from_cache_file("cache_filename_or_path") + +# [1.13] Check if Data is sorted. +# That will return an object `is_sorted` that contains information +# 1. status -- sorted or not +# 2. first_unsorted -- the index of the first unsorted element +is_sorted = events.is_sorted(lambda e: e["startTimestamp"]["epochSecond"]) + +# You can use this object as usual bool variable. +if is_sorted: + print("events Data obj is sorted!") + +# [1.14] Use `Data.show()` to look at the first N messages in the stream. +data_with_non_data_obj_via_add.show(n=6) +# Will print +# ------------- Printed first 6 records ------------- +# [1] ------ +# 1 +# [2] ------ +# 2 +# [3] ------ +# 3 +# [4] ------ +# 'a' +# [5] ------ +# {'id': 123} +# [6] ------ +# 'c' + +# [1.15] You can remove the cache file of the Data object, if required. +data_obj_from_cache.clear_cache() + + +# [1.16] Get the message by its ID from the Data object in one line. +msg = next(data_obj_from_cache.find_by(record_field="MessageId", field_values=["msg-id"])) + +# [1.17] Update metadata for Data objects. +# d1.metadata - {} +d1.update_metadata({"a": 1, "b": [10], "c": {"a": 100}}) +# d1.metadata - {'a': 1, 'b': [10], 'c': {'a': 100}} +d1.update_metadata({"a": 2, "b": 20, "c": {"a": 200, "b": 300}}) +# d1.metadata - {'a': 2, 'b': [10, 20], 'c': {'a': 200, 'b': 300}} +# d1.update_metadata({"a": {}}) - This throws AttributeError: 'int' object has no attribute 'update'. +# To set key whose value is of non-dict type to dict we can use change_type="change" argument. +d1.update_metadata({"a": {}}, change_type="change") +# d1.metadata - {'a': {}, 'b': [10, 20], 'c': {'a': 200, 'b': 300}} +# change_type can be either 'update' (default) or 'change' - overwrite existing value or create a new one if it +# doesn't exist. + +###################################### +# [2] Working with converters. +###################################### +# There are currently three implementations of ITimestampConverter class: DatetimeConverte, DatetimeStringConverter and ProtobufTimestampConverter. +# They all implement same methods from base class. +# Note that some accuracy may be lost during conversion. +# If for example you use to_microseconds nanoseconds will be cut off instead of rounding. + +# [2.1] DatetimeConverter. +# DatetimeConverter takes datetime.datetime object as input. + +datetime_obj = datetime(year=2023, month=1, day=5, hour=14, minute=38, second=25, microsecond=1460) + +# It has methods that return the datetime in different formas: + +date_ms = DatetimeConverter.to_milliseconds(datetime_obj) +date_us = DatetimeConverter.to_microseconds(datetime_obj) +# Converting to nanoseconds justs adds three trailing zeros as datetime object doesn't have nanoseconds. +date_ns = DatetimeConverter.to_nanoseconds(datetime_obj) + +# [2.2] DatetimeStringConverter +# DatetimeStringConverter takes string in "yyyy-MM-ddTHH:mm:ss[.SSSSSSSSS]Z" format. + +date_string = "2023-01-05T14:38:25.00146Z" + +# We have same methods as in DatetimeConverter +date_ms_from_string = DatetimeStringConverter.to_milliseconds(date_string) +date_us_from_string = DatetimeStringConverter.to_microseconds(date_string) +date_ns_from_string = DatetimeStringConverter.to_nanoseconds(date_string) + +# We can also get datetime object from string +datetime_from_string = DatetimeStringConverter.to_datetime(date_string) + +# [2.3] ProtobufTimestampConverter +# Protobuf timestamps must be in form {"epochSecond": seconds, "nano": nanoseconds} + +protobuf_timestamp = {"epochSecond": 1672929505, "nano": 1_460_000} + +date_ms_from_timestamp = ProtobufTimestampConverter.to_milliseconds(protobuf_timestamp) +date_us_from_timestamp = ProtobufTimestampConverter.to_microseconds(protobuf_timestamp) +date_ns_from_timestamp = ProtobufTimestampConverter.to_nanoseconds(protobuf_timestamp) +datetime_from_timestamp = ProtobufTimestampConverter.to_datetime(protobuf_timestamp) + +###################################### +# [3] Working with EventTree and EventTreeCollection. +###################################### +# Can be useful if you have data-stream with < 100k elements, otherwise it +# takes too much RAM. + +# [3.1] Build a custom EventTree +# To create an EventTree object you need to provide name, id and data of the root event. +tree = EventTree(event_name="root event", event_id="root_id", data={"data": [1, 2, 3, 4, 5]}) + +# To add new node use append_event. parent_id is necessary, data is optional. +tree.append_event(event_name="A", event_id="A_id", data=None, parent_id="root_id") + +# [3.3] Building the EventTreeCollection. +data_source: IDataSource # You should init DataSource object. E.g. from LwDP module. +data_source = DummyDataSource() # Note! We use fake DS here. +# ETCDriver here is a stub, actually the lib doesn't have such a class. +# You can take it in LwDP module or create yourself class if you have some special events structure. +from th2_data_services.data_source.lwdp.event_tree import HttpETCDriver as ETCDriver + +# If you don't specify data_source for the driver then it won't recover detached events. +driver: IETCDriver # You should init ETCDriver object. E.g. from LwDP module or your custom class. +driver = ETCDriver(data_source=data_source, use_stub=True) + +etc = EventTreeCollection(driver) +etc.build(events) +etc.show() +# It'll print the following: +# Set of auto-generated events for ds lib testing +# ├── Plain event 1 +# └── Plain event 2 + +print(etc) +# EventTreeCollection(trees=1, events=3[trees=3, detached=0]) -# [4] Working with EventsTree and EventsTreeCollection. -# [4.1] Building the EventsTreeCollection. +# Detached events isn't empty. +assert etc.get_detached_events() # returns list of detached_events. -# If you don't specify data_source for the tree then it won't recover detached events. -collection = EventsTreeCollectionProvider5(events) +# recover_unknown_events -- used to recover some events parents. +# That won't work with DummyDataSource, so was commented +# etc.recover_unknown_events() -# Detached events isn't empty. -assert collection.detached_events +# After that the detached events should be empty because they were recovered. +# assert not etc.get_detached_events() -collection = EventsTreeCollectionProvider5(events, data_source=data_source) -# Detached events are empty because they were recovered. -assert not collection.detached_events +# ----- -# The collection has EventsTrees each with a tree of events. -# Using Collection and EventsTrees, you can work flexibly with events. +# The collection has EventTrees each with a tree of events. +# Using Collection and EventTrees, you can work flexibly with events. -# [4.1.1] Get leaves of all trees. -leaves: Tuple[dict] = collection.get_leaves() +# [3.3.1] Get leaves of all trees. +leaves: Tuple[dict] = etc.get_leaves() # Returns a tuple of leaves events -# [4.1.2] Get roots ids of all trees. -roots: List[str] = collection.get_roots_ids() +# [3.3.2] Get roots ids of all trees. +roots: List[str] = etc.get_roots_ids() +# Returns the list of root Ids: +# ['demo_book_1:th2-scope:20230105135705560873000:d61e930a-8d00-11ed-aa1a-d34a6155152d_1'] -# [4.1.3] Find an event in all trees. -find_event: Optional[dict] = collection.find(lambda event: "Send message" in event["eventType"]) +# [3.3.3] Find an event in all trees. +find_event: Optional[dict] = etc.find(lambda event: "Send message" in event["eventType"]) -# [4.1.4] Find all events in all trees. There is also iterable version 'findall_iter'. -find_events: List[dict] = collection.findall(lambda event: event["successful"] is True) +# [3.3.4] Find all events in all trees. There is also iterable version 'findall_iter'. +find_events: List[dict] = etc.findall(lambda event: event["successful"] is True) -# [4.1.5] Find an ancestor of the event. -ancestor: Optional[dict] = collection.find_ancestor( - "8bbe3717-cf59-11eb-a3f7-094f904c3a62", filter=lambda event: "RootEvent" in event["eventName"] +# [3.3.5] Find an ancestor of the event. +ancestor: Optional[dict] = etc.find_ancestor( + "demo_book_1:th2-scope:20230105135705560873000:d61e930a-8d00-11ed-aa1a-d34a6155152d_1", + filter=lambda event: "RootEvent" in event["eventName"], ) -# [4.1.6] Get children of the event. There is also iterable version 'get_children_iter'. -children: Tuple[dict] = collection.get_children("814422e1-9c68-11eb-8598-691ebd7f413d") +# [3.3.6] Get children of the event. There is also iterable version 'get_children_iter'. +children: Tuple[dict] = etc.get_children( + "demo_book_1:th2-scope:20230105135705560873000:d61e930a-8d00-11ed-aa1a-d34a6155152d_1" +) -# [4.1.7] Get subtree for specified event. -subtree: EventsTree = collection.get_subtree("8e23774d-cf59-11eb-a6e3-55bfdb2b3f21") +# [3.3.7] Get subtree for specified event. +subtree: EventTree = etc.get_subtree( + "demo_book_1:th2-scope:20230105135705560873000:d61e930a-8d00-11ed-aa1a-d34a6155152d_1" +) -# [4.1.8] Get full path to the event. +# [3.3.8] Get full path to the event. # Looks like [ancestor_root, ancestor_level1, ancestor_level2, event] -event_path: List[dict] = collection.get_full_path("8e2524fa-cf59-11eb-a3f7-094f904c3a62") +event_path: List[dict] = etc.get_full_path( + "demo_book_1:th2-scope:20230105135705560873000:d61e930a-8d00-11ed-aa1a-d34a6155152d_1" +) -# [4.1.9] Get parent of the event. -parent = collection.get_parent("8e2524fa-cf59-11eb-a3f7-094f904c3a62") +# [3.3.9] Get parent of the event. +parent = etc.get_parent( + "demo_book_1:th2-scope:20230105135705560873000:d61e930a-8d00-11ed-aa1a-d34a6155152d_1" +) -# [4.1.10] Append new event to the collection. -collection.append_event( +# [3.3.10] Append new event to the collection. +etc.append_event( event={ "eventId": "a20f5ef4-c3fe-bb10-a29c-dd3d784909eb", "parentEventId": "8e2524fa-cf59-11eb-a3f7-094f904c3a62", @@ -331,35 +487,170 @@ collection.append_event( } ) -# [4.1.11] Show the entire collection. -collection.show() - -# [4.2] Working with the EventsTree. -# EventsTree has the same methods as EventsTreeCollection, but only for its own tree. - -# [4.2.1] Get collection trees. -trees: List[EventsTree] = collection.get_trees() -tree: EventsTree = trees[0] - -# But EventsTree provides a work with the tree, but does not modify it. -# If you want to modify the tree, use EventsTreeCollections. - -# [4.3] Working with ParentlessTree. -# ParentlessTree is EventsTree which has detached events with stubs. -parentless_trees: List[EventsTree] = collection.get_parentless_trees() - -# [4.4] Working with ParentEventsTreeCollection. -# ParentEventsTreeCollection is a tree like EventsTreeCollection but it has only events that have references. -collection = ParentEventsTreeCollectionProvider5(events, data_source=data_source) - -collection.show() - +# [3.3.11] Show the entire collection. +etc.show() +# It'll print the following: +# Set of auto-generated events for ds lib testing +# ├── Plain event 1 +# └── Plain event 2 + +# As you can see, nothing was changed, but we added the new event! +# let's look at the summary. + +print(etc.summary()) # the same as just print(etc) +# EventTreeCollection(trees=1, events=5[trees=3, detached=2]) +# You can see that it was added to detached. That's why you don't see the event +# via `show()`. `show()` prints only Trees! +# Use `etc.get_parentless_trees()` to convert detached events to trees. +# More information below in the corresponding section. + +# -------------- +# [3.4] Working with the EventTree. +# EventTree has the same methods as EventTreeCollection, but only for its own tree. + +# [3.4.1] Get a collection of trees. +trees: List[EventTree] = etc.get_trees() +tree: EventTree = trees[0] + +# But EventTree provides a work with the tree, but does not modify it. +# If you want to modify the tree, use EventTreeCollections. + +# [3.5] Working with ParentlessTree. +# ParentlessTree is an EventTree that has detached events with stubs. +parentless_trees: List[EventTree] = etc.get_parentless_trees() +print("parentless_trees contains:") +print(parentless_trees) +# [EventTree(name='', root_id='not_exists_in_the_events_stream', events=2), +# EventTree(name='', root_id='8e2524fa-cf59-11eb-a3f7-094f904c3a62', events=2)] + +print("\n" "etc after `get_parentless_trees`:") +print(etc.summary()) +# EventTreeCollection(trees=3[regular=1, parentless=2], events=7[trees=7, detached=0])' +etc.show() +# Set of auto-generated events for ds lib testing +# ├── Plain event 1 +# └── Plain event 2 +# +# └── Fake event +# +# └── StubEvent <--- the event that was added above + +# [3.6] Working with ParentEventTreeCollection. +# ParentEventTreeCollection is a tree collection like EventTreeCollection, +# but it has only events that have references. +data_source: IDataSource # You should init DataSource object. E.g. from LwDP module. +data_source = DummyDataSource() # Note! We use fake DS here. +# ETCDriver here is a stub, actually the lib doesn't have such a class. +# You can take it in LwDP module or create yourself class if you have some special events structure. +from th2_data_services.data_source.lwdp.event_tree import HttpETCDriver as ETCDriver + +driver = ETCDriver(data_source=data_source) +petc = ParentEventTreeCollection(driver) +petc.build(events) + +petc.show() +petc.summary() + +###################################### +# [4] Field Resolvers +###################################### +# Please read `Field Resolvers` block in readme first. + +# [4.1] Usage example from client code +from th2_data_services.data_source import ( + lwdp, +) # lwdp data_source initialize th2_data_services.config during import. +from th2_data_services.config import options as o_ +from th2_data_services.data_source.lwdp.stub_builder import http_message_stub_builder + +fake_data = [ + http_message_stub_builder.build({"messageId": "a", "messageType": "Root"}), + http_message_stub_builder.build({"messageId": "b", "messageType": "New"}), + http_message_stub_builder.build({"messageId": "c", "messageType": "Amend"}), + http_message_stub_builder.build({"messageId": "d", "messageType": "Cancel"}), +] +fake_data_obj = Data(fake_data) + +for m in fake_data_obj: + o_.mfr.expand_message(m) # mfr - stands for MessageFieldResolver +# or +for m in fake_data_obj.map(o_.mfr.expand_message): + pass + +# [4.2] Libraries usage. +# Don't import exact resolvers implementation in your code, please. +# Allow your client to do it instead. +# Just import `options` from `th2_data_services.config` and use it. +from th2_data_services.config import options as o_ + +for m in fake_data_obj: + o_.mfr.expand_message(m) +# or +for m in fake_data_obj.map(o_.mfr.expand_message): + pass + +# More tech details: +# In this case, there is no line `from th2_data_services.data_source import lwdp ` +# because we should not choose for the user which a data source to use. +# We do not know what he will choose, therefore, we must simply access +# the interface, which will be initialized by the user. + +###################################### +# [5] Using utility functions. +###################################### +from th2_data_services.utils.event_utils.frequencies import get_category_frequencies2 +from th2_data_services.utils.event_utils.totals import get_category_totals2 +from th2_data_services.utils.category import Category +from th2_data_services.utils.event_utils.event_utils import is_sorted + +# [5.1] Get the quantities of events for different categories. +metrics = [ + Category("date", lambda m: Th2TimestampConverter.to_datetime(m["startTimestamp"]).date()), + Category("status", lambda m: m["successful"]), +] +category_totals = get_category_totals2(events, metrics) +print(category_totals) +""" ++--------+------------+----------+---------+ +| | date | status | count | ++========+============+==========+=========+ +| | 2023-01-05 | True | 3 | ++--------+------------+----------+---------+ +| | 2023-01-05 | False | 1 | ++--------+------------+----------+---------+ +| count | | | 2 | ++--------+------------+----------+---------+ +| totals | | 1/1 | 4 | ++--------+------------+----------+---------+ +""" + +# [5.2] Get the number of events with status successful. +category = Category("status", lambda m: m["successful"]) +category_frequencies = get_category_frequencies2(events, category) +print(category_frequencies) +""" ++--------+---------------------+---------------------+---------+--------+ +| | timestamp_start | timestamp_end | False | True | ++========+=====================+=====================+=========+========+ +| | 2023-01-05T13:57:05 | 2023-01-05T13:57:06 | 0 | 3 | ++--------+---------------------+---------------------+---------+--------+ +| | 2023-01-05T14:02:05 | 2023-01-05T14:02:06 | 1 | 0 | ++--------+---------------------+---------------------+---------+--------+ +| count | | | | 2 | ++--------+---------------------+---------------------+---------+--------+ +| totals | | | 1 | 3 | ++--------+---------------------+---------------------+---------+--------+ +""" + +# [5.3] Check if events are sorted. +result = is_sorted(events) +print(result) ``` ## 2.3. Short theory -The library provides tools for handling stream data. What’s a stream? It's a sequence of elements from a source that +The library provides tools for handling stream data. What's a stream? It's a sequence of elements from a source that supports aggregate operations. ### Terms @@ -367,16 +658,16 @@ supports aggregate operations. - **Data object**: An instance of `Data` class which is wrapper under stream. - **Sequence of elements**: A _Data object_ provides an interface to a sequenced set of values of a specific element type. Stream inside the _Data - object_ **don’t actually store** elements; they are computed on demand. -- **DataSource**: - Any source of data. E.g. [Report Data Provider](https://github.com/th2-net/th2-rpt-data-provider), collections, + object_ **dont actually store** elements; they are computed on demand. +- **data source** (exactly in small letters): + Any source of data. E.g. [Lightweight Data Provider](https://github.com/th2-net/th2-lw-data-provider), collections, arrays, or I/O resources. -- **ProviderDataSource**: - The DataSource object whose source is [Report Data Provider](https://github.com/th2-net/th2-rpt-data-provider). +- **DataSource**: + A class that is an intermediate link between the SourceAPI and Commands. - **SourceAPI**: Each source has its own API to retrieve data. SourceAPI is a class that provide API for some data source. - **Commands**: - Objects that provide user-friendly interfaces for getting some data from DataSource. Commands use _SourceAPI_ to + Classes that provide user-friendly interfaces for getting some data from DataSource. Commands use _SourceAPI_ to achieve it. - **Adapters**: It's similar to function for `Data.map` method. Adoptable commands used it to update the data stream. @@ -388,8 +679,8 @@ supports aggregate operations. The library describes the high-level interfaces `ISourceAPI`, `IDataSource`, `ICommand`, `IAdapter`. -Any data source must be described by the `IDataSource` abstract class. These can be _FileDataSource_, _CSVDataSource_, _ -DBDataSource_ and other. +Any data source must be described by the `IDataSource` abstract class. These can be _FileDataSource_, +_CSVDataSource_, _DBDataSource_ and other. Usually, data sources have some kind of API. Databases - provide SQL language, when working with a file, you can read line by line, etc. This API is described by the `ISourceAPI` class. Because different versions of the same data source @@ -401,9 +692,8 @@ by `ICommand` classes. `IAdapter` classes transform data stream like functions for `Data.map` method. Essentially it's the same thing but more flexible. -Thus, the native `ProviderDataSource` and the set of commands for it are described. This approach provides great -opportunities for extension. You can easily create your own unique commands for _ProviderDataSource_, as well as entire -_DataSource_ classes. +For example, LwDP DataSource(https://github.com/th2-net/th2-ds-source-lwdp) uses these abstract classes to build its implementation.You can easily create your own unique commands for _LwDP DataSource_, as well as entire +_DataSource_ classes. [Here is a documentation](documentation/datasource.md) on how to implement these interfaces. ![Data stream pipeline](documentation/img/concept.png) @@ -423,6 +713,31 @@ Many stream operations return a stream themselves. This allows operations to be In contrast to collections, which are iterated explicitly (external iteration), stream operations do the iteration behind the scenes for you. Note, it doesn't mean you cannot iterate the _Data object_. + +### Data iteration + +The Data object constructor method takes in as argument either an iterator over objects or a generator function. +The Data object iterator handles each item in this iterator or generator as they are, meaning it doesn't try to read the content of item or return them modified in any way, instead returns the item itself. +The only exception to this is when Data object is built using iterator or generator over other Data objects. Note that this iterator or generator must only be yielding Data objects and nothing else. If we build from a mix of Data objects and some other types, Data objects' content won't be read and instead it will be returned as Data object itself. + +Small example to demonstrate: + +```python +from th2_data_services.data import Data + +d1 = Data([1,2,3]) +d2 = Data([4,5,6]) + +only_data_objects = Data([d1,d2]) # Will iterate as 1,2,3,4,5,6 +data_and_list = Data([d1,[4,5,6]]) # Will iterate as d1, [4,5,6] +data_and_numbers = Data([d1,4,5,6]) # Will iterate as d1,4,5,6 +lists_only = Data([1,2,3],[4,5,6]) # Will iterate as [1,2,3],[4,5,6] + +# If we want to iterate over content of list of lists, we should first create Data objects from them, +# then use them to construct new Data object as in case of d1 and d2, creating 'only_data_objects' in this example. +``` + + ### Data caching The _Data object_ provides the ability to use the cache. The cache works for each _Data object_, that is, you choose @@ -442,18 +757,21 @@ your source can be the data source, the parent cache, or own cache: Note that the cache state of the Data object is not inherited. -### EventsTree and collections +#### Forced caching +You can tell DS to cache data to specific cache file, which won't be deleted after script end. +You can see example in 1.12 section of [get_started_example](examples/get_started_example.py). + + +### EventTree and collections -#### EventsTree +#### EventTree -EventsTree is a tree-based data structure of events. It allows you get children and parents of event, display tree, get -full path to event etc. +`EventTree` is a tree-based data structure of events. It allows you get children and parents of event, +display tree, get full path to event etc. Details: -* EventsTree contains all events in memory. -* To reduce memory usage an EventsTreeCollection delete the 'body' field from events, but you can preserve it specify ' - preserve_body'. +* `EventTree` contains all events in memory. * Tree has some important terms: 1. _Ancestor_ is any relative of the event up the tree (grandparent, parent etc.). 2. _Parent_ is only the first relative of the event up the tree. @@ -472,28 +790,28 @@ Take a look at the following HTML tree to understand them. #### Collections -**EventsTreeCollection** is a collection of EventsTrees. The collection builds a few _EventsTree_ by passed _Data +**EventTreeCollection** is a collection of EventTrees. The collection builds a few _EventTree_ by passed _Data object_. Although you can change the tree directly, it's better to do it through collections because they are aware of -`detached_events` and can solve some events dependencies. The collection has similar features like a single _EventsTree_ -but applying them for all EventsTrees. +`detached_events` and can solve some events dependencies. The collection has similar features like a single _EventTree_ +but applying them for all _EventTrees_. -**ParentEventsTreeCollection** is a collection similar to EventsTreeCollection but containing only parent events that -are referenced in the data stream. It will be working data in the collection and trees of collection. The collection has -features similar to EventsTreeCollection. +**ParentEventTreeCollection** is a collection similar to _EventTreeCollection_ but containing only parent events that +are referenced in the data stream. The collection has features similar to _EventTreeCollection_. Details: +* To use ET collections you need to initialize them by _ETCDriver_. Data sources usually provide them. + You can create it by yourself depending on your data structure. * The collection has a feature to recover events. All events that are not in the received data stream, but which are referenced will be loaded from the data source. -* If you haven't passed a _DataSource object_ then the recovery of events will not occur. -* You can take `detached_events` to see which events are missing. It looks like `{parent_id: [events are referenced]}` +* You can take `detached_events` to see which events are missing. * If you want, you can build parentless trees where the missing events are stubbed instead. Just use `get_parentless_trees()`. Requirements: -1. Events have to have `event_name`, `event_id`, `parent_event_id` fields, which are described in the -passed `event_struct` object. +1. Events provided to ETC have to have `event_name`, `event_id`, `parent_event_id` fields. They +can have another names (it resolves in the driver). #### Hints @@ -504,21 +822,62 @@ passed `event_struct` object. * If you want to know that specified event exists, use the python `in` keyword (e.g. `'event-id' in events_tree`). * Use the python `len` keyword to get events number in the tree. +### Field Resolvers +Interface can be found in `th2_data_services/interfaces/utils/resolver.py`. +All data-sources should implement them. + +The idea of using resolvers: +It solves the problem of having a few DataSources with similar data, +but with different ways to get it. + +These classes provide you getter methods. +Using these classes allows you to freely switch between different data +formats and don't change your code. + +Resolvers solve the problem of data-format migration. +- fields place can be changed +- fields names can be changed + +Resolvers can work only with one event/message. +It means, if your message has sub-messages (like th2-messages in lwdp) it +won't work, because resolver will not know with which sub-message should it work. + +**Workaround** +1. Expand all your messages -> `new_d = your_data.map(MessageFieldResolver.expand_message)` +2. Use `ExpandedMessageFieldResolver` instead of usual `MessageFieldResolver` when + you take fields for expanded messages. + +**Implementation advice:** +1. raise NotImplementedError -- if your Implementation doesn't support this getter. + +**Performance impact:** +- It a bit slower than using naked field access `dict['key']`. + ## 2.4. Links - [Report Data Provider](https://github.com/th2-net/th2-rpt-data-provider) - [Th2 Data Services Utils](https://github.com/th2-net/th2-data-services-utils) -# 3. API +# 3. Best practices +Depending on how you work with `Data object`, it can be slow of fast. +As with a relational database, you can write a query that will return data slowly or quickly, +the same when working with a `Data object`. -If you are looking for classes description see the [API Documentation](documentation/api/index.md). +Follow the rules to make your work with Data object fast: +1. Use `Data.use_cache()` if you iterate data more than one time. +2. Try to don't iterate one `Data object` inside the other one. + If you should to do it, use short `Data object` first and long `Data object` inside the loop. + It'll allow you open the cache file or create a request to `Data source` less number of times. + +# 4. Official DataSource implementations -# 4. Examples +- [Lightweight Data Provider Data Source](https://github.com/th2-net/th2-ds-source-lwdp) -## 4.1. Notebooks -- [notebook_0.ipynb](examples/notebooks/notebook_0.ipynb) +# 5. API + +If you are looking for classes description see the [API Documentation](documentation/api/index.md). -## 4.2. *.py +# 6. Examples - [get_started_example.py](examples/get_started_example.py) diff --git a/api_gen.py b/api_gen.py index 04601c63..a14c7c2f 100644 --- a/api_gen.py +++ b/api_gen.py @@ -3,7 +3,7 @@ # The parameters of this function correspond to the CLI options generate_docs( ["th2_data_services"], - ignored_modules=["provider.v5.struct"], + # ignored_modules=[], output_path="./documentation/api", overview_file="index.md", validate=False, diff --git a/attach_file_to.sh b/attach_file_to.sh index b46a5d2b..d1f26d75 100755 --- a/attach_file_to.sh +++ b/attach_file_to.sh @@ -1,46 +1,35 @@ #!/bin/bash -set -euo pipefail +function get_line_number () { + local text=$1; + local file=$2; + grep "$text" $file -n -m1 | cut -d':' -f1 +} attachable_file=$1 attachable_file_path=$(find "$PWD" -name "$attachable_file") -output_file_path=$PWD"/"$2 +attach_to=$2 function main() { - status=$(git status) - - if [[ "$status" =~ .*"$attachable_file".* ]]; then - count=0 - start_line=0 - end_line=0 - - exec 0<"$output_file_path" - while read -r line - do - count=$((count+1)) - - if [[ $line =~ " + + + +# module `config.config` + + + + +**Global Variables** +--------------- +- **options** + + +--- + + + +## class `TH2Config` + + + + + + +### method `__init__` + +```python +__init__() → None +``` + +Global configuration for the DS library. + + + + +--- + + + +### method `setup_resolvers` + +```python +setup_resolvers( + for_event: EventFieldResolver, + for_message: MessageFieldResolver, + for_submessage: SubMessageFieldResolver, + for_expanded_message: ExpandedMessageFieldResolver +) → TH2Config +``` + +Use this to set up your custom resolvers. + + + +**Args:** + for_event: for_message: for_submessage: for_expanded_message: + + + +**Returns:** + self + + + + +--- + +_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/config.md b/documentation/api/config.md new file mode 100644 index 00000000..b990f7c4 --- /dev/null +++ b/documentation/api/config.md @@ -0,0 +1,16 @@ + + + + +# module `config` + + + + + + + + +--- + +_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/data.md b/documentation/api/data.md index 38881949..a21b9ba9 100644 --- a/documentation/api/data.md +++ b/documentation/api/data.md @@ -11,7 +11,7 @@ --- - + ## class `Data` A wrapper for data/data_stream. @@ -20,15 +20,16 @@ The class provides methods for working with data as a stream. Such approach to data analysis called streaming transformation. - + ### method `__init__` ```python __init__( - data: Optional[Iterator, Callable[, Generator[dict, NoneType]], List[Iterator]], + data: Optional[Iterator, Callable[, Generator[~DataIterValues, NoneType]], List[Iterable], Iterable], cache: bool = False, - workflow: List[Dict[str, Union[Callable, str]]] = None + workflow: List[Dict[str, Union[Callable, str]]] = None, + pickle_version: int = 4 ) ``` @@ -38,9 +39,18 @@ Data constructor. **Args:** - - `data`: Data source. Any iterable, Data object or function that creates generator. + - `data`: Data source. Any iterable, Data object or a function that creates generator. - `cache`: Set True if you want to write and read from cache. - - `workflow`: Workflow. + - `workflow`: DataWorkflow. + - `pickle_version`: Pickle protocol version. Set if using cache. + + +--- + +#### property cache_status + + + --- @@ -62,11 +72,55 @@ int: How many records in the Data stream. > 1. It is a wasteful operation if you are performing it on the Data object that has never been iterated before. >2. If you want just to check emptiness, use is_empty property instead. +--- + +#### property metadata + + + + + --- - + + +### method `build_cache` + +```python +build_cache(filename) +``` + +Creates cache file with provided name. + +Important: If the Data object cache status is True, it'll iterate itself. As a result the cache file will be created and copied. When you will iterate the Data object next time, it'll iterate created cache file. + + NOTE! If you build cache file, Data.cache_status was False and after that you'll set Data.cache_status == TRUE -- the Data object WON'T iterate build file because it doesn't keep the path to built cache file.. + + + +**Args:** + + - `filename`: Name or path to cache file. + +--- + + + +### method `clear_cache` + +```python +clear_cache() +``` + +Clears related to data object cache file. + +This function won't remove external cache file. + +--- + + ### method `filter` @@ -90,7 +144,7 @@ Append `filter` to workflow. --- - + ### method `find_by` @@ -117,19 +171,159 @@ When to use: You have IDs of some messages and you want get them in the stream --- - + + +### classmethod `from_any_file` + +```python +from_any_file(filename, mode='r') → Data[str] +``` + +Creates a Data object from any file with the provided name. + +It will just iterate file and return data line be line. + + + +**Args:** + + - `filename`: Name or path to the file. + - `mode`: Read mode of open function. + + + +**Returns:** + + - `Data`: Data object. + + + +**Raises:** + FileNotFoundError if provided file does not exist. + +--- + + + +### classmethod `from_cache_file` + +```python +from_cache_file(filename, pickle_version: int = 4) → Data +``` + +Creates Data object from cache file with provided name. + + + +**Args:** + + - `filename`: Name or path to cache file. + - `pickle_version`: Pickle protocol version. Change default value if your pickle file was created with another pickle version. + + + +**Returns:** + + - `Data`: Data object. + + + +**Raises:** + FileNotFoundError if provided file does not exist. + +--- + + + + +### classmethod `from_csv` + +```python +from_csv( + filename: Union[str, Path], + header=None, + header_first_line=False, + mode='r', + delimiter=',' +) → Data +``` + +Creates Data object from CSV file with provided name. + +It will iterate the CSV file as if you were doing it with CSV module. + + + +**Args:** + + - `filename`: Name or path to the file. + - `header`: If provided header for csv, Data object will yield Dict[str]. Note, if your first line is header in csv, it also will be yielded. + - `header_first_line`: If the first line of the csv file is header, it'll take header from the first line. Data object will yield Dict[str]. `header` argument is not required in this case. First line of the CSV file will be skipped (header line). + - `mode`: Read mode of open function. + - `delimiter`: CSV file delimiter. + + + +**Note:** + +> If `header` provided and `header_first_line == True`, Data object will yield Dict[str] where key names (columns) as described in the `header`. First line of the CSV file will be skipped. +> + +**Returns:** + + - `Data`: Data object. + + + +**Raises:** + FileNotFoundError if provided file does not exist. + +--- + + + +### classmethod `from_json` + +```python +from_json(filename, buffer_limit=250, gzip=False) → Data[dict] +``` + +Creates Data object from json-lines file with provided name. + + + +**Args:** + + - `filename`: Name or path to cache file. + - `buffer_limit`: If limit is 0 buffer will not be used. Number of messages in buffer before parsing. + - `gzip`: Set to true if file is json file compressed using gzip. + + + +**Returns:** + + - `Data`: Data object. + + + +**Raises:** + FileNotFoundError if provided file does not exist. + +--- + + ### method `get_cache_filepath` ```python -get_cache_filepath() → Union[Path, NoneType] +get_cache_filepath() → Path ``` Returns filepath for a cache file. --- - + ### method `get_pending_cache_filepath` @@ -141,7 +335,31 @@ Returns filepath for a pending cache file. --- - + + +### method `is_sorted` + +```python +is_sorted(get_timestamp_func: Callable[[Any], Any]) → IsSortedResult +``` + +Checks whether Data is sorted. + + + +**Args:** + + - `get_timestamp_func`: This function is responsible for getting the timestamp. + + + +**Returns:** + + - `IsSortedResult`: Whether data is sorted and additional info (e.g. index of the first unsorted element). + +--- + + ### method `limit` @@ -165,12 +383,12 @@ Limits the stream to `num` entries. --- - + ### method `map` ```python -map(callback: Callable) → Data +map(callback_or_adapter: Union[Callable, IRecordAdapter]) → Data ``` Append `transform` function to workflow. @@ -179,7 +397,7 @@ Append `transform` function to workflow. **Args:** - - `callback`: Transform function. + - `callback_or_adapter`: Transform function or an Adapter with IRecordAdapter interface implementation. If the function returns None value, this value will be skipped from OUT stream. If you don't want skip None values -- use `map_stream`. @@ -189,7 +407,63 @@ Append `transform` function to workflow. --- - + + +### method `map_stream` + +```python +map_stream( + adapter_or_generator: Union[IStreamAdapter, Callable[, Generator]] +) → Data +``` + +Append `stream-transform` function to workflow. + +If StreamAdapter is passed StreamAdapter.handle method will be used as a map function. + +Difference between map and map_stream: 1. map_stream allows you return None values. 2. map_stream allows you work with the whole stream but not with only 1 element, so you can implement some buffers inside handler. 3. map_stream works slightly efficient (faster on 5-10%). + + + +**Args:** + + - `adapter_or_generator`: StreamAdapter object or generator function. + + + +**Returns:** + + - `Data`: Data object. + +--- + + + +### method `map_yield` + +```python +map_yield(callback_or_adapter: Union[Callable, IRecordAdapter]) +``` + +Maps the stream using callback function or adapter. + +Differences between map and map yield: 1. map_yield is a wrapper function using map_stream. 2. map_yield iterates over each item in record if callback return value is a list or tuple. + + + +**Args:** + + - `callback_or_adapter`: Transform function or an Adapter with IRecordAdapter interface implementation. + + + +**Returns:** + + - `Data`: Data object. + +--- + + ### method `sift` @@ -213,7 +487,153 @@ Skips and limits records. --- - + + +### method `to_json` + +```python +to_json(filename: Union[str, Path], indent: int = None, overwrite: bool = False) +``` + +Converts data to valid json format. + + + +**Args:** + + - `filename` (str): Output JSON filename + - `indent` (int, optional): JSON format indent. Defaults to None. + - `overwrite` (bool, optional): Overwrite if filename exists. Defaults to False. + + + +**NOTE:** + +> Data object can iterate not only dicts. So not every data can be saved as json. +> + +**Raises:** + + - `FileExistsError`: If file exists and overwrite=False + +--- + + + +### method `to_json_lines` + +```python +to_json_lines( + filename: Union[str, Path], + indent: int = None, + overwrite: bool = False, + gzip: bool = False, + compresslevel: int = 5 +) +``` + +Converts Data to json lines. + +Every line is a valid json, but the whole file - not. + + + +**Args:** + + - `filename` (str): Output JSON filename. + - `indent` (int, optional): DON'T used now. + - `overwrite` (bool, optional): Overwrite if filename exists. Defaults to False. + - `gzip`: Set to True if you want to compress the file using gzip. + - `compresslevel`: gzip compression level. + + + +**NOTE:** + +> Data object can iterate not only dicts. So not every data can be saved as json. +> + +**Raises:** + + - `FileExistsError`: If file exists and overwrite=False + +--- + + + +### method `to_jsons` + +```python +to_jsons( + filename: Union[str, Path], + indent: int = None, + overwrite: bool = False, + gzip=False, + compresslevel=5 +) +``` + +[DEPRECATED] Converts data to json lines. + +Every line is a valid json, but the whole file - not. + + + +**Args:** + + - `filename` (str): Output JSON filename. + - `indent` (int, optional): DON'T used now. + - `overwrite` (bool, optional): Overwrite if filename exists. Defaults to False. + - `gzip`: Set to True if you want to compress the file using gzip. + - `compresslevel`: gzip compression level. + + + +**Raises:** + + - `FileExistsError`: If file exists and overwrite=False + +--- + + + +### method `update_metadata` + +```python +update_metadata(metadata: Dict) → Data +``` + +Update metadata of object with metadata argument. + +Metadata is updated with new values, meaning previous values are kept and added with new values. + +| Example: | data = Data(...) | # data.metadata => {'num': 1, 'nums': [1], 'letters': {'a': 97}} | new_metadata = {'num': 9, 'nums': [7], 'letters': {'z': 122}, 'new': 'key'} | data.update_metadata(new_metadata) | # data.metadata => {'num': 9, 'nums': [1,7], 'letters': {'a': 97, 'z': 122}, 'new': 'key'} + +If at least one value with is a list in one Data object, update_metadata adds both values in a list. + +| Example: | data = Data(...) | # data.metadata => {'str_example_one': ['str1'], 'str_example_two': 'str1'} | new_metadata = {'str_example_one': 'str2', 'str_example_two': ['str2']} | data.update_metadata(new_metadata) | # data.metadata => {'str_example_one': ['str1', 'str2'], 'str_example_two': ['str1', 'str2']} + + + +**Args:** + + - `metadata` (dict): New Metadata + + + +**Returns:** + Data objects (itself) + + + +**Raises:** + + - `Exception`: If metadata isn't dict, error will be raised. + - `AttributeError`: If you're trying to update key value with dict which isn't a dict. + +--- + + ### method `use_cache` @@ -237,7 +657,7 @@ Changes cache flag and returns self. --- - + ### method `write_to_file` diff --git a/documentation/api/decode_error_handler.md b/documentation/api/decode_error_handler.md deleted file mode 100644 index fd0bdd72..00000000 --- a/documentation/api/decode_error_handler.md +++ /dev/null @@ -1,31 +0,0 @@ - - - - -# module `decode_error_handler` - - - - -**Global Variables** ---------------- -- **UNICODE_REPLACE_HANDLER** - ---- - - - -## function `handler` - -```python -handler(err: UnicodeDecodeError) -``` - -Decode error handler that tries change utf-8 character to Unicode. - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/dummy.data_source.md b/documentation/api/dummy.data_source.md new file mode 100644 index 00000000..ceae9480 --- /dev/null +++ b/documentation/api/dummy.data_source.md @@ -0,0 +1,51 @@ + + + + +# module `dummy.data_source` + + + + + + +--- + + + +## class `DummyDataSource` +Dummy DataSource. + +Can be useful to create ETCDriver without concrete DataSource or to in unit tests. + + +--- + +#### property source_api + + + + + + + +--- + + + +### method `command` + +```python +command(cmd: ICommand) +``` + + + + + + + + +--- + +_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/dummy.md b/documentation/api/dummy.md new file mode 100644 index 00000000..0240beff --- /dev/null +++ b/documentation/api/dummy.md @@ -0,0 +1,16 @@ + + + + +# module `dummy` + + + + + + + + +--- + +_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/event_tree.etc_driver.md b/documentation/api/event_tree.etc_driver.md new file mode 100644 index 00000000..92ed4aab --- /dev/null +++ b/documentation/api/event_tree.etc_driver.md @@ -0,0 +1,129 @@ + + + + +# module `event_tree.etc_driver` + + + + + + +--- + + + +## class `IETCDriver` + + + + + + +### method `__init__` + +```python +__init__( + event_struct: IEventStruct, + data_source: IDataSource, + use_stub: bool = False +) +``` + +The driver for EventsTreeCollection and its inheritors. + + + +**Args:** + + - `event_struct`: Structure of the event. + - `data_source`: DataSource object. + - `use_stub`: Build stubs or not. + + + + +--- + + + +### method `build_stub_event` + +```python +build_stub_event(id_: str) → ~Th2EventType +``` + +Builds stub event to generate parentless trees. + + + +**Args:** + + - `id_`: Event Id. + +--- + + + +### method `get_event_id` + +```python +get_event_id(event: ~Th2EventType) +``` + +Returns event id from the event. + +--- + + + +### method `get_event_name` + +```python +get_event_name(event: ~Th2EventType) +``` + +Returns event name from the event. + +--- + + + +### method `get_events_by_id_from_source` + +```python +get_events_by_id_from_source(ids: Sequence) → list +``` + +Downloads the list of events from the provided data_source. + +--- + + + +### method `get_parent_event_id` + +```python +get_parent_event_id(event: ~Th2EventType) +``` + +Returns parent event id from the event. + +--- + + + +### method `stub_event_name` + +```python +stub_event_name() +``` + +Returns stub event name. + + + + +--- + +_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/event_tree.event_tree.md b/documentation/api/event_tree.event_tree.md new file mode 100644 index 00000000..26a3aa14 --- /dev/null +++ b/documentation/api/event_tree.event_tree.md @@ -0,0 +1,624 @@ + + + + +# module `event_tree.event_tree` + + + + + + +--- + + + +## class `EventTree` +EventTree is a tree-based data structure of events. + + +- get_x methods raise Exceptions if no result is found. +- find_x methods return None if no result is found. +- EventTree stores events as Nodes and interacts with them using an internal tree. +- Note that EventTree stores only one tree. If you want to store all trees, use EventTreeCollections. +- EventTree contains all events in memory. + +Take a look at the following HTML tree to understand some important terms. + +``` + +
+

Hello, world!

+

Goodbye!

+
+ +``` + + + +### method `__init__` + +```python +__init__(event_name: str, event_id: str, data: dict = None) +``` + +EventTree constructor. + + + +**Args:** + + - `event_name`: Event Name. + - `event_id`: Event Id. + - `data`: Data of event. + + + + +--- + + + +### method `append_event` + +```python +append_event( + event_name: str, + event_id: str, + parent_id: str, + data: dict = None +) → None +``` + +Appends the event to the tree. + + + +**Args:** + + - `event_name`: Event Name. + - `event_id`: Event Id. + - `parent_id`: Parent Id. + - `data`: Data of event. + +--- + + + +### method `find` + +```python +find(filter: Callable, stop: Callable = None) → Union[dict, NoneType] +``` + +Searches the first event match. + + +- The search uses 'filter' which is a filtering function. +- Optionally, the search uses 'stop' which is a stopping function. If 'stop' function returns 'True' then search is complete. + + + +**Args:** + + - `filter`: Filter function. + - `stop`: Stop function. If None searches for all nodes in the tree. + + + +**Returns:** + One matching event. + +--- + + + +### method `find_ancestor` + +```python +find_ancestor(id: str, filter: Callable) → Union[dict, NoneType] +``` + +Finds the ancestor of an event. + + + +**Args:** + + - `id`: Event id. + - `filter`: Filter function + + + +**Returns:** + Ancestor of Event. + +--- + + + +### method `findall` + +```python +findall( + filter: Callable, + stop: Callable = None, + max_count: int = None +) → List[dict] +``` + +Searches events matches. + + +- The search uses 'filter' which is a filtering function. +- Optionally, the search uses 'stop' which is a stopping function. If 'stop' function returns 'True' then search is complete. +- 'max_count' is a parameter that limits the search to a specified count. + + + +**Args:** + + - `filter`: Filter function. + - `stop`: Stop function. If None searches for all nodes in the tree. + - `max_count`: Max count of matched events. Stops searching when `max_count` will be reached. + + + +**Returns:** + Matching events. + +--- + + + +### method `findall_iter` + +```python +findall_iter( + filter: Callable, + stop: Callable = None, + max_count: int = None +) → Generator[dict, NoneType, NoneType] +``` + +Searches events matches as iterator. + + +- The search uses 'filter' which is a filtering function. +- Optionally, the search uses 'stop' which is a stopping function. If 'stop' function returns 'True' then search is complete. +- 'max_count' is a parameter that limits the search to a specified count. + + + +**Args:** + + - `filter`: Filter function. + - `stop`: Stop function. If None searches for all nodes in the tree. + - `max_count`: Max count of matched events. Stops searching when `max_count` will be reached. + + + +**Yields:** + Matching events. + +--- + + + +### method `get_all_events` + +```python +get_all_events() → List[dict] +``` + +Returns all events from the tree. + +--- + + + +### method `get_all_events_iter` + +```python +get_all_events_iter() → Generator[dict, NoneType, NoneType] +``` + +Returns all events from the tree as iterator. + +--- + + + +### method `get_ancestors` + +```python +get_ancestors(id: str) → List[dict] +``` + +Returns all event's ancestors in right order. + + + +**Args:** + + - `id`: Event id. + + + +**Returns:** + All event's ancestors. + + + +**Raises:** + + - `EventIdNotInTree`: If event id is not in the tree. + +--- + + + +### method `get_children` + +```python +get_children(id: str) → Tuple[dict] +``` + +Returns children for the event by its id. + + + +**Args:** + + - `id`: Event id. + + + +**Raises:** + + - `EventIdNotInTree`: If event id is not in the tree. + +--- + + + +### method `get_children_iter` + +```python +get_children_iter(id: str) → Generator[dict, NoneType, NoneType] +``` + +Returns children as iterator for the event by its id. + + + +**Args:** + + - `id`: Event id. + + + +**Raises:** + + - `EventIdNotInTree`: If event id is not in the tree. + +--- + + + +### method `get_event` + +```python +get_event(id: str) → dict +``` + +Returns an event by id. + + + +**Args:** + + - `id`: Event id. + + + +**Raises:** + + - `EventIdNotInTree`: If event id is not in the tree. + +--- + + + +### method `get_full_path` + +```python +get_full_path(id: str, field: str = None) → List[Union[str, dict]] +``` + +Returns the full path for the event by its id in right order. + + + +**Examples:** + + +Imagine we have the following tree. + +``` +Harry +├── Bill +└── Jane + ├── Diane + │ └── Mary + └── Mark +``` + +``` +tree.get_full_path('Jane', id) +['Harry-event-id', 'Jane-event-id'] + +tree.get_full_path('Jane', name) +['Harry-event-name', 'Jane-event-name'] + +tree.get_full_path('Jane') +['Harry-event', 'Jane-event'] +``` + + + +**Args:** + + - `id`: Event id. + - `field`: Field of event. + + + +**Returns:** + Full path of event. + + + +**Raises:** + + - `EventIdNotInTree`: If event id is not in the tree. + +--- + + + +### method `get_leaves` + +```python +get_leaves() → Tuple[dict] +``` + +Returns all tree leaves. + +--- + + + +### method `get_leaves_iter` + +```python +get_leaves_iter() → Generator[dict, NoneType, NoneType] +``` + +Returns all tree leaves as iterator. + +--- + + + +### method `get_parent` + +```python +get_parent(id: str) → Union[dict, NoneType] +``` + +Returns a parent for the event by its id. + +Returns None if the provided ID is a root of the tree. + + + +**Args:** + + - `id`: Event id. + + + +**Raises:** + + - `EventIdNotInTree`: If event id is not in the tree. + +--- + + + +### method `get_root` + +```python +get_root() → dict +``` + +Returns the root event. + +--- + + + +### method `get_root_id` + +```python +get_root_id() → str +``` + +Returns the root id. + +--- + + + +### method `get_root_name` + +```python +get_root_name() → str +``` + +Returns the root name. + +--- + + + +### method `get_subtree` + +```python +get_subtree(id: str) → EventTree +``` + +Returns subtree of the event by its id. + + + +**Args:** + + - `id`: Event id. + + + +**Returns:** + Subtree. + + + +**Raises:** + + - `EventIdNotInTree`: If event id is not in the tree. + +--- + + + +### method `merge_tree` + +```python +merge_tree( + parent_id: str, + other_tree: 'EventTree', + use_deepcopy: bool = False +) → None +``` + +Merges a EventTree to specified identifier. + + + +**Args:** + + - `parent_id`: Event id to which merge. + - `other_tree`: EventTree. + - `use_deepcopy`: True if you need deepcopy for your objects in event. + + + +**Raises:** + + - `EventIdNotInTree`: If event id is not in the tree. + +--- + + + +### method `show` + +```python +show() → None +``` + +Prints the EventTree as tree view. + +For example: + +``` +Root + |___ C01 + | |___ C11 + | |___ C111 + | |___ C112 + |___ C02 + |___ C03 + | |___ C31 +``` + +--- + + + +### method `summary` + +```python +summary() → str +``` + +Returns the tree summary. + +--- + + + +### method `update_event_name` + +```python +update_event_name(event_id: str, event_name: str) → None +``` + +Updates Event name in the tree. Note that it doesn't change internal data. + + + +**Args:** + + - `event_id`: Event id. + - `event_name`: Event name. + + + +**Raises:** + + - `EventIdNotInTree`: If event id is not in the tree. + +--- + + + +### method `update_parent_link` + +```python +update_parent_link(event_id: str, parent_id: str) → None +``` + +Updates the link to parent. + + + +**Args:** + + - `event_id`: Event id. + - `parent_id`: New parent id. + + + +**Raises:** + + - `EventIdNotInTree`: If event id is not in the tree. + - `TreeLoop`: If parent id will point to the descendant event. + + + + +--- + +_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/interfaces.events_tree.events_tree_collection.md b/documentation/api/event_tree.event_tree_collection.md similarity index 55% rename from documentation/api/interfaces.events_tree.events_tree_collection.md rename to documentation/api/event_tree.event_tree_collection.md index 80144ce0..239b0795 100644 --- a/documentation/api/interfaces.events_tree.events_tree_collection.md +++ b/documentation/api/event_tree.event_tree_collection.md @@ -1,8 +1,8 @@ - + -# module `interfaces.events_tree.events_tree_collection` +# module `event_tree.event_tree_collection` @@ -11,46 +11,32 @@ --- - + -## class `EventsTreeCollection` -EventsTreeCollection objective is building 'EventsTree's and storing them. +## class `EventTreeCollection` +EventTreeCollection objective is building 'EventsTree's and storing them. -- EventsTreeCollection stores all EventsTree. You can to refer to each of them. +- EventTreeCollection stores all EventsTree. You can to refer to each of them. - Recovery of missing events occurs when you have passed DataSource class to constructor. Otherwise you should execute the method 'recover_unknown_events' manually. Note that there is no point in the method if the list of detached events is empty. - + ### method `__init__` ```python -__init__( - data: Data, - data_source: IProviderDataSource = None, - preserve_body: bool = False, - stub: bool = False -) +__init__(driver: IETCDriver) ``` -EventsTreeCollection constructor. +EventTreeCollection constructor. **Args:** - - `data`: Data object with events. - - `data_source`: Provider Data Source object. - - `preserve_body`: If True it will preserve 'body' field in the Events. - - `stub`: If True it will create stub when event is broken. + - `driver`: initialized driver object. ---- - -#### property detached_events - -Returns detached events as a dict that looks like {'parent_id': ['referenced event', ...]}. - --- #### property len_detached_events @@ -73,7 +59,7 @@ Returns number of events in the trees inside the collection, including parentles --- - + ### method `append_event` @@ -91,7 +77,21 @@ Appends event into a tree. --- - + + +### method `build` + +```python +build(data: Iterable) +``` + + + + + +--- + + ### method `find` @@ -121,7 +121,7 @@ This method applicable only for trees (regular or parentless), not for detached --- - + ### method `find_ancestor` @@ -147,7 +147,7 @@ This method applicable only for trees (regular or parentless), not for detached --- - + ### method `findall` @@ -183,7 +183,7 @@ This method applicable only for trees (regular or parentless), not for detached --- - + ### method `findall_iter` @@ -219,7 +219,7 @@ This method applicable only for trees (regular or parentless), not for detached --- - + ### method `get_all_events` @@ -231,7 +231,7 @@ Returns all events from the collection. --- - + ### method `get_all_events_iter` @@ -243,7 +243,7 @@ Yields all events from the collection. --- - + ### method `get_ancestors` @@ -274,7 +274,7 @@ This method applicable only for trees (regular or parentless), not for detached --- - + ### method `get_children` @@ -300,7 +300,7 @@ This method applicable only for trees (regular or parentless), not for detached --- - + ### method `get_children_iter` @@ -310,7 +310,7 @@ get_children_iter(id: str) → Generator[dict, NoneType, NoneType] Yields children of the event by its id. -This method applicable only for trees (regular or parentless), not for detached events. +This method is applicable only for trees (regular or parentless), not for detached events. @@ -326,7 +326,7 @@ This method applicable only for trees (regular or parentless), not for detached --- - + ### method `get_detached_events` @@ -338,7 +338,7 @@ Returns detached events list. --- - + ### method `get_detached_events_iter` @@ -350,7 +350,7 @@ Yields detached events. --- - + ### method `get_event` @@ -374,7 +374,7 @@ Returns an event by its id. --- - + ### method `get_full_path` @@ -433,7 +433,7 @@ collection.get_full_path('Jane') --- - + ### method `get_leaves` @@ -445,7 +445,7 @@ Returns all trees leaves, including parentless trees. --- - + ### method `get_leaves_iter` @@ -457,16 +457,18 @@ Yields all trees leaves, including parentless trees. --- - + ### method `get_parent` ```python -get_parent(id: str) → dict +get_parent(id: str) → Union[dict, NoneType] ``` Returns a parent of the event by its id. +Returns None if the provided ID is a root of any of the trees in ETC. + **Args:** @@ -477,35 +479,35 @@ Returns a parent of the event by its id. **Raises:** - - `NodeIDAbsentError`: If event id is not in the trees. + - `EventIdNotInTree`: If event id is not in the tree. --- - + ### method `get_parentless_tree_collection` ```python -get_parentless_tree_collection() → EventsTreeCollection +get_parentless_tree_collection() → EventTreeCollection ``` -Builds and returns parentless trees by detached events as EventsTreeCollection. +Builds and returns parentless trees by detached events as EventTreeCollection. Detached events will be removed from the collection. **Returns:** - EventsTreeCollection. + EventTreeCollection. --- - + ### method `get_parentless_trees` ```python -get_parentless_trees() → List[EventsTree] +get_parentless_trees() → List[EventTree] ``` Builds and returns parentless trees by detached events. @@ -519,7 +521,7 @@ Detached events will be removed from the tree. --- - + ### method `get_root_by_id` @@ -550,7 +552,7 @@ If event id of parentless tree is passed, stub of this parentless tree will be r --- - + ### method `get_roots_ids` @@ -564,12 +566,12 @@ If there are parentless trees, they also will be return. --- - + ### method `get_subtree` ```python -get_subtree(id: str) → EventsTree +get_subtree(id: str) → EventTree ``` Returns subtree of the event by its id. @@ -595,12 +597,12 @@ This method applicable only for trees (regular or parentless), not for detached --- - + ### method `get_tree_by_id` ```python -get_tree_by_id(id) → EventsTree +get_tree_by_id(id) → EventTree ``` Returns a tree by id of any event in this tree. @@ -626,12 +628,12 @@ If event id of parentless tree is passed, stub of this parentless tree will be r --- - + ### method `get_trees` ```python -get_trees() → List[EventsTree] +get_trees() → List[EventTree] ``` Returns the list of trees inside the collection. @@ -640,25 +642,25 @@ If there are parentless trees, they also will be return. --- - + ### method `recover_unknown_events` ```python -recover_unknown_events(data_source: IProviderDataSource) → None +recover_unknown_events(preprocessor=None) → None ``` -Loads missed events and recover events. +Loads missed events and finish tree building. **Args:** - - `data_source`: Data Source. + - `preprocessor`: the function that will be executed for each recovered event before store. --- - + ### method `show` @@ -683,7 +685,7 @@ Root --- - + ### method `summary` @@ -693,7 +695,7 @@ summary() → str Returns the collection summary. -The same as repr(EventsTreeCollection). +The same as repr(EventTreeCollection). diff --git a/documentation/api/event_tree.exceptions.md b/documentation/api/event_tree.exceptions.md new file mode 100644 index 00000000..66654f35 --- /dev/null +++ b/documentation/api/event_tree.exceptions.md @@ -0,0 +1,162 @@ + + + + +# module `event_tree.exceptions` + + + + + + +--- + + + +## class `EventIdNotInTree` + + + + + + +### method `__init__` + +```python +__init__(id_: str) +``` + +Exception for the case when the tree hasn't the event. + + + +**Args:** + + - `id_`: Event id. + + + + + +--- + + + +## class `FieldIsNotExist` + + + + + + +### method `__init__` + +```python +__init__(field_name: str) +``` + +Exception for the case when event as dict hasn't field. + + + +**Args:** + + - `field_name`: Field name. + + + + + +--- + + + +## class `EventAlreadyExist` + + + + + + +### method `__init__` + +```python +__init__(event_id: str) +``` + +Exception for the case when event already exist in tree. + + + +**Args:** + + - `event_id`: Event id. + + + + + +--- + + + +## class `EventRootExist` + + + + + + +### method `__init__` + +```python +__init__(event_id: str) +``` + +Exception for the case when root already added in tree. + + + +**Args:** + + - `event_id`: Event id. + + + + + +--- + + + +## class `TreeLoop` + + + + + + +### method `__init__` + +```python +__init__(event_id: str, parent_id: str) +``` + +Exception for the case when an event has link to a parent which is its descendant. + + + +**Args:** + + - `event_id`: Event id. + - `parent_id`: Parent id. + + + + + + + +--- + +_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.v6.adapters.md b/documentation/api/event_tree.md similarity index 62% rename from documentation/api/provider.v6.adapters.md rename to documentation/api/event_tree.md index bdb5131d..400c1900 100644 --- a/documentation/api/provider.v6.adapters.md +++ b/documentation/api/event_tree.md @@ -1,15 +1,15 @@ - + -# module `provider.v6.adapters` +# module `event_tree` **Global Variables** --------------- -- **basic_adapters**: # Copyright 2022 Exactpro (Exactpro Systems Limited) +- **event_tree**: # Copyright 2022-2025 Exactpro (Exactpro Systems Limited) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -23,7 +23,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -- **event_adapters**: # Copyright 2022 Exactpro (Exactpro Systems Limited) +- **event_tree_collection**: # Copyright 2022-2025 Exactpro (Exactpro Systems Limited) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -37,7 +37,21 @@ # See the License for the specific language governing permissions and # limitations under the License. -- **message_adapters**: # Copyright 2022 Exactpro (Exactpro Systems Limited) +- **parent_event_tree_collection**: # Copyright 2022-2025 Exactpro (Exactpro Systems Limited) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +- **etc_driver**: # Copyright 2023-2025 Exactpro (Exactpro Systems Limited) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/documentation/api/event_tree.parent_event_tree_collection.md b/documentation/api/event_tree.parent_event_tree_collection.md new file mode 100644 index 00000000..9934edc8 --- /dev/null +++ b/documentation/api/event_tree.parent_event_tree_collection.md @@ -0,0 +1,47 @@ + + + + +# module `event_tree.parent_event_tree_collection` + + + + + + +--- + + + +## class `ParentEventTreeCollection` +ParentEventTreeCollections is a class like an EventsTreeCollections. + +ParentEventsTree contains all parent events that are referenced. + + +--- + +#### property len_detached_events + +Returns number of detached events in the collection. + +--- + +#### property len_parentless + +Returns number of events in the parentless trees inside the collection. + +--- + +#### property len_trees + +Returns number of events in the trees inside the collection, including parentless trees. + + + + + + +--- + +_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/events_tree.events_tree.md b/documentation/api/events_tree.events_tree.md deleted file mode 100644 index 4298fcd7..00000000 --- a/documentation/api/events_tree.events_tree.md +++ /dev/null @@ -1,514 +0,0 @@ - - - - -# module `events_tree.events_tree` - - - - - - ---- - - - -## class `EventsTree` -EventsTree is a tree-based data structure of events. - - -- get_x methods raise Exceptions if no result is found. -- find_x methods return None if no result is found. -- EventsTree stores events as Nodes and interacts with them using an internal tree. -- EventsTree removes the 'body' field by default to save memory, but you can keep it. -- Note that EventsTree stores only one tree. If you want to store all trees, use EventsTreeCollections. -- EventsTree contains all events in memory. - -Take a look at the following HTML tree to understand some important terms. - -``` - -
-

Hello, world!

-

Goodbye!

-
- -``` - - - -### method `__init__` - -```python -__init__(tree: Tree) -``` - -EventsTree constructor. - - - -**Args:** - - - `tree` (treelib.Tree): Tree. - - - - ---- - - - -### method `find` - -```python -find(filter: Callable, stop: Callable = None) → Union[dict, NoneType] -``` - -Searches the first event match. - - -- The search uses 'filter' which is a filtering function. -- Optionally, the search uses 'stop' which is a stopping function. If 'stop' function returns 'True' then search is complete. - - - -**Args:** - - - `filter`: Filter function. - - `stop`: Stop function. If None searches for all nodes in the tree. - - - -**Returns:** - One matching event. - ---- - - - -### method `find_ancestor` - -```python -find_ancestor(id: str, filter: Callable) → Union[dict, NoneType] -``` - -Finds the ancestor of an event. - - - -**Args:** - - - `id`: Event id. - - `filter`: Filter function - - - -**Returns:** - Ancestor of Event. - ---- - - - -### method `findall` - -```python -findall( - filter: Callable, - stop: Callable = None, - max_count: int = None -) → List[dict] -``` - -Searches events matches. - - -- The search uses 'filter' which is a filtering function. -- Optionally, the search uses 'stop' which is a stopping function. If 'stop' function returns 'True' then search is complete. -- 'max_count' is a parameter that limits the search to a specified count. - - - -**Args:** - - - `filter`: Filter function. - - `stop`: Stop function. If None searches for all nodes in the tree. - - `max_count`: Max count of matched events. Stops searching when `max_count` will be reached. - - - -**Returns:** - Matching events. - ---- - - - -### method `findall_iter` - -```python -findall_iter( - filter: Callable, - stop: Callable = None, - max_count: int = None -) → Generator[dict, NoneType, NoneType] -``` - -Searches events matches as iterator. - - -- The search uses 'filter' which is a filtering function. -- Optionally, the search uses 'stop' which is a stopping function. If 'stop' function returns 'True' then search is complete. -- 'max_count' is a parameter that limits the search to a specified count. - - - -**Args:** - - - `filter`: Filter function. - - `stop`: Stop function. If None searches for all nodes in the tree. - - `max_count`: Max count of matched events. Stops searching when `max_count` will be reached. - - - -**Yields:** - Matching events. - ---- - - - -### method `get_all_events` - -```python -get_all_events() → List[dict] -``` - -Returns all events from the tree. - ---- - - - -### method `get_all_events_iter` - -```python -get_all_events_iter() → Generator[dict, NoneType, NoneType] -``` - -Returns all events from the tree as iterator. - ---- - - - -### method `get_ancestors` - -```python -get_ancestors(id: str) → List[dict] -``` - -Returns all event's ancestors in right order. - - - -**Args:** - - - `id`: Event id. - - - -**Returns:** - All event's ancestors. - - - -**Raises:** - - - `EventIdNotInTree`: If event id is not in the tree. - ---- - - - -### method `get_children` - -```python -get_children(id: str) → Tuple[dict] -``` - -Returns children for the event by its id. - - - -**Args:** - - - `id`: Event id. - - - -**Raises:** - - - `EventIdNotInTree`: If event id is not in the tree. - ---- - - - -### method `get_children_iter` - -```python -get_children_iter(id: str) → Generator[dict, NoneType, NoneType] -``` - -Returns children as iterator for the event by its id. - - - -**Args:** - - - `id`: Event id. - - - -**Raises:** - - - `EventIdNotInTree`: If event id is not in the tree. - ---- - - - -### method `get_event` - -```python -get_event(id: str) → dict -``` - -Returns an event by id. - - - -**Args:** - - - `id`: Event id. - - - -**Raises:** - - - `EventIdNotInTree`: If event id is not in the tree. - ---- - - - -### method `get_full_path` - -```python -get_full_path(id: str, field: str = None) → List[Union[str, dict]] -``` - -Returns the full path for the event by its id in right order. - - - -**Examples:** - - -Imagine we have the following tree. - -``` -Harry -├── Bill -└── Jane - ├── Diane - │ └── Mary - └── Mark -``` - -``` -tree.get_full_path('Jane', id) -['Harry-event-id', 'Jane-event-id'] - -tree.get_full_path('Jane', name) -['Harry-event-name', 'Jane-event-name'] - -tree.get_full_path('Jane') -['Harry-event', 'Jane-event'] -``` - - - -**Args:** - - - `id`: Event id. - - `field`: Field of event. - - - -**Returns:** - Full path of event. - - - -**Raises:** - - - `EventIdNotInTree`: If event id is not in the tree. - ---- - - - -### method `get_leaves` - -```python -get_leaves() → Tuple[dict] -``` - -Returns all tree leaves. - ---- - - - -### method `get_leaves_iter` - -```python -get_leaves_iter() → Generator[dict, NoneType, NoneType] -``` - -Returns all tree leaves as iterator. - ---- - - - -### method `get_parent` - -```python -get_parent(id: str) → dict -``` - -Returns a parent for the event by its id. - - - -**Args:** - - - `id`: Event id. - - - -**Raises:** - - - `EventIdNotInTree`: If event id is not in the tree. - ---- - - - -### method `get_root` - -```python -get_root() → dict -``` - -Returns the root event. - ---- - - - -### method `get_root_id` - -```python -get_root_id() → str -``` - -Returns the root id. - ---- - - - -### method `get_root_name` - -```python -get_root_name() → str -``` - -Returns the root name. - ---- - - - -### method `get_subtree` - -```python -get_subtree(id: str) → EventsTree -``` - -Returns subtree of the event by its id. - - - -**Args:** - - - `id`: Event id. - - - -**Returns:** - Subtree. - - - -**Raises:** - - - `EventIdNotInTree`: If event id is not in the tree. - ---- - - - -### method `show` - -```python -show() → None -``` - -Prints the EventsTree as tree view. - -For example: - -``` -Root - |___ C01 - | |___ C11 - | |___ C111 - | |___ C112 - |___ C02 - |___ C03 - | |___ C31 -``` - ---- - - - -### method `summary` - -```python -summary() → str -``` - -Returns the tree summary. - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/events_tree.exceptions.md b/documentation/api/events_tree.exceptions.md deleted file mode 100644 index 08983146..00000000 --- a/documentation/api/events_tree.exceptions.md +++ /dev/null @@ -1,74 +0,0 @@ - - - - -# module `events_tree.exceptions` - - - - - - ---- - - - -## class `EventIdNotInTree` - - - - - - -### method `__init__` - -```python -__init__(id_) -``` - -Exception for the case when the tree hasn't the event. - - - -**Args:** - - - `id_`: Event id. - - - - - ---- - - - -## class `FieldIsNotExist` - - - - - - -### method `__init__` - -```python -__init__(field_name) -``` - -Exception for the case when event as dict hasn't field. - - - -**Args:** - - - `field_name`: Field name. - - - - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/exceptions.md b/documentation/api/exceptions.md new file mode 100644 index 00000000..5a851053 --- /dev/null +++ b/documentation/api/exceptions.md @@ -0,0 +1,87 @@ + + + + +# module `exceptions` + + + + + + +--- + + + +## class `EventNotFound` + + + + + + +### method `__init__` + +```python +__init__(id_, error_description) +``` + +Exception for the case when the event was not found in data source. + + + +**Args:** + + - `id_`: Event id. + - `error_description`: Description of error + + + + + +--- + + + +## class `MessageNotFound` + + + + + + +### method `__init__` + +```python +__init__(id_, error_description) +``` + +Exception for the case when the message was not found in data source. + + + +**Args:** + + - `id_`: Event id. + - `error_description`: Description of error + + + + + +--- + + + +## class `CommandError` +Exception raised for errors in the command. + + + + + + + +--- + +_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/filter.md b/documentation/api/filter.md deleted file mode 100644 index 4be97e3e..00000000 --- a/documentation/api/filter.md +++ /dev/null @@ -1,54 +0,0 @@ - - - - -# module `filter` - - - - -**Global Variables** ---------------- -- **v** - - ---- - - - -## class `Filter` -The class for using rpt-data-provider filters API. - - - -### method `__init__` - -```python -__init__( - name: str, - values: Union[str, int, float, Sequence[Union[str, int, float]]], - negative: bool = False, - conjunct: bool = False -) -``` - -Filter constructor. - - - -**Args:** - - - `name` (str): Filter name. - - `values` (Union[str, int, float, Sequence[Union[str, int, float]]]): One string with filter value or list of filter values. - - `negative` (bool): If true, will match events/messages that do not match those specified values. If false, will match the events/messages by their values. Defaults to false. - - `conjunct` (bool): If true, each of the specific filter values should be applied If false, at least one of the specific filter values must be applied. - - - - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/index.md b/documentation/api/index.md index ec65cf78..e049dd1f 100644 --- a/documentation/api/index.md +++ b/documentation/api/index.md @@ -4,172 +4,69 @@ ## Modules +- [`config`](./config.md#module-config) +- [`config.config`](./config.config.md#module-configconfig) - [`data`](./data.md#module-data) -- [`decode_error_handler`](./decode_error_handler.md#module-decode_error_handler) -- [`events_tree`](./events_tree.md#module-events_tree) -- [`events_tree.events_tree`](./events_tree.events_tree.md#module-events_treeevents_tree) -- [`events_tree.exceptions`](./events_tree.exceptions.md#module-events_treeexceptions) -- [`filter`](./filter.md#module-filter) +- [`dummy`](./dummy.md#module-dummy) +- [`dummy.data_source`](./dummy.data_source.md#module-dummydata_source) +- [`event_tree`](./event_tree.md#module-event_tree) +- [`event_tree.etc_driver`](./event_tree.etc_driver.md#module-event_treeetc_driver) +- [`event_tree.event_tree`](./event_tree.event_tree.md#module-event_treeevent_tree) +- [`event_tree.event_tree_collection`](./event_tree.event_tree_collection.md#module-event_treeevent_tree_collection) +- [`event_tree.exceptions`](./event_tree.exceptions.md#module-event_treeexceptions) +- [`event_tree.parent_event_tree_collection`](./event_tree.parent_event_tree_collection.md#module-event_treeparent_event_tree_collection) +- [`exceptions`](./exceptions.md#module-exceptions) - [`interfaces`](./interfaces.md#module-interfaces) - [`interfaces.adapter`](./interfaces.adapter.md#module-interfacesadapter) - [`interfaces.command`](./interfaces.command.md#module-interfacescommand) - [`interfaces.data_source`](./interfaces.data_source.md#module-interfacesdata_source) -- [`interfaces.events_tree`](./interfaces.events_tree.md#module-interfacesevents_tree) -- [`interfaces.events_tree.events_tree_collection`](./interfaces.events_tree.events_tree_collection.md#module-interfacesevents_treeevents_tree_collection) -- [`interfaces.events_tree.parent_events_tree_collection`](./interfaces.events_tree.parent_events_tree_collection.md#module-interfacesevents_treeparent_events_tree_collection) - [`interfaces.source_api`](./interfaces.source_api.md#module-interfacessource_api) +- [`interfaces.struct`](./interfaces.struct.md#module-interfacesstruct) +- [`interfaces.stub_builder`](./interfaces.stub_builder.md#module-interfacesstub_builder) - [`interfaces.utils`](./interfaces.utils.md#module-interfacesutils) - [`interfaces.utils.converter`](./interfaces.utils.converter.md#module-interfacesutilsconverter) -- [`provider`](./provider.md#module-provider) -- [`provider.adapters`](./provider.adapters.md#module-provideradapters) -- [`provider.adapters.adapter_sse`](./provider.adapters.adapter_sse.md#module-provideradaptersadapter_sse) -- [`provider.command`](./provider.command.md#module-providercommand) -- [`provider.exceptions`](./provider.exceptions.md#module-providerexceptions) -- [`provider.interfaces`](./provider.interfaces.md#module-providerinterfaces) -- [`provider.interfaces.command`](./provider.interfaces.command.md#module-providerinterfacescommand): Interfaces for Provider Commands. -- [`provider.interfaces.data_source`](./provider.interfaces.data_source.md#module-providerinterfacesdata_source): Interfaces for Provider Data Source. -- [`provider.interfaces.filter`](./provider.interfaces.filter.md#module-providerinterfacesfilter) -- [`provider.interfaces.source_api`](./provider.interfaces.source_api.md#module-providerinterfacessource_api) -- [`provider.interfaces.struct`](./provider.interfaces.struct.md#module-providerinterfacesstruct) -- [`provider.interfaces.stub_builder`](./provider.interfaces.stub_builder.md#module-providerinterfacesstub_builder) -- [`provider.utils`](./provider.utils.md#module-providerutils) -- [`provider.utils.converters`](./provider.utils.converters.md#module-providerutilsconverters) -- [`provider.utils.version_checker`](./provider.utils.version_checker.md#module-providerutilsversion_checker) -- [`provider.v5`](./provider.v5.md#module-providerv5) -- [`provider.v5.adapters`](./provider.v5.adapters.md#module-providerv5adapters) -- [`provider.v5.adapters.basic_adapters`](./provider.v5.adapters.basic_adapters.md#module-providerv5adaptersbasic_adapters) -- [`provider.v5.adapters.event_adapters`](./provider.v5.adapters.event_adapters.md#module-providerv5adaptersevent_adapters) -- [`provider.v5.adapters.message_adapters`](./provider.v5.adapters.message_adapters.md#module-providerv5adaptersmessage_adapters) -- [`provider.v5.command_resolver`](./provider.v5.command_resolver.md#module-providerv5command_resolver) -- [`provider.v5.commands`](./provider.v5.commands.md#module-providerv5commands) -- [`provider.v5.commands.grpc`](./provider.v5.commands.grpc.md#module-providerv5commandsgrpc) -- [`provider.v5.commands.http`](./provider.v5.commands.http.md#module-providerv5commandshttp) -- [`provider.v5.data_source`](./provider.v5.data_source.md#module-providerv5data_source) -- [`provider.v5.data_source.grpc`](./provider.v5.data_source.grpc.md#module-providerv5data_sourcegrpc) -- [`provider.v5.data_source.http`](./provider.v5.data_source.http.md#module-providerv5data_sourcehttp) -- [`provider.v5.events_tree`](./provider.v5.events_tree.md#module-providerv5events_tree) -- [`provider.v5.events_tree.events_tree_collection`](./provider.v5.events_tree.events_tree_collection.md#module-providerv5events_treeevents_tree_collection) -- [`provider.v5.events_tree.parent_events_tree_collection`](./provider.v5.events_tree.parent_events_tree_collection.md#module-providerv5events_treeparent_events_tree_collection) -- [`provider.v5.filters`](./provider.v5.filters.md#module-providerv5filters) -- [`provider.v5.filters.event_filters`](./provider.v5.filters.event_filters.md#module-providerv5filtersevent_filters) -- [`provider.v5.filters.filter`](./provider.v5.filters.filter.md#module-providerv5filtersfilter) -- [`provider.v5.filters.message_filters`](./provider.v5.filters.message_filters.md#module-providerv5filtersmessage_filters) -- [`provider.v5.interfaces`](./provider.v5.interfaces.md#module-providerv5interfaces) -- [`provider.v5.interfaces.command`](./provider.v5.interfaces.command.md#module-providerv5interfacescommand) -- [`provider.v5.provider_api`](./provider.v5.provider_api.md#module-providerv5provider_api) -- [`provider.v5.provider_api.grpc`](./provider.v5.provider_api.grpc.md#module-providerv5provider_apigrpc) -- [`provider.v5.provider_api.http`](./provider.v5.provider_api.http.md#module-providerv5provider_apihttp) -- [`provider.v5.stub_builder`](./provider.v5.stub_builder.md#module-providerv5stub_builder) -- [`provider.v6`](./provider.v6.md#module-providerv6) -- [`provider.v6.commands`](./provider.v6.commands.md#module-providerv6commands) -- [`provider.v6.filters`](./provider.v6.filters.md#module-providerv6filters) -- [`provider.v6.struct`](./provider.v6.struct.md#module-providerv6struct) -- [`provider.v6.stub_builder`](./provider.v6.stub_builder.md#module-providerv6stub_builder) -- [`sse_client`](./sse_client.md#module-sse_client) -- [`th2_gui_report`](./th2_gui_report.md#module-th2_gui_report) -- [`utils`](./utils.md#module-utils) -- [`utils.converters`](./utils.converters.md#module-utilsconverters) +- [`interfaces.utils.resolver`](./interfaces.utils.resolver.md#module-interfacesutilsresolver) ## Classes +- [`config.TH2Config`](./config.config.md#class-th2config) - [`data.Data`](./data.md#class-data): A wrapper for data/data_stream. -- [`events_tree.EventsTree`](./events_tree.events_tree.md#class-eventstree): EventsTree is a tree-based data structure of events. -- [`exceptions.EventIdNotInTree`](./events_tree.exceptions.md#class-eventidnotintree) -- [`exceptions.FieldIsNotExist`](./events_tree.exceptions.md#class-fieldisnotexist) -- [`filter.Filter`](./filter.md#class-filter): The class for using rpt-data-provider filters API. -- [`adapter.IAdapter`](./interfaces.adapter.md#class-iadapter): High level interface for Adapter. -- [`adapter.IEventAdapter`](./interfaces.adapter.md#class-ieventadapter): Interface of Adapter for events. -- [`adapter.IMessageAdapter`](./interfaces.adapter.md#class-imessageadapter): Interface of Adapter for messages. +- [`data.DataWorkflow`](./data.md#class-dataworkflow) +- [`data.WfLimitRecord`](./data.md#class-wflimitrecord): WfLimitRecord(type: str, callback: Callable, limit: int) +- [`data_source.DummyDataSource`](./dummy.data_source.md#class-dummydatasource): Dummy DataSource. +- [`etc_driver.IETCDriver`](./event_tree.etc_driver.md#class-ietcdriver) +- [`event_tree.EventTree`](./event_tree.event_tree.md#class-eventtree): EventTree is a tree-based data structure of events. +- [`event_tree_collection.EventTreeCollection`](./event_tree.event_tree_collection.md#class-eventtreecollection): EventTreeCollection objective is building 'EventsTree's and storing them. +- [`exceptions.EventAlreadyExist`](./event_tree.exceptions.md#class-eventalreadyexist) +- [`exceptions.EventIdNotInTree`](./event_tree.exceptions.md#class-eventidnotintree) +- [`exceptions.EventRootExist`](./event_tree.exceptions.md#class-eventrootexist) +- [`exceptions.FieldIsNotExist`](./event_tree.exceptions.md#class-fieldisnotexist) +- [`exceptions.TreeLoop`](./event_tree.exceptions.md#class-treeloop) +- [`parent_event_tree_collection.ParentEventTreeCollection`](./event_tree.parent_event_tree_collection.md#class-parenteventtreecollection): ParentEventTreeCollections is a class like an EventsTreeCollections. +- [`exceptions.CommandError`](./exceptions.md#class-commanderror): Exception raised for errors in the command. +- [`exceptions.EventNotFound`](./exceptions.md#class-eventnotfound) +- [`exceptions.MessageNotFound`](./exceptions.md#class-messagenotfound) +- [`adapter.IRecordAdapter`](./interfaces.adapter.md#class-irecordadapter): Interface of Adapter for record. +- [`adapter.IStreamAdapter`](./interfaces.adapter.md#class-istreamadapter): Interface of Adapter for streams. - [`command.ICommand`](./interfaces.command.md#class-icommand): High level interface for Command. - [`data_source.IDataSource`](./interfaces.data_source.md#class-idatasource) -- [`events_tree_collection.EventsTreeCollection`](./interfaces.events_tree.events_tree_collection.md#class-eventstreecollection): EventsTreeCollection objective is building 'EventsTree's and storing them. -- [`parent_events_tree_collection.ParentEventsTreeCollection`](./interfaces.events_tree.parent_events_tree_collection.md#class-parenteventstreecollection): ParentEventsTreeCollections is a class like an EventsTreeCollections. - [`source_api.ISourceAPI`](./interfaces.source_api.md#class-isourceapi): High level interface for Source API. +- [`struct.IEventStruct`](./interfaces.struct.md#class-ieventstruct): Just to mark Event Struct class. +- [`struct.IMessageStruct`](./interfaces.struct.md#class-imessagestruct): Just to mark Message Struct class. +- [`stub_builder.IEventStub`](./interfaces.stub_builder.md#class-ieventstub): Just to mark Event Stub class. +- [`stub_builder.IMessageStub`](./interfaces.stub_builder.md#class-imessagestub): Just to mark Message Stub class. +- [`stub_builder.IStub`](./interfaces.stub_builder.md#class-istub) - [`converter.ITimestampConverter`](./interfaces.utils.converter.md#class-itimestampconverter) -- [`adapter_sse.SSEAdapter`](./provider.adapters.adapter_sse.md#class-sseadapter): SSE Adapter handles bytes from sse-stream into Dict object. -- [`command.ProviderAdaptableCommand`](./provider.command.md#class-provideradaptablecommand) -- [`exceptions.CommandError`](./provider.exceptions.md#class-commanderror): Exception raised for errors in the command. -- [`exceptions.EventNotFound`](./provider.exceptions.md#class-eventnotfound) -- [`exceptions.MessageNotFound`](./provider.exceptions.md#class-messagenotfound) -- [`command.IGRPCProviderCommand`](./provider.interfaces.command.md#class-igrpcprovidercommand): Interface of command for rpt-data-provider which works via GRPC. -- [`command.IHTTPProviderCommand`](./provider.interfaces.command.md#class-ihttpprovidercommand): Interface of command for rpt-data-provider which works via HTTP. -- [`command.IProviderCommand`](./provider.interfaces.command.md#class-iprovidercommand): Interface of command for rpt-data-provider. -- [`data_source.IGRPCProviderDataSource`](./provider.interfaces.data_source.md#class-igrpcproviderdatasource): Interface of DataSource that provides work with rpt-data-provider via GRPC. -- [`data_source.IHTTPProviderDataSource`](./provider.interfaces.data_source.md#class-ihttpproviderdatasource): Interface of DataSource that provides work with rpt-data-provider via HTTP. -- [`data_source.IProviderDataSource`](./provider.interfaces.data_source.md#class-iproviderdatasource) -- [`filter.IProviderFilter`](./provider.interfaces.filter.md#class-iproviderfilter) -- [`source_api.IGRPCProviderSourceAPI`](./provider.interfaces.source_api.md#class-igrpcprovidersourceapi): Interface for Source API of rpt-data-provider which works via GRPC. -- [`source_api.IHTTPProviderSourceAPI`](./provider.interfaces.source_api.md#class-ihttpprovidersourceapi): Interface for Source API of rpt-data-provider which works via HTTP. -- [`source_api.IProviderSourceAPI`](./provider.interfaces.source_api.md#class-iprovidersourceapi): Interface for Source API of rpt-data-provider. -- [`struct.IEventStruct`](./provider.interfaces.struct.md#class-ieventstruct): Just to mark Event Struct class. -- [`struct.IMessageStruct`](./provider.interfaces.struct.md#class-imessagestruct): Just to mark Message Struct class. -- [`stub_builder.IEventStub`](./provider.interfaces.stub_builder.md#class-ieventstub): Just to mark Event Stub class. -- [`stub_builder.IMessageStub`](./provider.interfaces.stub_builder.md#class-imessagestub): Just to mark Message Stub class. -- [`stub_builder.IStub`](./provider.interfaces.stub_builder.md#class-istub) -- [`converters.Th2TimestampConverter`](./provider.utils.converters.md#class-th2timestampconverter): Converts Th2 timestamps. -- [`basic_adapters.GRPCObjectToDictAdapter`](./provider.v5.adapters.basic_adapters.md#class-grpcobjecttodictadapter): GRPC Adapter decodes a GRPC object into a Dict object. -- [`event_adapters.DeleteEventWrappersAdapter`](./provider.v5.adapters.event_adapters.md#class-deleteeventwrappersadapter): Adapter that deletes unnecessary wrappers in events. -- [`message_adapters.CodecPipelinesAdapter`](./provider.v5.adapters.message_adapters.md#class-codecpipelinesadapter): Adapter for codec-pipeline messages from provider v5. -- [`message_adapters.DeleteMessageWrappersAdapter`](./provider.v5.adapters.message_adapters.md#class-deletemessagewrappersadapter): Adapter that deletes unnecessary wrappers in messages. -- [`grpc.GetEventById`](./provider.v5.commands.grpc.md#class-geteventbyid): A Class-Command for request to rpt-data-provider. -- [`grpc.GetEventByIdGRPCObject`](./provider.v5.commands.grpc.md#class-geteventbyidgrpcobject): A Class-Command for request to rpt-data-provider. -- [`grpc.GetEvents`](./provider.v5.commands.grpc.md#class-getevents): A Class-Command for request to rpt-data-provider. -- [`grpc.GetEventsById`](./provider.v5.commands.grpc.md#class-geteventsbyid): A Class-Command for request to rpt-data-provider. -- [`grpc.GetEventsGRPCObjects`](./provider.v5.commands.grpc.md#class-geteventsgrpcobjects): A Class-Command for request to rpt-data-provider. -- [`grpc.GetMessageById`](./provider.v5.commands.grpc.md#class-getmessagebyid): A Class-Command for request to rpt-data-provider. -- [`grpc.GetMessageByIdGRPCObject`](./provider.v5.commands.grpc.md#class-getmessagebyidgrpcobject): A Class-Command for request to rpt-data-provider. -- [`grpc.GetMessages`](./provider.v5.commands.grpc.md#class-getmessages): A Class-Command for request to rpt-data-provider. -- [`grpc.GetMessagesById`](./provider.v5.commands.grpc.md#class-getmessagesbyid): A Class-Command for request to rpt-data-provider. -- [`grpc.GetMessagesGRPCObject`](./provider.v5.commands.grpc.md#class-getmessagesgrpcobject): A Class-Command for request to rpt-data-provider. -- [`http.GetEventById`](./provider.v5.commands.http.md#class-geteventbyid): A Class-Command for request to rpt-data-provider. -- [`http.GetEvents`](./provider.v5.commands.http.md#class-getevents): A Class-Command for request to rpt-data-provider. -- [`http.GetEventsById`](./provider.v5.commands.http.md#class-geteventsbyid): A Class-Command for request to rpt-data-provider. -- [`http.GetEventsSSEBytes`](./provider.v5.commands.http.md#class-geteventsssebytes): A Class-Command for request to rpt-data-provider. -- [`http.GetEventsSSEEvents`](./provider.v5.commands.http.md#class-geteventssseevents): A Class-Command for request to rpt-data-provider. -- [`http.GetMessageById`](./provider.v5.commands.http.md#class-getmessagebyid): A Class-Command for request to rpt-data-provider. -- [`http.GetMessages`](./provider.v5.commands.http.md#class-getmessages): A Class-Command for request to rpt-data-provider. -- [`http.GetMessagesById`](./provider.v5.commands.http.md#class-getmessagesbyid): A Class-Command for request to rpt-data-provider. -- [`http.GetMessagesSSEBytes`](./provider.v5.commands.http.md#class-getmessagesssebytes): A Class-Command for request to rpt-data-provider. -- [`http.GetMessagesSSEEvents`](./provider.v5.commands.http.md#class-getmessagessseevents): A Class-Command for request to rpt-data-provider. -- [`grpc.GRPCProvider5DataSource`](./provider.v5.data_source.grpc.md#class-grpcprovider5datasource): DataSource class which provide work with rpt-data-provider. -- [`http.HTTPProvider5DataSource`](./provider.v5.data_source.http.md#class-httpprovider5datasource): DataSource class which provide work with rpt-data-provider. -- [`events_tree_collection.EventsTreeCollectionProvider5`](./provider.v5.events_tree.events_tree_collection.md#class-eventstreecollectionprovider5): EventsTreesCollections for data-provider v5. -- [`parent_events_tree_collection.ParentEventsTreeCollectionProvider5`](./provider.v5.events_tree.parent_events_tree_collection.md#class-parenteventstreecollectionprovider5): ParentEventsTreeCollection for data-provider v5. -- [`event_filters.AttachedMessageIdFilter`](./provider.v5.filters.event_filters.md#class-attachedmessageidfilter): Filters the events that are linked to the specified message id. -- [`event_filters.BodyFilter`](./provider.v5.filters.event_filters.md#class-bodyfilter): Will match the events which body contains one of the given substrings. -- [`event_filters.FailedStatusFilter`](./provider.v5.filters.event_filters.md#class-failedstatusfilter): Will match the events which status equals failed. -- [`event_filters.NameFilter`](./provider.v5.filters.event_filters.md#class-namefilter): Will match the events which name contains one of the given substrings. -- [`event_filters.PassedStatusFilter`](./provider.v5.filters.event_filters.md#class-passedstatusfilter): Will match the events which status equals passed. -- [`event_filters.TypeFilter`](./provider.v5.filters.event_filters.md#class-typefilter): Will match the events which type contains one of the given substrings. -- [`filter.Provider5EventFilter`](./provider.v5.filters.filter.md#class-provider5eventfilter): Base class for Event Filters of Provider v5. -- [`filter.Provider5Filter`](./provider.v5.filters.filter.md#class-provider5filter): General interface for Filters of Provider v5. -- [`filter.Provider5MessageFilter`](./provider.v5.filters.filter.md#class-provider5messagefilter): Base class for Message Filters of Provider v5. -- [`message_filters.AttachedEventIdsFilter`](./provider.v5.filters.message_filters.md#class-attachedeventidsfilter): Filters the messages that are linked to the specified event id. -- [`message_filters.BodyBinaryFilter`](./provider.v5.filters.message_filters.md#class-bodybinaryfilter): Will match the messages by their binary body. -- [`message_filters.BodyFilter`](./provider.v5.filters.message_filters.md#class-bodyfilter): Will match the messages by their parsed body. -- [`message_filters.TypeFilter`](./provider.v5.filters.message_filters.md#class-typefilter): Will match the messages by their full type name. -- [`command.IGRPCProvider5Command`](./provider.v5.interfaces.command.md#class-igrpcprovider5command): Interface of command for rpt-data-provider. -- [`command.IHTTPProvider5Command`](./provider.v5.interfaces.command.md#class-ihttpprovider5command): Interface of command for rpt-data-provider. -- [`grpc.BasicRequest`](./provider.v5.provider_api.grpc.md#class-basicrequest): BasicRequest(start_timestamp, end_timestamp, result_count_limit, keep_open, search_direction, filters) -- [`grpc.GRPCProvider5API`](./provider.v5.provider_api.grpc.md#class-grpcprovider5api) -- [`http.HTTPProvider5API`](./provider.v5.provider_api.http.md#class-httpprovider5api) -- [`stub_builder.Provider5EventStubBuilder`](./provider.v5.stub_builder.md#class-provider5eventstubbuilder) -- [`stub_builder.Provider5MessageStubBuilder`](./provider.v5.stub_builder.md#class-provider5messagestubbuilder) -- [`struct.GRPCProvider6EventStruct`](./provider.v6.struct.md#class-grpcprovider6eventstruct): Interface for Event of data-provider v6. -- [`stub_builder.Provider6EventStubBuilder`](./provider.v6.stub_builder.md#class-provider6eventstubbuilder) -- [`stub_builder.Provider6MessageStubBuilder`](./provider.v6.stub_builder.md#class-provider6messagestubbuilder) -- [`sse_client.SSEClient`](./sse_client.md#class-sseclient): Patch for sseclient-py to get availability to configure decode error handler. -- [`th2_gui_report.Th2GUIReport`](./th2_gui_report.md#class-th2guireport): Class for creating gui link by event ID or message ID. -- [`converters.DatetimeStringConverter`](./utils.converters.md#class-datetimestringconverter): Converts datetime strings. +- [`resolver.EventFieldResolver`](./interfaces.utils.resolver.md#class-eventfieldresolver) +- [`resolver.EventFieldResolver`](./interfaces.utils.resolver.md#class-eventfieldresolver) +- [`resolver.ExpandedMessageFieldResolver`](./interfaces.utils.resolver.md#class-expandedmessagefieldresolver) +- [`resolver.MessageFieldResolver`](./interfaces.utils.resolver.md#class-messagefieldresolver) +- [`resolver.MessageFieldResolver`](./interfaces.utils.resolver.md#class-messagefieldresolver) +- [`resolver.SubMessageFieldResolver`](./interfaces.utils.resolver.md#class-submessagefieldresolver) ## Functions -- [`decode_error_handler.handler`](./decode_error_handler.md#function-handler): Decode error handler that tries change utf-8 character to Unicode. -- [`version_checker.get_package_version`](./provider.utils.version_checker.md#function-get_package_version) -- [`version_checker.get_version_by_pip`](./provider.utils.version_checker.md#function-get_version_by_pip) -- [`version_checker.verify_grpc_version`](./provider.utils.version_checker.md#function-verify_grpc_version) -- [`command_resolver.resolver_get_event_by_id`](./provider.v5.command_resolver.md#function-resolver_get_event_by_id): Resolves what 'GetEventById' command you need to use based Data Source. -- [`command_resolver.resolver_get_events_by_id`](./provider.v5.command_resolver.md#function-resolver_get_events_by_id): Resolves what 'GetEventsById' command you need to use based Data Source. +- No functions --- diff --git a/documentation/api/interfaces.adapter.md b/documentation/api/interfaces.adapter.md index 4b0e34a5..1b48500f 100644 --- a/documentation/api/interfaces.adapter.md +++ b/documentation/api/interfaces.adapter.md @@ -11,77 +11,48 @@ --- - + -## class `IAdapter` -High level interface for Adapter. +## class `IStreamAdapter` +Interface of Adapter for streams. --- - + ### method `handle` ```python -handle(record: Any) → Any +handle(stream: Iterable) → Any ``` - - - - - ---- - - - -## class `IMessageAdapter` -Interface of Adapter for messages. - - - - ---- - - - -### method `handle` - -```python -handle(message: dict) → Any -``` - - - - +Stream handle function that should yield data (not return). --- - + -## class `IEventAdapter` -Interface of Adapter for events. +## class `IRecordAdapter` +Interface of Adapter for record. --- - + ### method `handle` ```python -handle(event: dict) → Any +handle(record: dict) → Any ``` - - - +One record handle function that should return data. diff --git a/documentation/api/interfaces.command.md b/documentation/api/interfaces.command.md index 358640c2..25f9b31b 100644 --- a/documentation/api/interfaces.command.md +++ b/documentation/api/interfaces.command.md @@ -14,7 +14,7 @@ --- - + ## class `ICommand` High level interface for Command. @@ -24,7 +24,7 @@ High level interface for Command. --- - + ### method `handle` diff --git a/documentation/api/interfaces.data_source.md b/documentation/api/interfaces.data_source.md index 61cc3d0c..01afacf5 100644 --- a/documentation/api/interfaces.data_source.md +++ b/documentation/api/interfaces.data_source.md @@ -11,7 +11,7 @@ --- - + ## class `IDataSource` @@ -31,7 +31,7 @@ --- - + ### method `command` diff --git a/documentation/api/interfaces.events_tree.events_tree.md b/documentation/api/interfaces.events_tree.events_tree.md deleted file mode 100644 index f80ad139..00000000 --- a/documentation/api/interfaces.events_tree.events_tree.md +++ /dev/null @@ -1,481 +0,0 @@ - - - - -# module `interfaces.events_tree.events_tree` - - - - - - ---- - - - -## class `EventsTree` -EventsTree - is a useful wrapper for your retrieved data. - - -- get_x methods raise Exceptions if no result is found. -- find_x methods return None if no result is found. -- EventsTree stores events as Nodes and interacts with them using an internal tree. -- EventsTree removes the 'body' field by default to save memory, but you can keep it. -- Note that EventsTree stores only one tree. If you want to store all trees, use EventsTreeCollections. -- EventsTree contains all events in memory. - -Take a look at the following HTML tree to understand some important terms. - -``` - -
-

Hello, world!

-

Goodbye!

-
- -``` - - - -### method `__init__` - -```python -__init__(tree: Tree) -``` - -EventsTree constructor. - - - -**Args:** - - - `tree` (treelib.Tree): Tree. - - - - ---- - - - -### method `append_node` - -```python -append_node(node: Node, parent_id: str) → None -``` - -Appends a node to the tree. - - - -**Args:** - - - `node`: Node. - - `parent_id`: Parent event id. - ---- - - - -### method `find` - -```python -find(filter: Callable, stop: Callable = None) → Union[dict, NoneType] -``` - -Searches the first event match. - - -- The search uses 'filter' which is a filtering function. -- Optionally, the search uses 'stop' which is a stopping function. If 'stop' function returns 'True' then search is complete. - - - -**Args:** - - - `filter`: Filter function. - - `stop`: Stop function. If None searches for all nodes in the tree. - - - -**Returns:** - One matching event. - ---- - - - -### method `find_ancestor` - -```python -find_ancestor(id: str, filter: Callable) → Union[dict, NoneType] -``` - -Finds the ancestor of an event. - - - -**Args:** - - - `id`: Event id. - - `filter`: Filter function - - - -**Returns:** - Ancestor of Event. - ---- - - - -### method `findall` - -```python -findall( - filter: Callable, - stop: Callable = None, - max_count: int = None -) → List[dict] -``` - -Searches events matches. - - -- The search uses 'filter' which is a filtering function. -- Optionally, the search uses 'stop' which is a stopping function. If 'stop' function returns 'True' then search is complete. -- 'max_count' is a parameter that limits the search to a specified count. - - - -**Args:** - - - `filter`: Filter function. - - `stop`: Stop function. If None searches for all nodes in the tree. - - `max_count`: Max count of matched events. Stops searching when `max_count` will be reached. - - - -**Returns:** - Matching events. - ---- - - - -### method `findall_iter` - -```python -findall_iter( - filter: Callable, - stop: Callable = None, - max_count: int = None -) → Generator[dict, NoneType, NoneType] -``` - -Searches events matches as iterator. - - -- The search uses 'filter' which is a filtering function. -- Optionally, the search uses 'stop' which is a stopping function. If 'stop' function returns 'True' then search is complete. -- 'max_count' is a parameter that limits the search to a specified count. - - - -**Args:** - - - `filter`: Filter function. - - `stop`: Stop function. If None searches for all nodes in the tree. - - `max_count`: Max count of matched events. Stops searching when `max_count` will be reached. - - - -**Yields:** - Matching events. - ---- - - - -### method `get_all_events` - -```python -get_all_events() → List[dict] -``` - -Gets all events from the tree. - ---- - - - -### method `get_all_events_iter` - -```python -get_all_events_iter() → Generator[dict, NoneType, NoneType] -``` - -Gets all events from the tree as iterator. - ---- - - - -### method `get_ancestors` - -```python -get_ancestors(id: str) → List[dict] -``` - -Returns all event's ancestors in right order. - - - -**Args:** - - - `id`: Event id. - - - -**Returns:** - All event's ancestors. - - - -**Raises:** - - - `EventIdNotInTree`: If event id not in the tree. - ---- - - - -### method `get_children` - -```python -get_children(id: str) → Tuple[dict] -``` - -Gets children for an event. - - - -**Args:** - - - `id`: Event id. - - - -**Raises:** - - - `EventIdNotInTree`: If event id not in the tree. - ---- - - - -### method `get_children_iter` - -```python -get_children_iter(id: str) → Generator[dict, NoneType, NoneType] -``` - -Gets children as iterator for an event. - - - -**Args:** - - - `id`: Event id. - - - -**Raises:** - - - `EventIdNotInTree`: If event id not in the tree. - ---- - - - -### method `get_event` - -```python -get_event(id: str) → dict -``` - -Gets event by id. - - - -**Args:** - - - `id`: Event id. - - - -**Raises:** - - - `EventIdNotInTree`: If event id not in the tree. - ---- - - - -### method `get_full_path` - -```python -get_full_path(id: str, field: str = None) → List[Union[str, dict]] -``` - -Returns full path for an event in right order. - -Harry ├── Bill └── Jane ├── Diane │ └── Mary └── Mark - - - -**Examples:** - tree.get_full_path('Jane', id) ['Harry-event-id', 'Jane-event-id'] - - tree.get_full_path('Jane', name) ['Harry-event-name', 'Jane-event-name'] - - tree.get_full_path('Jane', event) ['Harry-event', 'Jane-event'] - - - -**Args:** - - - `id`: Event id. - - `field`: Field of event. - - - -**Returns:** - Full path of event. - - - -**Raises:** - - - `EventIdNotInTree`: If event id not in the tree. - ---- - - - -### method `get_leaves` - -```python -get_leaves() → Tuple[dict] -``` - -Gets all tree leaves. - ---- - - - -### method `get_parent` - -```python -get_parent(id: str) → dict -``` - -Gets parent for an event. - - - -**Args:** - - - `id`: Event id. - - - -**Raises:** - - - `EventIdNotInTree`: If event id not in the tree. - ---- - - - -### method `get_root` - -```python -get_root() → dict -``` - -Gets root event. - ---- - - - -### method `get_root_id` - -```python -get_root_id() → str -``` - -Gets root id. - ---- - - - -### method `get_subtree` - -```python -get_subtree(id: str) → EventsTree -``` - -Gets subtree of event by id. - - - -**Args:** - - - `id`: Event id. - - - -**Returns:** - Subtree. - - - -**Raises:** - - - `EventIdNotInTree`: If event id not in the tree. - ---- - - - -### method `show` - -```python -show() → None -``` - -Prints EventsTree as tree view. - -For example: - -``` -Root - |___ C01 - | |___ C11 - | |___ C111 - | |___ C112 - |___ C02 - |___ C03 - | |___ C31 -``` - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/interfaces.events_tree.events_trees_collection.md b/documentation/api/interfaces.events_tree.events_trees_collection.md deleted file mode 100644 index 819b628e..00000000 --- a/documentation/api/interfaces.events_tree.events_trees_collection.md +++ /dev/null @@ -1,539 +0,0 @@ - - - - -# module `interfaces.events_tree.events_trees_collection` - - - - - - ---- - - - -## class `EventsTreesCollection` -EventsTreeCollection objective is building 'EventsTree's and storing them. - -EventsTreeCollection stores all EventsTree. You can to refer to each of them. - - - -### method `__init__` - -```python -__init__( - data: Data, - data_source: IProviderDataSource = None, - preserve_body: bool = False, - stub: bool = False -) -``` - -EventsTreesCollection constructor. - - - -**Args:** - - - `data`: Data object. - - `data_source`: Data Source object. - - `preserve_body`: If True it will preserve 'body' field in the Events. - - `stub`: If True it will create stub when event is broken. - - ---- - -#### property detached_events - -Gets detached events as dict with a view {'parent_id': ['referenced event', ...]}. - - - ---- - - - -### method `append_element` - -```python -append_element(event: dict) → None -``` - -Appends event into tree. - - - -**Args:** - - - `event`: Event. - ---- - - - -### method `find` - -```python -find(filter: Callable, stop: Callable = None) → Union[dict, NoneType] -``` - -Searches the first event match. - - -- The search uses 'filter' which is a filtering function. -- Optionally, the search uses 'stop' which is a stopping function. If 'stop' function returns 'True' then search is complete. - - - -**Args:** - - - `filter`: Filter function. - - `stop`: Stop function. If None searches for all nodes in the trees. - - - -**Returns:** - One matching event. - ---- - - - -### method `find_ancestor` - -```python -find_ancestor(id: str, filter: Callable) → Union[dict, NoneType] -``` - -Finds the ancestor of an event. - - - -**Args:** - - - `id`: Event id. - - `filter`: Filter function - - - -**Returns:** - Ancestor of Event. - ---- - - - -### method `findall` - -```python -findall( - filter: Callable, - stop: Callable = None, - max_count: int = None -) → List[dict] -``` - -Searches events matches. - - -- The search uses 'filter' which is a filtering function. -- Optionally, the search uses 'stop' which is a stopping function. If 'stop' function returns 'True' then search is complete. -- 'max_count' is a parameter that limits the search to a specified count. - - - -**Args:** - - - `filter`: Filter function. - - `stop`: Stop function. If None searches for all nodes in the trees. - - `max_count`: Max count of matched events. Stops searching when `max_count` will be reached. - - - -**Returns:** - Matching events. - ---- - - - -### method `findall_iter` - -```python -findall_iter( - filter: Callable, - stop: Callable = None, - max_count: int = None -) → Generator[dict, NoneType, NoneType] -``` - -Searches events matches as iterator. - - -- The search uses 'filter' which is a filtering function. -- Optionally, the search uses 'stop' which is a stopping function. If 'stop' function returns 'True' then search is complete. -- 'max_count' is a parameter that limits the search to a specified count. - - - -**Args:** - - - `filter`: Filter function. - - `stop`: Stop function. If None searches for all nodes in the trees. - - `max_count`: Max count of matched events. Stops searching when `max_count` will be reached. - - - -**Yields:** - Matching events. - ---- - - - -### method `get_all_events` - -```python -get_all_events() → List[dict] -``` - -Gets all events from the trees. - ---- - - - -### method `get_all_events_iter` - -```python -get_all_events_iter() → Generator[dict, NoneType, NoneType] -``` - -Gets all events from the trees as iterator. - ---- - - - -### method `get_ancestors` - -```python -get_ancestors(id: str) → List[dict] -``` - -Returns all event's ancestors in right order. - - - -**Args:** - - - `id`: Event id. - - - -**Returns:** - All event's ancestors. - - - -**Raises:** - - - `EventIdNotInTree`: If event id is not in the trees. - ---- - - - -### method `get_children` - -```python -get_children(id: str) → Tuple[dict] -``` - -Gets children for an event. - - - -**Args:** - - - `id`: Event id. - - - -**Raises:** - - - `EventIdNotInTree`: If event id is not in the trees. - ---- - - - -### method `get_children_iter` - -```python -get_children_iter(id: str) → Generator[dict, NoneType, NoneType] -``` - -Gets children as iterator for an event. - - - -**Args:** - - - `id`: Event id. - - - -**Raises:** - - - `EventIdNotInTree`: If event id is not in the trees. - ---- - - - -### method `get_event` - -```python -get_event(id: str) → Union[dict, NoneType] -``` - -Gets event by id. - - - -**Args:** - - - `id`: Event id. - - - -**Raises:** - - - `EventIdNotInTree`: If event id is not in the trees. - ---- - - - -### method `get_full_path` - -```python -get_full_path(id: str, field: str = None) → List[Union[str, dict]] -``` - -Returns full path for an event in right order. - - - -**Examples:** - - -Imagine we have the following tree. - -``` -Harry -├── Bill -└── Jane - ├── Diane - │ └── Mary - └── Mark -``` - -``` -collection.get_full_path('Jane', id) -['Harry-event-id', 'Jane-event-id'] - -collection.get_full_path('Jane', name) -['Harry-event-name', 'Jane-event-name'] - -collection.get_full_path('Jane') -['Harry-event', 'Jane-event'] -``` - - - -**Args:** - - - `id`: Event id. - - `field`: Field of event. - - - -**Returns:** - Full path of event. - - - -**Raises:** - - - `EventIdNotInTree`: If event id is not in the trees. - ---- - - - -### method `get_leaves` - -```python -get_leaves() → Tuple[dict] -``` - -Gets all trees leaves. - ---- - - - -### method `get_parent` - -```python -get_parent(id: str) → dict -``` - -Gets parent for an event. - - - -**Args:** - - - `id`: Event id. - - - -**Raises:** - - - `NodeIDAbsentError`: If event id is not in the trees. - ---- - - - -### method `get_parentless_trees` - -```python -get_parentless_trees() → List[EventsTree] -``` - -Gets parentless trees. - - - -**Returns:** - Parentlees trees. - ---- - - - -### method `get_root_by_id` - -```python -get_root_by_id(id) → EventsTree -``` - -Gets root tree by id as EventsTree class. - - - -**Args:** - - - `id`: Root id. - - - -**Returns:** - Root tree. - - - -**Raises:** - - - `EventIdNotInTree`: If event id is not in the trees. - ---- - - - -### method `get_roots_ids` - -```python -get_roots_ids() → List[str] -``` - -Gets roots ids. - ---- - - - -### method `get_subtree` - -```python -get_subtree(id: str) → EventsTree -``` - -Gets subtree of event by id. - - - -**Args:** - - - `id`: Event id. - - - -**Returns:** - Subtree. - - - -**Raises:** - - - `EventIdNotInTree`: If event id is not in the trees. - ---- - - - -### method `get_trees` - -```python -get_trees() → List[EventsTree] -``` - -Gets trees as EventsTree class. - ---- - - - -### method `show` - -```python -show() -``` - -Prints all EventsTree as tree view. - -For example: - -``` -Root - |___ C01 - | |___ C11 - | |___ C111 - | |___ C112 - |___ C02 - |___ C03 - | |___ C31 -``` - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/interfaces.events_tree.exceptions.md b/documentation/api/interfaces.events_tree.exceptions.md deleted file mode 100644 index 8ce6e951..00000000 --- a/documentation/api/interfaces.events_tree.exceptions.md +++ /dev/null @@ -1,74 +0,0 @@ - - - - -# module `interfaces.events_tree.exceptions` - - - - - - ---- - - - -## class `EventIdNotInTree` - - - - - - -### method `__init__` - -```python -__init__(id_) -``` - -Exception for the case when the tree hasn't the event. - - - -**Args:** - - - `id_`: Event id. - - - - - ---- - - - -## class `FieldIsNotExist` - - - - - - -### method `__init__` - -```python -__init__(field_name) -``` - -Exception for the case when event as dict hasn't field. - - - -**Args:** - - - `field_name`: Field name. - - - - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/interfaces.events_tree.parent_events_tree_collection.md b/documentation/api/interfaces.events_tree.parent_events_tree_collection.md deleted file mode 100644 index 9efb4d62..00000000 --- a/documentation/api/interfaces.events_tree.parent_events_tree_collection.md +++ /dev/null @@ -1,77 +0,0 @@ - - - - -# module `interfaces.events_tree.parent_events_tree_collection` - - - - - - ---- - - - -## class `ParentEventsTreeCollection` -ParentEventsTreeCollections is a class like an EventsTreeCollections. - -ParentEventsTree contains all parent events that are referenced. - - - -### method `__init__` - -```python -__init__( - data: Data, - data_source: IProviderDataSource = None, - preserve_body: bool = False, - stub: bool = False -) -``` - -ParentEventsTreeCollection constructor. - - - -**Args:** - - - `data`: Data object. - - `data_source`: Data Source object. - - `preserve_body`: If True then save body of event. - - `stub`: If True it will create stub when event is broken. - - ---- - -#### property detached_events - -Returns detached events as a dict that looks like {'parent_id': ['referenced event', ...]}. - ---- - -#### property len_detached_events - -Returns number of detached events in the collection. - ---- - -#### property len_parentless - -Returns number of events in the parentless trees inside the collection. - ---- - -#### property len_trees - -Returns number of events in the trees inside the collection, including parentless trees. - - - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/interfaces.events_tree.parent_events_trees_collection.md b/documentation/api/interfaces.events_tree.parent_events_trees_collection.md deleted file mode 100644 index e7c9053f..00000000 --- a/documentation/api/interfaces.events_tree.parent_events_trees_collection.md +++ /dev/null @@ -1,59 +0,0 @@ - - - - -# module `interfaces.events_tree.parent_events_trees_collection` - - - - - - ---- - - - -## class `ParentEventsTreesCollection` -ParentEventsTreeCollections is a class like an EventsTreeCollections. - -ParentEventsTree contains all parent events that are referenced. - - - -### method `__init__` - -```python -__init__( - data: Data, - data_source: IProviderDataSource = None, - preserve_body: bool = False, - stub: bool = False -) -``` - -ParentEventsTreesCollection constructor. - - - -**Args:** - - - `data`: Data object. - - `data_source`: Data Source object. - - `preserve_body`: If True then save body of event. - - `stub`: If True it will create stub when event is broken. - - ---- - -#### property detached_events - -Gets detached events as dict with a view {'parent_id': ['referenced event', ...]}. - - - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/interfaces.source_api.md b/documentation/api/interfaces.source_api.md index 45cd2fe3..9616c74c 100644 --- a/documentation/api/interfaces.source_api.md +++ b/documentation/api/interfaces.source_api.md @@ -11,7 +11,7 @@ --- - + ## class `ISourceAPI` High level interface for Source API. diff --git a/documentation/api/interfaces.struct.md b/documentation/api/interfaces.struct.md new file mode 100644 index 00000000..037c0a27 --- /dev/null +++ b/documentation/api/interfaces.struct.md @@ -0,0 +1,46 @@ + + + + +# module `interfaces.struct` + + + + + + +--- + + + +## class `IEventStruct` +Just to mark Event Struct class. + +Actually, this class doesn't describe the structure, it describes filed names. + +It should look like a class with constants. + + + + + +--- + + + +## class `IMessageStruct` +Just to mark Message Struct class. + +Actually, this class doesn't describe the structure, it describes filed names. + +It should look like a class with constants. + + + + + + + +--- + +_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/interfaces.stub_builder.md b/documentation/api/interfaces.stub_builder.md new file mode 100644 index 00000000..80feb94e --- /dev/null +++ b/documentation/api/interfaces.stub_builder.md @@ -0,0 +1,198 @@ + + + + +# module `interfaces.stub_builder` + + + + + + +--- + + + +## class `IStub` + + + + + + +### method `__init__` + +```python +__init__() +``` + +Stab interface. + + +--- + +#### property template + + + + + + + +--- + + + +### method `build` + +```python +build(fields: dict) → dict +``` + +Builds a stub by template. + +All keys will be overwrited by fields. New keys from fields will be added to stub. + + + +**Args:** + + - `fields`: Fields that will overwrite template. + + + +**Returns:** + Stub dict. + + + +**Raises:** + + - `TypeError`: If required fields is absent in changed fields list. + + +--- + + + +## class `IEventStub` +Just to mark Event Stub class. + + + +### method `__init__` + +```python +__init__() +``` + +Stab interface. + + +--- + +#### property template + + + + + + + +--- + + + +### method `build` + +```python +build(fields: dict) → dict +``` + +Builds a stub by template. + +All keys will be overwrited by fields. New keys from fields will be added to stub. + + + +**Args:** + + - `fields`: Fields that will overwrite template. + + + +**Returns:** + Stub dict. + + + +**Raises:** + + - `TypeError`: If required fields is absent in changed fields list. + + +--- + + + +## class `IMessageStub` +Just to mark Message Stub class. + + + +### method `__init__` + +```python +__init__() +``` + +Stab interface. + + +--- + +#### property template + + + + + + + +--- + + + +### method `build` + +```python +build(fields: dict) → dict +``` + +Builds a stub by template. + +All keys will be overwrited by fields. New keys from fields will be added to stub. + + + +**Args:** + + - `fields`: Fields that will overwrite template. + + + +**Returns:** + Stub dict. + + + +**Raises:** + + - `TypeError`: If required fields is absent in changed fields list. + + + + +--- + +_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/interfaces.utils.converter.md b/documentation/api/interfaces.utils.converter.md index 56c06501..565431a3 100644 --- a/documentation/api/interfaces.utils.converter.md +++ b/documentation/api/interfaces.utils.converter.md @@ -11,7 +11,7 @@ --- - + ## class `ITimestampConverter` @@ -23,21 +23,41 @@ --- - + ### classmethod `parse_timestamp` ```python -parse_timestamp(timestamp: ~TimestampType) → (, ) +parse_timestamp(timestamp: ~TimestampType) → Tuple[str, str] ``` -Returns string representation of Unix time separated to seconds and nanoseconds. +Returns string representation of Unix time. + +Separated for seconds and nanoseconds. + +Please note, nanoseconds can have zeroes from left. e.g. 2022-03-05T23:56:44.00123Z -> ('1646524604', '001230000') --- - + + +### classmethod `parse_timestamp_int` + +```python +parse_timestamp_int(timestamp: ~TimestampType) → Tuple[int, int] +``` + +Returns int representation of Unix time. + +Separated for seconds and nanoseconds. + +e.g. 2022-03-05T23:56:44.00123Z -> (1646524604, 001230000) + +--- + + ### classmethod `to_datetime` @@ -45,9 +65,9 @@ e.g. 2022-03-05T23:56:44.00123Z -> ('1646524604', '001230000') to_datetime(timestamp: ~TimestampType) → datetime ``` -Converts timestamp to datetime object. +Converts timestamp to UTC datetime object. -If your timestamp has nanoseconds, they will be just cut (not rounding). +If your timestamp has nanoseconds, they will be just cut (not rounded). @@ -63,7 +83,35 @@ If your timestamp has nanoseconds, they will be just cut (not rounding). --- - + + +### classmethod `to_datetime_str` + +```python +to_datetime_str(timestamp: ~TimestampType) → str +``` + +Converts timestamp to UTC datetime string in ISO format. + +Format example: + - 2022-03-06T04:56:44.123456789 + - 2022-03-06T04:56:44.000000000 + + + +**Args:** + + - `timestamp`: TimestampType object to convert. + + + +**Returns:** + + - `str`: datetime string in YYYY-MM-DDTHH:MM:SS.mmmmmm format. + +--- + + ### classmethod `to_microseconds` @@ -89,7 +137,33 @@ If your timestamp has nanoseconds, they will be just cut (not rounding). --- - + + +### classmethod `to_milliseconds` + +```python +to_milliseconds(timestamp: ~TimestampType) → int +``` + +Converts timestamp to milliseconds. + +If your timestamp has nanoseconds, they will be just cut (not rounding). + + + +**Args:** + + - `timestamp`: TimestampType object to convert. + + + +**Returns:** + + - `int`: Timestamp in microseconds format. + +--- + + ### classmethod `to_nanoseconds` @@ -111,6 +185,56 @@ Converts timestamp to nanoseconds. - `int`: Timestamp in nanoseconds format. +--- + + + +### classmethod `to_seconds` + +```python +to_seconds(timestamp: ~TimestampType) +``` + +Converts timestamp to seconds. + +If your timestamp has nanoseconds, they will be just cut (not rounding). + + + +**Args:** + + - `timestamp`: TimestampType object to convert. + + + +**Returns:** + + - `int`: Timestamp in seconds format. + +--- + + + +### classmethod `to_th2_timestamp` + +```python +to_th2_timestamp(timestamp: ~TimestampType) → dict +``` + +Converts timestamp to th2 timestamp. + + + +**Args:** + + - `timestamp`: int object to convert. + + + +**Returns:** + + - `dict`: {"epochSecond": seconds, "nano": nanoseconds} + diff --git a/documentation/api/interfaces.utils.md b/documentation/api/interfaces.utils.md index 061d151c..032ed70e 100644 --- a/documentation/api/interfaces.utils.md +++ b/documentation/api/interfaces.utils.md @@ -1,6 +1,6 @@ - + # module `interfaces.utils` diff --git a/documentation/api/interfaces.utils.resolver.md b/documentation/api/interfaces.utils.resolver.md new file mode 100644 index 00000000..3af91c83 --- /dev/null +++ b/documentation/api/interfaces.utils.resolver.md @@ -0,0 +1,960 @@ + + + + +# module `interfaces.utils.resolver` + + + + + + +--- + + + +## class `EventFieldResolver` + + + + + + + +--- + + + +### method `get_attached_messages_ids` + +```python +get_attached_messages_ids(event) → List[str] +``` + + + + + +--- + + + +### method `get_batch_id` + +```python +get_batch_id(event) → str +``` + + + + + +--- + + + +### method `get_body` + +```python +get_body(event) → Any +``` + + + + + +--- + + + +### method `get_end_timestamp` + +```python +get_end_timestamp(event) → Dict[str, int] +``` + + + + + +--- + + + +### method `get_id` + +```python +get_id(event) → str +``` + + + + + +--- + + + +### method `get_is_batched` + +```python +get_is_batched(event) → bool +``` + + + + + +--- + + + +### method `get_name` + +```python +get_name(event) → str +``` + + + + + +--- + + + +### method `get_parent_id` + +```python +get_parent_id(event) → str +``` + + + + + +--- + + + +### method `get_start_timestamp` + +```python +get_start_timestamp(event) → Dict[str, int] +``` + + + + + +--- + + + +### method `get_status` + +```python +get_status(event) → str +``` + + + + + +--- + + + +### method `get_type` + +```python +get_type(event) → str +``` + + + + + + +--- + + + +## class `EventFieldResolver` + + + + + + + +--- + + + +### method `get_attached_messages_ids` + +```python +get_attached_messages_ids(event) → List[str] +``` + + + + + +--- + + + +### method `get_batch_id` + +```python +get_batch_id(event) → str +``` + + + + + +--- + + + +### method `get_body` + +```python +get_body(event) → Any +``` + + + + + +--- + + + +### method `get_end_timestamp` + +```python +get_end_timestamp(event) → Dict[str, int] +``` + + + + + +--- + + + +### method `get_id` + +```python +get_id(event) → str +``` + + + + + +--- + + + +### method `get_is_batched` + +```python +get_is_batched(event) → bool +``` + + + + + +--- + + + +### method `get_name` + +```python +get_name(event) → str +``` + + + + + +--- + + + +### method `get_parent_id` + +```python +get_parent_id(event) → str +``` + + + + + +--- + + + +### method `get_start_timestamp` + +```python +get_start_timestamp(event) → Dict[str, int] +``` + + + + + +--- + + + +### method `get_status` + +```python +get_status(event) → str +``` + + + + + +--- + + + +### method `get_type` + +```python +get_type(event) → str +``` + + + + + + +--- + + + +## class `MessageFieldResolver` + + + + + + + +--- + + + +### method `expand_message` + +```python +expand_message(message) → List[Dict[str, Any]] +``` + +Extract a compounded message into a list of individual messages. + +Use it with `data.map_yield` instead of `data.map`. + +Warnings: expand_message function is not backward-compatible. If you use it in your scripts, there is no guarantee that everything will work if you change data-source because different data-sources have different messages structure. + + + +**Args:** + + - `message`: Th2Message + + + +**Returns:** + Iterable[Th2Message] + +--- + + + +### method `get_attached_event_ids` + +```python +get_attached_event_ids(message) → List[str] +``` + + + + + +--- + + + +### method `get_body` + +```python +get_body(message) → Union[Dict[str, Any], List[Dict[str, Any]]] +``` + + + + + +--- + + + +### method `get_body_base64` + +```python +get_body_base64(message) → str +``` + + + + + +--- + + + +### method `get_direction` + +```python +get_direction(message) → str +``` + + + + + +--- + + + +### method `get_id` + +```python +get_id(message) → str +``` + + + + + +--- + + + +### method `get_sequence` + +```python +get_sequence(message) → str +``` + + + + + +--- + + + +### method `get_session_id` + +```python +get_session_id(message) → str +``` + + + + + +--- + + + +### method `get_timestamp` + +```python +get_timestamp(message) → Dict[str, int] +``` + + + + + +--- + + + +### method `get_type` + +```python +get_type(message) → str +``` + +This field was removed since LwDP3. + +Don't use it in new scripts. + + +--- + + + +## class `MessageFieldResolver` + + + + + + + +--- + + + +### method `expand_message` + +```python +expand_message(message) → List[Dict[str, Any]] +``` + +Extract a compounded message into a list of individual messages. + +Use it with `data.map_yield` instead of `data.map`. + +Warnings: expand_message function is not backward-compatible. If you use it in your scripts, there is no guarantee that everything will work if you change data-source because different data-sources have different messages structure. + + + +**Args:** + + - `message`: Th2Message + + + +**Returns:** + Iterable[Th2Message] + +--- + + + +### method `get_attached_event_ids` + +```python +get_attached_event_ids(message) → List[str] +``` + + + + + +--- + + + +### method `get_body` + +```python +get_body(message) → Union[Dict[str, Any], List[Dict[str, Any]]] +``` + + + + + +--- + + + +### method `get_body_base64` + +```python +get_body_base64(message) → str +``` + + + + + +--- + + + +### method `get_direction` + +```python +get_direction(message) → str +``` + + + + + +--- + + + +### method `get_id` + +```python +get_id(message) → str +``` + + + + + +--- + + + +### method `get_sequence` + +```python +get_sequence(message) → str +``` + + + + + +--- + + + +### method `get_session_id` + +```python +get_session_id(message) → str +``` + + + + + +--- + + + +### method `get_timestamp` + +```python +get_timestamp(message) → Dict[str, int] +``` + + + + + +--- + + + +### method `get_type` + +```python +get_type(message) → str +``` + +This field was removed since LwDP3. + +Don't use it in new scripts. + + +--- + + + +## class `SubMessageFieldResolver` + + + + + + + +--- + + + +### method `get_fields` + +```python +get_fields(message) → Dict[str, Any] +``` + + + + + +--- + + + +### method `get_metadata` + +```python +get_metadata(message) → Dict[str, Any] +``` + + + + + +--- + + + +### method `get_protocol` + +```python +get_protocol(message) → str +``` + + + + + +--- + + + +### method `get_subsequence` + +```python +get_subsequence(message) → List[int] +``` + + + + + +--- + + + +### method `get_type` + +```python +get_type(message) → str +``` + + + + + + +--- + + + +## class `ExpandedMessageFieldResolver` + + + + + + + +--- + + + +### method `get_attached_event_ids` + +```python +get_attached_event_ids(message) → List[str] +``` + + + + + +--- + + + +### method `get_body` + +```python +get_body(message) → Dict[str, Any] +``` + + + + + +--- + + + +### method `get_body_base64` + +```python +get_body_base64(message) → str +``` + + + + + +--- + + + +### method `get_direction` + +```python +get_direction(message) → str +``` + + + + + +--- + + + +### method `get_fields` + +```python +get_fields(message) → Dict[str, Any] +``` + + + + + +--- + + + +### method `get_id` + +```python +get_id(message) → str +``` + + + + + +--- + + + +### method `get_metadata` + +```python +get_metadata(message) → Dict[str, Any] +``` + + + + + +--- + + + +### method `get_protocol` + +```python +get_protocol(message) → str +``` + + + + + +--- + + + +### method `get_sequence` + +```python +get_sequence(message) → str +``` + + + + + +--- + + + +### method `get_session_id` + +```python +get_session_id(message) → str +``` + + + + + +--- + + + +### method `get_subsequence` + +```python +get_subsequence(message) → List[int] +``` + + + + + +--- + + + +### method `get_timestamp` + +```python +get_timestamp(message) → Dict[str, int] +``` + + + + + +--- + + + +### method `get_type` + +```python +get_type(message) → str +``` + + + + + + + + +--- + +_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.adapters.adapter_provider5.md b/documentation/api/provider.adapters.adapter_provider5.md deleted file mode 100644 index 09e8fd1c..00000000 --- a/documentation/api/provider.adapters.adapter_provider5.md +++ /dev/null @@ -1,39 +0,0 @@ - - - - -# module `provider.adapters.adapter_provider5` - - - - - ---- - - - -## function `adapter_provider5` - -```python -adapter_provider5(record: dict) → Union[List[dict], dict] -``` - -Provider 5 adapter. - - - -**Args:** - - - `record`: Th2Message dict. - - - -**Returns:** - Th2Message dict. - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.adapters.adapter_sse.md b/documentation/api/provider.adapters.adapter_sse.md deleted file mode 100644 index cfc9ea5f..00000000 --- a/documentation/api/provider.adapters.adapter_sse.md +++ /dev/null @@ -1,50 +0,0 @@ - - - - -# module `provider.adapters.adapter_sse` - - - - - - ---- - - - -## class `SSEAdapter` -SSE Adapter handles bytes from sse-stream into Dict object. - - - - ---- - - - -### method `handle` - -```python -handle(record: Event) → dict -``` - -Adapter handler. - - - -**Args:** - - - `record`: SSE Event. - - - -**Returns:** - Dict object. - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.command.md b/documentation/api/provider.command.md deleted file mode 100644 index 12414f57..00000000 --- a/documentation/api/provider.command.md +++ /dev/null @@ -1,64 +0,0 @@ - - - - -# module `provider.command` - - - - - - ---- - - - -## class `ProviderAdaptableCommand` - - - - - - -### method `__init__` - -```python -__init__() -``` - -Class to make Command classes adaptable. - - - - ---- - - - -### method `apply_adapter` - -```python -apply_adapter(adapter: 'Callable') → 'ProviderAdaptableCommand' -``` - -Adds adapter to the Command workflow. - -Note, sequence that you will add adapters make sense. - - - -**Args:** - - - `adapter`: Callable function that will be used as adapter. - - - -**Returns:** - self - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.exceptions.md b/documentation/api/provider.exceptions.md deleted file mode 100644 index a63f6d50..00000000 --- a/documentation/api/provider.exceptions.md +++ /dev/null @@ -1,85 +0,0 @@ - - - - -# module `provider.exceptions` - - - - - - ---- - - - -## class `EventNotFound` - - - - - - -### method `__init__` - -```python -__init__(id_) -``` - -Exception for the case when the the event was not found in data source. - - - -**Args:** - - - `id_`: Event id. - - - - - ---- - - - -## class `MessageNotFound` - - - - - - -### method `__init__` - -```python -__init__(id_) -``` - -Exception for the case when the the message was not found in data source. - - - -**Args:** - - - `id_`: Event id. - - - - - ---- - - - -## class `CommandError` -Exception raised for errors in the command. - - - - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.interfaces.command.md b/documentation/api/provider.interfaces.command.md deleted file mode 100644 index ac0d1127..00000000 --- a/documentation/api/provider.interfaces.command.md +++ /dev/null @@ -1,92 +0,0 @@ - - - - -# module `provider.interfaces.command` -Interfaces for Provider Commands. - -**Global Variables** ---------------- -- **TYPE_CHECKING** - - ---- - - - -## class `IProviderCommand` -Interface of command for rpt-data-provider. - - - - ---- - - - -### method `handle` - -```python -handle(data_source: 'IProviderDataSource') -``` - - - - - - ---- - - - -## class `IHTTPProviderCommand` -Interface of command for rpt-data-provider which works via HTTP. - - - - ---- - - - -### method `handle` - -```python -handle(data_source: 'IHTTPProviderDataSource') -``` - - - - - - ---- - - - -## class `IGRPCProviderCommand` -Interface of command for rpt-data-provider which works via GRPC. - - - - ---- - - - -### method `handle` - -```python -handle(data_source: 'IGRPCProviderDataSource') -``` - - - - - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.interfaces.data_source.md b/documentation/api/provider.interfaces.data_source.md deleted file mode 100644 index 548c8cd8..00000000 --- a/documentation/api/provider.interfaces.data_source.md +++ /dev/null @@ -1,299 +0,0 @@ - - - - -# module `provider.interfaces.data_source` -Interfaces for Provider Data Source. - - - ---- - - - -## class `IProviderDataSource` - - - - - - -### method `__init__` - -```python -__init__( - url: str, - event_struct: IEventStruct, - message_struct: IMessageStruct, - event_stub_builder: IEventStub, - message_stub_builder: IMessageStub -) -``` - -Interface of DataSource that provides work with rpt-data-provider. - - - -**Args:** - - - `url`: Url address to data provider. - - `event_struct`: Event struct class. - - `message_struct`: Message struct class. - - `event_stub_builder`: Event stub builder class. - - `message_stub_builder`: Message stub builder class. - - ---- - -#### property event_struct - -Returns event structure class. - ---- - -#### property event_stub_builder - -Returns event stub template. - ---- - -#### property message_struct - -Returns message structure class. - ---- - -#### property message_stub_builder - -Returns message stub template. - ---- - -#### property source_api - -Returns Provider API. - ---- - -#### property url - -str: URL of rpt-data-provider. - - - ---- - - - -### method `command` - -```python -command(cmd: IProviderCommand) -``` - -Execute the transmitted command. - - ---- - - - -## class `IHTTPProviderDataSource` -Interface of DataSource that provides work with rpt-data-provider via HTTP. - - - -### method `__init__` - -```python -__init__( - url: str, - event_struct: IEventStruct, - message_struct: IMessageStruct, - event_stub_builder: IEventStub, - message_stub_builder: IMessageStub -) -``` - -Interface of DataSource that provides work with rpt-data-provider. - - - -**Args:** - - - `url`: Url address to data provider. - - `event_struct`: Event struct class. - - `message_struct`: Message struct class. - - `event_stub_builder`: Event stub builder class. - - `message_stub_builder`: Message stub builder class. - - ---- - -#### property event_struct - -Returns event structure class. - ---- - -#### property event_stub_builder - -Returns event stub template. - ---- - -#### property message_struct - -Returns message structure class. - ---- - -#### property message_stub_builder - -Returns message stub template. - ---- - -#### property source_api - -Returns HTTP Provider API. - ---- - -#### property url - -str: URL of rpt-data-provider. - - - ---- - - - -### method `check_connect` - -```python -check_connect( - timeout: (, ), - certification: bool = True -) → None -``` - -Checks whether url is working. - - - -**Args:** - - - `timeout`: How many seconds to wait for the server to send data before giving up. - - `certification`: Checking SSL certification. - - - -**Raises:** - - - `urllib3.exceptions.HTTPError`: If unable to connect to host. - ---- - - - -### method `command` - -```python -command(cmd: IHTTPProviderCommand) -``` - -Execute the transmitted HTTP command. - - ---- - - - -## class `IGRPCProviderDataSource` -Interface of DataSource that provides work with rpt-data-provider via GRPC. - - - -### method `__init__` - -```python -__init__( - url: str, - event_struct: IEventStruct, - message_struct: IMessageStruct, - event_stub_builder: IEventStub, - message_stub_builder: IMessageStub -) -``` - -Interface of DataSource that provides work with rpt-data-provider. - - - -**Args:** - - - `url`: Url address to data provider. - - `event_struct`: Event struct class. - - `message_struct`: Message struct class. - - `event_stub_builder`: Event stub builder class. - - `message_stub_builder`: Message stub builder class. - - ---- - -#### property event_struct - -Returns event structure class. - ---- - -#### property event_stub_builder - -Returns event stub template. - ---- - -#### property message_struct - -Returns message structure class. - ---- - -#### property message_stub_builder - -Returns message stub template. - ---- - -#### property source_api - -Returns GRPC Provider API. - ---- - -#### property url - -str: URL of rpt-data-provider. - - - ---- - - - -### method `command` - -```python -command(cmd: IGRPCProviderCommand) -``` - -Execute the transmitted GRPC command. - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.interfaces.filter.md b/documentation/api/provider.interfaces.filter.md deleted file mode 100644 index 5bab6e23..00000000 --- a/documentation/api/provider.interfaces.filter.md +++ /dev/null @@ -1,29 +0,0 @@ - - - - -# module `provider.interfaces.filter` - - - - - - ---- - - - -## class `IProviderFilter` - - - - - - - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.interfaces.source_api.md b/documentation/api/provider.interfaces.source_api.md deleted file mode 100644 index 28714f1e..00000000 --- a/documentation/api/provider.interfaces.source_api.md +++ /dev/null @@ -1,49 +0,0 @@ - - - - -# module `provider.interfaces.source_api` - - - - - - ---- - - - -## class `IProviderSourceAPI` -Interface for Source API of rpt-data-provider. - - - - - ---- - - - -## class `IHTTPProviderSourceAPI` -Interface for Source API of rpt-data-provider which works via HTTP. - - - - - ---- - - - -## class `IGRPCProviderSourceAPI` -Interface for Source API of rpt-data-provider which works via GRPC. - - - - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.interfaces.struct.md b/documentation/api/provider.interfaces.struct.md deleted file mode 100644 index c5bf5bc1..00000000 --- a/documentation/api/provider.interfaces.struct.md +++ /dev/null @@ -1,42 +0,0 @@ - - - - -# module `provider.interfaces.struct` - - - - - - ---- - - - -## class `IEventStruct` -Just to mark Event Struct class. - -It should look like a class with constants. - - - - - ---- - - - -## class `IMessageStruct` -Just to mark Message Struct class. - -It should look like a class with constants. - - - - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.interfaces.stub_builder.md b/documentation/api/provider.interfaces.stub_builder.md deleted file mode 100644 index 0c7e55bc..00000000 --- a/documentation/api/provider.interfaces.stub_builder.md +++ /dev/null @@ -1,174 +0,0 @@ - - - - -# module `provider.interfaces.stub_builder` - - - - - - ---- - - - -## class `IStub` - - - - - - -### method `__init__` - -```python -__init__() -``` - -Stab interface. - - ---- - -#### property template - - - - - - - ---- - - - -### method `build` - -```python -build(fields: dict) → dict -``` - -Builds a stub. - - - -**Args:** - fields: - - - -**Returns:** - - - `TypeError`: If required fields is absent in changed fields list. - - ---- - - - -## class `IEventStub` -Just to mark Event Stub class. - - - -### method `__init__` - -```python -__init__() -``` - -Stab interface. - - ---- - -#### property template - - - - - - - ---- - - - -### method `build` - -```python -build(fields: dict) → dict -``` - -Builds a stub. - - - -**Args:** - fields: - - - -**Returns:** - - - `TypeError`: If required fields is absent in changed fields list. - - ---- - - - -## class `IMessageStub` -Just to mark Message Stub class. - - - -### method `__init__` - -```python -__init__() -``` - -Stab interface. - - ---- - -#### property template - - - - - - - ---- - - - -### method `build` - -```python -build(fields: dict) → dict -``` - -Builds a stub. - - - -**Args:** - fields: - - - -**Returns:** - - - `TypeError`: If required fields is absent in changed fields list. - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.utils.converters.md b/documentation/api/provider.utils.converters.md deleted file mode 100644 index 1cbf1a66..00000000 --- a/documentation/api/provider.utils.converters.md +++ /dev/null @@ -1,45 +0,0 @@ - - - - -# module `provider.utils.converters` - - - - - - ---- - - - -## class `Th2TimestampConverter` -Converts Th2 timestamps. - -If you request microseconds but your timestamp has nanoseconds, they will be just cut (not rounding). - -Expected timestamp format {'epochSecond': 123, 'nano': 500}. - - - - ---- - - - -### classmethod `parse_timestamp` - -```python -parse_timestamp(timestamp: dict) → (, ) -``` - - - - - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.utils.md b/documentation/api/provider.utils.md deleted file mode 100644 index bf145f77..00000000 --- a/documentation/api/provider.utils.md +++ /dev/null @@ -1,16 +0,0 @@ - - - - -# module `provider.utils` - - - - - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.utils.version_checker.md b/documentation/api/provider.utils.version_checker.md deleted file mode 100644 index fd914bbf..00000000 --- a/documentation/api/provider.utils.version_checker.md +++ /dev/null @@ -1,60 +0,0 @@ - - - - -# module `provider.utils.version_checker` - - - - - ---- - - - -## function `get_version_by_pip` - -```python -get_version_by_pip(package_name: str) -``` - - - - - - ---- - - - -## function `get_package_version` - -```python -get_package_version(package_name: str) -``` - - - - - - ---- - - - -## function `verify_grpc_version` - -```python -verify_grpc_version(valid: List[str]) -``` - - - - - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.v5.adapters.basic_adapters.md b/documentation/api/provider.v5.adapters.basic_adapters.md deleted file mode 100644 index 58e01628..00000000 --- a/documentation/api/provider.v5.adapters.basic_adapters.md +++ /dev/null @@ -1,50 +0,0 @@ - - - - -# module `provider.v5.adapters.basic_adapters` - - - - - - ---- - - - -## class `GRPCObjectToDictAdapter` -GRPC Adapter decodes a GRPC object into a Dict object. - - - - ---- - - - -### method `handle` - -```python -handle(record: Union[MessageData, EventData]) → dict -``` - -Decodes MessageData or EventData as GRPC object into a Dict object. - - - -**Args:** - - - `record`: MessageData/EventData. - - - -**Returns:** - Dict object. - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.v5.adapters.event_adapters.md b/documentation/api/provider.v5.adapters.event_adapters.md deleted file mode 100644 index c0aab170..00000000 --- a/documentation/api/provider.v5.adapters.event_adapters.md +++ /dev/null @@ -1,70 +0,0 @@ - - - - -# module `provider.v5.adapters.event_adapters` - - - - - - ---- - - - -## class `DeleteEventWrappersAdapter` -Adapter that deletes unnecessary wrappers in events. - -It used for events to which an AdaptorGRPCObjectToDict has been applied. - - - -### method `__init__` - -```python -__init__( - event_struct: Provider5EventStruct = Provider5EventStruct(EVENT_ID='eventId', PARENT_EVENT_ID='parentEventId', STATUS='successful', NAME='eventName', TYPE='type', BATCH_ID='batchId', IS_BATCHED='isBatched', EVENT_TYPE='eventType', END_TIMESTAMP='endTimestamp', START_TIMESTAMP='startTimestamp', ATTACHED_MESSAGES_IDS='attachedMessageIds', BODY='body') -) -``` - -AdapterDeleteEventWrappers constructor. - - - -**Args:** - - - `event_struct`: Event struct. - - - - ---- - - - -### method `handle` - -```python -handle(event: dict) → dict -``` - -Deletes unnecessary wrappers for fields eventId, parentEventId and BatchId. - - - -**Args:** - - - `event`: Event. - - - -**Returns:** - Event without wrappers. - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.v5.adapters.events_adapters.md b/documentation/api/provider.v5.adapters.events_adapters.md deleted file mode 100644 index af6f9337..00000000 --- a/documentation/api/provider.v5.adapters.events_adapters.md +++ /dev/null @@ -1,70 +0,0 @@ - - - - -# module `provider.v5.adapters.events_adapters` - - - - - - ---- - - - -## class `AdapterDeleteEventWrappers` -Adapter that delete unnecessary wrappers in events. - -It used for events to which an AdaptorGRPCObjectToDict has been applied. - - - -### method `__init__` - -```python -__init__( - event_struct: Provider5EventStruct = Provider5EventStruct(EVENT_ID='eventId', PARENT_EVENT_ID='parentEventId', STATUS='successful', NAME='eventName', TYPE='type', BATCH_ID='batchId', IS_BATCHED='isBatched', EVENT_TYPE='eventType', END_TIMESTAMP='endTimestamp', START_TIMESTAMP='startTimestamp', ATTACHED_MESSAGES_IDS='attachedMessageIds', BODY='body') -) -``` - -AdapterDeleteEventWrappers constructor. - - - -**Args:** - - - `event_struct`: Event struct. - - - - ---- - - - -### method `handle` - -```python -handle(event: dict) → dict -``` - -Deletes unnecessary wrappers for fields eventId, parentEventId and BatchId. - - - -**Args:** - - - `event`: Event. - - - -**Returns:** - Event without wrappers. - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.v5.adapters.message_adapters.md b/documentation/api/provider.v5.adapters.message_adapters.md deleted file mode 100644 index 211e225f..00000000 --- a/documentation/api/provider.v5.adapters.message_adapters.md +++ /dev/null @@ -1,122 +0,0 @@ - - - - -# module `provider.v5.adapters.message_adapters` - - - - - - ---- - - - -## class `DeleteMessageWrappersAdapter` -Adapter that deletes unnecessary wrappers in messages. - -It used for the message to which an AdaptorGRPCObjectToDict has been applied. - - - -### method `__init__` - -```python -__init__( - message_struct: Provider5MessageStruct = Provider5MessageStruct(DIRECTION='direction', SESSION_ID='sessionId', MESSAGE_TYPE='messageType', CONNECTION_ID='connectionId', SESSION_ALIAS='sessionAlias', SUBSEQUENCE='subsequence', SEQUENCE='sequence', TIMESTAMP='timestamp', BODY='body', BODY_BASE64='bodyBase64', TYPE='type', MESSAGE_ID='messageId', ATTACHED_EVENT_IDS='attachedEventIds') -) -``` - -AdapterDeleteMessageWrappers constructor. - - - -**Args:** - - - `message_struct`: Message struct. - - - - ---- - - - -### method `handle` - -```python -handle(message: dict) → dict -``` - -Deletes unnecessary wrappers for field message_id. - - - -**Args:** - - - `message`: Message. - - - -**Returns:** - Message without wrappers. - - ---- - - - -## class `CodecPipelinesAdapter` -Adapter for codec-pipeline messages from provider v5. - -Codec-pipeline messages have sub-messages in the body. This adapter used for split codec-pipeline message to separate messages. - - - -### method `__init__` - -```python -__init__(ignore_errors=False) -``` - -AdapterCodecPipelines constructor. - - - -**Args:** - - - `ignore_errors`: If True it will ignore errors and return message as is. - - - - ---- - - - -### method `handle` - -```python -handle(message: dict) → Union[List[dict], dict] -``` - -Adapter handler. - - - -**Args:** - - - `message`: Th2Message dict. - - - -**Returns:** - Th2Message dict. - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.v5.adapters.messages_adapters.md b/documentation/api/provider.v5.adapters.messages_adapters.md deleted file mode 100644 index 7b8f4cf1..00000000 --- a/documentation/api/provider.v5.adapters.messages_adapters.md +++ /dev/null @@ -1,70 +0,0 @@ - - - - -# module `provider.v5.adapters.messages_adapters` - - - - - - ---- - - - -## class `AdapterDeleteMessageWrappers` -Adapter that delete unnecessary wrappers in events. - -It used for message to which an AdaptorGRPCObjectToDict has been applied. - - - -### method `__init__` - -```python -__init__( - message_struct: Provider5MessageStruct = Provider5MessageStruct(DIRECTION='direction', SESSION_ID='sessionId', MESSAGE_TYPE='messageType', CONNECTION_ID='connectionId', SESSION_ALIAS='sessionAlias', SUBSEQUENCE='subsequence', SEQUENCE='sequence', TIMESTAMP='timestamp', BODY='body', BODY_BASE64='bodyBase64', TYPE='type', MESSAGE_ID='messageId', ATTACHED_EVENT_IDS='attachedEventIds') -) -``` - -AdapterDeleteMessageWrappers constructor. - - - -**Args:** - - - `message_struct`: Message struct. - - - - ---- - - - -### method `handle` - -```python -handle(message: dict) → dict -``` - -Deletes unnecessary wrappers for field message_id. - - - -**Args:** - - - `message`: Message. - - - -**Returns:** - Message without wrappers. - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.v5.command_resolver.md b/documentation/api/provider.v5.command_resolver.md deleted file mode 100644 index b81c3079..00000000 --- a/documentation/api/provider.v5.command_resolver.md +++ /dev/null @@ -1,67 +0,0 @@ - - - - -# module `provider.v5.command_resolver` - - - - - ---- - - - -## function `resolver_get_event_by_id` - -```python -resolver_get_event_by_id( - data_source: IProviderDataSource -) → Union[Type[GetEventById], Type[GetEventById]] -``` - -Resolves what 'GetEventById' command you need to use based Data Source. - - - -**Args:** - - - `data_source`: DataSource instance. - - - -**Returns:** - GetEventById command. - - ---- - - - -## function `resolver_get_events_by_id` - -```python -resolver_get_events_by_id( - data_source: IProviderDataSource -) → Union[Type[GetEventsById], Type[GetEventsById]] -``` - -Resolves what 'GetEventsById' command you need to use based Data Source. - - - -**Args:** - - - `data_source`: DataSource instance. - - - -**Returns:** - GetEventsById command. - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.v5.commands.grpc.md b/documentation/api/provider.v5.commands.grpc.md deleted file mode 100644 index 65935d69..00000000 --- a/documentation/api/provider.v5.commands.grpc.md +++ /dev/null @@ -1,622 +0,0 @@ - - - - -# module `provider.v5.commands.grpc` - - - - - - ---- - - - -## class `GetEventByIdGRPCObject` -A Class-Command for request to rpt-data-provider. - -It retrieves the event by id as GRPC object. - - - -**Returns:** - - - `EventData`: Th2 event. - - - -### method `__init__` - -```python -__init__(id: str) -``` - -GetEventByIdGRPCObject constructor. - - - -**Args:** - - - `id`: Event id. - - - - ---- - - - -### method `handle` - -```python -handle(data_source: GRPCProvider5DataSource) → EventData -``` - - - - - - ---- - - - -## class `GetEventById` -A Class-Command for request to rpt-data-provider. - -It retrieves the event by id with `attachedMessageIds` list. - - - -**Returns:** - - - `dict`: Th2 event. - - - -**Raises:** - - - `EventNotFound`: If event by Id wasn't found. - - - -### method `__init__` - -```python -__init__(id: str, use_stub=False) -``` - -GetEventById constructor. - - - -**Args:** - - - `id`: Event id. - - `use_stub`: If True the command returns stub instead of exception. - - - - ---- - - - -### method `handle` - -```python -handle(data_source: GRPCProvider5DataSource) → dict -``` - - - - - - ---- - - - -## class `GetEventsById` -A Class-Command for request to rpt-data-provider. - -It retrieves the events by ids with `attachedMessageIds` list. - - - -**Returns:** - - - `List[dict]`: Th2 events. - - - -**Raises:** - - - `EventNotFound`: If any event by Id wasn't found. - - - -### method `__init__` - -```python -__init__(ids: List[str], use_stub=False) -``` - -GetEventsById constructor. - - - -**Args:** - - - `ids`: Events ids. - - `use_stub`: If True the command returns stub instead of exception. - - - - ---- - - - -### method `handle` - -```python -handle(data_source: GRPCProvider5DataSource) → List[dict] -``` - - - - - - ---- - - - -## class `GetEventsGRPCObjects` -A Class-Command for request to rpt-data-provider. - -It searches events stream as GRPC object by options. - - - -**Returns:** - - - `Iterable[EventData]`: Stream of Th2 events. - - - -### method `__init__` - -```python -__init__( - start_timestamp: datetime, - end_timestamp: datetime = None, - parent_event: str = None, - search_direction: str = 'NEXT', - resume_from_id: str = None, - result_count_limit: int = None, - keep_open: bool = False, - limit_for_parent: int = None, - attached_messages: bool = False, - filters: List[Filter] = None -) -``` - -GetEventsGRPCObjects constructor. - - - -**Args:** - - - `start_timestamp`: Start timestamp of search. - - `end_timestamp`: End timestamp of search. - - `resume_from_id`: Event id from which search starts. - - `parent_event`: Match events to the specified parent. - - `search_direction`: Search direction. - - `result_count_limit`: Result count limit. - - `keep_open`: If the search has reached the current moment. It is need to wait further for the appearance of new data. the one closest to the specified timestamp. - - `limit_for_parent`: How many children events for each parent do we want to request. - - `attached_messages`: Gets messages ids which linked to events. - - `filters`: Filters using in search for messages. - - - - ---- - - - -### method `handle` - -```python -handle(data_source: GRPCProvider5DataSource) → Iterable[EventData] -``` - - - - - - ---- - - - -## class `GetEvents` -A Class-Command for request to rpt-data-provider. - -It searches events stream by options. - - - -**Returns:** - - - `Iterable[dict]`: Stream of Th2 events. - - - -### method `__init__` - -```python -__init__( - start_timestamp: datetime, - end_timestamp: datetime = None, - parent_event: str = None, - search_direction: str = 'NEXT', - resume_from_id: str = None, - result_count_limit: int = None, - keep_open: bool = False, - limit_for_parent: int = None, - attached_messages: bool = False, - filters: List[Filter] = None, - cache: bool = False -) -``` - -GetEvents constructor. - - - -**Args:** - - - `start_timestamp`: Start timestamp of search. - - `end_timestamp`: End timestamp of search. - - `resume_from_id`: Event id from which search starts. - - `parent_event`: Match events to the specified parent. - - `search_direction`: Search direction. - - `result_count_limit`: Result count limit. - - `keep_open`: If the search has reached the current moment. It is need to wait further for the appearance of new data. the one closest to the specified timestamp. - - `limit_for_parent`: How many children events for each parent do we want to request. - - `attached_messages`: Gets messages ids which linked to events. - - `filters`: Filters using in search for messages. - - `cache`: If True, all requested data from rpt-data-provider will be saved to cache. - - - - ---- - - - -### method `handle` - -```python -handle(data_source: GRPCProvider5DataSource) → Data -``` - - - - - - ---- - - - -## class `GetMessageByIdGRPCObject` -A Class-Command for request to rpt-data-provider. - -It retrieves the message by id as GRPC Object. - - - -**Returns:** - - - `MessageData`: Th2 message. - - - -### method `__init__` - -```python -__init__(id: str) -``` - -GetMessageByIdGRPCObject constructor. - - - -**Args:** - - - `id`: Message id. - - - - ---- - - - -### method `handle` - -```python -handle(data_source: GRPCProvider5DataSource) → MessageData -``` - - - - - - ---- - - - -## class `GetMessageById` -A Class-Command for request to rpt-data-provider. - -It retrieves the message by id. - -Please note, Provider5 doesn't return `attachedEventIds`. It will be == []. It's expected that Provider7 will be support it. - - - -**Returns:** - - - `dict`: Th2 message. - - - -**Raises:** - - - `MessageNotFound`: If message by id wasn't found. - - - -### method `__init__` - -```python -__init__(id: str, use_stub=False) -``` - -GetMessageById constructor. - - - -**Args:** - - - `id`: Message id. - - `use_stub`: If True the command returns stub instead of exception. - - - - ---- - - - -### method `handle` - -```python -handle(data_source: GRPCProvider5DataSource) → dict -``` - - - - - - ---- - - - -## class `GetMessagesById` -A Class-Command for request to rpt-data-provider. - -It retrieves the messages by id. - -Please note, Provider5 doesn't return `attachedEventIds`. It will be == []. It's expected that Provider7 will be support it. - - - -**Returns:** - - - `List[dict]`: Th2 messages. - - - -**Raises:** - - - `MessageNotFound`: If any message by id wasn't found. - - - -### method `__init__` - -```python -__init__(ids: List[str], use_stub=False) -``` - -GetMessagesById constructor. - - - -**Args:** - - - `ids`: Messages id. - - `use_stub`: If True the command returns stub instead of exception. - - - - ---- - - - -### method `handle` - -```python -handle(data_source: GRPCProvider5DataSource) → List[dict] -``` - - - - - - ---- - - - -## class `GetMessagesGRPCObject` -A Class-Command for request to rpt-data-provider. - -It searches messages stream as GRPC object by options. - - - -**Returns:** - - - `Iterable[MessageData]`: Stream of Th2 messages. - - - -### method `__init__` - -```python -__init__( - start_timestamp: datetime, - stream: List[str], - end_timestamp: datetime = None, - resume_from_id: str = None, - search_direction: str = 'NEXT', - result_count_limit: int = None, - keep_open: bool = False, - message_id: List[str] = None, - attached_events: bool = False, - filters: List[Filter] = None -) -``` - -GetMessagesGRPCObject constructor. - - - -**Args:** - - - `start_timestamp`: Start timestamp of search. - - `end_timestamp`: End timestamp of search. - - `stream`: Alias of messages. - - `resume_from_id`: Message id from which search starts. - - `search_direction`: Search direction. - - `result_count_limit`: Result count limit. - - `keep_open`: If the search has reached the current moment. It is need to wait further for the appearance of new data. - - `message_id`: List of message ids to restore the search - - `attached_events`: If true, it will additionally load attachedEventsIds. - - `filters`: Filters using in search for messages. - - - - ---- - - - -### method `handle` - -```python -handle(data_source: GRPCProvider5DataSource) → List[MessageData] -``` - - - - - - ---- - - - -## class `GetMessages` -A Class-Command for request to rpt-data-provider. - -It searches messages stream by options. - - - -**Returns:** - - - `Iterable[dict]`: Stream of Th2 messages. - - - -### method `__init__` - -```python -__init__( - start_timestamp: datetime, - stream: List[str], - end_timestamp: datetime = None, - resume_from_id: str = None, - search_direction: str = 'NEXT', - result_count_limit: int = None, - keep_open: bool = False, - filters: List[Filter] = None, - message_id: List[str] = None, - attached_events: bool = False, - cache: bool = False -) -``` - -GetMessages constructor. - - - -**Args:** - - - `start_timestamp`: Start timestamp of search. - - `end_timestamp`: End timestamp of search. - - `stream`: Alias of messages. - - `resume_from_id`: Message id from which search starts. - - `search_direction`: Search direction. - - `result_count_limit`: Result count limit. - - `keep_open`: If the search has reached the current moment. It is need to wait further for the appearance of new data. - - `filters`: Filters using in search for messages. - - `message_id`: List of message ids to restore the search - - `attached_events`: If true, it will additionally load attachedEventsIds. - - `cache`: If True, all requested data from rpt-data-provider will be saved to cache. - - - - ---- - - - -### method `handle` - -```python -handle(data_source: GRPCProvider5DataSource) → Data -``` - - - - - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.v5.commands.http.md b/documentation/api/provider.v5.commands.http.md deleted file mode 100644 index 02ac7827..00000000 --- a/documentation/api/provider.v5.commands.http.md +++ /dev/null @@ -1,687 +0,0 @@ - - - - -# module `provider.v5.commands.http` - - - - -**Global Variables** ---------------- -- **UNICODE_REPLACE_HANDLER** - - ---- - - - -## class `GetEventById` -A Class-Command for request to rpt-data-provider. - -It retrieves the event by id with `attachedMessageIds` list. - - - -**Returns:** - - - `dict`: Th2 event. - - - -**Raises:** - - - `EventNotFound`: If event by Id wasn't found. - - - -### method `__init__` - -```python -__init__(id: str, use_stub: bool = False) -``` - -GetEventById constructor. - - - -**Args:** - - - `id`: Event id. - - `use_stub`: If True the command returns stub instead of exception. - - - - ---- - - - -### method `handle` - -```python -handle(data_source: HTTPProvider5DataSource) → dict -``` - - - - - - ---- - - - -## class `GetEventsById` -A Class-Command for request to rpt-data-provider. - -It retrieves the events by ids with `attachedMessageIds` list. - - - -**Returns:** - - - `List[dict]`: Th2 events. - - - -**Raises:** - - - `EventNotFound`: If any event by Id wasn't found. - - - -### method `__init__` - -```python -__init__(ids: List[str], use_stub: bool = False) -``` - -GetEventsById constructor. - - - -**Args:** - - - `ids`: Event id list. - - `use_stub`: If True the command returns stub instead of exception. - - - - ---- - - - -### method `handle` - -```python -handle(data_source: HTTPProvider5DataSource) -``` - - - - - - ---- - - - -## class `GetEventsSSEBytes` -A Class-Command for request to rpt-data-provider. - -It searches events stream by options. - - - -**Returns:** - - - `Iterable[dict]`: Stream of Th2 events. - - - -### method `__init__` - -```python -__init__( - start_timestamp: datetime, - end_timestamp: datetime = None, - parent_event: str = None, - search_direction: str = 'next', - resume_from_id: str = None, - result_count_limit: int = None, - keep_open: bool = False, - limit_for_parent: int = None, - attached_messages: bool = False, - filters: Union[Filter, Provider5EventFilter, Sequence[Union[Filter, Provider5EventFilter]]] = None -) -``` - -GetEventsSSEBytes constructor. - - - -**Args:** - - - `start_timestamp`: Start timestamp of search. - - `end_timestamp`: End timestamp of search. - - `parent_event`: Match events to the specified parent. - - `search_direction`: Search direction. - - `resume_from_id`: Event id from which search starts. - - `result_count_limit`: Result count limit. - - `keep_open`: If the search has reached the current moment. It is need to wait further for the appearance of new data. the one closest to the specified timestamp. - - `limit_for_parent`: How many children events for each parent do we want to request. - - `attached_messages`: Gets messages ids which linked to events. - - `filters`: Filters using in search for messages. - - - - ---- - - - -### method `handle` - -```python -handle(data_source: HTTPProvider5DataSource) -``` - - - - - - ---- - - - -## class `GetEventsSSEEvents` -A Class-Command for request to rpt-data-provider. - -It searches events stream by options. - - - -**Returns:** - - - `Iterable[dict]`: Stream of Th2 events. - - - -### method `__init__` - -```python -__init__( - start_timestamp: datetime, - end_timestamp: datetime = None, - parent_event: str = None, - search_direction: str = 'next', - resume_from_id: str = None, - result_count_limit: int = None, - keep_open: bool = False, - limit_for_parent: int = None, - attached_messages: bool = False, - filters: Union[Filter, Provider5EventFilter, Sequence[Union[Filter, Provider5EventFilter]]] = None, - char_enc: str = 'utf-8', - decode_error_handler: str = 'unicode_replace' -) -``` - -GetEventsSSEEvents constructor. - - - -**Args:** - - - `start_timestamp`: Start timestamp of search. - - `end_timestamp`: End timestamp of search. - - `parent_event`: Match events to the specified parent. - - `search_direction`: Search direction. - - `resume_from_id`: Event id from which search starts. - - `result_count_limit`: Result count limit. - - `keep_open`: If the search has reached the current moment. It is need to wait further for the appearance of new data. the one closest to the specified timestamp. - - `limit_for_parent`: How many children events for each parent do we want to request. - - `attached_messages`: Gets messages ids which linked to events. - - `filters`: Filters using in search for messages. - - `char_enc`: Encoding for the byte stream. - - `decode_error_handler`: Registered decode error handler. - - - - ---- - - - -### method `handle` - -```python -handle(data_source: HTTPProvider5DataSource) -``` - - - - - - ---- - - - -## class `GetEvents` -A Class-Command for request to rpt-data-provider. - -It searches events stream by options. - - - -**Returns:** - - - `Iterable[dict]`: Stream of Th2 events. - - - -### method `__init__` - -```python -__init__( - start_timestamp: datetime, - end_timestamp: datetime = None, - parent_event: str = None, - search_direction: str = 'next', - resume_from_id: str = None, - result_count_limit: int = None, - keep_open: bool = False, - limit_for_parent: int = None, - attached_messages: bool = False, - filters: Union[Filter, Provider5EventFilter, Sequence[Union[Filter, Provider5EventFilter]]] = None, - cache: bool = False -) -``` - -GetEvents constructor. - - - -**Args:** - - - `start_timestamp`: Start timestamp of search. - - `end_timestamp`: End timestamp of search. - - `parent_event`: Match events to the specified parent. - - `search_direction`: Search direction. - - `resume_from_id`: Event id from which search starts. - - `result_count_limit`: Result count limit. - - `keep_open`: If the search has reached the current moment. It is need to wait further for the appearance of new data. the one closest to the specified timestamp. - - `limit_for_parent`: How many children events for each parent do we want to request. - - `attached_messages`: Gets messages ids which linked to events. - - `filters`: Filters using in search for messages. - - `cache`: If True, all requested data from rpt-data-provider will be saved to cache. - - - - ---- - - - -### method `handle` - -```python -handle(data_source: HTTPProvider5DataSource) → Data -``` - - - - - - ---- - - - -## class `GetMessageById` -A Class-Command for request to rpt-data-provider. - -It retrieves the message by id. - -Please note, Provider5 doesn't return `attachedEventIds`. It will be == []. It's expected that Provider7 will be support it. - - - -**Returns:** - - - `dict`: Th2 message. - - - -**Raises:** - - - `MessageNotFound`: If message by id wasn't found. - - - -### method `__init__` - -```python -__init__(id: str, use_stub: bool = False) -``` - -GetMessageById constructor. - - - -**Args:** - - - `id`: Message id. - - `use_stub`: If True the command returns stub instead of exception. - - - - ---- - - - -### method `handle` - -```python -handle(data_source: HTTPProvider5DataSource) → dict -``` - - - - - - ---- - - - -## class `GetMessagesById` -A Class-Command for request to rpt-data-provider. - -It retrieves the messages by ids. - -Please note, Provider5 doesn't return `attachedEventIds`. It will be == []. It's expected that Provider7 will be support it. - - - -**Returns:** - - - `List[dict]`: Th2 messages. - - - -**Raises:** - - - `MessageNotFound`: If any message by id wasn't found. - - - -### method `__init__` - -```python -__init__(ids: List[str], use_stub: bool = False) -``` - -GetMessagesById constructor. - - - -**Args:** - - - `ids`: Message id list. - - `use_stub`: If True the command returns stub instead of exception. - - - - ---- - - - -### method `handle` - -```python -handle(data_source: HTTPProvider5DataSource) → List[dict] -``` - - - - - - ---- - - - -## class `GetMessagesSSEBytes` -A Class-Command for request to rpt-data-provider. - -It searches messages stream by options. - - - -**Returns:** - - - `Iterable[dict]`: Stream of Th2 messages. - - - -### method `__init__` - -```python -__init__( - start_timestamp: datetime, - stream: List[str], - end_timestamp: datetime = None, - resume_from_id: str = None, - search_direction: str = 'next', - result_count_limit: int = None, - keep_open: bool = False, - message_id: List[str] = None, - attached_events: bool = False, - lookup_limit_days: int = None, - filters: Union[Filter, Provider5MessageFilter, Sequence[Union[Filter, Provider5MessageFilter]]] = None -) -``` - -GetMessagesSSEBytes constructor. - - - -**Args:** - - - `start_timestamp`: Start timestamp of search. - - `end_timestamp`: End timestamp of search. - - `stream`: Alias of messages. - - `resume_from_id`: Message id from which search starts. - - `search_direction`: Search direction. - - `result_count_limit`: Result count limit. - - `keep_open`: If the search has reached the current moment. It is need to wait further for the appearance of new data. - - `message_id`: List of message IDs to restore search. If given, it has the highest priority and ignores stream (uses streams from ids), startTimestamp and resumeFromId. - - `attached_events`: If true, additionally load attached_event_ids - - `lookup_limit_days`: The number of days that will be viewed on the first request to get the one closest to the specified timestamp. - - `filters`: Filters using in search for messages. - - - - ---- - - - -### method `handle` - -```python -handle( - data_source: HTTPProvider5DataSource -) → Generator[dict, NoneType, NoneType] -``` - - - - - - ---- - - - -## class `GetMessagesSSEEvents` -A Class-Command for request to rpt-data-provider. - -It searches messages stream by options. - - - -**Returns:** - - - `Iterable[dict]`: Stream of Th2 messages. - - - -### method `__init__` - -```python -__init__( - start_timestamp: datetime, - stream: List[str], - end_timestamp: datetime = None, - resume_from_id: str = None, - search_direction: str = 'next', - result_count_limit: int = None, - keep_open: bool = False, - message_id: List[str] = None, - attached_events: bool = False, - lookup_limit_days: int = None, - filters: Union[Filter, Provider5MessageFilter, Sequence[Union[Filter, Provider5MessageFilter]]] = None, - char_enc: str = 'utf-8', - decode_error_handler: str = 'unicode_replace' -) -``` - -GetMessagesSSEEvents constructor. - - - -**Args:** - - - `start_timestamp`: Start timestamp of search. - - `end_timestamp`: End timestamp of search. - - `stream`: Alias of messages. - - `resume_from_id`: Message id from which search starts. - - `search_direction`: Search direction. - - `result_count_limit`: Result count limit. - - `keep_open`: If the search has reached the current moment. It is need to wait further for the appearance of new data. - - `message_id`: List of message IDs to restore search. If given, it has the highest priority and ignores stream (uses streams from ids), startTimestamp and resumeFromId. - - `attached_events`: If true, additionally load attached_event_ids - - `lookup_limit_days`: The number of days that will be viewed on the first request to get the one closest to the specified timestamp. - - `filters`: Filters using in search for messages. - - `char_enc`: Character encode that will use SSEClient. - - `decode_error_handler`: Decode error handler. - - - - ---- - - - -### method `handle` - -```python -handle( - data_source: HTTPProvider5DataSource -) → Generator[dict, NoneType, NoneType] -``` - - - - - - ---- - - - -## class `GetMessages` -A Class-Command for request to rpt-data-provider. - -It searches messages stream by options. - - - -**Returns:** - - - `Iterable[dict]`: Stream of Th2 messages. - - - -### method `__init__` - -```python -__init__( - start_timestamp: datetime, - stream: List[str], - end_timestamp: datetime = None, - resume_from_id: str = None, - search_direction: str = 'next', - result_count_limit: int = None, - keep_open: bool = False, - message_id: List[str] = None, - attached_events: bool = False, - lookup_limit_days: int = None, - filters: Union[Filter, Provider5MessageFilter, Sequence[Union[Filter, Provider5MessageFilter]]] = None, - char_enc: str = 'utf-8', - decode_error_handler: str = 'unicode_replace', - cache: bool = False -) -``` - -GetMessages constructor. - - - -**Args:** - - - `start_timestamp`: Start timestamp of search. - - `end_timestamp`: End timestamp of search. - - `stream`: Alias of messages. - - `resume_from_id`: Message id from which search starts. - - `search_direction`: Search direction. - - `result_count_limit`: Result count limit. - - `keep_open`: If the search has reached the current moment. It is need to wait further for the appearance of new data. - - `message_id`: List of message IDs to restore search. If given, it has the highest priority and ignores stream (uses streams from ids), startTimestamp and resumeFromId. - - `attached_events`: If true, additionally load attached_event_ids - - `lookup_limit_days`: The number of days that will be viewed on the first request to get the one closest to the specified timestamp. - - `filters`: Filters using in search for messages. - - `char_enc`: Encoding for the byte stream. - - `decode_error_handler`: Registered decode error handler. - - `cache`: If True, all requested data from rpt-data-provider will be saved to cache. - - - - ---- - - - -### method `handle` - -```python -handle(data_source: HTTPProvider5DataSource) → Data -``` - - - - - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.v5.commands.md b/documentation/api/provider.v5.commands.md deleted file mode 100644 index 6e892201..00000000 --- a/documentation/api/provider.v5.commands.md +++ /dev/null @@ -1,16 +0,0 @@ - - - - -# module `provider.v5.commands` - - - - - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.v5.data_source.grpc.md b/documentation/api/provider.v5.data_source.grpc.md deleted file mode 100644 index 5d0908c3..00000000 --- a/documentation/api/provider.v5.data_source.grpc.md +++ /dev/null @@ -1,124 +0,0 @@ - - - - -# module `provider.v5.data_source.grpc` - - - - -**Global Variables** ---------------- -- **TYPE_CHECKING** - - ---- - - - -## class `GRPCProvider5DataSource` -DataSource class which provide work with rpt-data-provider. - -Rpt-data-provider version: 5.x.y Protocol: GRPC - - - -### method `__init__` - -```python -__init__( - url: 'str', - event_struct: 'IEventStruct' = Provider5EventStruct(EVENT_ID='eventId', PARENT_EVENT_ID='parentEventId', STATUS='successful', NAME='eventName', TYPE='type', BATCH_ID='batchId', IS_BATCHED='isBatched', EVENT_TYPE='eventType', END_TIMESTAMP='endTimestamp', START_TIMESTAMP='startTimestamp', ATTACHED_MESSAGES_IDS='attachedMessageIds', BODY='body'), - message_struct: 'IMessageStruct' = Provider5MessageStruct(DIRECTION='direction', SESSION_ID='sessionId', MESSAGE_TYPE='messageType', CONNECTION_ID='connectionId', SESSION_ALIAS='sessionAlias', SUBSEQUENCE='subsequence', SEQUENCE='sequence', TIMESTAMP='timestamp', BODY='body', BODY_BASE64='bodyBase64', TYPE='type', MESSAGE_ID='messageId', ATTACHED_EVENT_IDS='attachedEventIds'), - event_stub_builder: 'IEventStub' = Provider5EventStubBuilder, - message_stub_builder: 'IMessageStub' = Provider5MessageStubBuilder -) -``` - -GRPCProvider5DataSource constructor. - - - -**Args:** - - - `url`: Url of rpt-data-provider. - - `event_struct`: Event structure that is supplied by rpt-data-provider. - - `message_struct`: Message structure that is supplied by rpt-data-provider. - - `event_stub_builder`: Stub builder for broken events. - - `message_stub_builder`: Stub builder for broken messages. - - ---- - -#### property event_struct - -Returns event structure class. - ---- - -#### property event_stub_builder - -Returns event stub template. - ---- - -#### property message_struct - -Returns message structure class. - ---- - -#### property message_stub_builder - -Returns message stub template. - ---- - -#### property source_api - -Returns Provider API. - ---- - -#### property url - -str: URL of rpt-data-provider. - - - ---- - - - -### method `command` - -```python -command(cmd: 'IGRPCProvider5Command') → Any -``` - -Execute the transmitted GRPC command. - - - -**Args:** - - - `cmd`: GRPC Command. - - - -**Returns:** - - - `Any`: Command response. - - - -**Raises:** - - - `CommandError`: If the command was broken. - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.v5.data_source.http.md b/documentation/api/provider.v5.data_source.http.md deleted file mode 100644 index ea647ef1..00000000 --- a/documentation/api/provider.v5.data_source.http.md +++ /dev/null @@ -1,134 +0,0 @@ - - - - -# module `provider.v5.data_source.http` - - - - -**Global Variables** ---------------- -- **UNICODE_REPLACE_HANDLER** -- **TYPE_CHECKING** - - ---- - - - -## class `HTTPProvider5DataSource` -DataSource class which provide work with rpt-data-provider. - -Rpt-data-provider version: 5.x.y Protocol: HTTP - - - -### method `__init__` - -```python -__init__( - url: 'str', - chunk_length: 'int' = 65536, - char_enc: 'str' = 'utf-8', - decode_error_handler: 'str' = 'unicode_replace', - event_struct: 'IEventStruct' = Provider5EventStruct(EVENT_ID='eventId', PARENT_EVENT_ID='parentEventId', STATUS='successful', NAME='eventName', TYPE='type', BATCH_ID='batchId', IS_BATCHED='isBatched', EVENT_TYPE='eventType', END_TIMESTAMP='endTimestamp', START_TIMESTAMP='startTimestamp', ATTACHED_MESSAGES_IDS='attachedMessageIds', BODY='body'), - message_struct: 'IMessageStruct' = Provider5MessageStruct(DIRECTION='direction', SESSION_ID='sessionId', MESSAGE_TYPE='messageType', CONNECTION_ID='connectionId', SESSION_ALIAS='sessionAlias', SUBSEQUENCE='subsequence', SEQUENCE='sequence', TIMESTAMP='timestamp', BODY='body', BODY_BASE64='bodyBase64', TYPE='type', MESSAGE_ID='messageId', ATTACHED_EVENT_IDS='attachedEventIds'), - event_stub_builder: 'IEventStub' = Provider5EventStubBuilder, - message_stub_builder: 'IMessageStub' = Provider5MessageStubBuilder, - check_connect_timeout: '(int, float)' = 5, - use_ssl: 'bool' = True -) -``` - -HTTPProvider5DataSource constructor. - - - -**Args:** - - - `url`: HTTP data source url. - - `check_connect_timeout`: How many seconds to wait for the server to send data before giving up. - - `chunk_length`: How much of the content to read in one chunk. - - `char_enc`: Encoding for the byte stream. - - `decode_error_handler`: Registered decode error handler. - - `event_struct`: Struct of event from rpt-data-provider. - - `message_struct`: Struct of message from rpt-data-provider. - - `event_stub_builder`: Stub for event. - - `message_stub_builder`: Stub for message. - - `use_ssl`: Checking SSL/TSL certification. - - ---- - -#### property event_struct - -Returns event structure class. - ---- - -#### property event_stub_builder - -Returns event stub template. - ---- - -#### property message_struct - -Returns message structure class. - ---- - -#### property message_stub_builder - -Returns message stub template. - ---- - -#### property source_api - -HTTP Provider5 API. - ---- - -#### property url - -str: URL of rpt-data-provider. - - - ---- - - - -### method `command` - -```python -command(cmd: 'IHTTPProvider5Command') -``` - -HTTP Provider5 command processor. - - - -**Args:** - - - `cmd`: The command of data source to execute. - - - -**Returns:** - Data source command result. - - - -**Raises:** - - - `CommandError`: If the command was broken. - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.v5.events_tree.events_tree_collection.md b/documentation/api/provider.v5.events_tree.events_tree_collection.md deleted file mode 100644 index 796048f1..00000000 --- a/documentation/api/provider.v5.events_tree.events_tree_collection.md +++ /dev/null @@ -1,77 +0,0 @@ - - - - -# module `provider.v5.events_tree.events_tree_collection` - - - - - - ---- - - - -## class `EventsTreeCollectionProvider5` -EventsTreesCollections for data-provider v5. - - - -### method `__init__` - -```python -__init__( - data: Data, - data_source: Union[GRPCProvider5DataSource, HTTPProvider5DataSource] = None, - preserve_body: bool = False, - event_struct: IEventStruct = Provider5EventStruct(EVENT_ID='eventId', PARENT_EVENT_ID='parentEventId', STATUS='successful', NAME='eventName', TYPE='type', BATCH_ID='batchId', IS_BATCHED='isBatched', EVENT_TYPE='eventType', END_TIMESTAMP='endTimestamp', START_TIMESTAMP='startTimestamp', ATTACHED_MESSAGES_IDS='attachedMessageIds', BODY='body'), - stub: bool = False -) -``` - -EventsTreeCollectionProvider5 constructor. - - - -**Args:** - - - `data`: Data object. - - `data_source`: Data Source object. - - `preserve_body`: If True it will preserve 'body' field in the Events. - - `event_struct`: Event struct object. - - `stub`: If True it will create stub when event is broken. - - ---- - -#### property detached_events - -Returns detached events as a dict that looks like {'parent_id': ['referenced event', ...]}. - ---- - -#### property len_detached_events - -Returns number of detached events in the collection. - ---- - -#### property len_parentless - -Returns number of events in the parentless trees inside the collection. - ---- - -#### property len_trees - -Returns number of events in the trees inside the collection, including parentless trees. - - - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.v5.events_tree.events_trees_collection.md b/documentation/api/provider.v5.events_tree.events_trees_collection.md deleted file mode 100644 index df7701ad..00000000 --- a/documentation/api/provider.v5.events_tree.events_trees_collection.md +++ /dev/null @@ -1,59 +0,0 @@ - - - - -# module `provider.v5.events_tree.events_trees_collection` - - - - - - ---- - - - -## class `EventsTreesCollectionProvider5` -EventsTreesCollections for data-provider v5. - - - -### method `__init__` - -```python -__init__( - data: Data, - data_source: Union[GRPCProvider5DataSource, HTTPProvider5DataSource] = None, - preserve_body: bool = False, - event_struct: IEventStruct = Provider5EventStruct(EVENT_ID='eventId', PARENT_EVENT_ID='parentEventId', STATUS='successful', NAME='eventName', TYPE='type', BATCH_ID='batchId', IS_BATCHED='isBatched', EVENT_TYPE='eventType', END_TIMESTAMP='endTimestamp', START_TIMESTAMP='startTimestamp', ATTACHED_MESSAGES_IDS='attachedMessageIds', BODY='body'), - stub: bool = False -) -``` - -EventsTreesCollectionProvider5 constructor. - - - -**Args:** - - - `data`: Data object. - - `data_source`: Data Source object. - - `preserve_body`: If True it will preserve 'body' field in the Events. - - `event_struct`: Event struct object. - - `stub`: If True it will create stub when event is broken. - - ---- - -#### property detached_events - -Gets detached events as dict with a view {'parent_id': ['referenced event', ...]}. - - - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.v5.events_tree.parent_events_tree_collection.md b/documentation/api/provider.v5.events_tree.parent_events_tree_collection.md deleted file mode 100644 index 820eadf7..00000000 --- a/documentation/api/provider.v5.events_tree.parent_events_tree_collection.md +++ /dev/null @@ -1,77 +0,0 @@ - - - - -# module `provider.v5.events_tree.parent_events_tree_collection` - - - - - - ---- - - - -## class `ParentEventsTreeCollectionProvider5` -ParentEventsTreeCollection for data-provider v5. - - - -### method `__init__` - -```python -__init__( - data: Data, - data_source: Union[GRPCProvider5DataSource, HTTPProvider5DataSource] = None, - preserve_body: bool = False, - event_struct: IEventStruct = Provider5EventStruct(EVENT_ID='eventId', PARENT_EVENT_ID='parentEventId', STATUS='successful', NAME='eventName', TYPE='type', BATCH_ID='batchId', IS_BATCHED='isBatched', EVENT_TYPE='eventType', END_TIMESTAMP='endTimestamp', START_TIMESTAMP='startTimestamp', ATTACHED_MESSAGES_IDS='attachedMessageIds', BODY='body'), - stub: bool = False -) -``` - -ParentEventsTreeCollectionProvider5 constructor. - - - -**Args:** - - - `data`: Data object. - - `data_source`: Data Source object. - - `preserve_body`: If True it will preserve 'body' field in the Events. - - `event_struct`: Event struct object. - - `stub`: If True it will create stub when event is broken. - - ---- - -#### property detached_events - -Returns detached events as a dict that looks like {'parent_id': ['referenced event', ...]}. - ---- - -#### property len_detached_events - -Returns number of detached events in the collection. - ---- - -#### property len_parentless - -Returns number of events in the parentless trees inside the collection. - ---- - -#### property len_trees - -Returns number of events in the trees inside the collection, including parentless trees. - - - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.v5.events_tree.parent_events_trees_collection.md b/documentation/api/provider.v5.events_tree.parent_events_trees_collection.md deleted file mode 100644 index c9977ad7..00000000 --- a/documentation/api/provider.v5.events_tree.parent_events_trees_collection.md +++ /dev/null @@ -1,59 +0,0 @@ - - - - -# module `provider.v5.events_tree.parent_events_trees_collection` - - - - - - ---- - - - -## class `ParentsEventsTreesCollectionProvider5` -ParentsEventsTreesCollection for data-provider v5. - - - -### method `__init__` - -```python -__init__( - data: Data, - data_source: Union[GRPCProvider5DataSource, HTTPProvider5DataSource] = None, - preserve_body: bool = False, - event_struct: IEventStruct = Provider5EventStruct(EVENT_ID='eventId', PARENT_EVENT_ID='parentEventId', STATUS='successful', NAME='eventName', TYPE='type', BATCH_ID='batchId', IS_BATCHED='isBatched', EVENT_TYPE='eventType', END_TIMESTAMP='endTimestamp', START_TIMESTAMP='startTimestamp', ATTACHED_MESSAGES_IDS='attachedMessageIds', BODY='body'), - stub: bool = False -) -``` - -ParentsEventsTreesCollectionProvider5 constructor. - - - -**Args:** - - - `data`: Data object. - - `data_source`: Data Source object. - - `preserve_body`: If True it will preserve 'body' field in the Events. - - `event_struct`: Event struct object. - - `stub`: If True it will create stub when event is broken. - - ---- - -#### property detached_events - -Gets detached events as dict with a view {'parent_id': ['referenced event', ...]}. - - - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.v5.filters.event_filters.md b/documentation/api/provider.v5.filters.event_filters.md deleted file mode 100644 index e7a938a7..00000000 --- a/documentation/api/provider.v5.filters.event_filters.md +++ /dev/null @@ -1,146 +0,0 @@ - - - - -# module `provider.v5.filters.event_filters` - - - - - - ---- - - - -## class `TypeFilter` -Will match the events which type contains one of the given substrings. - - - - - ---- - - - -## class `NameFilter` -Will match the events which name contains one of the given substrings. - - - - - ---- - - - -## class `BodyFilter` -Will match the events which body contains one of the given substrings. - - - - - ---- - - - -## class `AttachedMessageIdFilter` -Filters the events that are linked to the specified message id. - - - - - ---- - - - -## class `PassedStatusFilter` -Will match the events which status equals passed. - - - -### method `__init__` - -```python -__init__() -``` - - - - - - - - ---- - - - -### method `url` - -```python -url() → str -``` - -Generates the filter part of the HTTP protocol API. - -For help use this readme: https://github.com/th2-net/th2-rpt-data-provider#filters-api. - - - -**Returns:** - - - `str`: Generated filter. - - ---- - - - -## class `FailedStatusFilter` -Will match the events which status equals failed. - - - -### method `__init__` - -```python -__init__() -``` - - - - - - - - ---- - - - -### method `url` - -```python -url() → str -``` - -Generates the filter part of the HTTP protocol API. - -For help use this readme: https://github.com/th2-net/th2-rpt-data-provider#filters-api. - - - -**Returns:** - - - `str`: Generated filter. - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.v5.filters.filter.md b/documentation/api/provider.v5.filters.filter.md deleted file mode 100644 index 684b69bc..00000000 --- a/documentation/api/provider.v5.filters.filter.md +++ /dev/null @@ -1,193 +0,0 @@ - - - - -# module `provider.v5.filters.filter` - - - - - - ---- - - - -## class `Provider5Filter` -General interface for Filters of Provider v5. - - - -### method `__init__` - -```python -__init__( - name: str, - values: Union[str, int, float, Sequence[Union[str, int, float]]], - negative: bool = False, - conjunct: bool = False -) -``` - -Filter constructor. - - - -**Args:** - - - `name` (str): Filter name. - - `values` (Union[str, int, float, Sequence[Union[str, int, float]]]): One string with filter value or list of filter values. - - `negative` (bool): If true, will match events/messages that do not match those specified values. If false, will match the events/messages by their values. Defaults to false. - - `conjunct` (bool): If true, each of the specific filter values should be applied If false, at least one of the specific filter values must be applied. - - - - ---- - - - -### method `grpc` - -```python -grpc() → Filter -``` - -Generates the grpc object of the GRPC protocol API. - ---- - - - -### method `url` - -```python -url() → str -``` - -Generates the filter part of the HTTP protocol API. - -For help use this readme: https://github.com/th2-net/th2-rpt-data-provider#filters-api. - - - -**Returns:** - - - `str`: Generated filter. - - ---- - - - -## class `Provider5EventFilter` -Base class for Event Filters of Provider v5. - - - -### method `__init__` - -```python -__init__(values: Sequence[Any], negative: bool = False, conjunct: bool = False) -``` - - - - - - - - ---- - - - -### method `grpc` - -```python -grpc() → Filter -``` - -Generates the grpc object of the GRPC protocol API. - ---- - - - -### method `url` - -```python -url() → str -``` - -Generates the filter part of the HTTP protocol API. - -For help use this readme: https://github.com/th2-net/th2-rpt-data-provider#filters-api. - - - -**Returns:** - - - `str`: Generated filter. - - ---- - - - -## class `Provider5MessageFilter` -Base class for Message Filters of Provider v5. - - - -### method `__init__` - -```python -__init__(values: Sequence[Any], negative: bool = False, conjunct: bool = False) -``` - - - - - - - - ---- - - - -### method `grpc` - -```python -grpc() → Filter -``` - -Generates the grpc object of the GRPC protocol API. - ---- - - - -### method `url` - -```python -url() → str -``` - -Generates the filter part of the HTTP protocol API. - -For help use this readme: https://github.com/th2-net/th2-rpt-data-provider#filters-api. - - - -**Returns:** - - - `str`: Generated filter. - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.v5.filters.md b/documentation/api/provider.v5.filters.md deleted file mode 100644 index 0b0a865c..00000000 --- a/documentation/api/provider.v5.filters.md +++ /dev/null @@ -1,16 +0,0 @@ - - - - -# module `provider.v5.filters` - - - - - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.v5.filters.message_filters.md b/documentation/api/provider.v5.filters.message_filters.md deleted file mode 100644 index 8fa74bc0..00000000 --- a/documentation/api/provider.v5.filters.message_filters.md +++ /dev/null @@ -1,60 +0,0 @@ - - - - -# module `provider.v5.filters.message_filters` - - - - - - ---- - - - -## class `TypeFilter` -Will match the messages by their full type name. - - - - - ---- - - - -## class `BodyBinaryFilter` -Will match the messages by their binary body. - - - - - ---- - - - -## class `BodyFilter` -Will match the messages by their parsed body. - - - - - ---- - - - -## class `AttachedEventIdsFilter` -Filters the messages that are linked to the specified event id. - - - - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.v5.interfaces.command.md b/documentation/api/provider.v5.interfaces.command.md deleted file mode 100644 index 737d4093..00000000 --- a/documentation/api/provider.v5.interfaces.command.md +++ /dev/null @@ -1,70 +0,0 @@ - - - - -# module `provider.v5.interfaces.command` - - - - - - ---- - - - -## class `IHTTPProvider5Command` -Interface of command for rpt-data-provider. - -Rpt-data-provider version: 5.x.y Protocol: HTTP - - - - ---- - - - -### method `handle` - -```python -handle(data_source: HTTPProvider5DataSource) -``` - - - - - - ---- - - - -## class `IGRPCProvider5Command` -Interface of command for rpt-data-provider. - -Rpt-data-provider version: 5.x.y Protocol: GRPC - - - - ---- - - - -### method `handle` - -```python -handle(data_source: GRPCProvider5DataSource) -``` - - - - - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.v5.interfaces.filter.md b/documentation/api/provider.v5.interfaces.filter.md deleted file mode 100644 index f6b12b30..00000000 --- a/documentation/api/provider.v5.interfaces.filter.md +++ /dev/null @@ -1,235 +0,0 @@ - - - - -# module `provider.v5.interfaces.filter` - - - - - - ---- - - - -## class `Provider5Filter` - - - - - - -### method `__init__` - -```python -__init__( - name: str, - values: Union[List[str], Tuple[str], str], - negative: bool = False, - conjunct: bool = False, - exact: bool = False -) -``` - -Filter constructor. - - - -**Args:** - - - `name` (str): Filter name. - - `values` (Union[List[str], Tuple[str], str]): One string with filter value or list of filter values. - - `negative` (bool): If true, will match events/messages that do not match those specified values. If false, will match the events/messages by their values. Defaults to false. - - `conjunct` (bool): If true, each of the specific filter values should be applied If false, at least one of the specific filter values must be applied. - - `exact` (bool): .............. TODO - - - - ---- - - - -### method `grpc` - -```python -grpc() → Filter -``` - - - - - ---- - - - -### method `url` - -```python -url() → str -``` - -Forms a filter. - -For help use this readme: https://github.com/th2-net/th2-rpt-data-provider#filters-api. - - - -**Returns:** - - - `str`: Formed filter. - - ---- - - - -## class `Provider5EventFilter` -Interface of command for rpt-data-provider. - -Rpt-data-provider version: 5.x.y Protocol: HTTP - - - -### method `__init__` - -```python -__init__( - name: str, - values: Union[List[str], Tuple[str], str], - negative: bool = False, - conjunct: bool = False, - exact: bool = False -) -``` - -Filter constructor. - - - -**Args:** - - - `name` (str): Filter name. - - `values` (Union[List[str], Tuple[str], str]): One string with filter value or list of filter values. - - `negative` (bool): If true, will match events/messages that do not match those specified values. If false, will match the events/messages by their values. Defaults to false. - - `conjunct` (bool): If true, each of the specific filter values should be applied If false, at least one of the specific filter values must be applied. - - `exact` (bool): .............. TODO - - - - ---- - - - -### method `grpc` - -```python -grpc() → Filter -``` - - - - - ---- - - - -### method `url` - -```python -url() → str -``` - -Forms a filter. - -For help use this readme: https://github.com/th2-net/th2-rpt-data-provider#filters-api. - - - -**Returns:** - - - `str`: Formed filter. - - ---- - - - -## class `Provider5MessageFilter` -Interface of command for rpt-data-provider. - -Rpt-data-provider version: 5.x.y Protocol: GRPC - - - -### method `__init__` - -```python -__init__( - name: str, - values: Union[List[str], Tuple[str], str], - negative: bool = False, - conjunct: bool = False, - exact: bool = False -) -``` - -Filter constructor. - - - -**Args:** - - - `name` (str): Filter name. - - `values` (Union[List[str], Tuple[str], str]): One string with filter value or list of filter values. - - `negative` (bool): If true, will match events/messages that do not match those specified values. If false, will match the events/messages by their values. Defaults to false. - - `conjunct` (bool): If true, each of the specific filter values should be applied If false, at least one of the specific filter values must be applied. - - `exact` (bool): .............. TODO - - - - ---- - - - -### method `grpc` - -```python -grpc() → Filter -``` - - - - - ---- - - - -### method `url` - -```python -url() → str -``` - -Forms a filter. - -For help use this readme: https://github.com/th2-net/th2-rpt-data-provider#filters-api. - - - -**Returns:** - - - `str`: Formed filter. - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.v5.provider_api.grpc.md b/documentation/api/provider.v5.provider_api.grpc.md deleted file mode 100644 index 7d62044e..00000000 --- a/documentation/api/provider.v5.provider_api.grpc.md +++ /dev/null @@ -1,252 +0,0 @@ - - - - -# module `provider.v5.provider_api.grpc` - - - - - - ---- - - - -## class `BasicRequest` -BasicRequest(start_timestamp, end_timestamp, result_count_limit, keep_open, search_direction, filters) - - - - - ---- - - - -## class `GRPCProvider5API` - - - - - - -### method `__init__` - -```python -__init__(url: str) -``` - -GRPC Provider5 API. - - - -**Args:** - - - `url`: GRPC data source url. - - - - ---- - - - -### method `get_event` - -```python -get_event(event_id: str) → EventData -``` - -GRPC-API `getEvent` call returns a single event with the specified id. - ---- - - - -### method `get_event_filter_info` - -```python -get_event_filter_info(filter_name: str) → FilterInfo -``` - -GRPC-API `getEventFilterInfo` call returns event filter info. - ---- - - - -### method `get_events_filters` - -```python -get_events_filters() → ListFilterName -``` - -GRPC-API `getEventsFilters` call returns all the names of sse event filters. - ---- - - - -### method `get_message` - -```python -get_message(message_id: str) → MessageData -``` - -GRPC-API `getMessage` call returns a single message with the specified id. - ---- - - - -### method `get_message_filter_info` - -```python -get_message_filter_info(filter_name: str) → FilterInfo -``` - -GRPC-API `getMessageFilterInfo` call returns message filter info. - ---- - - - -### method `get_message_streams` - -```python -get_message_streams() → StringList -``` - -GRPC-API `getMessageStreams` call returns a list of message stream names. - ---- - - - -### method `get_messages_filters` - -```python -get_messages_filters() → ListFilterName -``` - -GRPC-API `getMessagesFilters` call returns all the names of sse message filters. - ---- - - - -### method `match_event` - -```python -match_event(event_id: str, filters: List[Filter]) → IsMatched -``` - -GRPC-API `matchEvent` call checks that the event with the specified id is matched by the filter. - ---- - - - -### method `match_message` - -```python -match_message(message_id: str, filters: List[Filter]) → IsMatched -``` - -GRPC-API `matchMessage` call checks that the message with the specified id is matched by the filter. - ---- - - - -### method `search_events` - -```python -search_events( - start_timestamp: int = None, - end_timestamp: int = None, - parent_event: str = None, - search_direction: str = 'NEXT', - resume_from_id: str = None, - result_count_limit: int = None, - keep_open: bool = False, - limit_for_parent: int = None, - metadata_only: bool = True, - attached_messages: bool = False, - filters: Optional[List[Filter]] = None -) → Iterable[StreamResponse] -``` - -GRPC-API `searchEvents` call creates an event or an event metadata stream that matches the filter. - - - -**Args:** - - - `start_timestamp`: Sets the search starting point. Expected in nanoseconds. One of the 'start_timestamp' or 'resume_from_id' must not absent. - - `end_timestamp`: Sets the timestamp to which the search will be performed, starting with 'start_timestamp'. Expected in nanoseconds. - - `parent_event`: Match events to the specified parent. - - `search_direction`: Sets the lookup direction. Can be 'NEXT' or 'PREVIOUS'. - - `resume_from_id`: The last event id from which we start searching for events. - - `result_count_limit`: Sets the maximum amount of events to return. - - `keep_open`: Option if the search has reached the current moment, it is necessary to wait further for the appearance of new data. - - `limit_for_parent`: How many children events for each parent do we want to request. - - `metadata_only`: Receive only metadata (true) or entire event (false) (without attachedMessageIds). - - `attached_messages`: Option if you want to load attachedMessageIds additionally. - - `filters`: Which filters to apply in a search. - - - -**Returns:** - Iterable object which return events as parts of streaming response. - ---- - - - -### method `search_messages` - -```python -search_messages( - start_timestamp: int, - stream: List[str], - end_timestamp: int = None, - resume_from_id: str = None, - search_direction: str = 'NEXT', - result_count_limit: int = None, - keep_open: bool = False, - filters: Optional[List[Filter]] = None, - message_id: Optional[List[str]] = None, - attached_events: bool = False -) → Iterable[StreamResponse] -``` - -GRPC-API `searchMessages` call creates a message stream that matches the filter. - - - -**Args:** - - - `start_timestamp`: Sets the search starting point. Expected in nanoseconds. One of the 'start_timestamp' or 'resume_from_id' must not absent. - - `stream`: Sets the stream ids to search in. - - `end_timestamp`: Sets the timestamp to which the search will be performed, starting with 'start_timestamp'. Expected in nanoseconds. - - `search_direction`: Sets the lookup direction. Can be 'NEXT' or 'PREVIOUS'. - - `resume_from_id`: The last event id from which we start searching for messages. - - `result_count_limit`: Sets the maximum amount of messages to return. - - `keep_open`: Option if the search has reached the current moment, it is necessary to wait further for the appearance of new data. - - `filters`: Which filters to apply in a search. - - `message_id`: List of message ids to restore the search. - - `attached_events`: If true, it will additionally load attachedEventsIds. - - - -**Returns:** - Iterable object which return messages as parts of streaming response. - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.v5.provider_api.http.md b/documentation/api/provider.v5.provider_api.http.md deleted file mode 100644 index 9ca7da21..00000000 --- a/documentation/api/provider.v5.provider_api.http.md +++ /dev/null @@ -1,298 +0,0 @@ - - - - -# module `provider.v5.provider_api.http` - - - - -**Global Variables** ---------------- -- **UNICODE_REPLACE_HANDLER** - - ---- - - - -## class `HTTPProvider5API` - - - - - - -### method `__init__` - -```python -__init__( - url: str, - chunk_length: int = 65536, - decode_error_handler: str = 'unicode_replace', - char_enc: str = 'utf-8', - use_ssl: bool = True -) -``` - -HTTP Provider5 API. - - - -**Args:** - - - `url`: HTTP data source url. - - `chunk_length`: How much of the content to read in one chunk. - - `char_enc`: Encoding for the byte stream. - - `decode_error_handler`: Registered decode error handler. - - `use_ssl`: If False SSL/TSL certification is disable. - - - - ---- - - - -### method `execute_request` - -```python -execute_request(url: str) → Response -``` - -Sends a GET request to provider. - - - -**Args:** - - - `url`: Url for a get request to rpt-data-provider. - - - -**Returns:** - - - `requests.Response`: Response data. - ---- - - - -### method `execute_sse_request` - -```python -execute_sse_request(url: str) → Generator[bytes, NoneType, NoneType] -``` - -Create stream connection. - - - -**Args:** - - - `url`: Url. - - - -**Yields:** - - - `str`: Response stream data. - ---- - - - -### method `get_url_event_filter_info` - -```python -get_url_event_filter_info(filter_name: str) → str -``` - -SSE-API `filters/sse-events/{filter_name}` call returns filter info. - -https://github.com/th2-net/th2-rpt-data-provider#filters-api - ---- - - - -### method `get_url_events_filters` - -```python -get_url_events_filters() → str -``` - -SSE-API `/filters/sse-events` call returns all names of sse event filters. - -https://github.com/th2-net/th2-rpt-data-provider#filters-api - ---- - - - -### method `get_url_find_event_by_id` - -```python -get_url_find_event_by_id(event_id: str) → str -``` - -REST-API `event` call returns a single event with the specified id. - ---- - - - -### method `get_url_find_events_by_id` - -```python -get_url_find_events_by_id(*ids) → str -``` - -REST-API `events` call returns a list of events with the specified ids. - -Note, at a time you can request no more eventSearchChunkSize. - -Deprecated, use `get_url_find_event_by_id` instead. - ---- - - - -### method `get_url_find_message_by_id` - -```python -get_url_find_message_by_id(message_id: str) → str -``` - -REST-API `message` call returns a single message with the specified id. - ---- - - - -### method `get_url_match_event_by_id` - -```python -get_url_match_event_by_id(event_id: str, filters: str = '') → str -``` - -REST-API `match/event/{id}` call returns boolean value. - -Checks that event with the specified id is matched by filter. - -https://github.com/th2-net/th2-rpt-data-provider#filters-api - ---- - - - -### method `get_url_match_message_by_id` - -```python -get_url_match_message_by_id(message_id: str, filters: str = '') → str -``` - -REST-API `match/message/{id}` call returns boolean value. - -Checks that message with the specified id is matched by filter. - -https://github.com/th2-net/th2-rpt-data-provider#filters-api - ---- - - - -### method `get_url_message_filter_info` - -```python -get_url_message_filter_info(filter_name: str) → str -``` - -SSE-API `filters/sse-messages/{filter name}` call returns filter info. - -https://github.com/th2-net/th2-rpt-data-provider#filters-api - ---- - - - -### method `get_url_message_streams` - -```python -get_url_message_streams() → str -``` - -REST-API `messageStreams` call returns a list of message stream names. - ---- - - - -### method `get_url_messages_filters` - -```python -get_url_messages_filters() → str -``` - -SSE-API `filters/sse-messages` call returns all names of sse message filters. - -https://github.com/th2-net/th2-rpt-data-provider#filters-api - ---- - - - -### method `get_url_search_sse_events` - -```python -get_url_search_sse_events( - start_timestamp: int, - end_timestamp: Optional[int] = None, - parent_event: Optional[str] = None, - resume_from_id: Optional[str] = None, - search_direction: Optional[str] = 'next', - result_count_limit: Union[int, float] = None, - keep_open: Optional[bool] = False, - limit_for_parent: Union[int, float] = None, - metadata_only: Optional[bool] = True, - attached_messages: Optional[bool] = False, - filters: Optional[str] = None -) → str -``` - -REST-API `search/sse/events` call create a sse channel of event metadata that matches the filter. - -https://github.com/th2-net/th2-rpt-data-provider#sse-requests-api - ---- - - - -### method `get_url_search_sse_messages` - -```python -get_url_search_sse_messages( - start_timestamp: int, - stream: List[str], - end_timestamp: Optional[int] = None, - resume_from_id: Optional[str] = None, - search_direction: Optional[str] = 'next', - result_count_limit: Union[int, float] = None, - keep_open: bool = False, - message_id: Optional[List[str]] = None, - attached_events: bool = False, - lookup_limit_days: Union[int, float] = None, - filters: Optional[str] = None -) → str -``` - -REST-API `search/sse/messages` call create a sse channel of messages that matches the filter. - -https://github.com/th2-net/th2-rpt-data-provider#sse-requests-api - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.v5.stub_builder.md b/documentation/api/provider.v5.stub_builder.md deleted file mode 100644 index 703e591d..00000000 --- a/documentation/api/provider.v5.stub_builder.md +++ /dev/null @@ -1,104 +0,0 @@ - - - - -# module `provider.v5.stub_builder` - - - - -**Global Variables** ---------------- -- **provider5_event_stub_builder** -- **provider5_message_stub_builder** - - ---- - - - -## class `Provider5EventStubBuilder` - - - - - - -### method `__init__` - -```python -__init__( - event_struct=Provider5EventStruct(EVENT_ID='eventId', PARENT_EVENT_ID='parentEventId', STATUS='successful', NAME='eventName', TYPE='type', BATCH_ID='batchId', IS_BATCHED='isBatched', EVENT_TYPE='eventType', END_TIMESTAMP='endTimestamp', START_TIMESTAMP='startTimestamp', ATTACHED_MESSAGES_IDS='attachedMessageIds', BODY='body') -) -``` - -Event stub builder for Provider v5. - - - -**Args:** - - - `event_struct`: Event struct class. - - ---- - -#### property template - -Event stub template. - - - -**Returns:** - (dict) Event stub template. - - - - ---- - - - -## class `Provider5MessageStubBuilder` - - - - - - -### method `__init__` - -```python -__init__( - message_struct=Provider5MessageStruct(DIRECTION='direction', SESSION_ID='sessionId', MESSAGE_TYPE='messageType', CONNECTION_ID='connectionId', SESSION_ALIAS='sessionAlias', SUBSEQUENCE='subsequence', SEQUENCE='sequence', TIMESTAMP='timestamp', BODY='body', BODY_BASE64='bodyBase64', TYPE='type', MESSAGE_ID='messageId', ATTACHED_EVENT_IDS='attachedEventIds') -) -``` - -Event stub builder for Provider v5. - - - -**Args:** - - - `message_struct`: Message struct class. - - ---- - -#### property template - -Message stub template. - - - -**Returns:** - (dict) Message stub template. - - - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.v5.utils.converters.md b/documentation/api/provider.v5.utils.converters.md deleted file mode 100644 index 5f7804ca..00000000 --- a/documentation/api/provider.v5.utils.converters.md +++ /dev/null @@ -1,45 +0,0 @@ - - - - -# module `provider.v5.utils.converters` - - - - - - ---- - - - -## class `Th2TimestampConverter` -Converts Th2 timestamps. - -If you request microseconds but your timestamp has nanoseconds, they will be just cut (not rounding). - -Expected timestamp format {'epochSecond': 123, 'nano': 500}. - - - - ---- - - - -### classmethod `parse_timestamp` - -```python -parse_timestamp(timestamp: dict) → (, ) -``` - - - - - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.v5.utils.md b/documentation/api/provider.v5.utils.md deleted file mode 100644 index 07222a0d..00000000 --- a/documentation/api/provider.v5.utils.md +++ /dev/null @@ -1,16 +0,0 @@ - - - - -# module `provider.v5.utils` - - - - - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.v6.adapters.basic_adapters.md b/documentation/api/provider.v6.adapters.basic_adapters.md deleted file mode 100644 index c33a7169..00000000 --- a/documentation/api/provider.v6.adapters.basic_adapters.md +++ /dev/null @@ -1,50 +0,0 @@ - - - - -# module `provider.v6.adapters.basic_adapters` - - - - - - ---- - - - -## class `GRPCObjectToDictAdapter` -GRPC Adapter decodes a GRPC object into a Dict object. - - - - ---- - - - -### method `handle` - -```python -handle(record: Union[MessageGroupResponse, EventResponse]) → dict -``` - -Decodes MessageGroupResponse or EventResponse as GRPC object into a Dict object. - - - -**Args:** - - - `record`: MessageGroupResponse/EventResponse. - - - -**Returns:** - Dict object. - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.v6.adapters.event_adapters.md b/documentation/api/provider.v6.adapters.event_adapters.md deleted file mode 100644 index 8490635e..00000000 --- a/documentation/api/provider.v6.adapters.event_adapters.md +++ /dev/null @@ -1,95 +0,0 @@ - - - - -# module `provider.v6.adapters.event_adapters` - - - - - - ---- - - - -## class `DeleteEventWrappersAdapter` -Adapter that deletes unnecessary wrappers in events. - -It used for events to which an AdaptorGRPCObjectToDict has been applied. - - - -### method `__init__` - -```python -__init__( - event_struct: Provider6EventStruct = Provider6EventStruct(EVENT_ID='eventId', PARENT_EVENT_ID='parentEventId', STATUS='successful', NAME='eventName', TYPE='type', BATCH_ID='batchId', IS_BATCHED='isBatched', EVENT_TYPE='eventType', END_TIMESTAMP='endTimestamp', START_TIMESTAMP='startTimestamp', ATTACHED_MESSAGES_IDS='attachedMessageIds', BODY='body') -) -``` - -AdapterDeleteEventWrappers constructor. - - - -**Args:** - - - `event_struct`: Event struct. - - - - ---- - - - -### method `handle` - -```python -handle(event: dict) → dict -``` - -Deletes unnecessary wrappers for fields eventId, parentEventId and BatchId. - - - -**Args:** - - - `event`: Event. - - - -**Returns:** - Event without wrappers. - - ---- - - - -## class `DeleteSystemEvents` -Adapter that deletes unnecessary system events. - - - - ---- - - - -### method `handle` - -```python -handle(event: dict) → Union[dict, NoneType] -``` - -Deletes unnecessary system events. - -System events have form '{'hasEnded': bool, 'hasStarted': bool, 'lastId': bool}' - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.v6.adapters.message_adapters.md b/documentation/api/provider.v6.adapters.message_adapters.md deleted file mode 100644 index 7ab637e9..00000000 --- a/documentation/api/provider.v6.adapters.message_adapters.md +++ /dev/null @@ -1,122 +0,0 @@ - - - - -# module `provider.v6.adapters.message_adapters` - - - - - - ---- - - - -## class `DeleteMessageWrappersAdapter` -Adapter that deletes unnecessary wrappers in messages. - -It used for the message to which an AdaptorGRPCObjectToDict has been applied. - - - -### method `__init__` - -```python -__init__( - message_struct: Provider6MessageStruct = Provider6MessageStruct(DIRECTION='direction', SESSION_ID='sessionId', MESSAGE_TYPE='messageType', CONNECTION_ID='connectionId', SESSION_ALIAS='sessionAlias', SUBSEQUENCE='subsequence', SEQUENCE='sequence', TIMESTAMP='timestamp', BODY='parsedMessages', BODY_BASE64='rawMessageBase64', TYPE='type', MESSAGE_ID='id', ATTACHED_EVENT_IDS='attachedEventIds') -) -``` - -AdapterDeleteMessageWrappers constructor. - - - -**Args:** - - - `message_struct`: Message struct. - - - - ---- - - - -### method `handle` - -```python -handle(message: dict) → dict -``` - -Deletes unnecessary wrappers for field message_id. - - - -**Args:** - - - `message`: Message. - - - -**Returns:** - Message without wrappers. - - ---- - - - -## class `CodecPipelinesAdapter` -Adapter for codec-pipeline messages from provider v6. - -Codec-pipeline messages have sub-messages in the body. This adapter used for split codec-pipeline message to separate messages. - - - -### method `__init__` - -```python -__init__(ignore_errors=False) -``` - -AdapterCodecPipelines constructor. - - - -**Args:** - - - `ignore_errors`: If True it will ignore errors and return message as is. - - - - ---- - - - -### method `handle` - -```python -handle(message: dict) → Union[List[dict], dict] -``` - -Adapter handler. - - - -**Args:** - - - `message`: Th2Message dict. - - - -**Returns:** - Th2Message dict. - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.v6.command_resolver.md b/documentation/api/provider.v6.command_resolver.md deleted file mode 100644 index 5e35e1ae..00000000 --- a/documentation/api/provider.v6.command_resolver.md +++ /dev/null @@ -1,67 +0,0 @@ - - - - -# module `provider.v6.command_resolver` - - - - - ---- - - - -## function `resolver_get_event_by_id` - -```python -resolver_get_event_by_id( - data_source: IProviderDataSource -) → Union[Type[GetEventById], Type[GetEventById]] -``` - -Resolves what 'GetEventById' command you need to use based Data Source. - - - -**Args:** - - - `data_source`: DataSource instance. - - - -**Returns:** - GetEventById command. - - ---- - - - -## function `resolver_get_events_by_id` - -```python -resolver_get_events_by_id( - data_source: IProviderDataSource -) → Union[Type[GetEventsById], Type[GetEventsById]] -``` - -Resolves what 'GetEventsById' command you need to use based Data Source. - - - -**Args:** - - - `data_source`: DataSource instance. - - - -**Returns:** - GetEventsById command. - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.v6.commands.grpc.md b/documentation/api/provider.v6.commands.grpc.md deleted file mode 100644 index 1a51d0fe..00000000 --- a/documentation/api/provider.v6.commands.grpc.md +++ /dev/null @@ -1,624 +0,0 @@ - - - - -# module `provider.v6.commands.grpc` - - - - - - ---- - - - -## class `GetEventByIdGRPCObject` -A Class-Command for request to rpt-data-provider. - -It retrieves the event by id as GRPC object. - - - -**Returns:** - - - `EventResponse`: Th2 event. - - - -### method `__init__` - -```python -__init__(id: str) -``` - -GetEventByIdGRPCObject constructor. - - - -**Args:** - - - `id`: Event id. - - - - ---- - - - -### method `handle` - -```python -handle(data_source: GRPCProvider6DataSource) → EventResponse -``` - - - - - - ---- - - - -## class `GetEventById` -A Class-Command for request to rpt-data-provider. - -It retrieves the event by id with `attachedMessageIds` list. - - - -**Returns:** - - - `dict`: Th2 event. - - - -**Raises:** - - - `EventNotFound`: If event by Id wasn't found. - - - -### method `__init__` - -```python -__init__(id: str, use_stub=False) -``` - -GetEventById constructor. - - - -**Args:** - - - `id`: Event id. - - `use_stub`: If True the command returns stub instead of exception. - - - - ---- - - - -### method `handle` - -```python -handle(data_source: GRPCProvider6DataSource) → dict -``` - - - - - - ---- - - - -## class `GetEventsById` -A Class-Command for request to rpt-data-provider. - -It retrieves the events by ids with `attachedMessageIds` list. - - - -**Returns:** - - - `List[dict]`: Th2 events. - - - -**Raises:** - - - `EventNotFound`: If any event by Id wasn't found. - - - -### method `__init__` - -```python -__init__(ids: List[str], use_stub=False) -``` - -GetEventsById constructor. - - - -**Args:** - - - `ids`: Events ids. - - `use_stub`: If True the command returns stub instead of exception. - - - - ---- - - - -### method `handle` - -```python -handle(data_source: GRPCProvider6DataSource) → List[dict] -``` - - - - - - ---- - - - -## class `GetEventsGRPCObjects` -A Class-Command for request to rpt-data-provider. - -It searches events stream as GRPC object by options. - - - -**Returns:** - - - `Iterable[EventResponse]`: Stream of Th2 events. - - - -### method `__init__` - -```python -__init__( - start_timestamp: datetime, - end_timestamp: datetime = None, - parent_event: str = None, - search_direction: str = 'NEXT', - resume_from_id: str = None, - result_count_limit: int = None, - keep_open: bool = False, - limit_for_parent: int = None, - attached_messages: bool = False, - filters: List[Provider6Filter] = None -) -``` - -GetEventsGRPCObjects constructor. - - - -**Args:** - - - `start_timestamp`: Start timestamp of search. - - `end_timestamp`: End timestamp of search. - - `resume_from_id`: Event id from which search starts. - - `parent_event`: Match events to the specified parent. - - `search_direction`: Search direction. - - `result_count_limit`: Result count limit. - - `keep_open`: If the search has reached the current moment. It is need to wait further for the appearance of new data. the one closest to the specified timestamp. - - `limit_for_parent`: How many children events for each parent do we want to request. - - `attached_messages`: Gets messages ids which linked to events. - - `filters`: Filters using in search for messages. - - - - ---- - - - -### method `handle` - -```python -handle(data_source: GRPCProvider6DataSource) → Iterable[EventResponse] -``` - - - - - - ---- - - - -## class `GetEvents` -A Class-Command for request to rpt-data-provider. - -It searches events stream by options. - - - -**Returns:** - - - `Iterable[dict]`: Stream of Th2 events. - - - -### method `__init__` - -```python -__init__( - start_timestamp: datetime, - end_timestamp: datetime = None, - parent_event: str = None, - search_direction: str = 'NEXT', - resume_from_id: str = None, - result_count_limit: int = None, - keep_open: bool = False, - limit_for_parent: int = None, - attached_messages: bool = False, - filters: List[Provider6Filter] = None, - cache: bool = False -) -``` - -GetEvents constructor. - - - -**Args:** - - - `start_timestamp`: Start timestamp of search. - - `end_timestamp`: End timestamp of search. - - `resume_from_id`: Event id from which search starts. - - `parent_event`: Match events to the specified parent. - - `search_direction`: Search direction. - - `result_count_limit`: Result count limit. - - `keep_open`: If the search has reached the current moment. It is need to wait further for the appearance of new data. the one closest to the specified timestamp. - - `limit_for_parent`: How many children events for each parent do we want to request. - - `attached_messages`: Gets messages ids which linked to events. - - `filters`: Filters using in search for messages. - - `cache`: If True, all requested data from rpt-data-provider will be saved to cache. - - - - ---- - - - -### method `handle` - -```python -handle(data_source: GRPCProvider6DataSource) → Data -``` - - - - - - ---- - - - -## class `GetMessageByIdGRPCObject` -A Class-Command for request to rpt-data-provider. - -It retrieves the message by id as GRPC Object. - - - -**Returns:** - - - `MessageGroupResponse`: Th2 message. - - - -### method `__init__` - -```python -__init__(id: str) -``` - -GetMessageByIdGRPCObject constructor. - - - -**Args:** - - - `id`: Message id. - - - - ---- - - - -### method `handle` - -```python -handle(data_source: GRPCProvider6DataSource) → MessageGroupResponse -``` - - - - - - ---- - - - -## class `GetMessageById` -A Class-Command for request to rpt-data-provider. - -It retrieves the message by id. - -Please note, Provider6 doesn't return `attachedEventIds`. It will be == []. It's expected that Provider7 will be support it. - - - -**Returns:** - - - `dict`: Th2 message. - - - -**Raises:** - - - `MessageNotFound`: If message by id wasn't found. - - - -### method `__init__` - -```python -__init__(id: str, use_stub=False) -``` - -GetMessageById constructor. - - - -**Args:** - - - `id`: Message id. - - `use_stub`: If True the command returns stub instead of exception. - - - - ---- - - - -### method `handle` - -```python -handle(data_source: GRPCProvider6DataSource) → dict -``` - - - - - - ---- - - - -## class `GetMessagesById` -A Class-Command for request to rpt-data-provider. - -It retrieves the messages by id. - -Please note, Provider6 doesn't return `attachedEventIds`. It will be == []. It's expected that Provider7 will be support it. - - - -**Returns:** - - - `List[dict]`: Th2 messages. - - - -**Raises:** - - - `MessageNotFound`: If any message by id wasn't found. - - - -### method `__init__` - -```python -__init__(ids: List[str], use_stub=False) -``` - -GetMessagesById constructor. - - - -**Args:** - - - `ids`: Messages id. - - `use_stub`: If True the command returns stub instead of exception. - - - - ---- - - - -### method `handle` - -```python -handle(data_source: GRPCProvider6DataSource) → List[dict] -``` - - - - - - ---- - - - -## class `GetMessagesGRPCObject` -A Class-Command for request to rpt-data-provider. - -It searches messages stream as GRPC object by options. - - - -**Returns:** - - - `Iterable[MessageGroupResponse]`: Stream of Th2 messages. - - - -### method `__init__` - -```python -__init__( - start_timestamp: datetime, - stream: List[Union[str, Streams]], - end_timestamp: datetime = None, - search_direction: str = 'NEXT', - result_count_limit: int = None, - keep_open: bool = False, - message_id: List[str] = None, - attached_events: bool = False, - stream_pointers: List[MessageStreamPointer] = None, - filters: List[Provider6Filter] = None -) -``` - -GetMessagesGRPCObject constructor. - - - -**Args:** - - - `start_timestamp`: Start timestamp of search. - - `end_timestamp`: End timestamp of search. - - `stream`: Alias of messages. - - `search_direction`: Search direction. - - `result_count_limit`: Result count limit. - - `keep_open`: If the search has reached the current moment. It is need to wait further for the appearance of new data. - - `message_id`: List of message ids to restore the search - - `attached_events`: If true, it will additionally load attachedEventsIds. - - `stream_pointers`: List of stream pointers to restore the search from. start_timestamp will be ignored if this parameter is specified. This parameter is only received from the provider. - - `filters`: Filters using in search for messages. - - - - ---- - - - -### method `handle` - -```python -handle(data_source: GRPCProvider6DataSource) → List[MessageGroupResponse] -``` - - - - - - ---- - - - -## class `GetMessages` -A Class-Command for request to rpt-data-provider. - -It searches messages stream by options. - - - -**Returns:** - - - `Iterable[dict]`: Stream of Th2 messages. - - - -### method `__init__` - -```python -__init__( - start_timestamp: datetime, - stream: List[Union[str, Streams]], - end_timestamp: datetime = None, - resume_from_id: str = None, - search_direction: str = 'NEXT', - result_count_limit: int = None, - keep_open: bool = False, - filters: List[Provider6Filter] = None, - message_id: List[str] = None, - attached_events: bool = False, - stream_pointers: List[MessageStreamPointer] = None, - cache: bool = False -) -``` - -GetMessages constructor. - - - -**Args:** - - - `start_timestamp`: Start timestamp of search. - - `end_timestamp`: End timestamp of search. - - `stream`: Alias of messages. - - `resume_from_id`: Message id from which search starts. - - `search_direction`: Search direction. - - `result_count_limit`: Result count limit. - - `keep_open`: If the search has reached the current moment. It is need to wait further for the appearance of new data. - - `filters`: Filters using in search for messages. - - `message_id`: List of message ids to restore the search - - `attached_events`: If true, it will additionally load attachedEventsIds. - - `stream_pointers`: List of stream pointers to restore the search from. start_timestamp will be ignored if this parameter is specified. This parameter is only received from the provider. - - `cache`: If True, all requested data from rpt-data-provider will be saved to cache. - - - - ---- - - - -### method `handle` - -```python -handle(data_source: GRPCProvider6DataSource) → Data -``` - - - - - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.v6.commands.http.md b/documentation/api/provider.v6.commands.http.md deleted file mode 100644 index 9e0d9552..00000000 --- a/documentation/api/provider.v6.commands.http.md +++ /dev/null @@ -1,687 +0,0 @@ - - - - -# module `provider.v6.commands.http` - - - - -**Global Variables** ---------------- -- **UNICODE_REPLACE_HANDLER** - - ---- - - - -## class `GetEventById` -A Class-Command for request to rpt-data-provider. - -It retrieves the event by id with `attachedMessageIds` list. - - - -**Returns:** - - - `dict`: Th2 event. - - - -**Raises:** - - - `EventNotFound`: If event by Id wasn't found. - - - -### method `__init__` - -```python -__init__(id: str, use_stub=False) -``` - -GetEventById constructor. - - - -**Args:** - - - `id`: Event id. - - `use_stub`: If True the command returns stub instead of exception. - - - - ---- - - - -### method `handle` - -```python -handle(data_source: HTTPProvider6DataSource) → dict -``` - - - - - - ---- - - - -## class `GetEventsById` -A Class-Command for request to rpt-data-provider. - -It retrieves the events by ids with `attachedMessageIds` list. - - - -**Returns:** - - - `List[dict]`: Th2 events. - - - -**Raises:** - - - `EventNotFound`: If any event by Id wasn't found. - - - -### method `__init__` - -```python -__init__(ids: List[str], use_stub=False) -``` - -GetEventsById constructor. - - - -**Args:** - - - `ids`: Event id list. - - `use_stub`: If True the command returns stub instead of exception. - - - - ---- - - - -### method `handle` - -```python -handle(data_source: HTTPProvider6DataSource) -``` - - - - - - ---- - - - -## class `GetEventsSSEBytes` -A Class-Command for request to rpt-data-provider. - -It searches events stream by options. - - - -**Returns:** - - - `Iterable[dict]`: Stream of Th2 events. - - - -### method `__init__` - -```python -__init__( - start_timestamp: datetime, - end_timestamp: datetime = None, - parent_event: str = None, - search_direction: str = 'next', - resume_from_id: str = None, - result_count_limit: int = None, - keep_open: bool = False, - limit_for_parent: int = None, - attached_messages: bool = False, - filters: (, List[Provider6Filter]) = None -) -``` - -GetEventsSSEBytes constructor. - - - -**Args:** - - - `start_timestamp`: Start timestamp of search. - - `end_timestamp`: End timestamp of search. - - `parent_event`: Match events to the specified parent. - - `search_direction`: Search direction. - - `resume_from_id`: Event id from which search starts. - - `result_count_limit`: Result count limit. - - `keep_open`: If the search has reached the current moment. It is need to wait further for the appearance of new data. the one closest to the specified timestamp. - - `limit_for_parent`: How many children events for each parent do we want to request. - - `attached_messages`: Gets messages ids which linked to events. - - `filters`: Filters using in search for messages. - - - - ---- - - - -### method `handle` - -```python -handle(data_source: HTTPProvider6DataSource) -``` - - - - - - ---- - - - -## class `GetEventsSSEEvents` -A Class-Command for request to rpt-data-provider. - -It searches events stream by options. - - - -**Returns:** - - - `Iterable[dict]`: Stream of Th2 events. - - - -### method `__init__` - -```python -__init__( - start_timestamp: datetime, - end_timestamp: datetime = None, - parent_event: str = None, - search_direction: str = 'next', - resume_from_id: str = None, - result_count_limit: int = None, - keep_open: bool = False, - limit_for_parent: int = None, - attached_messages: bool = False, - filters: (, List[Provider6Filter]) = None, - char_enc: str = 'utf-8', - decode_error_handler: str = 'unicode_replace' -) -``` - -GetEventsSSEEvents constructor. - - - -**Args:** - - - `start_timestamp`: Start timestamp of search. - - `end_timestamp`: End timestamp of search. - - `parent_event`: Match events to the specified parent. - - `search_direction`: Search direction. - - `resume_from_id`: Event id from which search starts. - - `result_count_limit`: Result count limit. - - `keep_open`: If the search has reached the current moment. It is need to wait further for the appearance of new data. the one closest to the specified timestamp. - - `limit_for_parent`: How many children events for each parent do we want to request. - - `attached_messages`: Gets messages ids which linked to events. - - `filters`: Filters using in search for messages. - - `char_enc`: Encoding for the byte stream. - - `decode_error_handler`: Registered decode error handler. - - - - ---- - - - -### method `handle` - -```python -handle(data_source: HTTPProvider6DataSource) -``` - - - - - - ---- - - - -## class `GetEvents` -A Class-Command for request to rpt-data-provider. - -It searches events stream by options. - - - -**Returns:** - - - `Iterable[dict]`: Stream of Th2 events. - - - -### method `__init__` - -```python -__init__( - start_timestamp: datetime, - end_timestamp: datetime = None, - parent_event: str = None, - search_direction: str = 'next', - resume_from_id: str = None, - result_count_limit: int = None, - keep_open: bool = False, - limit_for_parent: int = None, - attached_messages: bool = False, - filters: (, List[Provider6Filter]) = None, - cache: bool = False -) -``` - -GetEvents constructor. - - - -**Args:** - - - `start_timestamp`: Start timestamp of search. - - `end_timestamp`: End timestamp of search. - - `parent_event`: Match events to the specified parent. - - `search_direction`: Search direction. - - `resume_from_id`: Event id from which search starts. - - `result_count_limit`: Result count limit. - - `keep_open`: If the search has reached the current moment. It is need to wait further for the appearance of new data. the one closest to the specified timestamp. - - `limit_for_parent`: How many children events for each parent do we want to request. - - `attached_messages`: Gets messages ids which linked to events. - - `filters`: Filters using in search for messages. - - `cache`: If True, all requested data from rpt-data-provider will be saved to cache. - - - - ---- - - - -### method `handle` - -```python -handle(data_source: HTTPProvider6DataSource) → Data -``` - - - - - - ---- - - - -## class `GetMessageById` -A Class-Command for request to rpt-data-provider. - -It retrieves the message by id. - -Please note, Provider6 doesn't return `attachedEventIds`. It will be == []. It's expected that Provider7 will be support it. - - - -**Returns:** - - - `dict`: Th2 message. - - - -**Raises:** - - - `MessageNotFound`: If message by id wasn't found. - - - -### method `__init__` - -```python -__init__(id: str, use_stub=False) -``` - -GetMessageById constructor. - - - -**Args:** - - - `id`: Message id. - - `use_stub`: If True the command returns stub instead of exception. - - - - ---- - - - -### method `handle` - -```python -handle(data_source: HTTPProvider6DataSource) → dict -``` - - - - - - ---- - - - -## class `GetMessagesById` -A Class-Command for request to rpt-data-provider. - -It retrieves the messages by ids. - -Please note, Provider6 doesn't return `attachedEventIds`. It will be == []. It's expected that Provider7 will be support it. - - - -**Returns:** - - - `List[dict]`: Th2 messages. - - - -**Raises:** - - - `MessageNotFound`: If any message by id wasn't found. - - - -### method `__init__` - -```python -__init__(ids: List[str], use_stub=False) -``` - -GetMessagesById constructor. - - - -**Args:** - - - `ids`: Message id list. - - `use_stub`: If True the command returns stub instead of exception. - - - - ---- - - - -### method `handle` - -```python -handle(data_source: HTTPProvider6DataSource) → List[dict] -``` - - - - - - ---- - - - -## class `GetMessagesSSEBytes` -A Class-Command for request to rpt-data-provider. - -It searches messages stream by options. - - - -**Returns:** - - - `Iterable[dict]`: Stream of Th2 messages. - - - -### method `__init__` - -```python -__init__( - start_timestamp: datetime, - stream: List[Union[str, Streams]], - end_timestamp: datetime = None, - resume_from_id: str = None, - search_direction: str = 'next', - result_count_limit: int = None, - keep_open: bool = False, - message_id: List[str] = None, - attached_events: bool = False, - lookup_limit_days: int = None, - filters: (, List[Provider6Filter]) = None -) -``` - -GetMessagesSSEBytes constructor. - - - -**Args:** - - - `start_timestamp`: Start timestamp of search. - - `end_timestamp`: End timestamp of search. - - `stream`: Alias of messages. - - `resume_from_id`: Message id from which search starts. - - `search_direction`: Search direction. - - `result_count_limit`: Result count limit. - - `keep_open`: If the search has reached the current moment. It is need to wait further for the appearance of new data. - - `message_id`: List of message IDs to restore search. If given, it has the highest priority and ignores stream (uses streams from ids), startTimestamp and resumeFromId. - - `attached_events`: If true, additionally load attached_event_ids - - `lookup_limit_days`: The number of days that will be viewed on the first request to get the one closest to the specified timestamp. - - `filters`: Filters using in search for messages. - - - - ---- - - - -### method `handle` - -```python -handle( - data_source: HTTPProvider6DataSource -) → Generator[dict, NoneType, NoneType] -``` - - - - - - ---- - - - -## class `GetMessagesSSEEvents` -A Class-Command for request to rpt-data-provider. - -It searches messages stream by options. - - - -**Returns:** - - - `Iterable[dict]`: Stream of Th2 messages. - - - -### method `__init__` - -```python -__init__( - start_timestamp: datetime, - stream: List[Union[str, Streams]], - end_timestamp: datetime = None, - resume_from_id: str = None, - search_direction: str = 'next', - result_count_limit: int = None, - keep_open: bool = False, - message_id: List[str] = None, - attached_events: bool = False, - lookup_limit_days: int = None, - filters: (, List[Provider6Filter]) = None, - char_enc: str = 'utf-8', - decode_error_handler: str = 'unicode_replace' -) -``` - -GetMessagesSSEEvents constructor. - - - -**Args:** - - - `start_timestamp`: Start timestamp of search. - - `end_timestamp`: End timestamp of search. - - `stream`: Alias of messages. - - `resume_from_id`: Message id from which search starts. - - `search_direction`: Search direction. - - `result_count_limit`: Result count limit. - - `keep_open`: If the search has reached the current moment. It is need to wait further for the appearance of new data. - - `message_id`: List of message IDs to restore search. If given, it has the highest priority and ignores stream (uses streams from ids), startTimestamp and resumeFromId. - - `attached_events`: If true, additionally load attached_event_ids - - `lookup_limit_days`: The number of days that will be viewed on the first request to get the one closest to the specified timestamp. - - `filters`: Filters using in search for messages. - - `char_enc`: Character encode that will use SSEClient. - - `decode_error_handler`: Decode error handler. - - - - ---- - - - -### method `handle` - -```python -handle( - data_source: HTTPProvider6DataSource -) → Generator[dict, NoneType, NoneType] -``` - - - - - - ---- - - - -## class `GetMessages` -A Class-Command for request to rpt-data-provider. - -It searches messages stream by options. - - - -**Returns:** - - - `Iterable[dict]`: Stream of Th2 messages. - - - -### method `__init__` - -```python -__init__( - start_timestamp: datetime, - stream: List[Union[str, Streams]], - end_timestamp: datetime = None, - resume_from_id: str = None, - search_direction: str = 'next', - result_count_limit: int = None, - keep_open: bool = False, - message_id: List[str] = None, - attached_events: bool = False, - lookup_limit_days: int = None, - filters: (, List[Provider6Filter]) = None, - char_enc: str = 'utf-8', - decode_error_handler: str = 'unicode_replace', - cache: bool = False -) -``` - -GetMessages constructor. - - - -**Args:** - - - `start_timestamp`: Start timestamp of search. - - `end_timestamp`: End timestamp of search. - - `stream`: Alias of messages. - - `resume_from_id`: Message id from which search starts. - - `search_direction`: Search direction. - - `result_count_limit`: Result count limit. - - `keep_open`: If the search has reached the current moment. It is need to wait further for the appearance of new data. - - `message_id`: List of message IDs to restore search. If given, it has the highest priority and ignores stream (uses streams from ids), startTimestamp and resumeFromId. - - `attached_events`: If true, additionally load attached_event_ids - - `lookup_limit_days`: The number of days that will be viewed on the first request to get the one closest to the specified timestamp. - - `filters`: Filters using in search for messages. - - `char_enc`: Encoding for the byte stream. - - `decode_error_handler`: Registered decode error handler. - - `cache`: If True, all requested data from rpt-data-provider will be saved to cache. - - - - ---- - - - -### method `handle` - -```python -handle(data_source: HTTPProvider6DataSource) → Data -``` - - - - - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.v6.commands.md b/documentation/api/provider.v6.commands.md deleted file mode 100644 index 7a96523f..00000000 --- a/documentation/api/provider.v6.commands.md +++ /dev/null @@ -1,16 +0,0 @@ - - - - -# module `provider.v6.commands` - - - - - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.v6.data_source.grpc.md b/documentation/api/provider.v6.data_source.grpc.md deleted file mode 100644 index 554ff2be..00000000 --- a/documentation/api/provider.v6.data_source.grpc.md +++ /dev/null @@ -1,124 +0,0 @@ - - - - -# module `provider.v6.data_source.grpc` - - - - -**Global Variables** ---------------- -- **TYPE_CHECKING** - - ---- - - - -## class `GRPCProvider6DataSource` -DataSource class which provide work with rpt-data-provider. - -Rpt-data-provider version: 6.x.y Protocol: GRPC - - - -### method `__init__` - -```python -__init__( - url: 'str', - event_struct: 'IEventStruct' = Provider6EventStruct(EVENT_ID='eventId', PARENT_EVENT_ID='parentEventId', STATUS='successful', NAME='eventName', TYPE='type', BATCH_ID='batchId', IS_BATCHED='isBatched', EVENT_TYPE='eventType', END_TIMESTAMP='endTimestamp', START_TIMESTAMP='startTimestamp', ATTACHED_MESSAGES_IDS='attachedMessageIds', BODY='body'), - message_struct: 'IMessageStruct' = Provider6MessageStruct(DIRECTION='direction', SESSION_ID='sessionId', MESSAGE_TYPE='messageType', CONNECTION_ID='connectionId', SESSION_ALIAS='sessionAlias', SUBSEQUENCE='subsequence', SEQUENCE='sequence', TIMESTAMP='timestamp', BODY='parsedMessages', BODY_BASE64='rawMessageBase64', TYPE='type', MESSAGE_ID='id', ATTACHED_EVENT_IDS='attachedEventIds'), - event_stub_builder: 'IEventStub' = Provider6EventStubBuilder, - message_stub_builder: 'IMessageStub' = Provider6MessageStubBuilder -) -``` - -GRPCProvider6DataSource constructor. - - - -**Args:** - - - `url`: Url of rpt-data-provider. - - `event_struct`: Event structure that is supplied by rpt-data-provider. - - `message_struct`: Message structure that is supplied by rpt-data-provider. - - `event_stub_builder`: Stub builder for broken events. - - `message_stub_builder`: Stub builder for broken messages. - - ---- - -#### property event_struct - -Returns event structure class. - ---- - -#### property event_stub_builder - -Returns event stub template. - ---- - -#### property message_struct - -Returns message structure class. - ---- - -#### property message_stub_builder - -Returns message stub template. - ---- - -#### property source_api - -Returns Provider API. - ---- - -#### property url - -str: URL of rpt-data-provider. - - - ---- - - - -### method `command` - -```python -command(cmd: 'IGRPCProvider6Command') → Any -``` - -Execute the transmitted GRPC command. - - - -**Args:** - - - `cmd`: GRPC Command. - - - -**Returns:** - - - `Any`: Command response. - - - -**Raises:** - - - `CommandError`: If the command was broken. - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.v6.data_source.http.md b/documentation/api/provider.v6.data_source.http.md deleted file mode 100644 index 74ea1b4d..00000000 --- a/documentation/api/provider.v6.data_source.http.md +++ /dev/null @@ -1,132 +0,0 @@ - - - - -# module `provider.v6.data_source.http` - - - - -**Global Variables** ---------------- -- **UNICODE_REPLACE_HANDLER** -- **TYPE_CHECKING** - - ---- - - - -## class `HTTPProvider6DataSource` -DataSource class which provide work with rpt-data-provider. - -Rpt-data-provider version: 5.x.y Protocol: HTTP - - - -### method `__init__` - -```python -__init__( - url: 'str', - chunk_length: 'int' = 65536, - char_enc: 'str' = 'utf-8', - decode_error_handler: 'str' = 'unicode_replace', - event_struct: 'IEventStruct' = Provider6EventStruct(EVENT_ID='eventId', PARENT_EVENT_ID='parentEventId', STATUS='successful', NAME='eventName', TYPE='type', BATCH_ID='batchId', IS_BATCHED='isBatched', EVENT_TYPE='eventType', END_TIMESTAMP='endTimestamp', START_TIMESTAMP='startTimestamp', ATTACHED_MESSAGES_IDS='attachedMessageIds', BODY='body'), - message_struct: 'IMessageStruct' = Provider6MessageStruct(DIRECTION='direction', SESSION_ID='sessionId', MESSAGE_TYPE='messageType', CONNECTION_ID='connectionId', SESSION_ALIAS='sessionAlias', SUBSEQUENCE='subsequence', SEQUENCE='sequence', TIMESTAMP='timestamp', BODY='parsedMessages', BODY_BASE64='rawMessageBase64', TYPE='type', MESSAGE_ID='id', ATTACHED_EVENT_IDS='attachedEventIds'), - event_stub_builder: 'IEventStub' = Provider6EventStubBuilder, - message_stub_builder: 'IMessageStub' = Provider6MessageStubBuilder, - check_connect_timeout: '(int, float)' = 5 -) -``` - -HTTPProvider6DataSource constructor. - - - -**Args:** - - - `url`: HTTP data source url. - - `check_connect_timeout`: How many seconds to wait for the server to send data before giving up. - - `chunk_length`: How much of the content to read in one chunk. - - `char_enc`: Encoding for the byte stream. - - `decode_error_handler`: Registered decode error handler. - - `event_struct`: Struct of event from rpt-data-provider. - - `message_struct`: Struct of message from rpt-data-provider. - - `event_stub_builder`: Stub for event. - - `message_stub_builder`: Stub for message. - - ---- - -#### property event_struct - -Returns event structure class. - ---- - -#### property event_stub_builder - -Returns event stub template. - ---- - -#### property message_struct - -Returns message structure class. - ---- - -#### property message_stub_builder - -Returns message stub template. - ---- - -#### property source_api - -HTTP Provider6 API. - ---- - -#### property url - -str: URL of rpt-data-provider. - - - ---- - - - -### method `command` - -```python -command(cmd: 'IHTTPProvider6Command') -``` - -HTTP Provider6 command processor. - - - -**Args:** - - - `cmd`: The command of data source to execute. - - - -**Returns:** - Data source command result. - - - -**Raises:** - - - `CommandError`: If the command was broken. - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.v6.data_source.md b/documentation/api/provider.v6.data_source.md deleted file mode 100644 index 8f853a2f..00000000 --- a/documentation/api/provider.v6.data_source.md +++ /dev/null @@ -1,46 +0,0 @@ - - - - -# module `provider.v6.data_source` - - - - -**Global Variables** ---------------- -- **grpc**: # Copyright 2022 Exactpro (Exactpro Systems Limited) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -- **http**: # Copyright 2022 Exactpro (Exactpro Systems Limited) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.v6.events_tree.events_tree_collection.md b/documentation/api/provider.v6.events_tree.events_tree_collection.md deleted file mode 100644 index cb22813f..00000000 --- a/documentation/api/provider.v6.events_tree.events_tree_collection.md +++ /dev/null @@ -1,77 +0,0 @@ - - - - -# module `provider.v6.events_tree.events_tree_collection` - - - - - - ---- - - - -## class `EventsTreeCollectionProvider6` -EventsTreesCollections for data-provider v6. - - - -### method `__init__` - -```python -__init__( - data: Data, - data_source: Union[GRPCProvider6DataSource, HTTPProvider6DataSource] = None, - preserve_body: bool = False, - event_struct: IEventStruct = Provider6EventStruct(EVENT_ID='eventId', PARENT_EVENT_ID='parentEventId', STATUS='successful', NAME='eventName', TYPE='type', BATCH_ID='batchId', IS_BATCHED='isBatched', EVENT_TYPE='eventType', END_TIMESTAMP='endTimestamp', START_TIMESTAMP='startTimestamp', ATTACHED_MESSAGES_IDS='attachedMessageIds', BODY='body'), - stub: bool = False -) -``` - -EventsTreeCollectionProvider6 constructor. - - - -**Args:** - - - `data`: Data object. - - `data_source`: Data Source object. - - `preserve_body`: If True it will preserve 'body' field in the Events. - - `event_struct`: Event struct object. - - `stub`: If True it will create stub when event is broken. - - ---- - -#### property detached_events - -Returns detached events as a dict that looks like {'parent_id': ['referenced event', ...]}. - ---- - -#### property len_detached_events - -Returns number of detached events in the collection. - ---- - -#### property len_parentless - -Returns number of events in the parentless trees inside the collection. - ---- - -#### property len_trees - -Returns number of events in the trees inside the collection, including parentless trees. - - - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.v6.events_tree.md b/documentation/api/provider.v6.events_tree.md deleted file mode 100644 index 2dfbef10..00000000 --- a/documentation/api/provider.v6.events_tree.md +++ /dev/null @@ -1,46 +0,0 @@ - - - - -# module `provider.v6.events_tree` - - - - -**Global Variables** ---------------- -- **events_tree_collection**: # Copyright 2022 Exactpro (Exactpro Systems Limited) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -- **parent_events_tree_collection**: # Copyright 2022 Exactpro (Exactpro Systems Limited) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.v6.events_tree.parent_events_tree_collection.md b/documentation/api/provider.v6.events_tree.parent_events_tree_collection.md deleted file mode 100644 index 46bbd87b..00000000 --- a/documentation/api/provider.v6.events_tree.parent_events_tree_collection.md +++ /dev/null @@ -1,77 +0,0 @@ - - - - -# module `provider.v6.events_tree.parent_events_tree_collection` - - - - - - ---- - - - -## class `ParentEventsTreeCollectionProvider6` -ParentEventsTreeCollection for data-provider v6. - - - -### method `__init__` - -```python -__init__( - data: Data, - data_source: Union[GRPCProvider6DataSource, HTTPProvider6DataSource] = None, - preserve_body: bool = False, - event_struct: IEventStruct = Provider6EventStruct(EVENT_ID='eventId', PARENT_EVENT_ID='parentEventId', STATUS='successful', NAME='eventName', TYPE='type', BATCH_ID='batchId', IS_BATCHED='isBatched', EVENT_TYPE='eventType', END_TIMESTAMP='endTimestamp', START_TIMESTAMP='startTimestamp', ATTACHED_MESSAGES_IDS='attachedMessageIds', BODY='body'), - stub: bool = False -) -``` - -ParentEventsTreeCollectionProvider6 constructor. - - - -**Args:** - - - `data`: Data object. - - `data_source`: Data Source object. - - `preserve_body`: If True it will preserve 'body' field in the Events. - - `event_struct`: Event struct object. - - `stub`: If True it will create stub when event is broken. - - ---- - -#### property detached_events - -Returns detached events as a dict that looks like {'parent_id': ['referenced event', ...]}. - ---- - -#### property len_detached_events - -Returns number of detached events in the collection. - ---- - -#### property len_parentless - -Returns number of events in the parentless trees inside the collection. - ---- - -#### property len_trees - -Returns number of events in the trees inside the collection, including parentless trees. - - - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.v6.filters.event_filters.md b/documentation/api/provider.v6.filters.event_filters.md deleted file mode 100644 index 8ef8bf85..00000000 --- a/documentation/api/provider.v6.filters.event_filters.md +++ /dev/null @@ -1,146 +0,0 @@ - - - - -# module `provider.v6.filters.event_filters` - - - - - - ---- - - - -## class `TypeFilter` -Will match the events which type contains one of the given substrings. - - - - - ---- - - - -## class `NameFilter` -Will match the events which name contains one of the given substrings. - - - - - ---- - - - -## class `BodyFilter` -Will match the events which body contains one of the given substrings. - - - - - ---- - - - -## class `AttachedMessageIdFilter` -Filters the events that are linked to the specified message id. - - - - - ---- - - - -## class `PassedStatusFilter` -Will match the events which status equals passed. - - - -### method `__init__` - -```python -__init__() -``` - - - - - - - - ---- - - - -### method `url` - -```python -url() → str -``` - -Generates the filter part of the HTTP protocol API. - -For help use this readme: https://github.com/th2-net/th2-rpt-data-provider#filters-api. - - - -**Returns:** - - - `str`: Generated filter. - - ---- - - - -## class `FailedStatusFilter` -Will match the events which status equals failed. - - - -### method `__init__` - -```python -__init__() -``` - - - - - - - - ---- - - - -### method `url` - -```python -url() → str -``` - -Generates the filter part of the HTTP protocol API. - -For help use this readme: https://github.com/th2-net/th2-rpt-data-provider#filters-api. - - - -**Returns:** - - - `str`: Generated filter. - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.v6.filters.filter.md b/documentation/api/provider.v6.filters.filter.md deleted file mode 100644 index c7e50547..00000000 --- a/documentation/api/provider.v6.filters.filter.md +++ /dev/null @@ -1,193 +0,0 @@ - - - - -# module `provider.v6.filters.filter` - - - - - - ---- - - - -## class `Provider6Filter` -General interface for Filters of Provider v6. - - - -### method `__init__` - -```python -__init__( - name: str, - values: Union[str, int, float, Sequence[Union[str, int, float]]], - negative: bool = False, - conjunct: bool = False -) -``` - -Filter constructor. - - - -**Args:** - - - `name` (str): Filter name. - - `values` (Union[str, int, float, Sequence[Union[str, int, float]]]): One string with filter value or list of filter values. - - `negative` (bool): If true, will match events/messages that do not match those specified values. If false, will match the events/messages by their values. Defaults to false. - - `conjunct` (bool): If true, each of the specific filter values should be applied If false, at least one of the specific filter values must be applied. - - - - ---- - - - -### method `grpc` - -```python -grpc() → Filter -``` - -Generates the grpc object of the GRPC protocol API. - ---- - - - -### method `url` - -```python -url() → str -``` - -Generates the filter part of the HTTP protocol API. - -For help use this readme: https://github.com/th2-net/th2-rpt-data-provider#filters-api. - - - -**Returns:** - - - `str`: Generated filter. - - ---- - - - -## class `Provider6EventFilter` -Base class for Event Filters of Provider v5. - - - -### method `__init__` - -```python -__init__(values: Sequence[Any], negative: bool = False, conjunct: bool = False) -``` - - - - - - - - ---- - - - -### method `grpc` - -```python -grpc() → Filter -``` - -Generates the grpc object of the GRPC protocol API. - ---- - - - -### method `url` - -```python -url() → str -``` - -Generates the filter part of the HTTP protocol API. - -For help use this readme: https://github.com/th2-net/th2-rpt-data-provider#filters-api. - - - -**Returns:** - - - `str`: Generated filter. - - ---- - - - -## class `Provider6MessageFilter` -Base class for Message Filters of Provider v5. - - - -### method `__init__` - -```python -__init__(values: Sequence[Any], negative: bool = False, conjunct: bool = False) -``` - - - - - - - - ---- - - - -### method `grpc` - -```python -grpc() → Filter -``` - -Generates the grpc object of the GRPC protocol API. - ---- - - - -### method `url` - -```python -url() → str -``` - -Generates the filter part of the HTTP protocol API. - -For help use this readme: https://github.com/th2-net/th2-rpt-data-provider#filters-api. - - - -**Returns:** - - - `str`: Generated filter. - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.v6.filters.md b/documentation/api/provider.v6.filters.md deleted file mode 100644 index 26ac7fb7..00000000 --- a/documentation/api/provider.v6.filters.md +++ /dev/null @@ -1,16 +0,0 @@ - - - - -# module `provider.v6.filters` - - - - - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.v6.filters.message_filters.md b/documentation/api/provider.v6.filters.message_filters.md deleted file mode 100644 index 1a444f60..00000000 --- a/documentation/api/provider.v6.filters.message_filters.md +++ /dev/null @@ -1,60 +0,0 @@ - - - - -# module `provider.v6.filters.message_filters` - - - - - - ---- - - - -## class `TypeFilter` -Will match the messages by their full type name. - - - - - ---- - - - -## class `BodyBinaryFilter` -Will match the messages by their binary body. - - - - - ---- - - - -## class `BodyFilter` -Will match the messages by their parsed body. - - - - - ---- - - - -## class `AttachedEventIdsFilter` -Filters the messages that are linked to the specified event id. - - - - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.v6.interfaces.command.md b/documentation/api/provider.v6.interfaces.command.md deleted file mode 100644 index 280fb230..00000000 --- a/documentation/api/provider.v6.interfaces.command.md +++ /dev/null @@ -1,70 +0,0 @@ - - - - -# module `provider.v6.interfaces.command` - - - - - - ---- - - - -## class `IHTTPProvider6Command` -Interface of command for rpt-data-provider. - -Rpt-data-provider version: 5.x.y Protocol: HTTP - - - - ---- - - - -### method `handle` - -```python -handle(data_source: HTTPProvider6DataSource) -``` - - - - - - ---- - - - -## class `IGRPCProvider6Command` -Interface of command for rpt-data-provider. - -Rpt-data-provider version: 5.x.y Protocol: GRPC - - - - ---- - - - -### method `handle` - -```python -handle(data_source: GRPCProvider6DataSource) -``` - - - - - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.v6.md b/documentation/api/provider.v6.md deleted file mode 100644 index 25766128..00000000 --- a/documentation/api/provider.v6.md +++ /dev/null @@ -1,16 +0,0 @@ - - - - -# module `provider.v6` - - - - - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.v6.provider_api.grpc.md b/documentation/api/provider.v6.provider_api.grpc.md deleted file mode 100644 index 506bfefb..00000000 --- a/documentation/api/provider.v6.provider_api.grpc.md +++ /dev/null @@ -1,250 +0,0 @@ - - - - -# module `provider.v6.provider_api.grpc` - - - - - - ---- - - - -## class `BasicRequest` -BasicRequest(start_timestamp, end_timestamp, result_count_limit, keep_open, search_direction, filters) - - - - - ---- - - - -## class `GRPCProvider6API` - - - - - - -### method `__init__` - -```python -__init__(url: str) -``` - -GRPC Provider6 API. - - - -**Args:** - - - `url`: GRPC data source url. - - - - ---- - - - -### method `get_event` - -```python -get_event(event_id: str) → EventResponse -``` - -GRPC-API `getEvent` call returns a single event with the specified id. - ---- - - - -### method `get_event_filter_info` - -```python -get_event_filter_info(filter_name: str) → FilterInfoResponse -``` - -GRPC-API `getEventFilterInfo` call returns event filter info. - ---- - - - -### method `get_events_filters` - -```python -get_events_filters() → FilterNamesResponse -``` - -GRPC-API `getEventsFilters` call returns all the names of sse event filters. - ---- - - - -### method `get_message` - -```python -get_message(message_id: str) → MessageGroupResponse -``` - -GRPC-API `getMessage` call returns a single message with the specified id. - ---- - - - -### method `get_message_filter_info` - -```python -get_message_filter_info(filter_name: str) → FilterInfoResponse -``` - -GRPC-API `getMessageFilterInfo` call returns message filter info. - ---- - - - -### method `get_message_streams` - -```python -get_message_streams() → MessageStreamsResponse -``` - -GRPC-API `getMessageStreams` call returns a list of message stream names. - ---- - - - -### method `get_messages_filters` - -```python -get_messages_filters() → FilterNamesResponse -``` - -GRPC-API `getMessagesFilters` call returns all the names of sse message filters. - ---- - - - -### method `match_event` - -```python -match_event(event_id: str, filters: List[Filter]) → MatchResponse -``` - -GRPC-API `matchEvent` call checks that the event with the specified id is matched by the filter. - ---- - - - -### method `match_message` - -```python -match_message(message_id: str, filters: List[Filter]) → MatchResponse -``` - -GRPC-API `matchMessage` call checks that the message with the specified id is matched by the filter. - ---- - - - -### method `search_events` - -```python -search_events( - start_timestamp: int = None, - end_timestamp: int = None, - parent_event: str = None, - search_direction: str = 'NEXT', - resume_from_id: str = None, - result_count_limit: int = None, - keep_open: bool = False, - limit_for_parent: int = None, - metadata_only: bool = True, - attached_messages: bool = False, - filters: Optional[List[Filter]] = None -) → Iterable[EventSearchResponse] -``` - -GRPC-API `searchEvents` call creates an event or an event metadata stream that matches the filter. - - - -**Args:** - - - `start_timestamp`: Sets the search starting point. Expected in nanoseconds. One of the 'start_timestamp' or 'resume_from_id' must not absent. - - `end_timestamp`: Sets the timestamp to which the search will be performed, starting with 'start_timestamp'. Expected in nanoseconds. - - `parent_event`: Match events to the specified parent. - - `search_direction`: Sets the lookup direction. Can be 'NEXT' or 'PREVIOUS'. - - `resume_from_id`: The last event id from which we start searching for events. - - `result_count_limit`: Sets the maximum amount of events to return. - - `keep_open`: Option if the search has reached the current moment, it is necessary to wait further for the appearance of new data. - - `limit_for_parent`: How many children events for each parent do we want to request. - - `metadata_only`: Receive only metadata (true) or entire event (false) (without attachedMessageIds). - - `attached_messages`: Option if you want to load attachedMessageIds additionally. - - `filters`: Which filters to apply in a search. - - - -**Returns:** - Iterable object which return events as parts of streaming response. - ---- - - - -### method `search_messages` - -```python -search_messages( - start_timestamp: int, - end_timestamp: int = None, - search_direction: str = 'NEXT', - result_count_limit: int = None, - stream: List[str] = None, - keep_open: bool = False, - stream_pointer: List[MessageStreamPointer] = None, - filters: Optional[List[Filter]] = None, - attached_events: bool = False -) → Iterable[MessageSearchResponse] -``` - -GRPC-API `searchMessages` call creates a message stream that matches the filter. - - - -**Args:** - - - `start_timestamp`: Sets the search starting point. Expected in nanoseconds. One of the 'start_timestamp' or 'resume_from_id' must not absent. - - `stream`: Sets the stream ids to search in. - - `end_timestamp`: Sets the timestamp to which the search will be performed, starting with 'start_timestamp'. Expected in nanoseconds. - - `search_direction`: Sets the lookup direction. Can be 'NEXT' or 'PREVIOUS'. - - `result_count_limit`: Sets the maximum amount of messages to return. - - `keep_open`: Option if the search has reached the current moment, it is necessary to wait further for the appearance of new data. - - `stream_pointer`: List of stream pointers to restore the search from. start_timestamp will be ignored if this parameter is specified. This parameter is only received from the provider. - - `filters`: Which filters to apply in a search. - - `attached_events`: If true, it will additionally load attachedEventsIds. - - - -**Returns:** - Iterable object which return messages as parts of streaming response or message stream pointers. - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.v6.provider_api.http.md b/documentation/api/provider.v6.provider_api.http.md deleted file mode 100644 index d2d0b3af..00000000 --- a/documentation/api/provider.v6.provider_api.http.md +++ /dev/null @@ -1,296 +0,0 @@ - - - - -# module `provider.v6.provider_api.http` - - - - -**Global Variables** ---------------- -- **UNICODE_REPLACE_HANDLER** - - ---- - - - -## class `HTTPProvider6API` - - - - - - -### method `__init__` - -```python -__init__( - url: str, - chunk_length: int = 65536, - decode_error_handler: str = 'unicode_replace', - char_enc: str = 'utf-8' -) -``` - -HTTP Provider6 API. - - - -**Args:** - - - `url`: HTTP data source url. - - `chunk_length`: How much of the content to read in one chunk. - - `char_enc`: Encoding for the byte stream. - - `decode_error_handler`: Registered decode error handler. - - - - ---- - - - -### method `execute_request` - -```python -execute_request(url: str) → Response -``` - -Sends a GET request to provider. - - - -**Args:** - - - `url`: Url for a get request to rpt-data-provider. - - - -**Returns:** - - - `requests.Response`: Response data. - ---- - - - -### method `execute_sse_request` - -```python -execute_sse_request(url: str) → Generator[bytes, NoneType, NoneType] -``` - -Create stream connection. - - - -**Args:** - - - `url`: Url. - - - -**Yields:** - - - `str`: Response stream data. - ---- - - - -### method `get_url_event_filter_info` - -```python -get_url_event_filter_info(filter_name: str) → str -``` - -SSE-API `filters/sse-events/{filter_name}` call returns filter info. - -https://github.com/th2-net/th2-rpt-data-provider#filters-api - ---- - - - -### method `get_url_events_filters` - -```python -get_url_events_filters() → str -``` - -SSE-API `/filters/sse-events` call returns all names of sse event filters. - -https://github.com/th2-net/th2-rpt-data-provider#filters-api - ---- - - - -### method `get_url_find_event_by_id` - -```python -get_url_find_event_by_id(event_id: str) → str -``` - -REST-API `event` call returns a single event with the specified id. - ---- - - - -### method `get_url_find_events_by_id` - -```python -get_url_find_events_by_id(*ids) → str -``` - -REST-API `events` call returns a list of events with the specified ids. - -Note, at a time you can request no more eventSearchChunkSize. - -Deprecated, use `get_url_find_event_by_id` instead. - ---- - - - -### method `get_url_find_message_by_id` - -```python -get_url_find_message_by_id(message_id: str) → str -``` - -REST-API `message` call returns a single message with the specified id. - ---- - - - -### method `get_url_match_event_by_id` - -```python -get_url_match_event_by_id(event_id: str, filters: str = '') → str -``` - -REST-API `match/event/{id}` call returns boolean value. - -Checks that event with the specified id is matched by filter. - -https://github.com/th2-net/th2-rpt-data-provider#filters-api - ---- - - - -### method `get_url_match_message_by_id` - -```python -get_url_match_message_by_id(message_id: str, filters: str = '') → str -``` - -REST-API `match/message/{id}` call returns boolean value. - -Checks that message with the specified id is matched by filter. - -https://github.com/th2-net/th2-rpt-data-provider#filters-api - ---- - - - -### method `get_url_message_filter_info` - -```python -get_url_message_filter_info(filter_name: str) → str -``` - -SSE-API `filters/sse-messages/{filter name}` call returns filter info. - -https://github.com/th2-net/th2-rpt-data-provider#filters-api - ---- - - - -### method `get_url_message_streams` - -```python -get_url_message_streams() → str -``` - -REST-API `messageStreams` call returns a list of message stream names. - ---- - - - -### method `get_url_messages_filters` - -```python -get_url_messages_filters() → str -``` - -SSE-API `filters/sse-messages` call returns all names of sse message filters. - -https://github.com/th2-net/th2-rpt-data-provider#filters-api - ---- - - - -### method `get_url_search_sse_events` - -```python -get_url_search_sse_events( - start_timestamp: int, - end_timestamp: Optional[int] = None, - parent_event: Optional[str] = None, - resume_from_id: Optional[str] = None, - search_direction: Optional[str] = 'next', - result_count_limit: Union[int, float] = None, - keep_open: Optional[bool] = False, - limit_for_parent: Union[int, float] = None, - metadata_only: Optional[bool] = True, - attached_messages: Optional[bool] = False, - filters: Optional[str] = None -) → str -``` - -REST-API `search/sse/events` call create a sse channel of event metadata that matches the filter. - -https://github.com/th2-net/th2-rpt-data-provider#sse-requests-api - ---- - - - -### method `get_url_search_sse_messages` - -```python -get_url_search_sse_messages( - start_timestamp: int, - stream: List[str], - end_timestamp: Optional[int] = None, - resume_from_id: Optional[str] = None, - search_direction: Optional[str] = 'next', - result_count_limit: Union[int, float] = None, - keep_open: bool = False, - message_id: Optional[List[str]] = None, - attached_events: bool = False, - lookup_limit_days: Union[int, float] = None, - filters: Optional[str] = None -) → str -``` - -REST-API `search/sse/messages` call create a sse channel of messages that matches the filter. - -https://github.com/th2-net/th2-rpt-data-provider#sse-requests-api - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.v6.streams.md b/documentation/api/provider.v6.streams.md deleted file mode 100644 index 9cf3ec2c..00000000 --- a/documentation/api/provider.v6.streams.md +++ /dev/null @@ -1,82 +0,0 @@ - - - - -# module `provider.v6.streams` - - - - - - ---- - - - -## class `Streams` -General interface for composite streams of Provider v6. - -The class gives the opportunity to make list of streams with direction for each. - - - -### method `__init__` - -```python -__init__(streams: List[str], direction: str = None) -``` - -Streams constructor. - - - -**Args:** - - - `streams`: List of Streams. - - `direction`: Direction of Streams (Only FIRST or SECOND). If None then is both directions. - - - - ---- - - - -### method `grpc` - -```python -grpc() → List[MessageStream] -``` - -Generates the grpc objects of the GRPC protocol API. - - - -**Returns:** - - - `List[MessageStream]`: List of Stream with specified direction. - ---- - - - -### method `url` - -```python -url() → str -``` - -Generates the stream part of the HTTP protocol API. - - - -**Returns:** - - - `str`: Generated streams. - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.v6.stub_builder.md b/documentation/api/provider.v6.stub_builder.md deleted file mode 100644 index 31dd25de..00000000 --- a/documentation/api/provider.v6.stub_builder.md +++ /dev/null @@ -1,104 +0,0 @@ - - - - -# module `provider.v6.stub_builder` - - - - -**Global Variables** ---------------- -- **provider6_event_stub_builder** -- **provider6_message_stub_builder** - - ---- - - - -## class `Provider6EventStubBuilder` - - - - - - -### method `__init__` - -```python -__init__( - event_struct=HTTPProvider6EventStruct(EVENT_ID='eventId', PARENT_EVENT_ID='parentEventId', STATUS='successful', NAME='eventName', TYPE='type', BATCH_ID='batchId', IS_BATCHED='isBatched', EVENT_TYPE='eventType', END_TIMESTAMP='endTimestamp', START_TIMESTAMP='startTimestamp', ATTACHED_MESSAGES_IDS='attachedMessageIds', BODY='body') -) -``` - -Event stub builder for Provider v6. - - - -**Args:** - - - `event_struct`: Event struct class. - - ---- - -#### property template - -Event stub template. - - - -**Returns:** - (dict) Event stub template. - - - - ---- - - - -## class `Provider6MessageStubBuilder` - - - - - - -### method `__init__` - -```python -__init__( - message_struct=HTTPProvider6MessageStruct(DIRECTION='direction', SESSION_ID='sessionId', MESSAGE_TYPE='messageType', CONNECTION_ID='connectionId', SESSION_ALIAS='sessionAlias', SUBSEQUENCE='subsequence', SEQUENCE='sequence', TIMESTAMP='timestamp', BODY='parsedMessages', BODY_BASE64='rawMessageBase64', TYPE='type', MESSAGE_ID='id', ATTACHED_EVENT_IDS='attachedEventIds') -) -``` - -Event stub builder for Provider 6. - - - -**Args:** - - - `message_struct`: Message struct class. - - ---- - -#### property template - -Message stub template. - - - -**Returns:** - (dict) Message stub template. - - - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/sse_client.md b/documentation/api/sse_client.md deleted file mode 100644 index a59476b3..00000000 --- a/documentation/api/sse_client.md +++ /dev/null @@ -1,51 +0,0 @@ - - - - -# module `sse_client` - - - - - - ---- - - - -## class `SSEClient` -Patch for sseclient-py to get availability to configure decode error handler. - - - -### method `__init__` - -```python -__init__(event_source, char_enc='utf-8', decode_errors_handler='strict') -``` - -Initialize the SSE client over an existing, ready to consume event source. - -The event source is expected to be a binary stream and have a close() method. That would usually be something that implements io.BinaryIOBase, like an httplib or urllib3 HTTPResponse object. - - - - ---- - - - -### method `events` - -```python -events() -``` - -Returns events in generator style. - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/th2.data_services.config.config.md b/documentation/api/th2.data_services.config.config.md new file mode 100644 index 00000000..22586045 --- /dev/null +++ b/documentation/api/th2.data_services.config.config.md @@ -0,0 +1,44 @@ + + + + +# module `th2_data_services.config.config` + + + + +**Global Variables** +--------------- +- **options** + + +--- + + + +## class `TH2Config` + + + + + + +### method `__init__` + +```python +__init__() → None +``` + + + + + + + + + + + +--- + +_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.v6.interfaces.md b/documentation/api/th2.data_services.config.md similarity index 71% rename from documentation/api/provider.v6.interfaces.md rename to documentation/api/th2.data_services.config.md index 48563c26..b5fbba93 100644 --- a/documentation/api/provider.v6.interfaces.md +++ b/documentation/api/th2.data_services.config.md @@ -1,15 +1,15 @@ - + -# module `provider.v6.interfaces` +# module `th2_data_services.config` **Global Variables** --------------- -- **command**: # Copyright 2022 Exactpro (Exactpro Systems Limited) +- **config**: # Copyright 2023 Exactpro (Exactpro Systems Limited) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/documentation/api/th2.data_services.data.md b/documentation/api/th2.data_services.data.md new file mode 100644 index 00000000..729e9c9e --- /dev/null +++ b/documentation/api/th2.data_services.data.md @@ -0,0 +1,402 @@ + + + + +# module `th2_data_services.data` + + + + + + +--- + + + +## class `Data` +A wrapper for data/data_stream. + +The class provides methods for working with data as a stream. + +Such approach to data analysis called streaming transformation. + + + +### method `__init__` + +```python +__init__( + data: Optional[Iterator, Callable[, Generator[~DataIterValues, NoneType]], List[Iterator]], + cache: bool = False, + workflow: List[Dict[str, Union[Callable, str]]] = None +) +``` + +Data constructor. + + + +**Args:** + + - `data`: Data source. Any iterable, Data object or a function that creates generator. + - `cache`: Set True if you want to write and read from cache. + - `workflow`: DataWorkflow. + + +--- + +#### property cache_status + + + + + +--- + +#### property is_empty + +bool: Indicates that the Data object doesn't contain data. + +--- + +#### property len + +int: How many records in the Data stream. + + + +**Notes:** + +> 1. It is a wasteful operation if you are performing it on the Data object that has never been iterated before. +>2. If you want just to check emptiness, use is_empty property instead. + +--- + +#### property metadata + + + + + + + +--- + + + +### method `build_cache` + +```python +build_cache(filename) +``` + +Creates cache file with provided name. + + + +**Args:** + + - `filename`: Name or path to cache file. + +--- + + + +### method `clear_cache` + +```python +clear_cache() +``` + +Clears related to data object cache file. + +This function won't remove external cache file. + +--- + + + +### method `filter` + +```python +filter(callback: Callable) → Data +``` + +Append `filter` to workflow. + + + +**Args:** + + - `callback`: Filter function. This function should return True or False. If function returns False, the record will be removed from the dataflow. + + + +**Returns:** + + - `Data`: Data object. + +--- + + + +### method `find_by` + +```python +find_by(record_field, field_values) → Generator +``` + +Get the records whose field value is written in the field_values list. + +When to use: You have IDs of some messages and you want get them in the stream and stop searching when you find all elements. + + + +**Args:** + + - `record_field`: The record field to be searched for in the field_values list. + - `field_values`: List of elements among which will be searched record[record_field]. + + + +**Yields:** + + - `dict`: Generator records. + +--- + + + +### classmethod `from_cache_file` + +```python +from_cache_file(filename) → Data +``` + +Creates Data object from cache file with provided name. + + + +**Args:** + + - `filename`: Name or path to cache file. + + + +**Returns:** + + - `Data`: Data object. + + + +**Raises:** + FileNotFoundError if provided file does not exist. + +--- + + + +### method `get_cache_filepath` + +```python +get_cache_filepath() → Path +``` + +Returns filepath for a cache file. + +--- + + + +### method `get_pending_cache_filepath` + +```python +get_pending_cache_filepath() → Path +``` + +Returns filepath for a pending cache file. + +--- + + + +### method `limit` + +```python +limit(num: int) → Data +``` + +Limits the stream to `num` entries. + + + +**Args:** + + - `num`: How many records will be provided. + + + +**Returns:** + + - `Data`: Data object. + +--- + + + +### method `map` + +```python +map(callback_or_adapter: Union[Callable, IRecordAdapter]) → Data +``` + +Append `transform` function to workflow. + + + +**Args:** + + - `callback_or_adapter`: Transform function or an Adapter with IRecordAdapter interface implementation. + + + +**Returns:** + + - `Data`: Data object. + +--- + + + +### method `map_stream` + +```python +map_stream( + adapter_or_generator: Union[IStreamAdapter, Callable[, Generator]] +) → Data +``` + +Append `stream-transform` function to workflow. + +If StreamAdapter is passed StreamAdapter.handle method will be used as a map function. + +Difference between map and map_stream: 1. map_stream allows you return None values. 2. map_stream allows you work with the whole stream but not with only 1 element, so you can implement some buffers inside handler. 3. map_stream works slightly efficent (faster on 5-10%). + + + +**Args:** + + - `adapter_or_generator`: StreamAdapter object or generator function. + + + +**Returns:** + + - `Data`: Data object. + +--- + + + +### method `sift` + +```python +sift(limit: int = None, skip: int = None) → Generator[dict, NoneType, NoneType] +``` + +Skips and limits records. + + + +**Args:** + + - `limit`: Limited records. + - `skip`: Skipped records. + + + +**Yields:** + Generator records. + +--- + + + +### method `update_metadata` + +```python +update_metadata(metadata: Dict) → Data +``` + +Update metadata of object with metadata argument. + +Metadata is updated with new values, meaning previous values are kept and added with new values. + +| Example: | data = Data(...) | # data.metadata => {'num': 1, 'nums': [1], 'letters': {'a': 97}} | new_metadata = {'num': 9, 'nums': [7], 'letters': {'z': 122}, 'new': 'key'} | data.update_metadata(new_metadata) | # data.metadata => {'num': 9, 'nums': [1,7], 'letters': {'a': 97, 'z': 122}, 'new': 'key'} + + + +**Args:** + + - `metadata` (dict): New Metadata + + + +**Returns:** + Data objects (itself) + + + +**Raises:** + + - `Exception`: If metadata isn't dict, error will be raised. + - `AttributeError`: If you're trying to update key value with dict which isn't a dict. + +--- + + + +### method `use_cache` + +```python +use_cache(status: bool = True) → Data +``` + +Changes cache flag and returns self. + + + +**Args:** + + - `status` (bool): If True the whole data stream will be saved to cache file. Further actions with the Data object will consume data from the cache file. True by default. + + + +**Returns:** + + - `Data`: Data object. + +--- + + + +### method `write_to_file` + +```python +write_to_file(file: str) → None +``` + +Writes the stream data to txt file. + + + +**Args:** + + - `file`: Path to file. + + + + +--- + +_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/th2.data_services.event_tree.etc_driver.md b/documentation/api/th2.data_services.event_tree.etc_driver.md new file mode 100644 index 00000000..34b4129a --- /dev/null +++ b/documentation/api/th2.data_services.event_tree.etc_driver.md @@ -0,0 +1,129 @@ + + + + +# module `th2_data_services.event_tree.etc_driver` + + + + + + +--- + + + +## class `IETCDriver` + + + + + + +### method `__init__` + +```python +__init__( + event_struct: IEventStruct, + data_source: IDataSource, + use_stub: bool = False +) +``` + +The driver for EventsTreeCollection and its inheritors. + + + +**Args:** + + - `event_struct`: Structure of the event. + - `data_source`: DataSource object. + - `use_stub`: Build stubs or not. + + + + +--- + + + +### method `build_stub_event` + +```python +build_stub_event(id_: str) → ~Th2EventType +``` + +Builds stub event to generate parentless trees. + + + +**Args:** + + - `id_`: Event Id. + +--- + + + +### method `get_event_id` + +```python +get_event_id(event: ~Th2EventType) +``` + +Returns event id from the event. + +--- + + + +### method `get_event_name` + +```python +get_event_name(event: ~Th2EventType) +``` + +Returns event name from the event. + +--- + + + +### method `get_events_by_id_from_source` + +```python +get_events_by_id_from_source(ids: Sequence) → list +``` + +Downloads the list of events from the provided data_source. + +--- + + + +### method `get_parent_event_id` + +```python +get_parent_event_id(event: ~Th2EventType) +``` + +Returns parent event id from the event. + +--- + + + +### method `stub_event_name` + +```python +stub_event_name() +``` + +Returns stub event name. + + + + +--- + +_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/th2.data_services.event_tree.event_tree.md b/documentation/api/th2.data_services.event_tree.event_tree.md new file mode 100644 index 00000000..3c8daae4 --- /dev/null +++ b/documentation/api/th2.data_services.event_tree.event_tree.md @@ -0,0 +1,622 @@ + + + + +# module `th2_data_services.event_tree.event_tree` + + + + + + +--- + + + +## class `EventTree` +EventTree is a tree-based data structure of events. + + +- get_x methods raise Exceptions if no result is found. +- find_x methods return None if no result is found. +- EventTree stores events as Nodes and interacts with them using an internal tree. +- Note that EventTree stores only one tree. If you want to store all trees, use EventTreeCollections. +- EventTree contains all events in memory. + +Take a look at the following HTML tree to understand some important terms. + +``` + +
+

Hello, world!

+

Goodbye!

+
+ +``` + + + +### method `__init__` + +```python +__init__(event_name: str, event_id: str, data: dict = None) +``` + +EventTree constructor. + + + +**Args:** + + - `event_name`: Event Name. + - `event_id`: Event Id. + - `data`: Data of event. + + + + +--- + + + +### method `append_event` + +```python +append_event( + event_name: str, + event_id: str, + parent_id: str, + data: dict = None +) → None +``` + +Appends the event to the tree. + + + +**Args:** + + - `event_name`: Event Name. + - `event_id`: Event Id. + - `parent_id`: Parent Id. + - `data`: Data of event. + +--- + + + +### method `find` + +```python +find(filter: Callable, stop: Callable = None) → Union[dict, NoneType] +``` + +Searches the first event match. + + +- The search uses 'filter' which is a filtering function. +- Optionally, the search uses 'stop' which is a stopping function. If 'stop' function returns 'True' then search is complete. + + + +**Args:** + + - `filter`: Filter function. + - `stop`: Stop function. If None searches for all nodes in the tree. + + + +**Returns:** + One matching event. + +--- + + + +### method `find_ancestor` + +```python +find_ancestor(id: str, filter: Callable) → Union[dict, NoneType] +``` + +Finds the ancestor of an event. + + + +**Args:** + + - `id`: Event id. + - `filter`: Filter function + + + +**Returns:** + Ancestor of Event. + +--- + + + +### method `findall` + +```python +findall( + filter: Callable, + stop: Callable = None, + max_count: int = None +) → List[dict] +``` + +Searches events matches. + + +- The search uses 'filter' which is a filtering function. +- Optionally, the search uses 'stop' which is a stopping function. If 'stop' function returns 'True' then search is complete. +- 'max_count' is a parameter that limits the search to a specified count. + + + +**Args:** + + - `filter`: Filter function. + - `stop`: Stop function. If None searches for all nodes in the tree. + - `max_count`: Max count of matched events. Stops searching when `max_count` will be reached. + + + +**Returns:** + Matching events. + +--- + + + +### method `findall_iter` + +```python +findall_iter( + filter: Callable, + stop: Callable = None, + max_count: int = None +) → Generator[dict, NoneType, NoneType] +``` + +Searches events matches as iterator. + + +- The search uses 'filter' which is a filtering function. +- Optionally, the search uses 'stop' which is a stopping function. If 'stop' function returns 'True' then search is complete. +- 'max_count' is a parameter that limits the search to a specified count. + + + +**Args:** + + - `filter`: Filter function. + - `stop`: Stop function. If None searches for all nodes in the tree. + - `max_count`: Max count of matched events. Stops searching when `max_count` will be reached. + + + +**Yields:** + Matching events. + +--- + + + +### method `get_all_events` + +```python +get_all_events() → List[dict] +``` + +Returns all events from the tree. + +--- + + + +### method `get_all_events_iter` + +```python +get_all_events_iter() → Generator[dict, NoneType, NoneType] +``` + +Returns all events from the tree as iterator. + +--- + + + +### method `get_ancestors` + +```python +get_ancestors(id: str) → List[dict] +``` + +Returns all event's ancestors in right order. + + + +**Args:** + + - `id`: Event id. + + + +**Returns:** + All event's ancestors. + + + +**Raises:** + + - `EventIdNotInTree`: If event id is not in the tree. + +--- + + + +### method `get_children` + +```python +get_children(id: str) → Tuple[dict] +``` + +Returns children for the event by its id. + + + +**Args:** + + - `id`: Event id. + + + +**Raises:** + + - `EventIdNotInTree`: If event id is not in the tree. + +--- + + + +### method `get_children_iter` + +```python +get_children_iter(id: str) → Generator[dict, NoneType, NoneType] +``` + +Returns children as iterator for the event by its id. + + + +**Args:** + + - `id`: Event id. + + + +**Raises:** + + - `EventIdNotInTree`: If event id is not in the tree. + +--- + + + +### method `get_event` + +```python +get_event(id: str) → dict +``` + +Returns an event by id. + + + +**Args:** + + - `id`: Event id. + + + +**Raises:** + + - `EventIdNotInTree`: If event id is not in the tree. + +--- + + + +### method `get_full_path` + +```python +get_full_path(id: str, field: str = None) → List[Union[str, dict]] +``` + +Returns the full path for the event by its id in right order. + + + +**Examples:** + + +Imagine we have the following tree. + +``` +Harry +├── Bill +└── Jane + ├── Diane + │ └── Mary + └── Mark +``` + +``` +tree.get_full_path('Jane', id) +['Harry-event-id', 'Jane-event-id'] + +tree.get_full_path('Jane', name) +['Harry-event-name', 'Jane-event-name'] + +tree.get_full_path('Jane') +['Harry-event', 'Jane-event'] +``` + + + +**Args:** + + - `id`: Event id. + - `field`: Field of event. + + + +**Returns:** + Full path of event. + + + +**Raises:** + + - `EventIdNotInTree`: If event id is not in the tree. + +--- + + + +### method `get_leaves` + +```python +get_leaves() → Tuple[dict] +``` + +Returns all tree leaves. + +--- + + + +### method `get_leaves_iter` + +```python +get_leaves_iter() → Generator[dict, NoneType, NoneType] +``` + +Returns all tree leaves as iterator. + +--- + + + +### method `get_parent` + +```python +get_parent(id: str) → dict +``` + +Returns a parent for the event by its id. + + + +**Args:** + + - `id`: Event id. + + + +**Raises:** + + - `EventIdNotInTree`: If event id is not in the tree. + +--- + + + +### method `get_root` + +```python +get_root() → dict +``` + +Returns the root event. + +--- + + + +### method `get_root_id` + +```python +get_root_id() → str +``` + +Returns the root id. + +--- + + + +### method `get_root_name` + +```python +get_root_name() → str +``` + +Returns the root name. + +--- + + + +### method `get_subtree` + +```python +get_subtree(id: str) → EventTree +``` + +Returns subtree of the event by its id. + + + +**Args:** + + - `id`: Event id. + + + +**Returns:** + Subtree. + + + +**Raises:** + + - `EventIdNotInTree`: If event id is not in the tree. + +--- + + + +### method `merge_tree` + +```python +merge_tree( + parent_id: str, + other_tree: 'EventTree', + use_deepcopy: bool = False +) → None +``` + +Merges a EventTree to specified identifier. + + + +**Args:** + + - `parent_id`: Event id to which merge. + - `other_tree`: EventTree. + - `use_deepcopy`: True if you need deepcopy for your objects in event. + + + +**Raises:** + + - `EventIdNotInTree`: If event id is not in the tree. + +--- + + + +### method `show` + +```python +show() → None +``` + +Prints the EventTree as tree view. + +For example: + +``` +Root + |___ C01 + | |___ C11 + | |___ C111 + | |___ C112 + |___ C02 + |___ C03 + | |___ C31 +``` + +--- + + + +### method `summary` + +```python +summary() → str +``` + +Returns the tree summary. + +--- + + + +### method `update_event_name` + +```python +update_event_name(event_id: str, event_name: str) → None +``` + +Updates Event name in the tree. Note that it doesn't change internal data. + + + +**Args:** + + - `event_id`: Event id. + - `event_name`: Event name. + + + +**Raises:** + + - `EventIdNotInTree`: If event id is not in the tree. + +--- + + + +### method `update_parent_link` + +```python +update_parent_link(event_id: str, parent_id: str) → None +``` + +Updates the link to parent. + + + +**Args:** + + - `event_id`: Event id. + - `parent_id`: New parent id. + + + +**Raises:** + + - `EventIdNotInTree`: If event id is not in the tree. + - `TreeLoop`: If parent id will point to the descendant event. + + + + +--- + +_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/th2.data_services.event_tree.event_tree_collection.md b/documentation/api/th2.data_services.event_tree.event_tree_collection.md new file mode 100644 index 00000000..03953463 --- /dev/null +++ b/documentation/api/th2.data_services.event_tree.event_tree_collection.md @@ -0,0 +1,703 @@ + + + + +# module `th2_data_services.event_tree.event_tree_collection` + + + + + + +--- + + + +## class `EventTreeCollection` +EventTreeCollection objective is building 'EventsTree's and storing them. + + +- EventTreeCollection stores all EventsTree. You can to refer to each of them. +- Recovery of missing events occurs when you have passed DataSource class to constructor. Otherwise you should execute the method 'recover_unknown_events' manually. Note that there is no point in the method if the list of detached events is empty. + + + +### method `__init__` + +```python +__init__(driver: IETCDriver) +``` + +EventTreeCollection constructor. + + + +**Args:** + + - `driver`: initialized driver object. + + +--- + +#### property len_detached_events + +Returns number of detached events in the collection. + +--- + +#### property len_parentless + +Returns number of events in the parentless trees inside the collection. + +--- + +#### property len_trees + +Returns number of events in the trees inside the collection, including parentless trees. + + + +--- + + + +### method `append_event` + +```python +append_event(event: dict) → None +``` + +Appends event into a tree. + + + +**Args:** + + - `event`: Event. + +--- + + + +### method `build` + +```python +build(data: Iterable) +``` + + + + + +--- + + + +### method `find` + +```python +find(filter: Callable, stop: Callable = None) → Union[dict, NoneType] +``` + +Searches the first event match. + + +- The search uses 'filter' which is a filtering function. +- Optionally, the search uses 'stop' which is a stopping function. If 'stop' function returns 'True' then search is complete. + +This method applicable only for trees (regular or parentless), not for detached events. + + + +**Args:** + + - `filter`: Filter function. + - `stop`: Stop function. If None searches for all nodes in the trees. + + + +**Returns:** + One matching event. + +--- + + + +### method `find_ancestor` + +```python +find_ancestor(id: str, filter: Callable) → Union[dict, NoneType] +``` + +Finds the ancestor of an event. + +This method applicable only for trees (regular or parentless), not for detached events. + + + +**Args:** + + - `id`: Event id. + - `filter`: Filter function + + + +**Returns:** + Ancestor of Event. + +--- + + + +### method `findall` + +```python +findall( + filter: Callable, + stop: Callable = None, + max_count: int = None +) → List[dict] +``` + +Searches events matches. + + +- The search uses 'filter' which is a filtering function. +- Optionally, the search uses 'stop' which is a stopping function. If 'stop' function returns 'True' then search is complete. +- 'max_count' is a parameter that limits the search to a specified count. + +This method applicable only for trees (regular or parentless), not for detached events. + + + +**Args:** + + - `filter`: Filter function. + - `stop`: Stop function. If None searches for all nodes in the trees. + - `max_count`: Max count of matched events. Stops searching when `max_count` will be reached. + + + +**Returns:** + Matching events. + +--- + + + +### method `findall_iter` + +```python +findall_iter( + filter: Callable, + stop: Callable = None, + max_count: int = None +) → Generator[dict, NoneType, NoneType] +``` + +Searches events matches as iterator. + + +- The search uses 'filter' which is a filtering function. +- Optionally, the search uses 'stop' which is a stopping function. If 'stop' function returns 'True' then search is complete. +- 'max_count' is a parameter that limits the search to a specified count. + +This method applicable only for trees (regular or parentless), not for detached events. + + + +**Args:** + + - `filter`: Filter function. + - `stop`: Stop function. If None searches for all nodes in the trees. + - `max_count`: Max count of matched events. Stops searching when `max_count` will be reached. + + + +**Yields:** + Matching events. + +--- + + + +### method `get_all_events` + +```python +get_all_events() → List[dict] +``` + +Returns all events from the collection. + +--- + + + +### method `get_all_events_iter` + +```python +get_all_events_iter() → Generator[dict, NoneType, NoneType] +``` + +Yields all events from the collection. + +--- + + + +### method `get_ancestors` + +```python +get_ancestors(id: str) → List[dict] +``` + +Returns all event's ancestors in right order. + +This method applicable only for trees (regular or parentless), not for detached events. + + + +**Args:** + + - `id`: Event id. + + + +**Returns:** + All event's ancestors. + + + +**Raises:** + + - `EventIdNotInTree`: If event id is not in the trees. + +--- + + + +### method `get_children` + +```python +get_children(id: str) → Tuple[dict] +``` + +Returns children of the event by its id. + +This method applicable only for trees (regular or parentless), not for detached events. + + + +**Args:** + + - `id`: Event id. + + + +**Raises:** + + - `EventIdNotInTree`: If event id is not in the trees. + +--- + + + +### method `get_children_iter` + +```python +get_children_iter(id: str) → Generator[dict, NoneType, NoneType] +``` + +Yields children of the event by its id. + +This method applicable only for trees (regular or parentless), not for detached events. + + + +**Args:** + + - `id`: Event id. + + + +**Raises:** + + - `EventIdNotInTree`: If event id is not in the trees. + +--- + + + +### method `get_detached_events` + +```python +get_detached_events() → List[dict] +``` + +Returns detached events list. + +--- + + + +### method `get_detached_events_iter` + +```python +get_detached_events_iter() → Generator[dict, NoneType, NoneType] +``` + +Yields detached events. + +--- + + + +### method `get_event` + +```python +get_event(id: str) → Union[dict, NoneType] +``` + +Returns an event by its id. + + + +**Args:** + + - `id`: Event id. + + + +**Raises:** + + - `EventIdNotInTree`: If event id is not in the collection. + +--- + + + +### method `get_full_path` + +```python +get_full_path(id: str, field: str = None) → List[Union[str, dict]] +``` + +Returns the full path for the event by its id in the right order. + +This method applicable only for trees (regular or parentless), not for detached events. + + + +**Examples:** + + +Imagine we have the following tree. + +``` +Harry +├── Bill +└── Jane + ├── Diane + │ └── Mary + └── Mark +``` + +``` +collection.get_full_path('Jane', id) +['Harry-event-id', 'Jane-event-id'] + +collection.get_full_path('Jane', name) +['Harry-event-name', 'Jane-event-name'] + +collection.get_full_path('Jane') +['Harry-event', 'Jane-event'] +``` + + + +**Args:** + + - `id`: Event id. + - `field`: Field of event. + + + +**Returns:** + Full path of event. + + + +**Raises:** + + - `EventIdNotInTree`: If event id is not in the trees. + +--- + + + +### method `get_leaves` + +```python +get_leaves() → Tuple[dict] +``` + +Returns all trees leaves, including parentless trees. + +--- + + + +### method `get_leaves_iter` + +```python +get_leaves_iter() → Generator[dict, NoneType, NoneType] +``` + +Yields all trees leaves, including parentless trees. + +--- + + + +### method `get_parent` + +```python +get_parent(id: str) → dict +``` + +Returns a parent of the event by its id. + + + +**Args:** + + - `id`: Event id. + + + +**Raises:** + + - `NodeIDAbsentError`: If event id is not in the trees. + +--- + + + +### method `get_parentless_tree_collection` + +```python +get_parentless_tree_collection() → EventTreeCollection +``` + +Builds and returns parentless trees by detached events as EventTreeCollection. + +Detached events will be removed from the collection. + + + +**Returns:** + EventTreeCollection. + +--- + + + +### method `get_parentless_trees` + +```python +get_parentless_trees() → List[EventTree] +``` + +Builds and returns parentless trees by detached events. + +Detached events will be removed from the tree. + + + +**Returns:** + List of parentless trees if they exist, otherwise empty list. + +--- + + + +### method `get_root_by_id` + +```python +get_root_by_id(id) → dict +``` + +Returns the root event of a tree by id of any event in this tree. + +If event id of parentless tree is passed, stub of this parentless tree will be returnd. + + + +**Args:** + + - `id`: Event id. + + + +**Returns:** + Th2Event. + + + +**Raises:** + + - `EventIdNotInTree`: If event id is not in the trees. + +--- + + + +### method `get_roots_ids` + +```python +get_roots_ids() → List[str] +``` + +Returns ids of all trees roots located in the collection. + +If there are parentless trees, they also will be return. + +--- + + + +### method `get_subtree` + +```python +get_subtree(id: str) → EventTree +``` + +Returns subtree of the event by its id. + +This method applicable only for trees (regular or parentless), not for detached events. + + + +**Args:** + + - `id`: Event id. + + + +**Returns:** + Subtree. + + + +**Raises:** + + - `EventIdNotInTree`: If event id is not in the trees. + +--- + + + +### method `get_tree_by_id` + +```python +get_tree_by_id(id) → EventTree +``` + +Returns a tree by id of any event in this tree. + +If event id of parentless tree is passed, stub of this parentless tree will be returnd. + + + +**Args:** + + - `id`: Event id. + + + +**Returns:** + Tree. + + + +**Raises:** + + - `EventIdNotInTree`: If event id is not in the trees. + +--- + + + +### method `get_trees` + +```python +get_trees() → List[EventTree] +``` + +Returns the list of trees inside the collection. + +If there are parentless trees, they also will be return. + +--- + + + +### method `recover_unknown_events` + +```python +recover_unknown_events(preprocessor=None) → None +``` + +Loads missed events and finish tree building. + + + +**Args:** + + - `preprocessor`: the function that will be executed for each recovered event before store. + +--- + + + +### method `show` + +```python +show() +``` + +Prints all EventsTrees as tree view. + +For example: + +``` +Root + |___ C01 + | |___ C11 + | |___ C111 + | |___ C112 + |___ C02 + |___ C03 + | |___ C31 +``` + +--- + + + +### method `summary` + +```python +summary() → str +``` + +Returns the collection summary. + +The same as repr(EventTreeCollection). + + + + +--- + +_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/th2.data_services.event_tree.exceptions.md b/documentation/api/th2.data_services.event_tree.exceptions.md new file mode 100644 index 00000000..4ce1f9bc --- /dev/null +++ b/documentation/api/th2.data_services.event_tree.exceptions.md @@ -0,0 +1,162 @@ + + + + +# module `th2_data_services.event_tree.exceptions` + + + + + + +--- + + + +## class `EventIdNotInTree` + + + + + + +### method `__init__` + +```python +__init__(id_: str) +``` + +Exception for the case when the tree hasn't the event. + + + +**Args:** + + - `id_`: Event id. + + + + + +--- + + + +## class `FieldIsNotExist` + + + + + + +### method `__init__` + +```python +__init__(field_name: str) +``` + +Exception for the case when event as dict hasn't field. + + + +**Args:** + + - `field_name`: Field name. + + + + + +--- + + + +## class `EventAlreadyExist` + + + + + + +### method `__init__` + +```python +__init__(event_id: str) +``` + +Exception for the case when event already exist in tree. + + + +**Args:** + + - `event_id`: Event id. + + + + + +--- + + + +## class `EventRootExist` + + + + + + +### method `__init__` + +```python +__init__(event_id: str) +``` + +Exception for the case when root already added in tree. + + + +**Args:** + + - `event_id`: Event id. + + + + + +--- + + + +## class `TreeLoop` + + + + + + +### method `__init__` + +```python +__init__(event_id: str, parent_id: str) +``` + +Exception for the case when an event has link to a parent which is its descendant. + + + +**Args:** + + - `event_id`: Event id. + - `parent_id`: Parent id. + + + + + + + +--- + +_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/th2.data_services.event_tree.md b/documentation/api/th2.data_services.event_tree.md new file mode 100644 index 00000000..e0e28dd0 --- /dev/null +++ b/documentation/api/th2.data_services.event_tree.md @@ -0,0 +1,88 @@ + + + + +# module `th2_data_services.event_tree` + + + + +**Global Variables** +--------------- +- **exceptions**: # Copyright 2022-2023 Exactpro (Exactpro Systems Limited) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +- **event_tree**: # Copyright 2022-2023 Exactpro (Exactpro Systems Limited) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +- **etc_driver**: # Copyright 2023 Exactpro (Exactpro Systems Limited) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +- **event_tree_collection**: # Copyright 2022-2023 Exactpro (Exactpro Systems Limited) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +- **parent_event_tree_collection**: # Copyright 2022-2023 Exactpro (Exactpro Systems Limited) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + + + + +--- + +_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/th2.data_services.event_tree.parent_event_tree_collection.md b/documentation/api/th2.data_services.event_tree.parent_event_tree_collection.md new file mode 100644 index 00000000..60d286bd --- /dev/null +++ b/documentation/api/th2.data_services.event_tree.parent_event_tree_collection.md @@ -0,0 +1,47 @@ + + + + +# module `th2_data_services.event_tree.parent_event_tree_collection` + + + + + + +--- + + + +## class `ParentEventTreeCollection` +ParentEventTreeCollections is a class like an EventsTreeCollections. + +ParentEventsTree contains all parent events that are referenced. + + +--- + +#### property len_detached_events + +Returns number of detached events in the collection. + +--- + +#### property len_parentless + +Returns number of events in the parentless trees inside the collection. + +--- + +#### property len_trees + +Returns number of events in the trees inside the collection, including parentless trees. + + + + + + +--- + +_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/th2.data_services.exceptions.md b/documentation/api/th2.data_services.exceptions.md new file mode 100644 index 00000000..6fd4cf1f --- /dev/null +++ b/documentation/api/th2.data_services.exceptions.md @@ -0,0 +1,83 @@ + + + + +# module `th2_data_services.exceptions` + + + + + + +--- + + + +## class `EventNotFound` + + + + + + +### method `__init__` + +```python +__init__(id_, error_description) +``` + +Exception for the case when the the event was not found in data source. + +**Args:** + + - `id_`: Event id. + - `error_description`: Description of error + + + + + +--- + + + +## class `MessageNotFound` + + + + + + +### method `__init__` + +```python +__init__(id_, error_description) +``` + +Exception for the case when the the message was not found in data source. + +**Args:** + + - `id_`: Event id. + - `error_description`: Description of error + + + + + +--- + + + +## class `CommandError` +Exception raised for errors in the command. + + + + + + + +--- + +_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/th2.data_services.interfaces.adapter.md b/documentation/api/th2.data_services.interfaces.adapter.md new file mode 100644 index 00000000..9aee27e8 --- /dev/null +++ b/documentation/api/th2.data_services.interfaces.adapter.md @@ -0,0 +1,62 @@ + + + + +# module `th2_data_services.interfaces.adapter` + + + + + + +--- + + + +## class `IStreamAdapter` +Interface of Adapter for streams. + + + + +--- + + + +### method `handle` + +```python +handle(stream: Iterable) → Any +``` + +Stream handle function that should yield data (not return). + + +--- + + + +## class `IRecordAdapter` +Interface of Adapter for record. + + + + +--- + + + +### method `handle` + +```python +handle(record: dict) → Any +``` + +One record handle function that should return data. + + + + +--- + +_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/th2.data_services.interfaces.command.md b/documentation/api/th2.data_services.interfaces.command.md new file mode 100644 index 00000000..c5c11b3d --- /dev/null +++ b/documentation/api/th2.data_services.interfaces.command.md @@ -0,0 +1,44 @@ + + + + +# module `th2_data_services.interfaces.command` + + + + +**Global Variables** +--------------- +- **TYPE_CHECKING** + + +--- + + + +## class `ICommand` +High level interface for Command. + + + + +--- + + + +### method `handle` + +```python +handle(data_source: 'IDataSource') +``` + + + + + + + + +--- + +_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/th2.data_services.interfaces.data_source.md b/documentation/api/th2.data_services.interfaces.data_source.md new file mode 100644 index 00000000..21a649bb --- /dev/null +++ b/documentation/api/th2.data_services.interfaces.data_source.md @@ -0,0 +1,51 @@ + + + + +# module `th2_data_services.interfaces.data_source` + + + + + + +--- + + + +## class `IDataSource` + + + + + +--- + +#### property source_api + + + + + + + +--- + + + +### method `command` + +```python +command(cmd: 'ICommand') +``` + + + + + + + + +--- + +_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/th2.data_services.interfaces.md b/documentation/api/th2.data_services.interfaces.md new file mode 100644 index 00000000..eba9cf88 --- /dev/null +++ b/documentation/api/th2.data_services.interfaces.md @@ -0,0 +1,116 @@ + + + + +# module `th2_data_services.interfaces` + + + + +**Global Variables** +--------------- +- **adapter**: # Copyright 2022-2023 Exactpro (Exactpro Systems Limited) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +- **command**: # Copyright 2022-2023 Exactpro (Exactpro Systems Limited) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +- **source_api**: # Copyright 2022-2023 Exactpro (Exactpro Systems Limited) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +- **data_source**: # Copyright 2022-2023 Exactpro (Exactpro Systems Limited) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +- **struct**: # Copyright 2022-2023 Exactpro (Exactpro Systems Limited) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +- **stub_builder**: # Copyright 2022-2023 Exactpro (Exactpro Systems Limited) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +- **utils**: # Copyright 2023 Exactpro (Exactpro Systems Limited) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + + + + +--- + +_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/th2.data_services.interfaces.source_api.md b/documentation/api/th2.data_services.interfaces.source_api.md new file mode 100644 index 00000000..1a8e2748 --- /dev/null +++ b/documentation/api/th2.data_services.interfaces.source_api.md @@ -0,0 +1,27 @@ + + + + +# module `th2_data_services.interfaces.source_api` + + + + + + +--- + + + +## class `ISourceAPI` +High level interface for Source API. + + + + + + + +--- + +_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/th2.data_services.interfaces.struct.md b/documentation/api/th2.data_services.interfaces.struct.md new file mode 100644 index 00000000..df71f1d1 --- /dev/null +++ b/documentation/api/th2.data_services.interfaces.struct.md @@ -0,0 +1,42 @@ + + + + +# module `th2_data_services.interfaces.struct` + + + + + + +--- + + + +## class `IEventStruct` +Just to mark Event Struct class. + +It should look like a class with constants. + + + + + +--- + + + +## class `IMessageStruct` +Just to mark Message Struct class. + +It should look like a class with constants. + + + + + + + +--- + +_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/th2.data_services.interfaces.stub_builder.md b/documentation/api/th2.data_services.interfaces.stub_builder.md new file mode 100644 index 00000000..c5661d77 --- /dev/null +++ b/documentation/api/th2.data_services.interfaces.stub_builder.md @@ -0,0 +1,174 @@ + + + + +# module `th2_data_services.interfaces.stub_builder` + + + + + + +--- + + + +## class `IStub` + + + + + + +### method `__init__` + +```python +__init__() +``` + +Stab interface. + + +--- + +#### property template + + + + + + + +--- + + + +### method `build` + +```python +build(fields: dict) → dict +``` + +Builds a stub. + + + +**Args:** + fields: + + + +**Returns:** + + - `TypeError`: If required fields is absent in changed fields list. + + +--- + + + +## class `IEventStub` +Just to mark Event Stub class. + + + +### method `__init__` + +```python +__init__() +``` + +Stab interface. + + +--- + +#### property template + + + + + + + +--- + + + +### method `build` + +```python +build(fields: dict) → dict +``` + +Builds a stub. + + + +**Args:** + fields: + + + +**Returns:** + + - `TypeError`: If required fields is absent in changed fields list. + + +--- + + + +## class `IMessageStub` +Just to mark Message Stub class. + + + +### method `__init__` + +```python +__init__() +``` + +Stab interface. + + +--- + +#### property template + + + + + + + +--- + + + +### method `build` + +```python +build(fields: dict) → dict +``` + +Builds a stub. + + + +**Args:** + fields: + + + +**Returns:** + + - `TypeError`: If required fields is absent in changed fields list. + + + + +--- + +_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/th2.data_services.interfaces.utils.converter.md b/documentation/api/th2.data_services.interfaces.utils.converter.md new file mode 100644 index 00000000..5a1f5f54 --- /dev/null +++ b/documentation/api/th2.data_services.interfaces.utils.converter.md @@ -0,0 +1,145 @@ + + + + +# module `th2_data_services.interfaces.utils.converter` + + + + + + +--- + + + +## class `ITimestampConverter` + + + + + + + +--- + + + +### classmethod `parse_timestamp` + +```python +parse_timestamp(timestamp: ~TimestampType) → (, ) +``` + +Returns string representation of Unix time separated to seconds and nanoseconds. + +e.g. 2022-03-05T23:56:44.00123Z -> ('1646524604', '001230000') + +--- + + + +### classmethod `to_datetime` + +```python +to_datetime(timestamp: ~TimestampType) → datetime +``` + +Converts timestamp to datetime object. + +If your timestamp has nanoseconds, they will be just cut (not rounding). + + + +**Args:** + + - `timestamp`: TimestampType object to convert. + + + +**Returns:** + + - `datetime`: Timestamp in python datetime format. + +--- + + + +### classmethod `to_microseconds` + +```python +to_microseconds(timestamp: ~TimestampType) → int +``` + +Converts timestamp to microseconds. + +If your timestamp has nanoseconds, they will be just cut (not rounding). + + + +**Args:** + + - `timestamp`: TimestampType object to convert. + + + +**Returns:** + + - `int`: Timestamp in microseconds format. + +--- + + + +### classmethod `to_milliseconds` + +```python +to_milliseconds(timestamp: ~TimestampType) +``` + +Converts timestamp to milliseconds. + +If your timestamp has nanoseconds, they will be just cut (not rounding). + + + +**Args:** + + - `timestamp`: TimestampType object to convert. + + + +**Returns:** + + - `int`: Timestamp in microseconds format. + +--- + + + +### classmethod `to_nanoseconds` + +```python +to_nanoseconds(timestamp: ~TimestampType) → int +``` + +Converts timestamp to nanoseconds. + + + +**Args:** + + - `timestamp`: TimestampType object to convert. + + + +**Returns:** + + - `int`: Timestamp in nanoseconds format. + + + + +--- + +_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/provider.v6.provider_api.md b/documentation/api/th2.data_services.interfaces.utils.md similarity index 77% rename from documentation/api/provider.v6.provider_api.md rename to documentation/api/th2.data_services.interfaces.utils.md index 84b233ba..afcd4379 100644 --- a/documentation/api/provider.v6.provider_api.md +++ b/documentation/api/th2.data_services.interfaces.utils.md @@ -1,15 +1,15 @@ - + -# module `provider.v6.provider_api` +# module `th2_data_services.interfaces.utils` **Global Variables** --------------- -- **grpc**: # Copyright 2022 Exactpro (Exactpro Systems Limited) +- **converter**: # Copyright 2023 Exactpro (Exactpro Systems Limited) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -23,7 +23,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -- **http**: # Copyright 2022 Exactpro (Exactpro Systems Limited) +- **resolver**: # Copyright 2023 Exactpro (Exactpro Systems Limited) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/documentation/api/th2.data_services.interfaces.utils.resolver.md b/documentation/api/th2.data_services.interfaces.utils.resolver.md new file mode 100644 index 00000000..6a215bd0 --- /dev/null +++ b/documentation/api/th2.data_services.interfaces.utils.resolver.md @@ -0,0 +1,378 @@ + + + + +# module `th2_data_services.interfaces.utils.resolver` + + + + + + +--- + + + +## class `EventFieldResolver` + + + + + + + +--- + + + +### method `get_attached_messages_ids` + +```python +get_attached_messages_ids(event) +``` + + + + + +--- + + + +### method `get_batch_id` + +```python +get_batch_id(event) +``` + + + + + +--- + + + +### method `get_body` + +```python +get_body(event) +``` + + + + + +--- + + + +### method `get_end_timestamp` + +```python +get_end_timestamp(event) +``` + + + + + +--- + + + +### method `get_id` + +```python +get_id(event) +``` + + + + + +--- + + + +### method `get_is_batched` + +```python +get_is_batched(event) +``` + + + + + +--- + + + +### method `get_name` + +```python +get_name(event) +``` + + + + + +--- + + + +### method `get_parent_id` + +```python +get_parent_id(event) +``` + + + + + +--- + + + +### method `get_start_timestamp` + +```python +get_start_timestamp(event) +``` + + + + + +--- + + + +### method `get_status` + +```python +get_status(event) +``` + + + + + +--- + + + +### method `get_type` + +```python +get_type(event) +``` + + + + + + +--- + + + +## class `MessageFieldResolver` + + + + + + + +--- + + + +### method `get_attached_event_ids` + +```python +get_attached_event_ids(message) +``` + + + + + +--- + + + +### method `get_body` + +```python +get_body(message) +``` + + + + + +--- + + + +### method `get_body_base64` + +```python +get_body_base64(message) +``` + + + + + +--- + + + +### method `get_connection_id` + +```python +get_connection_id(message) +``` + + + + + +--- + + + +### method `get_direction` + +```python +get_direction(message) +``` + + + + + +--- + + + +### method `get_fields` + +```python +get_fields(message) +``` + + + + + +--- + + + +### method `get_id` + +```python +get_id(message) +``` + + + + + +--- + + + +### method `get_sequence` + +```python +get_sequence(message) +``` + + + + + +--- + + + +### method `get_session_alias` + +```python +get_session_alias(message) +``` + + + + + +--- + + + +### method `get_session_id` + +```python +get_session_id(message) +``` + + + + + +--- + + + +### method `get_subsequence` + +```python +get_subsequence(message) +``` + + + + + +--- + + + +### method `get_timestamp` + +```python +get_timestamp(message) +``` + + + + + +--- + + + +### method `get_type` + +```python +get_type(message) +``` + + + + + + + + +--- + +_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/th2_gui_report.md b/documentation/api/th2_gui_report.md deleted file mode 100644 index 4e7ab6fd..00000000 --- a/documentation/api/th2_gui_report.md +++ /dev/null @@ -1,89 +0,0 @@ - - - - -# module `th2_gui_report` - - - - - - ---- - - - -## class `Th2GUIReport` -Class for creating gui link by event ID or message ID. - - - -### method `__init__` - -```python -__init__(provider_link: str) -``` - -Th2GUIReport constructor. - - - -**Args:** - - - `provider_link` (str): link to provider. - - - - ---- - - - -### method `get_event_link` - -```python -get_event_link(event_id: str) → str -``` - -Creates the link with event id. - - - -**Args:** - - - `event_id` (str): id for adding in link. - - - -**Returns:** - GUI link to event. - ---- - - - -### method `get_message_link` - -```python -get_message_link(message_id: str) → str -``` - -Creates the link with message id. - - - -**Args:** - - - `message_id` (str): id for adding in link. - - - -**Returns:** - GUI link to message. - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/utils.converters.md b/documentation/api/utils.converters.md deleted file mode 100644 index 2ba1dda5..00000000 --- a/documentation/api/utils.converters.md +++ /dev/null @@ -1,45 +0,0 @@ - - - - -# module `utils.converters` - - - - - - ---- - - - -## class `DatetimeStringConverter` -Converts datetime strings. - -If you request microseconds but your timestamp has nanoseconds, they will be just cut (not rounding). - -Expected timestamp format "yyyy-MM-ddTHH:mm:ss[.SSSSSSSSS]Z". - - - - ---- - - - -### classmethod `parse_timestamp` - -```python -parse_timestamp(datetime_string: str) → (, ) -``` - - - - - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/api/utils.md b/documentation/api/utils.md deleted file mode 100644 index 693fe4ed..00000000 --- a/documentation/api/utils.md +++ /dev/null @@ -1,16 +0,0 @@ - - - - -# module `utils` - - - - - - - - ---- - -_This file was automatically generated via [lazydocs](https://github.com/ml-tooling/lazydocs)._ diff --git a/documentation/datasource.md b/documentation/datasource.md new file mode 100644 index 00000000..b7d3ad41 --- /dev/null +++ b/documentation/datasource.md @@ -0,0 +1,90 @@ +# How to develop DataSource implementation +## Features +Technically we only need `SourceAPI` for fully functional data source. +It fetches us data from some kind of database. +`SourceAPI` is a class that provide API for some _data source_. + +But we can have other components that simplify repetitive tasks: +- **DataSource** - object storing or utilizing every other component in one way or other +- **Commands** - collection of pre-made command classes that use `SourceAPI`'s requests to return refined data +- **Adapters** - classes/methods that allow objects with one interface to convert to another + +All of these classes are inheriting from [th2 core interfaces](https://github.com/th2-net/th2-data-services/tree/master/th2_data_services/interfaces). +Now let's go over basic ideas on how to create them: + +## DataSource +`DataSource` is the main component which ties together everything from gathering data to processing it, so that the processed data has the interface we need. + +`DataSource` is an intermediate link between the `SourceAPI` and `Commands`. +It's the place where you initialize everything in the correct way, check the connection +and do all preparatory work. + +```python +class DataSource(IDataSource): + def init(self,source_address, *other_args): + self.api = SourceAPI(source_address) + ... + + def command(self, cmd: ICommand): + return cmd.handle(data_source=self.api) +``` + +You can manually process the data using raw data from `SourceAPI`, but to simplify this process +we usually use _command_ interface. +The _command_ method takes in a pre-made custom command object then runs it and returns processed data. + +## SourceAPI +How `SourceAPI` will be structured might be different based on your needs. + +The `ISourceAPI` interface does not restrict the contents of this class in any way. +The key idea is that the class should repeat the API of the original source as much as possible. + +To a greater extent, this is necessary so that the IDE tells you what parameters +the source API has and does not have to look for it in the source documentation every time. + +It can have any methods that you need. E.g.: + +```python +class SourceAPI(ISourceAPI): + def init(self, source_address): + self.source_address = source_address + ... + + def get_item(self): + ... +``` +Basically `SourceAPI` connects to _data source_ and reads/requests the data from it. + +## Adapters +Adapters handle converting interface of one type to another. + +```python +class AdapterFromXtoY(IAdapter): + def handle(self, X): + Y = # Implementation based on what X and Y are + return Y +``` + +## Commands + +`Commands` are a great way to call `SourceAPI` methods indirectly and utilizing raw data to return more meaningful data. + +Let's take an example of a command that finds an element in data by its ID. + +```python +class GetItemByID(ICommand): + def __init__(self, id): + self.id = id + self.adapter = AdapterFromXtoY() + + def handle(self, data_source: DataSource): + api: SourceAPI = data_source.api + item = api.get_item(id) + # If data's type is not something we want we can update it. + data = some_processing_with_item(item) + # E.g. we can apply adapters. + data = self.adapter.handle(data) + + return data +``` +This way we can create many `Commands` that we can reuse and in the long term is better than using `SourceAPI`'s basic methods to get data. diff --git a/documentation/frequencies.md b/documentation/frequencies.md new file mode 100644 index 00000000..c5e5ab4d --- /dev/null +++ b/documentation/frequencies.md @@ -0,0 +1,27 @@ +# get_category_frequencies + +get_category_frequencies is a function that takes in data of messages and events and returns a table, where data is aggregated in rows based on their timestamp and grouped in column based on categorizer function we provide. Timestamp aggregation logic is defined by 3 arguements: aggregation_level, gap_mode and zero_anchor. While aggregation_level is pretty self-explanatory as it just defines the range of aggregation, gap_mode and zero_anchor are a bit tricky. + +## gap_mode + +![image](./img/gap_mode.png) + +## zero_anchor + +When zero_anchor=True timestamp anchor script uses is set to 0. This means that every range is 0 + some integer * aggregation_level and anchor is not some message's/event's timestamp from our data. For this reason it's better using zero_anchor=True and gap_mode=1 raises exception as we might get unexpected results. + +## Example - zero_anchor = False + +![image](./img/example_zero_anchor_false.png) + +We can see that gap_mode=1 doesn't have equal distances between its ranges. Its range always start with existing timestamp in message or event. +gap_mode=2 and gap_mode=3 always have equal distances, meaning for example: If first range started on 2023-04-23 23:50:24, other ranges will be this timestamp + aggregation_level * some integer. +gap_mode=3 just adds empty ranges in between the ranges with value in it. + + +## Example - zero_anchor = True + +![image](./img/example_zero_anchor_true.png) + +As said before using gap_mode=1 with zero_anchor will raise exception. +For gap_mode=2 and 3 we see that first range doesn't start with existing timestamp from data, but rather a value that is divisible by aggregation_level. diff --git a/documentation/img/example_zero_anchor_false.png b/documentation/img/example_zero_anchor_false.png new file mode 100644 index 00000000..01c6aed5 Binary files /dev/null and b/documentation/img/example_zero_anchor_false.png differ diff --git a/documentation/img/example_zero_anchor_true.png b/documentation/img/example_zero_anchor_true.png new file mode 100644 index 00000000..f55608fa Binary files /dev/null and b/documentation/img/example_zero_anchor_true.png differ diff --git a/documentation/img/gap_mode.png b/documentation/img/gap_mode.png new file mode 100644 index 00000000..577083f7 Binary files /dev/null and b/documentation/img/gap_mode.png differ diff --git a/examples/get_started_example.py b/examples/get_started_example.py index b132ac99..aed714d5 100644 --- a/examples/get_started_example.py +++ b/examples/get_started_example.py @@ -1,207 +1,369 @@ -from collections import Generator -from typing import Tuple, List, Optional +from typing import Tuple, List, Optional, Generator from datetime import datetime -from th2_data_services import Data -from th2_data_services.events_tree import EventsTree -from th2_data_services.provider.v5.data_source.http import HTTPProvider5DataSource -from th2_data_services.provider.v5.commands import http as commands -from th2_data_services.provider.v5.events_tree import EventsTreeCollectionProvider5, ParentEventsTreeCollectionProvider5 -from th2_data_services.provider.v5.filters.event_filters import NameFilter, TypeFilter, FailedStatusFilter -from th2_data_services.provider.v5.filters.message_filters import BodyFilter +from th2_data_services.data import Data +from th2_data_services.dummy import DummyDataSource +from th2_data_services.event_tree import ( + EventTree, + EventTreeCollection, + ParentEventTreeCollection, + IETCDriver, +) +from th2_data_services.interfaces import IDataSource +from th2_data_services.utils.converters import ( + DatetimeConverter, + DatetimeStringConverter, + ProtobufTimestampConverter, + Th2TimestampConverter, +) +###################################### # [0] Lib configuration +###################################### + # [0.1] Interactive or Script mode # If you use the lib in interactive mode (jupyter, ipython) it's recommended to set the special # global parameter to True. It'll keep cache files if something went wrong. -import th2_data_services - -th2_data_services.INTERACTIVE_MODE = True - -# [0.2] Logging -# Import helper function to setup logging. -from th2_data_services import add_stderr_logger, add_file_logger - -add_stderr_logger() # Just execute it to activate DS lib logging. Debug level by default. -# or if you want to put logs to the file -add_file_logger() - -# [1] Create DataSource object to connect to rpt-data-provider. -DEMO_HOST = "10.100.66.66" # th2-kube-demo Host port where rpt-data-provider is located. -DEMO_PORT = "30999" # Node port of rpt-data-provider. -data_source = HTTPProvider5DataSource(f"http://{DEMO_HOST}:{DEMO_PORT}") - -START_TIME = datetime( - year=2021, month=6, day=17, hour=9, minute=44, second=41, microsecond=692724 -) # Datetime in utc format. -END_TIME = datetime(year=2021, month=6, day=17, hour=12, minute=45, second=50) - -# [2] Get events or messages from START_TIME to END_TIME. -# [2.1] Get events. -events: Data = data_source.command( - commands.GetEvents( - start_timestamp=START_TIME, - end_timestamp=END_TIME, - attached_messages=True, - # Use Filter class to apply rpt-data-provider filters. - # Do not use multiple classes of the same type. - filters=[ - TypeFilter("Send message"), - NameFilter(["ExecutionReport", "NewOrderSingle"]), # You can use multiple values. - FailedStatusFilter(), - ], - ) +from th2_data_services.config import options + +options.INTERACTIVE_MODE = True + +# Some example data +events = Data( + [ + { + "eventId": "demo_book_1:th2-scope:20230105135705560873000:d61e930a-8d00-11ed-aa1a-d34a6155152d_1", + "batchId": None, + "isBatched": False, + "eventName": "Set of auto-generated events for ds lib testing", + "eventType": "ds-lib-test-event", + "endTimestamp": {"epochSecond": 1672927025, "nano": 561751000}, + "startTimestamp": {"epochSecond": 1672927025, "nano": 560873000}, + "parentEventId": None, + "successful": True, + "bookId": "demo_book_1", + "scope": "th2-scope", + "attachedMessageIds": [], + "body": [], + }, + { + "eventId": "demo_book_1:th2-scope:20230105135705563522000:9adbb3e0-5f8b-4c28-a2ac-7361e8fa704c>demo_book_1:th2-scope:20230105135705563522000:d61e930a-8d00-11ed-aa1a-d34a6155152d_2", + "batchId": "demo_book_1:th2-scope:20230105135705563522000:9adbb3e0-5f8b-4c28-a2ac-7361e8fa704c", + "isBatched": True, + "eventName": "Plain event 1", + "eventType": "ds-lib-test-event", + "endTimestamp": {"epochSecond": 1672927025, "nano": 563640000}, + "startTimestamp": {"epochSecond": 1672927025, "nano": 563522000}, + "parentEventId": "demo_book_1:th2-scope:20230105135705560873000:d61e930a-8d00-11ed-aa1a-d34a6155152d_1", + "successful": True, + "bookId": "demo_book_1", + "scope": "th2-scope", + "attachedMessageIds": [], + "body": {"type": "message", "data": "ds-lib test body"}, + }, + { + "eventId": "demo_book_1:th2-scope:20230105135705563522000:9adbb3e0-5f8b-4c28-a2ac-7361e8fa704c>demo_book_1:th2-scope:20230105135705563757000:d61e930a-8d00-11ed-aa1a-d34a6155152d_3", + "batchId": "demo_book_1:th2-scope:20230105135705563522000:9adbb3e0-5f8b-4c28-a2ac-7361e8fa704c", + "isBatched": True, + "eventName": "Plain event 2", + "eventType": "ds-lib-test-event", + "endTimestamp": {"epochSecond": 1672927025, "nano": 563791000}, + "startTimestamp": {"epochSecond": 1672927025, "nano": 563757000}, + "parentEventId": "demo_book_1:th2-scope:20230105135705560873000:d61e930a-8d00-11ed-aa1a-d34a6155152d_1", + "successful": True, + "bookId": "demo_book_1", + "scope": "th2-scope", + "attachedMessageIds": [], + "body": {"type": "message", "data": "ds-lib test body"}, + }, + { + "eventId": "fake-eventId", + "batchId": "fake-batchId", + "isBatched": True, + "eventName": "Fake event", + "eventType": "ds-lib-test-event", + "endTimestamp": {"epochSecond": 1672927035, "nano": 563791000}, + "startTimestamp": {"epochSecond": 1672927325, "nano": 563757000}, + "parentEventId": "not_exists_in_the_events_stream", + "successful": False, + "bookId": "demo_book_1", + "scope": "th2-scope", + "attachedMessageIds": [], + "body": {"type": "message", "data": "ds-lib test body"}, + }, + ] ) -# [2.2] Get messages. -messages: Data = data_source.command( - commands.GetMessages( - start_timestamp=START_TIME, - end_timestamp=END_TIME, - attached_events=True, - stream=["demo-conn2"], - filters=BodyFilter("195"), # Filter message if there is a substring '195' in the body. - ) -) +###################################### +# [1] Working with a Data object. +###################################### -# [3] Work with a Data object. -# [3.1] Filter. +# [1.1] Filter. filtered_events: Data = events.filter(lambda e: e["body"] != []) # Filter events with empty body. -# [3.2] Map. +# [1.2] Map. def transform_function(record): return {"eventName": record["eventName"], "successful": record["successful"]} filtered_and_mapped_events = filtered_events.map(transform_function) -# [3.3] Data pipeline. +# [1.3] Data pipeline. # Instead of doing data transformations step by step you can do it in one line. -filtered_and_mapped_events_by_pipeline = events.filter(lambda e: e["body"] != []).map(transform_function) - +filtered_and_mapped_events_by_pipeline = events.filter(lambda e: e["body"] != []).map( + transform_function +) # Content of these two Data objects should be equal. assert list(filtered_and_mapped_events) == list(filtered_and_mapped_events_by_pipeline) -# [3.4] Sift. Skip the first few items or limit them. -events_from_11_to_end: Generator = events.sift(skip=10) -only_first_10_events: Generator = events.sift(limit=10) +# [1.4] Sift. Skip the first few items or limit them. +data = Data([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]) +items_from_11_to_end: Generator = data.sift(skip=10) +only_first_10_items: Generator = data.sift(limit=10) -# [3.5] Changing cache status. +# [1.5] Changing cache status. events.use_cache(True) # or just -events.use_cache() - -# [3.6] Walk through data. +events.use_cache() # If you want to activate cache. +# [1.6] Walk through data. for event in events: # Do something with event (event is a dict). print(event) # After first iteration the events has a cache file. -# Now they will be used the cache in following iteration. +# Now they will be used in the cache in the next iteration. -# [3.7] Get number of the elements in the Data object. +# [1.7] Get number of the elements in the Data object. number_of_events = events.len -# [3.8] Check that Data object isn't empty. +# [1.8] Check that Data object isn't empty. # The data source should be not empty. assert events.is_empty is False -# [3.9] Convert Data object to the list of elements(events or messages). +# [1.9] Convert Data object to the list of elements(events or messages). # Be careful, this can take too much memory. events_list = list(events) -# [3.10] Get event/message by id. -desired_event = "9ce8a2ff-d600-4366-9aba-2082cfc69901:ef1d722e-cf5e-11eb-bcd0-ced60009573f" -desired_events = [ - "deea079b-4235-4421-abf6-6a3ac1d04c76:ef1d3a20-cf5e-11eb-bcd0-ced60009573f", - "a34e3cb4-c635-4a90-8f42-37dd984209cb:ef1c5cea-cf5e-11eb-bcd0-ced60009573f", -] -desired_message = "demo-conn1:first:1619506157132265837" -desired_messages = [ - "demo-conn1:first:1619506157132265836", - "demo-conn1:first:1619506157132265833", -] - -data_source.command(commands.GetEventById(desired_event)) # Returns 1 event (dict). -data_source.command(commands.GetEventsById(desired_events)) # Returns 2 events list(dict). - -data_source.command(commands.GetMessageById(desired_message)) # Returns 1 message (dict). -data_source.command(commands.GetMessagesById(desired_messages)) # Returns 2 messages list(dict). - -# [3.11] The cache inheritance. +# [1.10] The cache inheritance. # Creates a new Data object that will use cache from the events Data object. -events_with_batch = events.filter(lambda record: record.get("batchId")) +events_filtered: Data = events.filter(lambda record: record.get("batchId")) # New Data objects don't use their own cache by default but use the cache of the parent Data object. -# Use use_cache method to activate caching. After that, the Data object will create its own cache file. -events_with_batch.use_cache(True) +# Use use_cache method to activate caching. +# After that, the Data object will create its own cache file. +events_filtered.use_cache() -list(events_with_batch) +list(events_filtered) # Just to iterate Data object (cache file will be created). -events_types_with_batch = events_with_batch.map(lambda record: {"eventType": record.get("eventType")}) +filtered_events_types = events_filtered.map(lambda record: {"eventType": record.get("eventType")}) -events_without_types_with_batch = events_types_with_batch.filter(lambda record: not record.get("eventType")) -events_without_types_with_batch.use_cache(True) +events_without_types_with_batch = filtered_events_types.filter( + lambda record: not record.get("eventType") +) +events_without_types_with_batch.use_cache() -# [3.12] Data objects joining. +# [1.11] Data objects joining. # You have the following 3 Data objects. d1 = Data([1, 2, 3]) d2 = Data(["a", {"id": 123}, "c"]) d3 = Data([7, 8, 9]) # You can join Data objects in following ways. +# Please note, new Data object will have cache status == False. data_via_init = Data([d1, d2, d3]) data_via_add = d1 + d2 + d3 data_with_non_data_obj_via_init = Data([d1, ["a", {"id": 123}, "c"], d3]) data_with_non_data_obj_via_add = d1 + ["a", {"id": 123}, "c"] + d3 +# You can join current Data object on place using +=. +# It will keep cache status. +d1 += d3 # d1 will become Data([1,2,3,7,8,9]) + +# [1.12] Build and read Data object cache files. +events.build_cache("cache_filename_or_path") +data_obj_from_cache = Data.from_cache_file("cache_filename_or_path") + +# [1.13] Check if Data is sorted. +# That will return an object `is_sorted` that contains information +# 1. status -- sorted or not +# 2. first_unsorted -- the index of the first unsorted element +is_sorted = events.is_sorted(lambda e: e["startTimestamp"]["epochSecond"]) + +# You can use this object as usual bool variable. +if is_sorted: + print("events Data obj is sorted!") + +# [1.14] Use `Data.show()` to look at the first N messages in the stream. +data_with_non_data_obj_via_add.show(n=6) +# Will print +# ------------- Printed first 6 records ------------- +# [1] ------ +# 1 +# [2] ------ +# 2 +# [3] ------ +# 3 +# [4] ------ +# 'a' +# [5] ------ +# {'id': 123} +# [6] ------ +# 'c' + +# [1.15] You can remove the cache file of the Data object, if required. +data_obj_from_cache.clear_cache() + + +# [1.16] Get the message by its ID from the Data object in one line. +msg = next(data_obj_from_cache.find_by(record_field="MessageId", field_values=["msg-id"])) + +# [1.17] Update metadata for Data objects. +# d1.metadata - {} +d1.update_metadata({"a": 1, "b": [10], "c": {"a": 100}}) +# d1.metadata - {'a': 1, 'b': [10], 'c': {'a': 100}} +d1.update_metadata({"a": 2, "b": 20, "c": {"a": 200, "b": 300}}) +# d1.metadata - {'a': 2, 'b': [10, 20], 'c': {'a': 200, 'b': 300}} +# d1.update_metadata({"a": {}}) - This throws AttributeError: 'int' object has no attribute 'update'. +# To set key whose value is of non-dict type to dict we can use change_type="change" argument. +d1.update_metadata({"a": {}}, change_type="change") +# d1.metadata - {'a': {}, 'b': [10, 20], 'c': {'a': 200, 'b': 300}} +# change_type can be either 'update' (default) or 'change' - overwrite existing value or create a new one if it +# doesn't exist. + +###################################### +# [2] Working with converters. +###################################### +# There are currently three implementations of ITimestampConverter class: DatetimeConverte, DatetimeStringConverter and ProtobufTimestampConverter. +# They all implement same methods from base class. +# Note that some accuracy may be lost during conversion. +# If for example you use to_microseconds nanoseconds will be cut off instead of rounding. + +# [2.1] DatetimeConverter. +# DatetimeConverter takes datetime.datetime object as input. + +datetime_obj = datetime(year=2023, month=1, day=5, hour=14, minute=38, second=25, microsecond=1460) + +# It has methods that return the datetime in different formas: + +date_ms = DatetimeConverter.to_milliseconds(datetime_obj) +date_us = DatetimeConverter.to_microseconds(datetime_obj) +# Converting to nanoseconds justs adds three trailing zeros as datetime object doesn't have nanoseconds. +date_ns = DatetimeConverter.to_nanoseconds(datetime_obj) + +# [2.2] DatetimeStringConverter +# DatetimeStringConverter takes string in "yyyy-MM-ddTHH:mm:ss[.SSSSSSSSS]Z" format. + +date_string = "2023-01-05T14:38:25.00146Z" + +# We have same methods as in DatetimeConverter +date_ms_from_string = DatetimeStringConverter.to_milliseconds(date_string) +date_us_from_string = DatetimeStringConverter.to_microseconds(date_string) +date_ns_from_string = DatetimeStringConverter.to_nanoseconds(date_string) + +# We can also get datetime object from string +datetime_from_string = DatetimeStringConverter.to_datetime(date_string) + +# [2.3] ProtobufTimestampConverter +# Protobuf timestamps must be in form {"epochSecond": seconds, "nano": nanoseconds} + +protobuf_timestamp = {"epochSecond": 1672929505, "nano": 1_460_000} + +date_ms_from_timestamp = ProtobufTimestampConverter.to_milliseconds(protobuf_timestamp) +date_us_from_timestamp = ProtobufTimestampConverter.to_microseconds(protobuf_timestamp) +date_ns_from_timestamp = ProtobufTimestampConverter.to_nanoseconds(protobuf_timestamp) +datetime_from_timestamp = ProtobufTimestampConverter.to_datetime(protobuf_timestamp) + +###################################### +# [3] Working with EventTree and EventTreeCollection. +###################################### +# Can be useful if you have data-stream with < 100k elements, otherwise it +# takes too much RAM. + +# [3.1] Build a custom EventTree +# To create an EventTree object you need to provide name, id and data of the root event. +tree = EventTree(event_name="root event", event_id="root_id", data={"data": [1, 2, 3, 4, 5]}) + +# To add new node use append_event. parent_id is necessary, data is optional. +tree.append_event(event_name="A", event_id="A_id", data=None, parent_id="root_id") + +# [3.3] Building the EventTreeCollection. +data_source: IDataSource # You should init DataSource object. E.g. from LwDP module. +data_source = DummyDataSource() # Note! We use fake DS here. +# ETCDriver here is a stub, actually the lib doesn't have such a class. +# You can take it in LwDP module or create yourself class if you have some special events structure. +from th2_data_services.data_source.lwdp.event_tree import HttpETCDriver as ETCDriver + +# If you don't specify data_source for the driver then it won't recover detached events. +driver: IETCDriver # You should init ETCDriver object. E.g. from LwDP module or your custom class. +driver = ETCDriver(data_source=data_source, use_stub=True) + +etc = EventTreeCollection(driver) +etc.build(events) +etc.show() +# It'll print the following: +# Set of auto-generated events for ds lib testing +# ├── Plain event 1 +# └── Plain event 2 + +print(etc) +# EventTreeCollection(trees=1, events=3[trees=3, detached=0]) -# [4] Working with EventsTree and EventsTreeCollection. -# [4.1] Building the EventsTreeCollection. +# Detached events isn't empty. +assert etc.get_detached_events() # returns list of detached_events. -# If you don't specify data_source for the tree then it won't recover detached events. -collection = EventsTreeCollectionProvider5(events) +# recover_unknown_events -- used to recover some events parents. +# That won't work with DummyDataSource, so was commented +# etc.recover_unknown_events() -# Detached events isn't empty. -assert collection.detached_events +# After that the detached events should be empty because they were recovered. +# assert not etc.get_detached_events() -collection = EventsTreeCollectionProvider5(events, data_source=data_source) -# Detached events are empty because they were recovered. -assert not collection.detached_events +# ----- -# The collection has EventsTrees each with a tree of events. -# Using Collection and EventsTrees, you can work flexibly with events. +# The collection has EventTrees each with a tree of events. +# Using Collection and EventTrees, you can work flexibly with events. -# [4.1.1] Get leaves of all trees. -leaves: Tuple[dict] = collection.get_leaves() +# [3.3.1] Get leaves of all trees. +leaves: Tuple[dict] = etc.get_leaves() # Returns a tuple of leaves events -# [4.1.2] Get roots ids of all trees. -roots: List[str] = collection.get_roots_ids() +# [3.3.2] Get roots ids of all trees. +roots: List[str] = etc.get_roots_ids() +# Returns the list of root Ids: +# ['demo_book_1:th2-scope:20230105135705560873000:d61e930a-8d00-11ed-aa1a-d34a6155152d_1'] -# [4.1.3] Find an event in all trees. -find_event: Optional[dict] = collection.find(lambda event: "Send message" in event["eventType"]) +# [3.3.3] Find an event in all trees. +find_event: Optional[dict] = etc.find(lambda event: "Send message" in event["eventType"]) -# [4.1.4] Find all events in all trees. There is also iterable version 'findall_iter'. -find_events: List[dict] = collection.findall(lambda event: event["successful"] is True) +# [3.3.4] Find all events in all trees. There is also iterable version 'findall_iter'. +find_events: List[dict] = etc.findall(lambda event: event["successful"] is True) -# [4.1.5] Find an ancestor of the event. -ancestor: Optional[dict] = collection.find_ancestor( - "8bbe3717-cf59-11eb-a3f7-094f904c3a62", filter=lambda event: "RootEvent" in event["eventName"] +# [3.3.5] Find an ancestor of the event. +ancestor: Optional[dict] = etc.find_ancestor( + "demo_book_1:th2-scope:20230105135705560873000:d61e930a-8d00-11ed-aa1a-d34a6155152d_1", + filter=lambda event: "RootEvent" in event["eventName"], ) -# [4.1.6] Get children of the event. There is also iterable version 'get_children_iter'. -children: Tuple[dict] = collection.get_children("814422e1-9c68-11eb-8598-691ebd7f413d") +# [3.3.6] Get children of the event. There is also iterable version 'get_children_iter'. +children: Tuple[dict] = etc.get_children( + "demo_book_1:th2-scope:20230105135705560873000:d61e930a-8d00-11ed-aa1a-d34a6155152d_1" +) -# [4.1.7] Get subtree for specified event. -subtree: EventsTree = collection.get_subtree("8e23774d-cf59-11eb-a6e3-55bfdb2b3f21") +# [3.3.7] Get subtree for specified event. +subtree: EventTree = etc.get_subtree( + "demo_book_1:th2-scope:20230105135705560873000:d61e930a-8d00-11ed-aa1a-d34a6155152d_1" +) -# [4.1.8] Get full path to the event. +# [3.3.8] Get full path to the event. # Looks like [ancestor_root, ancestor_level1, ancestor_level2, event] -event_path: List[dict] = collection.get_full_path("8e2524fa-cf59-11eb-a3f7-094f904c3a62") +event_path: List[dict] = etc.get_full_path( + "demo_book_1:th2-scope:20230105135705560873000:d61e930a-8d00-11ed-aa1a-d34a6155152d_1" +) -# [4.1.9] Get parent of the event. -parent = collection.get_parent("8e2524fa-cf59-11eb-a3f7-094f904c3a62") +# [3.3.9] Get parent of the event. +parent = etc.get_parent( + "demo_book_1:th2-scope:20230105135705560873000:d61e930a-8d00-11ed-aa1a-d34a6155152d_1" +) -# [4.1.10] Append new event to the collection. -collection.append_event( +# [3.3.10] Append new event to the collection. +etc.append_event( event={ "eventId": "a20f5ef4-c3fe-bb10-a29c-dd3d784909eb", "parentEventId": "8e2524fa-cf59-11eb-a3f7-094f904c3a62", @@ -209,25 +371,161 @@ def transform_function(record): } ) -# [4.1.11] Show the entire collection. -collection.show() - -# [4.2] Working with the EventsTree. -# EventsTree has the same methods as EventsTreeCollection, but only for its own tree. - -# [4.2.1] Get collection trees. -trees: List[EventsTree] = collection.get_trees() -tree: EventsTree = trees[0] - -# But EventsTree provides a work with the tree, but does not modify it. -# If you want to modify the tree, use EventsTreeCollections. - -# [4.3] Working with ParentlessTree. -# ParentlessTree is EventsTree which has detached events with stubs. -parentless_trees: List[EventsTree] = collection.get_parentless_trees() - -# [4.4] Working with ParentEventsTreeCollection. -# ParentEventsTreeCollection is a tree like EventsTreeCollection but it has only events that have references. -collection = ParentEventsTreeCollectionProvider5(events, data_source=data_source) - -collection.show() +# [3.3.11] Show the entire collection. +etc.show() +# It'll print the following: +# Set of auto-generated events for ds lib testing +# ├── Plain event 1 +# └── Plain event 2 + +# As you can see, nothing was changed, but we added the new event! +# let's look at the summary. + +print(etc.summary()) # the same as just print(etc) +# EventTreeCollection(trees=1, events=5[trees=3, detached=2]) +# You can see that it was added to detached. That's why you don't see the event +# via `show()`. `show()` prints only Trees! +# Use `etc.get_parentless_trees()` to convert detached events to trees. +# More information below in the corresponding section. + +# -------------- +# [3.4] Working with the EventTree. +# EventTree has the same methods as EventTreeCollection, but only for its own tree. + +# [3.4.1] Get a collection of trees. +trees: List[EventTree] = etc.get_trees() +tree: EventTree = trees[0] + +# But EventTree provides a work with the tree, but does not modify it. +# If you want to modify the tree, use EventTreeCollections. + +# [3.5] Working with ParentlessTree. +# ParentlessTree is an EventTree that has detached events with stubs. +parentless_trees: List[EventTree] = etc.get_parentless_trees() +print("parentless_trees contains:") +print(parentless_trees) +# [EventTree(name='', root_id='not_exists_in_the_events_stream', events=2), +# EventTree(name='', root_id='8e2524fa-cf59-11eb-a3f7-094f904c3a62', events=2)] + +print("\n" "etc after `get_parentless_trees`:") +print(etc.summary()) +# EventTreeCollection(trees=3[regular=1, parentless=2], events=7[trees=7, detached=0])' +etc.show() +# Set of auto-generated events for ds lib testing +# ├── Plain event 1 +# └── Plain event 2 +# +# └── Fake event +# +# └── StubEvent <--- the event that was added above + +# [3.6] Working with ParentEventTreeCollection. +# ParentEventTreeCollection is a tree collection like EventTreeCollection, +# but it has only events that have references. +data_source: IDataSource # You should init DataSource object. E.g. from LwDP module. +data_source = DummyDataSource() # Note! We use fake DS here. +# ETCDriver here is a stub, actually the lib doesn't have such a class. +# You can take it in LwDP module or create yourself class if you have some special events structure. +from th2_data_services.data_source.lwdp.event_tree import HttpETCDriver as ETCDriver + +driver = ETCDriver(data_source=data_source) +petc = ParentEventTreeCollection(driver) +petc.build(events) + +petc.show() +petc.summary() + +###################################### +# [4] Field Resolvers +###################################### +# Please read `Field Resolvers` block in readme first. + +# [4.1] Usage example from client code +from th2_data_services.data_source import ( + lwdp, +) # lwdp data_source initialize th2_data_services.config during import. +from th2_data_services.config import options as o_ +from th2_data_services.data_source.lwdp.stub_builder import http_message_stub_builder + +fake_data = [ + http_message_stub_builder.build({"messageId": "a", "messageType": "Root"}), + http_message_stub_builder.build({"messageId": "b", "messageType": "New"}), + http_message_stub_builder.build({"messageId": "c", "messageType": "Amend"}), + http_message_stub_builder.build({"messageId": "d", "messageType": "Cancel"}), +] +fake_data_obj = Data(fake_data) + +for m in fake_data_obj: + o_.mfr.expand_message(m) # mfr - stands for MessageFieldResolver +# or +for m in fake_data_obj.map(o_.mfr.expand_message): + pass + +# [4.2] Libraries usage. +# Don't import exact resolvers implementation in your code, please. +# Allow your client to do it instead. +# Just import `options` from `th2_data_services.config` and use it. +from th2_data_services.config import options as o_ + +for m in fake_data_obj: + o_.mfr.expand_message(m) +# or +for m in fake_data_obj.map(o_.mfr.expand_message): + pass + +# More tech details: +# In this case, there is no line `from th2_data_services.data_source import lwdp ` +# because we should not choose for the user which a data source to use. +# We do not know what he will choose, therefore, we must simply access +# the interface, which will be initialized by the user. + +###################################### +# [5] Using utility functions. +###################################### +from th2_data_services.utils.event_utils.frequencies import get_category_frequencies2 +from th2_data_services.utils.event_utils.totals import get_category_totals2 +from th2_data_services.utils.category import Category +from th2_data_services.utils.event_utils.event_utils import is_sorted + +# [5.1] Get the quantities of events for different categories. +metrics = [ + Category("date", lambda m: Th2TimestampConverter.to_datetime(m["startTimestamp"]).date()), + Category("status", lambda m: m["successful"]), +] +category_totals = get_category_totals2(events, metrics) +print(category_totals) +""" ++--------+------------+----------+---------+ +| | date | status | count | ++========+============+==========+=========+ +| | 2023-01-05 | True | 3 | ++--------+------------+----------+---------+ +| | 2023-01-05 | False | 1 | ++--------+------------+----------+---------+ +| count | | | 2 | ++--------+------------+----------+---------+ +| totals | | 1/1 | 4 | ++--------+------------+----------+---------+ +""" + +# [5.2] Get the number of events with status successful. +category = Category("status", lambda m: m["successful"]) +category_frequencies = get_category_frequencies2(events, category) +print(category_frequencies) +""" ++--------+---------------------+---------------------+---------+--------+ +| | timestamp_start | timestamp_end | False | True | ++========+=====================+=====================+=========+========+ +| | 2023-01-05T13:57:05 | 2023-01-05T13:57:06 | 0 | 3 | ++--------+---------------------+---------------------+---------+--------+ +| | 2023-01-05T14:02:05 | 2023-01-05T14:02:06 | 1 | 0 | ++--------+---------------------+---------------------+---------+--------+ +| count | | | | 2 | ++--------+---------------------+---------------------+---------+--------+ +| totals | | | 1 | 3 | ++--------+---------------------+---------------------+---------+--------+ +""" + +# [5.3] Check if events are sorted. +result = is_sorted(events) +print(result) diff --git a/examples/notebooks/notebook_0.ipynb b/examples/notebooks/notebook_0.ipynb deleted file mode 100644 index d4632cb6..00000000 --- a/examples/notebooks/notebook_0.ipynb +++ /dev/null @@ -1,36756 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "5d1ba9e7", - "metadata": {}, - "source": [ - "# Notebook 0\n", - "It is a notebook which shows how use DataSource, Data and EventFamily" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "6928306a", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/tmp/ipykernel_282136/3855546854.py:3: DeprecationWarning: Importing display from IPython.core.display is deprecated since IPython 7.14, please import from IPython display\n", - " from IPython.core.display import display, HTML\n" - ] - }, - { - "data": { - "text/html": [ - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "import time\n", - "import pandas as pd\n", - "from IPython.core.display import display, HTML\n", - "from pprint import pprint\n", - "from datetime import datetime\n", - "from th2_data_services import Data\n", - "from th2_data_services.events_tree import EventsTree\n", - "from th2_data_services.provider.v5.data_source.http import HTTPProvider5DataSource\n", - "from th2_data_services.provider.v5.commands import http\n", - "from th2_data_services.filter import Filter\n", - "from th2_data_services.provider.v5.events_tree import EventsTreeCollectionProvider5, ParentEventsTreeCollectionProvider5\n", - "from pandas import DataFrame\n", - "\n", - "# This settings for increase display jupyter notebook and dataframe table.\n", - "display(HTML(\"\"))\n", - "pd.options.display.max_rows = 550\n", - "pd.set_option('display.expand_frame_repr', False)\n", - "pd.set_option('display.max_colwidth', 1000)" - ] - }, - { - "cell_type": "markdown", - "id": "5c933070", - "metadata": {}, - "source": [ - "### We set up interval for th2-rpt-data-provider" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "7690daca", - "metadata": {}, - "outputs": [], - "source": [ - "DEMO_HOST = \"10.64.66.66\" #\"th2-kube-demo\" # Host port where rpt-data-provider is located.\n", - "DEMO_PORT = \"30999\" # Node port of rpt-data-provider.\n", - "\n", - "# Create DataSource class with host and route.\n", - "# You can change host and route using propeties.\n", - "data_source = HTTPProvider5DataSource(F\"http://{DEMO_HOST}:{DEMO_PORT}\")\n", - "\n", - "# Note that DataSource exists for each version rpt-data-provider.\n", - "\n", - "START_TIME = datetime(year=2021, month=6, day=20, hour=10, minute=44, second=41, microsecond=692724)\n", - "END_TIME = datetime(year=2021, month=6, day=20, hour=10, minute=45, second=49, microsecond=28579)" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "2d2670a5", - "metadata": {}, - "outputs": [], - "source": [ - "# For understand which event type on based name we get from stream.\n", - "def get_super_type(record):\n", - " name = record.get(\"eventName\")\n", - " parent_id = record.get(\"parentEventId\")\n", - " super_type = record.get(\"eventType\")\n", - " if super_type:\n", - " if \"Recon\" in name:\n", - " super_type = \"Recon Folder\"\n", - " else:\n", - " if not parent_id:\n", - " super_type = \"Test Run\"\n", - " else:\n", - " parent_event = collection.get_parent(parent_id)\n", - " if parent_event:\n", - " parent_super_type = get_super_type(parent_event)\n", - " if parent_super_type == \"Test Run\":\n", - " super_type = \"Test Case\"\n", - " elif parent_super_type == \"Recon Folder\":\n", - " super_type = \"Recon Rule\"\n", - " elif parent_super_type == \"Recon Rule\":\n", - " super_type = \"Recon Status\"\n", - " elif parent_super_type == \"Recon Status\":\n", - " super_type = \"Recon Event\"\n", - "\n", - " return super_type\n", - "\n", - "# Base extract (transform function)\n", - "# record is required arguments.\n", - "def extract_basic(record):\n", - " new_object = {\n", - " \"super_type\": get_super_type(record),\n", - " \"status\": \"SUCCESSFUL\" if record.get(\"successful\") else \"FAILED\",\n", - " \"body\": record.get(\"body\"),\n", - " \"parentEventId\": record.get(\"parentEventId\"),\n", - " \"eventId\": record.get(\"eventId\"),\n", - " \"eventName\": record.get(\"eventName\"),\n", - " \"body\": record.get(\"body\")\n", - " }\n", - " return new_object\n", - "\n", - "# Checking ancestor (filter function)\n", - "# record is required arguments.\n", - "def is_test_case_ancestor(record):\n", - " ancestor = collection.find_ancestor(record.get(\"eventId\"), lambda record: \"TS\" in record.get(\"eventName\"))\n", - " if ancestor:\n", - " return True\n", - " return False" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "0f641896", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[INFO] The events have loaded.\n" - ] - } - ], - "source": [ - "# You can change anything GetEvents. \n", - "# Arguments gets based on route for th2-rpt-data-provider.\n", - "# This example shows pull the events.\n", - "events: Data = data_source.command(\n", - " http.GetEvents(\n", - " start_timestamp=START_TIME,\n", - " end_timestamp=END_TIME,\n", - " attached_messages=True,\n", - " cache=True\n", - " )\n", - ")\n", - "\n", - "print(\"[INFO] The events have loaded.\")" - ] - }, - { - "cell_type": "markdown", - "id": "f5abcc70", - "metadata": {}, - "source": [ - "### We build events tree for furtuher assistance\n", - "\n", - "We build a collection for further assistance:\n", - "* collection = EventsTreeCollection(data) \n", - "\n", - "We passed data_source for the collection therefore unknown_events is recovered\n", - "* collection = EventsTreeCollection(data, data_source=data_source)" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "b89754ae", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[INFO] The collection has built!\n" - ] - } - ], - "source": [ - "collection = EventsTreeCollectionProvider5(events, data_source=data_source)\n", - "\n", - "print(\"[INFO] The collection has built!\")" - ] - }, - { - "cell_type": "markdown", - "id": "25eb4c06", - "metadata": {}, - "source": [ - "Using method `show()` we print view tree." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "86cd05dd", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[TS_1]Aggressive IOC vs two orders: second order's price is lower than first\n", - "├── Case[TC_1.1]: Trader DEMO-CONN1 vs trader DEMO-CONN2 for instrument INSTR1\n", - "│ ├── Check sequence rule SessionKey{sessionAlias='demo-conn1', direction=FIRST} - STEP2: Trader \"DEMO-CONN1\" receives Execution Report. The order stands on book in status NEW\n", - "│ │ ├── Check messages\n", - "│ │ │ └── Verification 'ExecutionReport' message\n", - "│ │ ├── Check sequence (expected 1 / actual 1 , check order false)\n", - "│ │ └── Pre-filtering (filtered 1 / processed 1) messages\n", - "│ │ └── Verification 'ExecutionReport' message\n", - "│ ├── Check sequence rule SessionKey{sessionAlias='demo-conn1', direction=FIRST} - STEP4: Trader \"DEMO-CONN1\" receives Execution Report. The order stands on book in status NEW\n", - "│ │ ├── Check messages\n", - "│ │ │ └── Verification 'ExecutionReport' message\n", - "│ │ ├── Check sequence (expected 1 / actual 1 , check order false)\n", - "│ │ └── Pre-filtering (filtered 1 / processed 1) messages\n", - "│ │ └── Verification 'ExecutionReport' message\n", - "│ ├── Check sequence rule SessionKey{sessionAlias='demo-conn1', direction=FIRST} - STEP6: Trader \"DEMO-CONN1\" receives Execution Reports with ExecType=F: first at Order2 and second on Order1.\n", - "│ │ ├── Check messages\n", - "│ │ │ ├── Verification 'ExecutionReport' message\n", - "│ │ │ └── Verification 'ExecutionReport' message\n", - "│ │ ├── Check sequence (expected 2 / actual 2 , check order true)\n", - "│ │ └── Pre-filtering (filtered 2 / processed 2) messages\n", - "│ │ ├── Verification 'ExecutionReport' message\n", - "│ │ └── Verification 'ExecutionReport' message\n", - "│ ├── Check sequence rule SessionKey{sessionAlias='demo-conn2', direction=FIRST} - STEP7: Trader \"DEMO-CONN2\" receives Execution Reports: first trade with Order2, next with Order1 and then cancellation\n", - "│ │ ├── Check messages\n", - "│ │ │ ├── Verification 'ExecutionReport' message\n", - "│ │ │ ├── Verification 'ExecutionReport' message\n", - "│ │ │ └── Verification 'ExecutionReport' message\n", - "│ │ ├── Check sequence (expected 3 / actual 3 , check order true)\n", - "│ │ └── Pre-filtering (filtered 3 / processed 3) messages\n", - "│ │ ├── Verification 'ExecutionReport' message\n", - "│ │ ├── Verification 'ExecutionReport' message\n", - "│ │ └── Verification 'ExecutionReport' message\n", - "│ ├── placeOrderFIX demo-conn1 - STEP1: Trader \"DEMO-CONN1\" sends request to create passive Order.\n", - "│ │ ├── Checkpoint\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn1' direction 'FIRST' sequence '1624005455622011522'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn1' direction 'SECOND' sequence '1624005455622140289'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn2' direction 'FIRST' sequence '1624005448022245399'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn2' direction 'SECOND' sequence '1624005448022426113'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc1' direction 'FIRST' sequence '1624005475720919499'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc1' direction 'SECOND' sequence '1624005475721015014'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc2' direction 'FIRST' sequence '1624005466840263372'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc2' direction 'SECOND' sequence '1624005466840347015'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-log' direction 'FIRST' sequence '1624029363623063053'\n", - "│ │ │ └── Checkpoint for session alias 'th2-hand-demo' direction 'FIRST' sequence '1623852603564709030'\n", - "│ │ ├── Received 'ExecutionReport' response message\n", - "│ │ ├── Send 'NewOrderSingle' message\n", - "│ │ └── Send 'NewOrderSingle' message to connectivity\n", - "│ ├── placeOrderFIX demo-conn1 - STEP3: Trader \"DEMO-CONN1\" sends request to create passive Order with price lower than first order.\n", - "│ │ ├── Checkpoint\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn1' direction 'FIRST' sequence '1624005455622011523'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn1' direction 'SECOND' sequence '1624005455622140290'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn2' direction 'FIRST' sequence '1624005448022245399'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn2' direction 'SECOND' sequence '1624005448022426113'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc1' direction 'FIRST' sequence '1624005475720919500'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc1' direction 'SECOND' sequence '1624005475721015014'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc2' direction 'FIRST' sequence '1624005466840263372'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc2' direction 'SECOND' sequence '1624005466840347015'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-log' direction 'FIRST' sequence '1624029363623063053'\n", - "│ │ │ └── Checkpoint for session alias 'th2-hand-demo' direction 'FIRST' sequence '1623852603564709030'\n", - "│ │ ├── Received 'ExecutionReport' response message\n", - "│ │ ├── Send 'NewOrderSingle' message\n", - "│ │ └── Send 'NewOrderSingle' message to connectivity\n", - "│ └── placeOrderFIX demo-conn2 - STEP5: Trader \"DEMO-CONN2\" sends request to create aggressive IOC Order.\n", - "│ ├── Checkpoint\n", - "│ │ ├── Checkpoint for session alias 'demo-conn1' direction 'FIRST' sequence '1624005455622011524'\n", - "│ │ ├── Checkpoint for session alias 'demo-conn1' direction 'SECOND' sequence '1624005455622140291'\n", - "│ │ ├── Checkpoint for session alias 'demo-conn2' direction 'FIRST' sequence '1624005448022245399'\n", - "│ │ ├── Checkpoint for session alias 'demo-conn2' direction 'SECOND' sequence '1624005448022426113'\n", - "│ │ ├── Checkpoint for session alias 'demo-dc1' direction 'FIRST' sequence '1624005475720919501'\n", - "│ │ ├── Checkpoint for session alias 'demo-dc1' direction 'SECOND' sequence '1624005475721015014'\n", - "│ │ ├── Checkpoint for session alias 'demo-dc2' direction 'FIRST' sequence '1624005466840263372'\n", - "│ │ ├── Checkpoint for session alias 'demo-dc2' direction 'SECOND' sequence '1624005466840347015'\n", - "│ │ ├── Checkpoint for session alias 'demo-log' direction 'FIRST' sequence '1624029363623063053'\n", - "│ │ └── Checkpoint for session alias 'th2-hand-demo' direction 'FIRST' sequence '1623852603564709030'\n", - "│ ├── Received 'ExecutionReport' response message\n", - "│ ├── Send 'NewOrderSingle' message\n", - "│ └── Send 'NewOrderSingle' message to connectivity\n", - "├── Case[TC_1.2]: Trader DEMO-CONN1 vs trader DEMO-CONN2 for instrument INSTR2\n", - "│ ├── Check sequence rule SessionKey{sessionAlias='demo-conn1', direction=FIRST} - STEP2: Trader \"DEMO-CONN1\" receives Execution Report. The order stands on book in status NEW\n", - "│ │ ├── Check messages\n", - "│ │ │ └── Verification 'ExecutionReport' message\n", - "│ │ ├── Check sequence (expected 1 / actual 1 , check order false)\n", - "│ │ └── Pre-filtering (filtered 1 / processed 1) messages\n", - "│ │ └── Verification 'ExecutionReport' message\n", - "│ ├── Check sequence rule SessionKey{sessionAlias='demo-conn1', direction=FIRST} - STEP4: Trader \"DEMO-CONN1\" receives Execution Report. The order stands on book in status NEW\n", - "│ │ ├── Check messages\n", - "│ │ │ └── Verification 'ExecutionReport' message\n", - "│ │ ├── Check sequence (expected 1 / actual 1 , check order false)\n", - "│ │ └── Pre-filtering (filtered 1 / processed 1) messages\n", - "│ │ └── Verification 'ExecutionReport' message\n", - "│ ├── Check sequence rule SessionKey{sessionAlias='demo-conn1', direction=FIRST} - STEP6: Trader \"DEMO-CONN1\" receives Execution Reports with ExecType=F: first at Order2 and second on Order1.\n", - "│ │ ├── Check messages\n", - "│ │ │ ├── Verification 'ExecutionReport' message\n", - "│ │ │ └── Verification 'ExecutionReport' message\n", - "│ │ ├── Check sequence (expected 2 / actual 2 , check order true)\n", - "│ │ └── Pre-filtering (filtered 2 / processed 2) messages\n", - "│ │ ├── Verification 'ExecutionReport' message\n", - "│ │ └── Verification 'ExecutionReport' message\n", - "│ ├── Check sequence rule SessionKey{sessionAlias='demo-conn2', direction=FIRST} - STEP7: Trader \"DEMO-CONN2\" receives Execution Reports: first trade with Order2, next with Order1 and then cancellation\n", - "│ │ ├── Check messages\n", - "│ │ │ ├── Verification 'ExecutionReport' message\n", - "│ │ │ ├── Verification 'ExecutionReport' message\n", - "│ │ │ └── Verification 'ExecutionReport' message\n", - "│ │ ├── Check sequence (expected 3 / actual 3 , check order true)\n", - "│ │ └── Pre-filtering (filtered 3 / processed 3) messages\n", - "│ │ ├── Verification 'ExecutionReport' message\n", - "│ │ ├── Verification 'ExecutionReport' message\n", - "│ │ └── Verification 'ExecutionReport' message\n", - "│ ├── placeOrderFIX demo-conn1 - STEP1: Trader \"DEMO-CONN1\" sends request to create passive Order.\n", - "│ │ ├── Checkpoint\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn1' direction 'FIRST' sequence '1624005455622011526'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn1' direction 'SECOND' sequence '1624005455622140291'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn2' direction 'FIRST' sequence '1624005448022245402'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn2' direction 'SECOND' sequence '1624005448022426114'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc1' direction 'FIRST' sequence '1624005475720919503'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc1' direction 'SECOND' sequence '1624005475721015015'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc2' direction 'FIRST' sequence '1624005466840263375'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc2' direction 'SECOND' sequence '1624005466840347016'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-log' direction 'FIRST' sequence '1624029363623063053'\n", - "│ │ │ └── Checkpoint for session alias 'th2-hand-demo' direction 'FIRST' sequence '1623852603564709030'\n", - "│ │ ├── Received 'ExecutionReport' response message\n", - "│ │ ├── Send 'NewOrderSingle' message\n", - "│ │ └── Send 'NewOrderSingle' message to connectivity\n", - "│ ├── placeOrderFIX demo-conn1 - STEP3: Trader \"DEMO-CONN1\" sends request to create passive Order with price lower than first order.\n", - "│ │ ├── Checkpoint\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn1' direction 'FIRST' sequence '1624005455622011527'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn1' direction 'SECOND' sequence '1624005455622140292'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn2' direction 'FIRST' sequence '1624005448022245402'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn2' direction 'SECOND' sequence '1624005448022426114'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc1' direction 'FIRST' sequence '1624005475720919504'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc1' direction 'SECOND' sequence '1624005475721015015'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc2' direction 'FIRST' sequence '1624005466840263375'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc2' direction 'SECOND' sequence '1624005466840347016'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-log' direction 'FIRST' sequence '1624029363623063053'\n", - "│ │ │ └── Checkpoint for session alias 'th2-hand-demo' direction 'FIRST' sequence '1623852603564709030'\n", - "│ │ ├── Received 'ExecutionReport' response message\n", - "│ │ ├── Send 'NewOrderSingle' message\n", - "│ │ └── Send 'NewOrderSingle' message to connectivity\n", - "│ └── placeOrderFIX demo-conn2 - STEP5: Trader \"DEMO-CONN2\" sends request to create aggressive IOC Order.\n", - "│ ├── Checkpoint\n", - "│ │ ├── Checkpoint for session alias 'demo-conn1' direction 'FIRST' sequence '1624005455622011528'\n", - "│ │ ├── Checkpoint for session alias 'demo-conn1' direction 'SECOND' sequence '1624005455622140293'\n", - "│ │ ├── Checkpoint for session alias 'demo-conn2' direction 'FIRST' sequence '1624005448022245402'\n", - "│ │ ├── Checkpoint for session alias 'demo-conn2' direction 'SECOND' sequence '1624005448022426114'\n", - "│ │ ├── Checkpoint for session alias 'demo-dc1' direction 'FIRST' sequence '1624005475720919505'\n", - "│ │ ├── Checkpoint for session alias 'demo-dc1' direction 'SECOND' sequence '1624005475721015015'\n", - "│ │ ├── Checkpoint for session alias 'demo-dc2' direction 'FIRST' sequence '1624005466840263375'\n", - "│ │ ├── Checkpoint for session alias 'demo-dc2' direction 'SECOND' sequence '1624005466840347016'\n", - "│ │ ├── Checkpoint for session alias 'demo-log' direction 'FIRST' sequence '1624029363623063053'\n", - "│ │ └── Checkpoint for session alias 'th2-hand-demo' direction 'FIRST' sequence '1623852603564709030'\n", - "│ ├── Received 'ExecutionReport' response message\n", - "│ ├── Send 'NewOrderSingle' message\n", - "│ └── Send 'NewOrderSingle' message to connectivity\n", - "├── Case[TC_1.3]: Trader DEMO-CONN1 vs trader DEMO-CONN2 for instrument INSTR3\n", - "│ ├── Check sequence rule SessionKey{sessionAlias='demo-conn1', direction=FIRST} - STEP2: Trader \"DEMO-CONN1\" receives Execution Report. The order stands on book in status NEW\n", - "│ │ ├── Check messages\n", - "│ │ │ └── Verification 'ExecutionReport' message\n", - "│ │ ├── Check sequence (expected 1 / actual 1 , check order false)\n", - "│ │ └── Pre-filtering (filtered 1 / processed 1) messages\n", - "│ │ └── Verification 'ExecutionReport' message\n", - "│ ├── Check sequence rule SessionKey{sessionAlias='demo-conn1', direction=FIRST} - STEP4: Trader \"DEMO-CONN1\" receives Execution Report. The order stands on book in status NEW\n", - "│ │ ├── Check messages\n", - "│ │ │ └── Verification 'ExecutionReport' message\n", - "│ │ ├── Check sequence (expected 1 / actual 1 , check order false)\n", - "│ │ └── Pre-filtering (filtered 1 / processed 1) messages\n", - "│ │ └── Verification 'ExecutionReport' message\n", - "│ ├── Check sequence rule SessionKey{sessionAlias='demo-conn1', direction=FIRST} - STEP6: Trader \"DEMO-CONN1\" receives Execution Reports with ExecType=F: first at Order2 and second on Order1.\n", - "│ │ ├── Check messages\n", - "│ │ │ ├── Verification 'ExecutionReport' message\n", - "│ │ │ └── Verification 'ExecutionReport' message\n", - "│ │ ├── Check sequence (expected 2 / actual 2 , check order true)\n", - "│ │ └── Pre-filtering (filtered 2 / processed 2) messages\n", - "│ │ ├── Verification 'ExecutionReport' message\n", - "│ │ └── Verification 'ExecutionReport' message\n", - "│ ├── Check sequence rule SessionKey{sessionAlias='demo-conn2', direction=FIRST} - STEP7: Trader \"DEMO-CONN2\" receives Execution Reports: first trade with Order2, next with Order1 and then cancellation\n", - "│ │ ├── Check messages\n", - "│ │ │ ├── Verification 'ExecutionReport' message\n", - "│ │ │ ├── Verification 'ExecutionReport' message\n", - "│ │ │ └── Verification 'ExecutionReport' message\n", - "│ │ ├── Check sequence (expected 3 / actual 3 , check order true)\n", - "│ │ └── Pre-filtering (filtered 3 / processed 3) messages\n", - "│ │ ├── Verification 'ExecutionReport' message\n", - "│ │ ├── Verification 'ExecutionReport' message\n", - "│ │ └── Verification 'ExecutionReport' message\n", - "│ ├── placeOrderFIX demo-conn1 - STEP1: Trader \"DEMO-CONN1\" sends request to create passive Order.\n", - "│ │ ├── Checkpoint\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn1' direction 'FIRST' sequence '1624005455622011530'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn1' direction 'SECOND' sequence '1624005455622140293'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn2' direction 'FIRST' sequence '1624005448022245405'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn2' direction 'SECOND' sequence '1624005448022426115'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc1' direction 'FIRST' sequence '1624005475720919507'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc1' direction 'SECOND' sequence '1624005475721015015'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc2' direction 'FIRST' sequence '1624005466840263378'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc2' direction 'SECOND' sequence '1624005466840347016'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-log' direction 'FIRST' sequence '1624029363623063053'\n", - "│ │ │ └── Checkpoint for session alias 'th2-hand-demo' direction 'FIRST' sequence '1623852603564709030'\n", - "│ │ ├── Received 'ExecutionReport' response message\n", - "│ │ ├── Send 'NewOrderSingle' message\n", - "│ │ └── Send 'NewOrderSingle' message to connectivity\n", - "│ ├── placeOrderFIX demo-conn1 - STEP3: Trader \"DEMO-CONN1\" sends request to create passive Order with price lower than first order.\n", - "│ │ ├── Checkpoint\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn1' direction 'FIRST' sequence '1624005455622011531'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn1' direction 'SECOND' sequence '1624005455622140294'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn2' direction 'FIRST' sequence '1624005448022245405'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn2' direction 'SECOND' sequence '1624005448022426115'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc1' direction 'FIRST' sequence '1624005475720919508'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc1' direction 'SECOND' sequence '1624005475721015015'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc2' direction 'FIRST' sequence '1624005466840263378'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc2' direction 'SECOND' sequence '1624005466840347016'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-log' direction 'FIRST' sequence '1624029363623063053'\n", - "│ │ │ └── Checkpoint for session alias 'th2-hand-demo' direction 'FIRST' sequence '1623852603564709030'\n", - "│ │ ├── Received 'ExecutionReport' response message\n", - "│ │ ├── Send 'NewOrderSingle' message\n", - "│ │ └── Send 'NewOrderSingle' message to connectivity\n", - "│ └── placeOrderFIX demo-conn2 - STEP5: Trader \"DEMO-CONN2\" sends request to create aggressive IOC Order.\n", - "│ ├── Checkpoint\n", - "│ │ ├── Checkpoint for session alias 'demo-conn1' direction 'FIRST' sequence '1624005455622011532'\n", - "│ │ ├── Checkpoint for session alias 'demo-conn1' direction 'SECOND' sequence '1624005455622140295'\n", - "│ │ ├── Checkpoint for session alias 'demo-conn2' direction 'FIRST' sequence '1624005448022245405'\n", - "│ │ ├── Checkpoint for session alias 'demo-conn2' direction 'SECOND' sequence '1624005448022426115'\n", - "│ │ ├── Checkpoint for session alias 'demo-dc1' direction 'FIRST' sequence '1624005475720919509'\n", - "│ │ ├── Checkpoint for session alias 'demo-dc1' direction 'SECOND' sequence '1624005475721015015'\n", - "│ │ ├── Checkpoint for session alias 'demo-dc2' direction 'FIRST' sequence '1624005466840263378'\n", - "│ │ ├── Checkpoint for session alias 'demo-dc2' direction 'SECOND' sequence '1624005466840347016'\n", - "│ │ ├── Checkpoint for session alias 'demo-log' direction 'FIRST' sequence '1624029363623063053'\n", - "│ │ └── Checkpoint for session alias 'th2-hand-demo' direction 'FIRST' sequence '1623852603564709030'\n", - "│ ├── Received 'ExecutionReport' response message\n", - "│ ├── Send 'NewOrderSingle' message\n", - "│ └── Send 'NewOrderSingle' message to connectivity\n", - "├── Case[TC_1.4]: Trader DEMO-CONN1 vs trader DEMO-CONN2 for instrument INSTR4\n", - "│ ├── Check sequence rule SessionKey{sessionAlias='demo-conn1', direction=FIRST} - STEP2: Trader \"DEMO-CONN1\" receives Execution Report. The order stands on book in status NEW\n", - "│ │ ├── Check messages\n", - "│ │ │ └── Verification 'ExecutionReport' message\n", - "│ │ ├── Check sequence (expected 1 / actual 1 , check order false)\n", - "│ │ └── Pre-filtering (filtered 1 / processed 1) messages\n", - "│ │ └── Verification 'ExecutionReport' message\n", - "│ ├── Check sequence rule SessionKey{sessionAlias='demo-conn1', direction=FIRST} - STEP4: Trader \"DEMO-CONN1\" receives Execution Report. The order stands on book in status NEW\n", - "│ │ ├── Check messages\n", - "│ │ │ └── Verification 'ExecutionReport' message\n", - "│ │ ├── Check sequence (expected 1 / actual 1 , check order false)\n", - "│ │ └── Pre-filtering (filtered 1 / processed 1) messages\n", - "│ │ └── Verification 'ExecutionReport' message\n", - "│ ├── Check sequence rule SessionKey{sessionAlias='demo-conn1', direction=FIRST} - STEP6: Trader \"DEMO-CONN1\" receives Execution Reports with ExecType=F: first at Order2 and second on Order1.\n", - "│ │ ├── Check messages\n", - "│ │ │ ├── Verification 'ExecutionReport' message\n", - "│ │ │ └── Verification 'ExecutionReport' message\n", - "│ │ ├── Check sequence (expected 2 / actual 2 , check order true)\n", - "│ │ └── Pre-filtering (filtered 2 / processed 2) messages\n", - "│ │ ├── Verification 'ExecutionReport' message\n", - "│ │ └── Verification 'ExecutionReport' message\n", - "│ ├── Check sequence rule SessionKey{sessionAlias='demo-conn2', direction=FIRST} - STEP7: Trader \"DEMO-CONN2\" receives Execution Reports: first trade with Order2, next with Order1 and then cancellation\n", - "│ │ ├── Check messages\n", - "│ │ │ ├── Verification 'ExecutionReport' message\n", - "│ │ │ ├── Verification 'ExecutionReport' message\n", - "│ │ │ └── Verification 'ExecutionReport' message\n", - "│ │ ├── Check sequence (expected 3 / actual 4 , check order true)\n", - "│ │ └── Pre-filtering (filtered 4 / processed 4) messages\n", - "│ │ ├── Verification 'ExecutionReport' message\n", - "│ │ ├── Verification 'ExecutionReport' message\n", - "│ │ ├── Verification 'ExecutionReport' message\n", - "│ │ └── Verification 'ExecutionReport' message\n", - "│ ├── placeOrderFIX demo-conn1 - STEP1: Trader \"DEMO-CONN1\" sends request to create passive Order.\n", - "│ │ ├── Checkpoint\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn1' direction 'FIRST' sequence '1624005455622011534'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn1' direction 'SECOND' sequence '1624005455622140295'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn2' direction 'FIRST' sequence '1624005448022245408'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn2' direction 'SECOND' sequence '1624005448022426116'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc1' direction 'FIRST' sequence '1624005475720919511'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc1' direction 'SECOND' sequence '1624005475721015015'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc2' direction 'FIRST' sequence '1624005466840263381'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc2' direction 'SECOND' sequence '1624005466840347016'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-log' direction 'FIRST' sequence '1624029363623063053'\n", - "│ │ │ └── Checkpoint for session alias 'th2-hand-demo' direction 'FIRST' sequence '1623852603564709030'\n", - "│ │ ├── Received 'ExecutionReport' response message\n", - "│ │ ├── Send 'NewOrderSingle' message\n", - "│ │ └── Send 'NewOrderSingle' message to connectivity\n", - "│ ├── placeOrderFIX demo-conn1 - STEP3: Trader \"DEMO-CONN1\" sends request to create passive Order with price lower than first order.\n", - "│ │ ├── Checkpoint\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn1' direction 'FIRST' sequence '1624005455622011535'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn1' direction 'SECOND' sequence '1624005455622140296'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn2' direction 'FIRST' sequence '1624005448022245408'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn2' direction 'SECOND' sequence '1624005448022426116'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc1' direction 'FIRST' sequence '1624005475720919512'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc1' direction 'SECOND' sequence '1624005475721015015'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc2' direction 'FIRST' sequence '1624005466840263381'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc2' direction 'SECOND' sequence '1624005466840347016'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-log' direction 'FIRST' sequence '1624029363623063053'\n", - "│ │ │ └── Checkpoint for session alias 'th2-hand-demo' direction 'FIRST' sequence '1623852603564709030'\n", - "│ │ ├── Received 'ExecutionReport' response message\n", - "│ │ ├── Send 'NewOrderSingle' message\n", - "│ │ └── Send 'NewOrderSingle' message to connectivity\n", - "│ └── placeOrderFIX demo-conn2 - STEP5: Trader \"DEMO-CONN2\" sends request to create aggressive IOC Order.\n", - "│ ├── Checkpoint\n", - "│ │ ├── Checkpoint for session alias 'demo-conn1' direction 'FIRST' sequence '1624005455622011536'\n", - "│ │ ├── Checkpoint for session alias 'demo-conn1' direction 'SECOND' sequence '1624005455622140297'\n", - "│ │ ├── Checkpoint for session alias 'demo-conn2' direction 'FIRST' sequence '1624005448022245408'\n", - "│ │ ├── Checkpoint for session alias 'demo-conn2' direction 'SECOND' sequence '1624005448022426116'\n", - "│ │ ├── Checkpoint for session alias 'demo-dc1' direction 'FIRST' sequence '1624005475720919513'\n", - "│ │ ├── Checkpoint for session alias 'demo-dc1' direction 'SECOND' sequence '1624005475721015015'\n", - "│ │ ├── Checkpoint for session alias 'demo-dc2' direction 'FIRST' sequence '1624005466840263381'\n", - "│ │ ├── Checkpoint for session alias 'demo-dc2' direction 'SECOND' sequence '1624005466840347016'\n", - "│ │ ├── Checkpoint for session alias 'demo-log' direction 'FIRST' sequence '1624029363623063053'\n", - "│ │ └── Checkpoint for session alias 'th2-hand-demo' direction 'FIRST' sequence '1623852603564709030'\n", - "│ ├── Received 'ExecutionReport' response message\n", - "│ ├── Send 'NewOrderSingle' message\n", - "│ └── Send 'NewOrderSingle' message to connectivity\n", - "├── Case[TC_1.5]: Trader DEMO-CONN1 vs trader DEMO-CONN2 for instrument INSTR5\n", - "│ ├── Check sequence rule SessionKey{sessionAlias='demo-conn1', direction=FIRST} - STEP2: Trader \"DEMO-CONN1\" receives Execution Report. The order stands on book in status NEW\n", - "│ │ ├── Check messages\n", - "│ │ │ └── Verification 'ExecutionReport' message\n", - "│ │ ├── Check sequence (expected 1 / actual 1 , check order false)\n", - "│ │ └── Pre-filtering (filtered 1 / processed 1) messages\n", - "│ │ └── Verification 'ExecutionReport' message\n", - "│ ├── Check sequence rule SessionKey{sessionAlias='demo-conn1', direction=FIRST} - STEP4: Trader \"DEMO-CONN1\" receives Execution Report. The order stands on book in status NEW\n", - "│ │ ├── Check messages\n", - "│ │ │ └── Verification 'ExecutionReport' message\n", - "│ │ ├── Check sequence (expected 1 / actual 1 , check order false)\n", - "│ │ └── Pre-filtering (filtered 1 / processed 1) messages\n", - "│ │ └── Verification 'ExecutionReport' message\n", - "│ ├── Check sequence rule SessionKey{sessionAlias='demo-conn1', direction=FIRST} - STEP6: Trader \"DEMO-CONN1\" receives Execution Reports with ExecType=F: first at Order2 and second on Order1.\n", - "│ │ ├── Check messages\n", - "│ │ │ ├── Verification 'ExecutionReport' message\n", - "│ │ │ └── Verification 'ExecutionReport' message\n", - "│ │ ├── Check sequence (expected 2 / actual 2 , check order true)\n", - "│ │ └── Pre-filtering (filtered 2 / processed 2) messages\n", - "│ │ ├── Verification 'ExecutionReport' message\n", - "│ │ └── Verification 'ExecutionReport' message\n", - "│ ├── Check sequence rule SessionKey{sessionAlias='demo-conn2', direction=FIRST} - STEP7: Trader \"DEMO-CONN2\" receives Execution Reports: first trade with Order2, next with Order1 and then cancellation\n", - "│ │ ├── Check messages\n", - "│ │ │ ├── Verification 'ExecutionReport' message\n", - "│ │ │ ├── Verification 'ExecutionReport' message\n", - "│ │ │ └── Verification 'ExecutionReport' message\n", - "│ │ ├── Check sequence (expected 3 / actual 3 , check order true)\n", - "│ │ └── Pre-filtering (filtered 3 / processed 3) messages\n", - "│ │ ├── Verification 'ExecutionReport' message\n", - "│ │ ├── Verification 'ExecutionReport' message\n", - "│ │ └── Verification 'ExecutionReport' message\n", - "│ ├── placeOrderFIX demo-conn1 - STEP1: Trader \"DEMO-CONN1\" sends request to create passive Order.\n", - "│ │ ├── Checkpoint\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn1' direction 'FIRST' sequence '1624005455622011538'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn1' direction 'SECOND' sequence '1624005455622140297'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn2' direction 'FIRST' sequence '1624005448022245412'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn2' direction 'SECOND' sequence '1624005448022426117'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc1' direction 'FIRST' sequence '1624005475720919515'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc1' direction 'SECOND' sequence '1624005475721015015'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc2' direction 'FIRST' sequence '1624005466840263384'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc2' direction 'SECOND' sequence '1624005466840347016'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-log' direction 'FIRST' sequence '1624029363623063053'\n", - "│ │ │ └── Checkpoint for session alias 'th2-hand-demo' direction 'FIRST' sequence '1623852603564709030'\n", - "│ │ ├── Received 'ExecutionReport' response message\n", - "│ │ ├── Send 'NewOrderSingle' message\n", - "│ │ └── Send 'NewOrderSingle' message to connectivity\n", - "│ ├── placeOrderFIX demo-conn1 - STEP3: Trader \"DEMO-CONN1\" sends request to create passive Order with price lower than first order.\n", - "│ │ ├── Checkpoint\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn1' direction 'FIRST' sequence '1624005455622011539'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn1' direction 'SECOND' sequence '1624005455622140298'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn2' direction 'FIRST' sequence '1624005448022245412'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn2' direction 'SECOND' sequence '1624005448022426117'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc1' direction 'FIRST' sequence '1624005475720919516'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc1' direction 'SECOND' sequence '1624005475721015015'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc2' direction 'FIRST' sequence '1624005466840263384'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc2' direction 'SECOND' sequence '1624005466840347016'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-log' direction 'FIRST' sequence '1624029363623063053'\n", - "│ │ │ └── Checkpoint for session alias 'th2-hand-demo' direction 'FIRST' sequence '1623852603564709030'\n", - "│ │ ├── Received 'ExecutionReport' response message\n", - "│ │ ├── Send 'NewOrderSingle' message\n", - "│ │ └── Send 'NewOrderSingle' message to connectivity\n", - "│ └── placeOrderFIX demo-conn2 - STEP5: Trader \"DEMO-CONN2\" sends request to create aggressive IOC Order.\n", - "│ ├── Checkpoint\n", - "│ │ ├── Checkpoint for session alias 'demo-conn1' direction 'FIRST' sequence '1624005455622011540'\n", - "│ │ ├── Checkpoint for session alias 'demo-conn1' direction 'SECOND' sequence '1624005455622140299'\n", - "│ │ ├── Checkpoint for session alias 'demo-conn2' direction 'FIRST' sequence '1624005448022245412'\n", - "│ │ ├── Checkpoint for session alias 'demo-conn2' direction 'SECOND' sequence '1624005448022426117'\n", - "│ │ ├── Checkpoint for session alias 'demo-dc1' direction 'FIRST' sequence '1624005475720919517'\n", - "│ │ ├── Checkpoint for session alias 'demo-dc1' direction 'SECOND' sequence '1624005475721015015'\n", - "│ │ ├── Checkpoint for session alias 'demo-dc2' direction 'FIRST' sequence '1624005466840263384'\n", - "│ │ ├── Checkpoint for session alias 'demo-dc2' direction 'SECOND' sequence '1624005466840347016'\n", - "│ │ ├── Checkpoint for session alias 'demo-log' direction 'FIRST' sequence '1624029363623063053'\n", - "│ │ └── Checkpoint for session alias 'th2-hand-demo' direction 'FIRST' sequence '1623852603564709030'\n", - "│ ├── Received 'ExecutionReport' response message\n", - "│ ├── Send 'NewOrderSingle' message\n", - "│ └── Send 'NewOrderSingle' message to connectivity\n", - "└── Case[TC_1.6]: Trader DEMO-CONN1 vs trader DEMO-CONN2 for instrument INSTR6\n", - " └── placeOrderFIX demo-conn1 - STEP1: Trader \"DEMO-CONN1\" sends request to create passive Order.\n", - " ├── Checkpoint\n", - " │ ├── Checkpoint for session alias 'demo-conn1' direction 'FIRST' sequence '1624005455622011542'\n", - " │ ├── Checkpoint for session alias 'demo-conn1' direction 'SECOND' sequence '1624005455622140299'\n", - " │ ├── Checkpoint for session alias 'demo-conn2' direction 'FIRST' sequence '1624005448022245415'\n", - " │ ├── Checkpoint for session alias 'demo-conn2' direction 'SECOND' sequence '1624005448022426118'\n", - " │ ├── Checkpoint for session alias 'demo-dc1' direction 'FIRST' sequence '1624005475720919519'\n", - " │ ├── Checkpoint for session alias 'demo-dc1' direction 'SECOND' sequence '1624005475721015016'\n", - " │ ├── Checkpoint for session alias 'demo-dc2' direction 'FIRST' sequence '1624005466840263387'\n", - " │ ├── Checkpoint for session alias 'demo-dc2' direction 'SECOND' sequence '1624005466840347017'\n", - " │ ├── Checkpoint for session alias 'demo-log' direction 'FIRST' sequence '1624029363623063053'\n", - " │ └── Checkpoint for session alias 'th2-hand-demo' direction 'FIRST' sequence '1623852603564709030'\n", - " ├── Received 'BusinessMessageReject' response message\n", - " ├── Send 'NewOrderSingle' message\n", - " └── Send 'NewOrderSingle' message to connectivity\n", - "\n", - "Simulator - RootEvent - 2021-04-13T14:57:02.421105Z\n", - "├── Rule with class name 'KotlinFIXRule' for session alias 'fix-demo-server1' with id '1' was added to simulator - 2021-04-13T14:57:07.618996Z\n", - "│ ├── Send 'BusinessMessageReject' message\n", - "│ ├── Send 'ExecutionReport' message\n", - "│ ├── Send 'ExecutionReport' message\n", - "│ ├── Send 'ExecutionReport' message\n", - "│ ├── Send 'ExecutionReport' message\n", - "│ ├── Send 'ExecutionReport' message\n", - "│ ├── Send 'ExecutionReport' message\n", - "│ ├── Send 'ExecutionReport' message\n", - "│ ├── Send 'ExecutionReport' message\n", - "│ ├── Send 'ExecutionReport' message\n", - "│ ├── Send 'ExecutionReport' message\n", - "│ ├── Send 'ExecutionReport' message\n", - "│ ├── Send 'ExecutionReport' message\n", - "│ ├── Send 'ExecutionReport' message\n", - "│ ├── Send 'ExecutionReport' message\n", - "│ ├── Send 'ExecutionReport' message\n", - "│ ├── Send 'ExecutionReport' message\n", - "│ ├── Send 'ExecutionReport' message\n", - "│ ├── Send 'ExecutionReport' message\n", - "│ ├── Send 'ExecutionReport' message\n", - "│ └── Send 'ExecutionReport' message\n", - "└── Rule with class name 'KotlinFIXRule' for session alias 'fix-demo-server2' with id '2' was added to simulator - 2021-04-13T14:57:08.018732Z\n", - " ├── Send 'ExecutionReport' message\n", - " ├── Send 'ExecutionReport' message\n", - " ├── Send 'ExecutionReport' message\n", - " ├── Send 'ExecutionReport' message\n", - " ├── Send 'ExecutionReport' message\n", - " ├── Send 'ExecutionReport' message\n", - " ├── Send 'ExecutionReport' message\n", - " ├── Send 'ExecutionReport' message\n", - " ├── Send 'ExecutionReport' message\n", - " ├── Send 'ExecutionReport' message\n", - " ├── Send 'ExecutionReport' message\n", - " ├── Send 'ExecutionReport' message\n", - " ├── Send 'ExecutionReport' message\n", - " ├── Send 'ExecutionReport' message\n", - " ├── Send 'ExecutionReport' message\n", - " ├── Send 'ExecutionReport' message\n", - " ├── Send 'ExecutionReport' message\n", - " ├── Send 'ExecutionReport' message\n", - " ├── Send 'ExecutionReport' message\n", - " ├── Send 'ExecutionReport' message\n", - " ├── Send 'ExecutionReport' message\n", - " ├── Send 'ExecutionReport' message\n", - " ├── Send 'ExecutionReport' message\n", - " ├── Send 'ExecutionReport' message\n", - " ├── Send 'ExecutionReport' message\n", - " ├── Send 'ExecutionReport' message\n", - " ├── Send 'ExecutionReport' message\n", - " ├── Send 'ExecutionReport' message\n", - " ├── Send 'ExecutionReport' message\n", - " ├── Send 'ExecutionReport' message\n", - " ├── Send 'ExecutionReport' message\n", - " ├── Send 'ExecutionReport' message\n", - " ├── Send 'ExecutionReport' message\n", - " ├── Send 'ExecutionReport' message\n", - " ├── Send 'ExecutionReport' message\n", - " ├── Send 'ExecutionReport' message\n", - " ├── Send 'ExecutionReport' message\n", - " ├── Send 'ExecutionReport' message\n", - " ├── Send 'ExecutionReport' message\n", - " ├── Send 'ExecutionReport' message\n", - " ├── Send 'ExecutionReport' message\n", - " ├── Send 'ExecutionReport' message\n", - " ├── Send 'ExecutionReport' message\n", - " ├── Send 'ExecutionReport' message\n", - " ├── Send 'ExecutionReport' message\n", - " ├── Send 'ExecutionReport' message\n", - " ├── Send 'ExecutionReport' message\n", - " ├── Send 'ExecutionReport' message\n", - " ├── Send 'ExecutionReport' message\n", - " ├── Send 'ExecutionReport' message\n", - " └── Send 'ExecutionReport' message\n", - "\n", - "Connectivity 'demo-conn1' 2021-06-18T08:37:45.618708Z\n", - "└── ServiceEvents\n", - " ├── Reject sent for Message 1311: Required tag missing (Required tag missing, field=45):45\n", - " └── Rejecting invalid message: quickfix.FieldException: Required tag missing, field=45: 8=FIXT.1.1\u00019=112\u000135=j\u000134=1311\u000149=FGW\u000152=20210620-10:45:38.290\u000156=DEMO-CONN1\u000158=Unknown SecurityID\u0001371=48\u0001372=D\u0001379=2202035\u0001380=2\u000110=252\u0001\n", - "\n", - "Recon: Demo_Recon\n", - "├── Rule: ['demo-conn1', 'demo-conn2'] vs ['demo-log']\n", - "│ └── No match\n", - "│ ├── Remove 'NewOrderSingle' id='demo-conn1:SECOND:1624005455622135205' Hash='7009491514226292581' Group='NOS_CONN' Hash['SecondaryClOrdID': 11111, 'SecurityID': INSTR1]\n", - "│ ├── Remove 'NewOrderSingle' id='demo-conn1:SECOND:1624005455622135206' Hash='9109085565557408626' Group='NOS_CONN' Hash['SecondaryClOrdID': 22222, 'SecurityID': INSTR1]\n", - "│ ├── Remove 'NewOrderSingle' id='demo-conn1:SECOND:1624005455622135207' Hash='-6798959314518195988' Group='NOS_CONN' Hash['SecondaryClOrdID': 11111, 'SecurityID': INSTR2]\n", - "│ ├── Remove 'NewOrderSingle' id='demo-conn1:SECOND:1624005455622135208' Hash='255011743932618104' Group='NOS_CONN' Hash['SecondaryClOrdID': 22222, 'SecurityID': INSTR2]\n", - "│ ├── Remove 'NewOrderSingle' id='demo-conn1:SECOND:1624005455622135209' Hash='-8710003674304438575' Group='NOS_CONN' Hash['SecondaryClOrdID': 11111, 'SecurityID': INSTR3]\n", - "│ ├── Remove 'NewOrderSingle' id='demo-conn1:SECOND:1624005455622135210' Hash='-25247830425272190' Group='NOS_CONN' Hash['SecondaryClOrdID': 22222, 'SecurityID': INSTR3]\n", - "│ ├── Remove 'NewOrderSingle' id='demo-conn1:SECOND:1624005455622135211' Hash='9142400804910536496' Group='NOS_CONN' Hash['SecondaryClOrdID': 11111, 'SecurityID': INSTR4]\n", - "│ ├── Remove 'NewOrderSingle' id='demo-conn1:SECOND:1624005455622135212' Hash='5003206531323649912' Group='NOS_CONN' Hash['SecondaryClOrdID': 22222, 'SecurityID': INSTR4]\n", - "│ ├── Remove 'NewOrderSingle' id='demo-conn1:SECOND:1624005455622135213' Hash='-7539913357818383607' Group='NOS_CONN' Hash['SecondaryClOrdID': 11111, 'SecurityID': INSTR5]\n", - "│ ├── Remove 'NewOrderSingle' id='demo-conn1:SECOND:1624005455622135214' Hash='-3631733169209459363' Group='NOS_CONN' Hash['SecondaryClOrdID': 22222, 'SecurityID': INSTR5]\n", - "│ ├── Remove 'NewOrderSingle' id='demo-conn1:SECOND:1624005455622135215' Hash='-1652240969129971924' Group='NOS_CONN' Hash['SecondaryClOrdID': 11111, 'SecurityID': INSTR6]\n", - "│ ├── Remove 'NewOrderSingle' id='demo-conn2:SECOND:1624005448022421036' Hash='3210110562847338001' Group='NOS_CONN' Hash['SecondaryClOrdID': 33333, 'SecurityID': INSTR1]\n", - "│ ├── Remove 'NewOrderSingle' id='demo-conn2:SECOND:1624005448022421037' Hash='2022982225733544569' Group='NOS_CONN' Hash['SecondaryClOrdID': 33333, 'SecurityID': INSTR2]\n", - "│ ├── Remove 'NewOrderSingle' id='demo-conn2:SECOND:1624005448022421038' Hash='-2705192066397611092' Group='NOS_CONN' Hash['SecondaryClOrdID': 33333, 'SecurityID': INSTR3]\n", - "│ ├── Remove 'NewOrderSingle' id='demo-conn2:SECOND:1624005448022421039' Hash='-3810261582785232455' Group='NOS_CONN' Hash['SecondaryClOrdID': 33333, 'SecurityID': INSTR4]\n", - "│ └── Remove 'NewOrderSingle' id='demo-conn2:SECOND:1624005448022421040' Hash='-3378881774735559571' Group='NOS_CONN' Hash['SecondaryClOrdID': 33333, 'SecurityID': INSTR5]\n", - "└── Rule: ['demo-conn1'] vs ['demo-conn2']\n", - " ├── Matched failed\n", - " │ └── Match by '['TrdMatchID': 490]'\n", - " └── Matched passed\n", - " ├── Match by '['TrdMatchID': 481]'\n", - " ├── Match by '['TrdMatchID': 482]'\n", - " ├── Match by '['TrdMatchID': 483]'\n", - " ├── Match by '['TrdMatchID': 484]'\n", - " ├── Match by '['TrdMatchID': 485]'\n", - " ├── Match by '['TrdMatchID': 486]'\n", - " ├── Match by '['TrdMatchID': 487]'\n", - " ├── Match by '['TrdMatchID': 488]'\n", - " └── Match by '['TrdMatchID': 489]'\n", - "\n" - ] - } - ], - "source": [ - "collection.show()" - ] - }, - { - "cell_type": "markdown", - "id": "95d70c04", - "metadata": {}, - "source": [ - "If you want to append a new event then use `append_event(event)` " - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "1b247008", - "metadata": {}, - "outputs": [], - "source": [ - "event = {\n", - " \"parentEventId\": \"6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c1114ac-d1b4-11eb-9278-591e568ad66e\",\n", - " \"eventId\": \"test_id\",\n", - " \"eventName\": \"Test Event\"\n", - "}\n", - "collection.append_event(event)" - ] - }, - { - "cell_type": "markdown", - "id": "37c21d63", - "metadata": {}, - "source": [ - "You can also refer to the tree separately from the collection." - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "d91b9a4a", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[TS_1]Aggressive IOC vs two orders: second order's price is lower than first\n", - "├── Case[TC_1.1]: Trader DEMO-CONN1 vs trader DEMO-CONN2 for instrument INSTR1\n", - "│ ├── Check sequence rule SessionKey{sessionAlias='demo-conn1', direction=FIRST} - STEP2: Trader \"DEMO-CONN1\" receives Execution Report. The order stands on book in status NEW\n", - "│ │ ├── Check messages\n", - "│ │ │ └── Verification 'ExecutionReport' message\n", - "│ │ ├── Check sequence (expected 1 / actual 1 , check order false)\n", - "│ │ └── Pre-filtering (filtered 1 / processed 1) messages\n", - "│ │ └── Verification 'ExecutionReport' message\n", - "│ ├── Check sequence rule SessionKey{sessionAlias='demo-conn1', direction=FIRST} - STEP4: Trader \"DEMO-CONN1\" receives Execution Report. The order stands on book in status NEW\n", - "│ │ ├── Check messages\n", - "│ │ │ └── Verification 'ExecutionReport' message\n", - "│ │ ├── Check sequence (expected 1 / actual 1 , check order false)\n", - "│ │ └── Pre-filtering (filtered 1 / processed 1) messages\n", - "│ │ └── Verification 'ExecutionReport' message\n", - "│ ├── Check sequence rule SessionKey{sessionAlias='demo-conn1', direction=FIRST} - STEP6: Trader \"DEMO-CONN1\" receives Execution Reports with ExecType=F: first at Order2 and second on Order1.\n", - "│ │ ├── Check messages\n", - "│ │ │ ├── Verification 'ExecutionReport' message\n", - "│ │ │ └── Verification 'ExecutionReport' message\n", - "│ │ ├── Check sequence (expected 2 / actual 2 , check order true)\n", - "│ │ └── Pre-filtering (filtered 2 / processed 2) messages\n", - "│ │ ├── Verification 'ExecutionReport' message\n", - "│ │ └── Verification 'ExecutionReport' message\n", - "│ ├── Check sequence rule SessionKey{sessionAlias='demo-conn2', direction=FIRST} - STEP7: Trader \"DEMO-CONN2\" receives Execution Reports: first trade with Order2, next with Order1 and then cancellation\n", - "│ │ ├── Check messages\n", - "│ │ │ ├── Verification 'ExecutionReport' message\n", - "│ │ │ ├── Verification 'ExecutionReport' message\n", - "│ │ │ └── Verification 'ExecutionReport' message\n", - "│ │ ├── Check sequence (expected 3 / actual 3 , check order true)\n", - "│ │ └── Pre-filtering (filtered 3 / processed 3) messages\n", - "│ │ ├── Verification 'ExecutionReport' message\n", - "│ │ ├── Verification 'ExecutionReport' message\n", - "│ │ └── Verification 'ExecutionReport' message\n", - "│ ├── placeOrderFIX demo-conn1 - STEP1: Trader \"DEMO-CONN1\" sends request to create passive Order.\n", - "│ │ ├── Checkpoint\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn1' direction 'FIRST' sequence '1624005455622011522'\n", - "│ │ │ │ └── Test Event\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn1' direction 'SECOND' sequence '1624005455622140289'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn2' direction 'FIRST' sequence '1624005448022245399'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn2' direction 'SECOND' sequence '1624005448022426113'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc1' direction 'FIRST' sequence '1624005475720919499'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc1' direction 'SECOND' sequence '1624005475721015014'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc2' direction 'FIRST' sequence '1624005466840263372'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc2' direction 'SECOND' sequence '1624005466840347015'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-log' direction 'FIRST' sequence '1624029363623063053'\n", - "│ │ │ └── Checkpoint for session alias 'th2-hand-demo' direction 'FIRST' sequence '1623852603564709030'\n", - "│ │ ├── Received 'ExecutionReport' response message\n", - "│ │ ├── Send 'NewOrderSingle' message\n", - "│ │ └── Send 'NewOrderSingle' message to connectivity\n", - "│ ├── placeOrderFIX demo-conn1 - STEP3: Trader \"DEMO-CONN1\" sends request to create passive Order with price lower than first order.\n", - "│ │ ├── Checkpoint\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn1' direction 'FIRST' sequence '1624005455622011523'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn1' direction 'SECOND' sequence '1624005455622140290'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn2' direction 'FIRST' sequence '1624005448022245399'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn2' direction 'SECOND' sequence '1624005448022426113'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc1' direction 'FIRST' sequence '1624005475720919500'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc1' direction 'SECOND' sequence '1624005475721015014'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc2' direction 'FIRST' sequence '1624005466840263372'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc2' direction 'SECOND' sequence '1624005466840347015'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-log' direction 'FIRST' sequence '1624029363623063053'\n", - "│ │ │ └── Checkpoint for session alias 'th2-hand-demo' direction 'FIRST' sequence '1623852603564709030'\n", - "│ │ ├── Received 'ExecutionReport' response message\n", - "│ │ ├── Send 'NewOrderSingle' message\n", - "│ │ └── Send 'NewOrderSingle' message to connectivity\n", - "│ └── placeOrderFIX demo-conn2 - STEP5: Trader \"DEMO-CONN2\" sends request to create aggressive IOC Order.\n", - "│ ├── Checkpoint\n", - "│ │ ├── Checkpoint for session alias 'demo-conn1' direction 'FIRST' sequence '1624005455622011524'\n", - "│ │ ├── Checkpoint for session alias 'demo-conn1' direction 'SECOND' sequence '1624005455622140291'\n", - "│ │ ├── Checkpoint for session alias 'demo-conn2' direction 'FIRST' sequence '1624005448022245399'\n", - "│ │ ├── Checkpoint for session alias 'demo-conn2' direction 'SECOND' sequence '1624005448022426113'\n", - "│ │ ├── Checkpoint for session alias 'demo-dc1' direction 'FIRST' sequence '1624005475720919501'\n", - "│ │ ├── Checkpoint for session alias 'demo-dc1' direction 'SECOND' sequence '1624005475721015014'\n", - "│ │ ├── Checkpoint for session alias 'demo-dc2' direction 'FIRST' sequence '1624005466840263372'\n", - "│ │ ├── Checkpoint for session alias 'demo-dc2' direction 'SECOND' sequence '1624005466840347015'\n", - "│ │ ├── Checkpoint for session alias 'demo-log' direction 'FIRST' sequence '1624029363623063053'\n", - "│ │ └── Checkpoint for session alias 'th2-hand-demo' direction 'FIRST' sequence '1623852603564709030'\n", - "│ ├── Received 'ExecutionReport' response message\n", - "│ ├── Send 'NewOrderSingle' message\n", - "│ └── Send 'NewOrderSingle' message to connectivity\n", - "├── Case[TC_1.2]: Trader DEMO-CONN1 vs trader DEMO-CONN2 for instrument INSTR2\n", - "│ ├── Check sequence rule SessionKey{sessionAlias='demo-conn1', direction=FIRST} - STEP2: Trader \"DEMO-CONN1\" receives Execution Report. The order stands on book in status NEW\n", - "│ │ ├── Check messages\n", - "│ │ │ └── Verification 'ExecutionReport' message\n", - "│ │ ├── Check sequence (expected 1 / actual 1 , check order false)\n", - "│ │ └── Pre-filtering (filtered 1 / processed 1) messages\n", - "│ │ └── Verification 'ExecutionReport' message\n", - "│ ├── Check sequence rule SessionKey{sessionAlias='demo-conn1', direction=FIRST} - STEP4: Trader \"DEMO-CONN1\" receives Execution Report. The order stands on book in status NEW\n", - "│ │ ├── Check messages\n", - "│ │ │ └── Verification 'ExecutionReport' message\n", - "│ │ ├── Check sequence (expected 1 / actual 1 , check order false)\n", - "│ │ └── Pre-filtering (filtered 1 / processed 1) messages\n", - "│ │ └── Verification 'ExecutionReport' message\n", - "│ ├── Check sequence rule SessionKey{sessionAlias='demo-conn1', direction=FIRST} - STEP6: Trader \"DEMO-CONN1\" receives Execution Reports with ExecType=F: first at Order2 and second on Order1.\n", - "│ │ ├── Check messages\n", - "│ │ │ ├── Verification 'ExecutionReport' message\n", - "│ │ │ └── Verification 'ExecutionReport' message\n", - "│ │ ├── Check sequence (expected 2 / actual 2 , check order true)\n", - "│ │ └── Pre-filtering (filtered 2 / processed 2) messages\n", - "│ │ ├── Verification 'ExecutionReport' message\n", - "│ │ └── Verification 'ExecutionReport' message\n", - "│ ├── Check sequence rule SessionKey{sessionAlias='demo-conn2', direction=FIRST} - STEP7: Trader \"DEMO-CONN2\" receives Execution Reports: first trade with Order2, next with Order1 and then cancellation\n", - "│ │ ├── Check messages\n", - "│ │ │ ├── Verification 'ExecutionReport' message\n", - "│ │ │ ├── Verification 'ExecutionReport' message\n", - "│ │ │ └── Verification 'ExecutionReport' message\n", - "│ │ ├── Check sequence (expected 3 / actual 3 , check order true)\n", - "│ │ └── Pre-filtering (filtered 3 / processed 3) messages\n", - "│ │ ├── Verification 'ExecutionReport' message\n", - "│ │ ├── Verification 'ExecutionReport' message\n", - "│ │ └── Verification 'ExecutionReport' message\n", - "│ ├── placeOrderFIX demo-conn1 - STEP1: Trader \"DEMO-CONN1\" sends request to create passive Order.\n", - "│ │ ├── Checkpoint\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn1' direction 'FIRST' sequence '1624005455622011526'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn1' direction 'SECOND' sequence '1624005455622140291'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn2' direction 'FIRST' sequence '1624005448022245402'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn2' direction 'SECOND' sequence '1624005448022426114'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc1' direction 'FIRST' sequence '1624005475720919503'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc1' direction 'SECOND' sequence '1624005475721015015'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc2' direction 'FIRST' sequence '1624005466840263375'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc2' direction 'SECOND' sequence '1624005466840347016'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-log' direction 'FIRST' sequence '1624029363623063053'\n", - "│ │ │ └── Checkpoint for session alias 'th2-hand-demo' direction 'FIRST' sequence '1623852603564709030'\n", - "│ │ ├── Received 'ExecutionReport' response message\n", - "│ │ ├── Send 'NewOrderSingle' message\n", - "│ │ └── Send 'NewOrderSingle' message to connectivity\n", - "│ ├── placeOrderFIX demo-conn1 - STEP3: Trader \"DEMO-CONN1\" sends request to create passive Order with price lower than first order.\n", - "│ │ ├── Checkpoint\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn1' direction 'FIRST' sequence '1624005455622011527'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn1' direction 'SECOND' sequence '1624005455622140292'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn2' direction 'FIRST' sequence '1624005448022245402'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn2' direction 'SECOND' sequence '1624005448022426114'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc1' direction 'FIRST' sequence '1624005475720919504'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc1' direction 'SECOND' sequence '1624005475721015015'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc2' direction 'FIRST' sequence '1624005466840263375'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc2' direction 'SECOND' sequence '1624005466840347016'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-log' direction 'FIRST' sequence '1624029363623063053'\n", - "│ │ │ └── Checkpoint for session alias 'th2-hand-demo' direction 'FIRST' sequence '1623852603564709030'\n", - "│ │ ├── Received 'ExecutionReport' response message\n", - "│ │ ├── Send 'NewOrderSingle' message\n", - "│ │ └── Send 'NewOrderSingle' message to connectivity\n", - "│ └── placeOrderFIX demo-conn2 - STEP5: Trader \"DEMO-CONN2\" sends request to create aggressive IOC Order.\n", - "│ ├── Checkpoint\n", - "│ │ ├── Checkpoint for session alias 'demo-conn1' direction 'FIRST' sequence '1624005455622011528'\n", - "│ │ ├── Checkpoint for session alias 'demo-conn1' direction 'SECOND' sequence '1624005455622140293'\n", - "│ │ ├── Checkpoint for session alias 'demo-conn2' direction 'FIRST' sequence '1624005448022245402'\n", - "│ │ ├── Checkpoint for session alias 'demo-conn2' direction 'SECOND' sequence '1624005448022426114'\n", - "│ │ ├── Checkpoint for session alias 'demo-dc1' direction 'FIRST' sequence '1624005475720919505'\n", - "│ │ ├── Checkpoint for session alias 'demo-dc1' direction 'SECOND' sequence '1624005475721015015'\n", - "│ │ ├── Checkpoint for session alias 'demo-dc2' direction 'FIRST' sequence '1624005466840263375'\n", - "│ │ ├── Checkpoint for session alias 'demo-dc2' direction 'SECOND' sequence '1624005466840347016'\n", - "│ │ ├── Checkpoint for session alias 'demo-log' direction 'FIRST' sequence '1624029363623063053'\n", - "│ │ └── Checkpoint for session alias 'th2-hand-demo' direction 'FIRST' sequence '1623852603564709030'\n", - "│ ├── Received 'ExecutionReport' response message\n", - "│ ├── Send 'NewOrderSingle' message\n", - "│ └── Send 'NewOrderSingle' message to connectivity\n", - "├── Case[TC_1.3]: Trader DEMO-CONN1 vs trader DEMO-CONN2 for instrument INSTR3\n", - "│ ├── Check sequence rule SessionKey{sessionAlias='demo-conn1', direction=FIRST} - STEP2: Trader \"DEMO-CONN1\" receives Execution Report. The order stands on book in status NEW\n", - "│ │ ├── Check messages\n", - "│ │ │ └── Verification 'ExecutionReport' message\n", - "│ │ ├── Check sequence (expected 1 / actual 1 , check order false)\n", - "│ │ └── Pre-filtering (filtered 1 / processed 1) messages\n", - "│ │ └── Verification 'ExecutionReport' message\n", - "│ ├── Check sequence rule SessionKey{sessionAlias='demo-conn1', direction=FIRST} - STEP4: Trader \"DEMO-CONN1\" receives Execution Report. The order stands on book in status NEW\n", - "│ │ ├── Check messages\n", - "│ │ │ └── Verification 'ExecutionReport' message\n", - "│ │ ├── Check sequence (expected 1 / actual 1 , check order false)\n", - "│ │ └── Pre-filtering (filtered 1 / processed 1) messages\n", - "│ │ └── Verification 'ExecutionReport' message\n", - "│ ├── Check sequence rule SessionKey{sessionAlias='demo-conn1', direction=FIRST} - STEP6: Trader \"DEMO-CONN1\" receives Execution Reports with ExecType=F: first at Order2 and second on Order1.\n", - "│ │ ├── Check messages\n", - "│ │ │ ├── Verification 'ExecutionReport' message\n", - "│ │ │ └── Verification 'ExecutionReport' message\n", - "│ │ ├── Check sequence (expected 2 / actual 2 , check order true)\n", - "│ │ └── Pre-filtering (filtered 2 / processed 2) messages\n", - "│ │ ├── Verification 'ExecutionReport' message\n", - "│ │ └── Verification 'ExecutionReport' message\n", - "│ ├── Check sequence rule SessionKey{sessionAlias='demo-conn2', direction=FIRST} - STEP7: Trader \"DEMO-CONN2\" receives Execution Reports: first trade with Order2, next with Order1 and then cancellation\n", - "│ │ ├── Check messages\n", - "│ │ │ ├── Verification 'ExecutionReport' message\n", - "│ │ │ ├── Verification 'ExecutionReport' message\n", - "│ │ │ └── Verification 'ExecutionReport' message\n", - "│ │ ├── Check sequence (expected 3 / actual 3 , check order true)\n", - "│ │ └── Pre-filtering (filtered 3 / processed 3) messages\n", - "│ │ ├── Verification 'ExecutionReport' message\n", - "│ │ ├── Verification 'ExecutionReport' message\n", - "│ │ └── Verification 'ExecutionReport' message\n", - "│ ├── placeOrderFIX demo-conn1 - STEP1: Trader \"DEMO-CONN1\" sends request to create passive Order.\n", - "│ │ ├── Checkpoint\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn1' direction 'FIRST' sequence '1624005455622011530'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn1' direction 'SECOND' sequence '1624005455622140293'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn2' direction 'FIRST' sequence '1624005448022245405'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn2' direction 'SECOND' sequence '1624005448022426115'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc1' direction 'FIRST' sequence '1624005475720919507'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc1' direction 'SECOND' sequence '1624005475721015015'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc2' direction 'FIRST' sequence '1624005466840263378'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc2' direction 'SECOND' sequence '1624005466840347016'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-log' direction 'FIRST' sequence '1624029363623063053'\n", - "│ │ │ └── Checkpoint for session alias 'th2-hand-demo' direction 'FIRST' sequence '1623852603564709030'\n", - "│ │ ├── Received 'ExecutionReport' response message\n", - "│ │ ├── Send 'NewOrderSingle' message\n", - "│ │ └── Send 'NewOrderSingle' message to connectivity\n", - "│ ├── placeOrderFIX demo-conn1 - STEP3: Trader \"DEMO-CONN1\" sends request to create passive Order with price lower than first order.\n", - "│ │ ├── Checkpoint\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn1' direction 'FIRST' sequence '1624005455622011531'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn1' direction 'SECOND' sequence '1624005455622140294'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn2' direction 'FIRST' sequence '1624005448022245405'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn2' direction 'SECOND' sequence '1624005448022426115'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc1' direction 'FIRST' sequence '1624005475720919508'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc1' direction 'SECOND' sequence '1624005475721015015'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc2' direction 'FIRST' sequence '1624005466840263378'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc2' direction 'SECOND' sequence '1624005466840347016'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-log' direction 'FIRST' sequence '1624029363623063053'\n", - "│ │ │ └── Checkpoint for session alias 'th2-hand-demo' direction 'FIRST' sequence '1623852603564709030'\n", - "│ │ ├── Received 'ExecutionReport' response message\n", - "│ │ ├── Send 'NewOrderSingle' message\n", - "│ │ └── Send 'NewOrderSingle' message to connectivity\n", - "│ └── placeOrderFIX demo-conn2 - STEP5: Trader \"DEMO-CONN2\" sends request to create aggressive IOC Order.\n", - "│ ├── Checkpoint\n", - "│ │ ├── Checkpoint for session alias 'demo-conn1' direction 'FIRST' sequence '1624005455622011532'\n", - "│ │ ├── Checkpoint for session alias 'demo-conn1' direction 'SECOND' sequence '1624005455622140295'\n", - "│ │ ├── Checkpoint for session alias 'demo-conn2' direction 'FIRST' sequence '1624005448022245405'\n", - "│ │ ├── Checkpoint for session alias 'demo-conn2' direction 'SECOND' sequence '1624005448022426115'\n", - "│ │ ├── Checkpoint for session alias 'demo-dc1' direction 'FIRST' sequence '1624005475720919509'\n", - "│ │ ├── Checkpoint for session alias 'demo-dc1' direction 'SECOND' sequence '1624005475721015015'\n", - "│ │ ├── Checkpoint for session alias 'demo-dc2' direction 'FIRST' sequence '1624005466840263378'\n", - "│ │ ├── Checkpoint for session alias 'demo-dc2' direction 'SECOND' sequence '1624005466840347016'\n", - "│ │ ├── Checkpoint for session alias 'demo-log' direction 'FIRST' sequence '1624029363623063053'\n", - "│ │ └── Checkpoint for session alias 'th2-hand-demo' direction 'FIRST' sequence '1623852603564709030'\n", - "│ ├── Received 'ExecutionReport' response message\n", - "│ ├── Send 'NewOrderSingle' message\n", - "│ └── Send 'NewOrderSingle' message to connectivity\n", - "├── Case[TC_1.4]: Trader DEMO-CONN1 vs trader DEMO-CONN2 for instrument INSTR4\n", - "│ ├── Check sequence rule SessionKey{sessionAlias='demo-conn1', direction=FIRST} - STEP2: Trader \"DEMO-CONN1\" receives Execution Report. The order stands on book in status NEW\n", - "│ │ ├── Check messages\n", - "│ │ │ └── Verification 'ExecutionReport' message\n", - "│ │ ├── Check sequence (expected 1 / actual 1 , check order false)\n", - "│ │ └── Pre-filtering (filtered 1 / processed 1) messages\n", - "│ │ └── Verification 'ExecutionReport' message\n", - "│ ├── Check sequence rule SessionKey{sessionAlias='demo-conn1', direction=FIRST} - STEP4: Trader \"DEMO-CONN1\" receives Execution Report. The order stands on book in status NEW\n", - "│ │ ├── Check messages\n", - "│ │ │ └── Verification 'ExecutionReport' message\n", - "│ │ ├── Check sequence (expected 1 / actual 1 , check order false)\n", - "│ │ └── Pre-filtering (filtered 1 / processed 1) messages\n", - "│ │ └── Verification 'ExecutionReport' message\n", - "│ ├── Check sequence rule SessionKey{sessionAlias='demo-conn1', direction=FIRST} - STEP6: Trader \"DEMO-CONN1\" receives Execution Reports with ExecType=F: first at Order2 and second on Order1.\n", - "│ │ ├── Check messages\n", - "│ │ │ ├── Verification 'ExecutionReport' message\n", - "│ │ │ └── Verification 'ExecutionReport' message\n", - "│ │ ├── Check sequence (expected 2 / actual 2 , check order true)\n", - "│ │ └── Pre-filtering (filtered 2 / processed 2) messages\n", - "│ │ ├── Verification 'ExecutionReport' message\n", - "│ │ └── Verification 'ExecutionReport' message\n", - "│ ├── Check sequence rule SessionKey{sessionAlias='demo-conn2', direction=FIRST} - STEP7: Trader \"DEMO-CONN2\" receives Execution Reports: first trade with Order2, next with Order1 and then cancellation\n", - "│ │ ├── Check messages\n", - "│ │ │ ├── Verification 'ExecutionReport' message\n", - "│ │ │ ├── Verification 'ExecutionReport' message\n", - "│ │ │ └── Verification 'ExecutionReport' message\n", - "│ │ ├── Check sequence (expected 3 / actual 4 , check order true)\n", - "│ │ └── Pre-filtering (filtered 4 / processed 4) messages\n", - "│ │ ├── Verification 'ExecutionReport' message\n", - "│ │ ├── Verification 'ExecutionReport' message\n", - "│ │ ├── Verification 'ExecutionReport' message\n", - "│ │ └── Verification 'ExecutionReport' message\n", - "│ ├── placeOrderFIX demo-conn1 - STEP1: Trader \"DEMO-CONN1\" sends request to create passive Order.\n", - "│ │ ├── Checkpoint\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn1' direction 'FIRST' sequence '1624005455622011534'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn1' direction 'SECOND' sequence '1624005455622140295'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn2' direction 'FIRST' sequence '1624005448022245408'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn2' direction 'SECOND' sequence '1624005448022426116'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc1' direction 'FIRST' sequence '1624005475720919511'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc1' direction 'SECOND' sequence '1624005475721015015'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc2' direction 'FIRST' sequence '1624005466840263381'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc2' direction 'SECOND' sequence '1624005466840347016'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-log' direction 'FIRST' sequence '1624029363623063053'\n", - "│ │ │ └── Checkpoint for session alias 'th2-hand-demo' direction 'FIRST' sequence '1623852603564709030'\n", - "│ │ ├── Received 'ExecutionReport' response message\n", - "│ │ ├── Send 'NewOrderSingle' message\n", - "│ │ └── Send 'NewOrderSingle' message to connectivity\n", - "│ ├── placeOrderFIX demo-conn1 - STEP3: Trader \"DEMO-CONN1\" sends request to create passive Order with price lower than first order.\n", - "│ │ ├── Checkpoint\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn1' direction 'FIRST' sequence '1624005455622011535'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn1' direction 'SECOND' sequence '1624005455622140296'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn2' direction 'FIRST' sequence '1624005448022245408'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn2' direction 'SECOND' sequence '1624005448022426116'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc1' direction 'FIRST' sequence '1624005475720919512'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc1' direction 'SECOND' sequence '1624005475721015015'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc2' direction 'FIRST' sequence '1624005466840263381'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc2' direction 'SECOND' sequence '1624005466840347016'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-log' direction 'FIRST' sequence '1624029363623063053'\n", - "│ │ │ └── Checkpoint for session alias 'th2-hand-demo' direction 'FIRST' sequence '1623852603564709030'\n", - "│ │ ├── Received 'ExecutionReport' response message\n", - "│ │ ├── Send 'NewOrderSingle' message\n", - "│ │ └── Send 'NewOrderSingle' message to connectivity\n", - "│ └── placeOrderFIX demo-conn2 - STEP5: Trader \"DEMO-CONN2\" sends request to create aggressive IOC Order.\n", - "│ ├── Checkpoint\n", - "│ │ ├── Checkpoint for session alias 'demo-conn1' direction 'FIRST' sequence '1624005455622011536'\n", - "│ │ ├── Checkpoint for session alias 'demo-conn1' direction 'SECOND' sequence '1624005455622140297'\n", - "│ │ ├── Checkpoint for session alias 'demo-conn2' direction 'FIRST' sequence '1624005448022245408'\n", - "│ │ ├── Checkpoint for session alias 'demo-conn2' direction 'SECOND' sequence '1624005448022426116'\n", - "│ │ ├── Checkpoint for session alias 'demo-dc1' direction 'FIRST' sequence '1624005475720919513'\n", - "│ │ ├── Checkpoint for session alias 'demo-dc1' direction 'SECOND' sequence '1624005475721015015'\n", - "│ │ ├── Checkpoint for session alias 'demo-dc2' direction 'FIRST' sequence '1624005466840263381'\n", - "│ │ ├── Checkpoint for session alias 'demo-dc2' direction 'SECOND' sequence '1624005466840347016'\n", - "│ │ ├── Checkpoint for session alias 'demo-log' direction 'FIRST' sequence '1624029363623063053'\n", - "│ │ └── Checkpoint for session alias 'th2-hand-demo' direction 'FIRST' sequence '1623852603564709030'\n", - "│ ├── Received 'ExecutionReport' response message\n", - "│ ├── Send 'NewOrderSingle' message\n", - "│ └── Send 'NewOrderSingle' message to connectivity\n", - "├── Case[TC_1.5]: Trader DEMO-CONN1 vs trader DEMO-CONN2 for instrument INSTR5\n", - "│ ├── Check sequence rule SessionKey{sessionAlias='demo-conn1', direction=FIRST} - STEP2: Trader \"DEMO-CONN1\" receives Execution Report. The order stands on book in status NEW\n", - "│ │ ├── Check messages\n", - "│ │ │ └── Verification 'ExecutionReport' message\n", - "│ │ ├── Check sequence (expected 1 / actual 1 , check order false)\n", - "│ │ └── Pre-filtering (filtered 1 / processed 1) messages\n", - "│ │ └── Verification 'ExecutionReport' message\n", - "│ ├── Check sequence rule SessionKey{sessionAlias='demo-conn1', direction=FIRST} - STEP4: Trader \"DEMO-CONN1\" receives Execution Report. The order stands on book in status NEW\n", - "│ │ ├── Check messages\n", - "│ │ │ └── Verification 'ExecutionReport' message\n", - "│ │ ├── Check sequence (expected 1 / actual 1 , check order false)\n", - "│ │ └── Pre-filtering (filtered 1 / processed 1) messages\n", - "│ │ └── Verification 'ExecutionReport' message\n", - "│ ├── Check sequence rule SessionKey{sessionAlias='demo-conn1', direction=FIRST} - STEP6: Trader \"DEMO-CONN1\" receives Execution Reports with ExecType=F: first at Order2 and second on Order1.\n", - "│ │ ├── Check messages\n", - "│ │ │ ├── Verification 'ExecutionReport' message\n", - "│ │ │ └── Verification 'ExecutionReport' message\n", - "│ │ ├── Check sequence (expected 2 / actual 2 , check order true)\n", - "│ │ └── Pre-filtering (filtered 2 / processed 2) messages\n", - "│ │ ├── Verification 'ExecutionReport' message\n", - "│ │ └── Verification 'ExecutionReport' message\n", - "│ ├── Check sequence rule SessionKey{sessionAlias='demo-conn2', direction=FIRST} - STEP7: Trader \"DEMO-CONN2\" receives Execution Reports: first trade with Order2, next with Order1 and then cancellation\n", - "│ │ ├── Check messages\n", - "│ │ │ ├── Verification 'ExecutionReport' message\n", - "│ │ │ ├── Verification 'ExecutionReport' message\n", - "│ │ │ └── Verification 'ExecutionReport' message\n", - "│ │ ├── Check sequence (expected 3 / actual 3 , check order true)\n", - "│ │ └── Pre-filtering (filtered 3 / processed 3) messages\n", - "│ │ ├── Verification 'ExecutionReport' message\n", - "│ │ ├── Verification 'ExecutionReport' message\n", - "│ │ └── Verification 'ExecutionReport' message\n", - "│ ├── placeOrderFIX demo-conn1 - STEP1: Trader \"DEMO-CONN1\" sends request to create passive Order.\n", - "│ │ ├── Checkpoint\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn1' direction 'FIRST' sequence '1624005455622011538'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn1' direction 'SECOND' sequence '1624005455622140297'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn2' direction 'FIRST' sequence '1624005448022245412'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn2' direction 'SECOND' sequence '1624005448022426117'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc1' direction 'FIRST' sequence '1624005475720919515'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc1' direction 'SECOND' sequence '1624005475721015015'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc2' direction 'FIRST' sequence '1624005466840263384'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc2' direction 'SECOND' sequence '1624005466840347016'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-log' direction 'FIRST' sequence '1624029363623063053'\n", - "│ │ │ └── Checkpoint for session alias 'th2-hand-demo' direction 'FIRST' sequence '1623852603564709030'\n", - "│ │ ├── Received 'ExecutionReport' response message\n", - "│ │ ├── Send 'NewOrderSingle' message\n", - "│ │ └── Send 'NewOrderSingle' message to connectivity\n", - "│ ├── placeOrderFIX demo-conn1 - STEP3: Trader \"DEMO-CONN1\" sends request to create passive Order with price lower than first order.\n", - "│ │ ├── Checkpoint\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn1' direction 'FIRST' sequence '1624005455622011539'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn1' direction 'SECOND' sequence '1624005455622140298'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn2' direction 'FIRST' sequence '1624005448022245412'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-conn2' direction 'SECOND' sequence '1624005448022426117'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc1' direction 'FIRST' sequence '1624005475720919516'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc1' direction 'SECOND' sequence '1624005475721015015'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc2' direction 'FIRST' sequence '1624005466840263384'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-dc2' direction 'SECOND' sequence '1624005466840347016'\n", - "│ │ │ ├── Checkpoint for session alias 'demo-log' direction 'FIRST' sequence '1624029363623063053'\n", - "│ │ │ └── Checkpoint for session alias 'th2-hand-demo' direction 'FIRST' sequence '1623852603564709030'\n", - "│ │ ├── Received 'ExecutionReport' response message\n", - "│ │ ├── Send 'NewOrderSingle' message\n", - "│ │ └── Send 'NewOrderSingle' message to connectivity\n", - "│ └── placeOrderFIX demo-conn2 - STEP5: Trader \"DEMO-CONN2\" sends request to create aggressive IOC Order.\n", - "│ ├── Checkpoint\n", - "│ │ ├── Checkpoint for session alias 'demo-conn1' direction 'FIRST' sequence '1624005455622011540'\n", - "│ │ ├── Checkpoint for session alias 'demo-conn1' direction 'SECOND' sequence '1624005455622140299'\n", - "│ │ ├── Checkpoint for session alias 'demo-conn2' direction 'FIRST' sequence '1624005448022245412'\n", - "│ │ ├── Checkpoint for session alias 'demo-conn2' direction 'SECOND' sequence '1624005448022426117'\n", - "│ │ ├── Checkpoint for session alias 'demo-dc1' direction 'FIRST' sequence '1624005475720919517'\n", - "│ │ ├── Checkpoint for session alias 'demo-dc1' direction 'SECOND' sequence '1624005475721015015'\n", - "│ │ ├── Checkpoint for session alias 'demo-dc2' direction 'FIRST' sequence '1624005466840263384'\n", - "│ │ ├── Checkpoint for session alias 'demo-dc2' direction 'SECOND' sequence '1624005466840347016'\n", - "│ │ ├── Checkpoint for session alias 'demo-log' direction 'FIRST' sequence '1624029363623063053'\n", - "│ │ └── Checkpoint for session alias 'th2-hand-demo' direction 'FIRST' sequence '1623852603564709030'\n", - "│ ├── Received 'ExecutionReport' response message\n", - "│ ├── Send 'NewOrderSingle' message\n", - "│ └── Send 'NewOrderSingle' message to connectivity\n", - "└── Case[TC_1.6]: Trader DEMO-CONN1 vs trader DEMO-CONN2 for instrument INSTR6\n", - " └── placeOrderFIX demo-conn1 - STEP1: Trader \"DEMO-CONN1\" sends request to create passive Order.\n", - " ├── Checkpoint\n", - " │ ├── Checkpoint for session alias 'demo-conn1' direction 'FIRST' sequence '1624005455622011542'\n", - " │ ├── Checkpoint for session alias 'demo-conn1' direction 'SECOND' sequence '1624005455622140299'\n", - " │ ├── Checkpoint for session alias 'demo-conn2' direction 'FIRST' sequence '1624005448022245415'\n", - " │ ├── Checkpoint for session alias 'demo-conn2' direction 'SECOND' sequence '1624005448022426118'\n", - " │ ├── Checkpoint for session alias 'demo-dc1' direction 'FIRST' sequence '1624005475720919519'\n", - " │ ├── Checkpoint for session alias 'demo-dc1' direction 'SECOND' sequence '1624005475721015016'\n", - " │ ├── Checkpoint for session alias 'demo-dc2' direction 'FIRST' sequence '1624005466840263387'\n", - " │ ├── Checkpoint for session alias 'demo-dc2' direction 'SECOND' sequence '1624005466840347017'\n", - " │ ├── Checkpoint for session alias 'demo-log' direction 'FIRST' sequence '1624029363623063053'\n", - " │ └── Checkpoint for session alias 'th2-hand-demo' direction 'FIRST' sequence '1623852603564709030'\n", - " ├── Received 'BusinessMessageReject' response message\n", - " ├── Send 'NewOrderSingle' message\n", - " └── Send 'NewOrderSingle' message to connectivity\n", - "\n" - ] - } - ], - "source": [ - "tree = collection.get_trees()[0]\n", - "tree.show()" - ] - }, - { - "cell_type": "markdown", - "id": "1994c1c1", - "metadata": {}, - "source": [ - "You can get subtree by id use `get_subtree(event_id)` method in the collection or each tree.." - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "87af9d17", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "placeOrderFIX demo-conn1 - STEP3: Trader \"DEMO-CONN1\" sends request to create passive Order with price lower than first order.\n", - "├── Checkpoint\n", - "│ ├── Checkpoint for session alias 'demo-conn1' direction 'FIRST' sequence '1624005455622011523'\n", - "│ ├── Checkpoint for session alias 'demo-conn1' direction 'SECOND' sequence '1624005455622140290'\n", - "│ ├── Checkpoint for session alias 'demo-conn2' direction 'FIRST' sequence '1624005448022245399'\n", - "│ ├── Checkpoint for session alias 'demo-conn2' direction 'SECOND' sequence '1624005448022426113'\n", - "│ ├── Checkpoint for session alias 'demo-dc1' direction 'FIRST' sequence '1624005475720919500'\n", - "│ ├── Checkpoint for session alias 'demo-dc1' direction 'SECOND' sequence '1624005475721015014'\n", - "│ ├── Checkpoint for session alias 'demo-dc2' direction 'FIRST' sequence '1624005466840263372'\n", - "│ ├── Checkpoint for session alias 'demo-dc2' direction 'SECOND' sequence '1624005466840347015'\n", - "│ ├── Checkpoint for session alias 'demo-log' direction 'FIRST' sequence '1624029363623063053'\n", - "│ └── Checkpoint for session alias 'th2-hand-demo' direction 'FIRST' sequence '1623852603564709030'\n", - "├── Received 'ExecutionReport' response message\n", - "├── Send 'NewOrderSingle' message\n", - "└── Send 'NewOrderSingle' message to connectivity\n", - "\n" - ] - } - ], - "source": [ - "tree.get_subtree(\"8d7ed4f1-d1b4-11eb-bae5-57b0c4472880\").show()" - ] - }, - { - "cell_type": "markdown", - "id": "fb3da910", - "metadata": {}, - "source": [ - "You can get leaves from all trees use `get_leaves()` method in the collection or each tree." - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "24081502", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'attachedMessageIds': [],\n", - " 'batchId': '53c1abd6-b2f9-4378-b061-434a3315c4a2',\n", - " 'endTimestamp': {'epochSecond': 1624185896, 'nano': 625264000},\n", - " 'eventId': '53c1abd6-b2f9-4378-b061-434a3315c4a2:8d722b53-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '8d722b52-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185896, 'nano': 205141000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'e71f316c-6912-43b1-a6cb-60c328a8239b',\n", - " 'endTimestamp': {'epochSecond': 1624185896, 'nano': 419542000},\n", - " 'eventId': 'e71f316c-6912-43b1-a6cb-60c328a8239b:8d71dd30-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '8d6f6c2f-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185896, 'nano': 214108000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '9df66bf9-adeb-4443-aeb1-aafcdfff6b66',\n", - " 'endTimestamp': {'epochSecond': 1624185898, 'nano': 46707000},\n", - " 'eventId': '9df66bf9-adeb-4443-aeb1-aafcdfff6b66:8e86f6c4-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '8e86f6c3-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185898, 'nano': 39168000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '064f3825-7ed0-4ae8-a5ef-a6b339d894e3',\n", - " 'endTimestamp': {'epochSecond': 1624185898, 'nano': 46525000},\n", - " 'eventId': '064f3825-7ed0-4ae8-a5ef-a6b339d894e3:8e86cfb1-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '8e868190-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185898, 'nano': 43152000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'f01baf75-606b-47f7-95ac-75b797efd7ed',\n", - " 'endTimestamp': {'epochSecond': 1624185899, 'nano': 719106000},\n", - " 'eventId': 'f01baf75-606b-47f7-95ac-75b797efd7ed:8f7a5786-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '8f7a5785-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185899, 'nano': 620545000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'f01baf75-606b-47f7-95ac-75b797efd7ed',\n", - " 'endTimestamp': {'epochSecond': 1624185899, 'nano': 719362000},\n", - " 'eventId': 'f01baf75-606b-47f7-95ac-75b797efd7ed:8f7a5787-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '8f7a5785-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185899, 'nano': 620545000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '97ed6ada-667e-4d7e-b39c-90f8be81b8f3',\n", - " 'endTimestamp': {'epochSecond': 1624185899, 'nano': 642180000},\n", - " 'eventId': '97ed6ada-667e-4d7e-b39c-90f8be81b8f3:8f799432-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '8f7834a1-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185899, 'nano': 627174000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '97ed6ada-667e-4d7e-b39c-90f8be81b8f3',\n", - " 'endTimestamp': {'epochSecond': 1624185899, 'nano': 718695000},\n", - " 'eventId': '97ed6ada-667e-4d7e-b39c-90f8be81b8f3:8f7a0963-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '8f7834a1-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185899, 'nano': 627174000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'f3042deb-f287-40a7-b4d9-97a61f4e061f',\n", - " 'endTimestamp': {'epochSecond': 1624185899, 'nano': 936038000},\n", - " 'eventId': 'f3042deb-f287-40a7-b4d9-97a61f4e061f:8fa6709f-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '8fa6709e-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185899, 'nano': 724004000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'f3042deb-f287-40a7-b4d9-97a61f4e061f',\n", - " 'endTimestamp': {'epochSecond': 1624185899, 'nano': 936160000},\n", - " 'eventId': 'f3042deb-f287-40a7-b4d9-97a61f4e061f:8fa670a0-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '8fa6709e-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185899, 'nano': 724004000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'f3042deb-f287-40a7-b4d9-97a61f4e061f',\n", - " 'endTimestamp': {'epochSecond': 1624185899, 'nano': 936270000},\n", - " 'eventId': 'f3042deb-f287-40a7-b4d9-97a61f4e061f:8fa670a1-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '8fa6709e-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185899, 'nano': 724004000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '79ec9dec-7d95-43f8-8cf3-4f6f4e117e31',\n", - " 'endTimestamp': {'epochSecond': 1624185899, 'nano': 933217000},\n", - " 'eventId': '79ec9dec-7d95-43f8-8cf3-4f6f4e117e31:8fa5381a-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '8f9643f9-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185899, 'nano': 824990000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '79ec9dec-7d95-43f8-8cf3-4f6f4e117e31',\n", - " 'endTimestamp': {'epochSecond': 1624185899, 'nano': 935174000},\n", - " 'eventId': '79ec9dec-7d95-43f8-8cf3-4f6f4e117e31:8fa5ad4b-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '8f9643f9-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185899, 'nano': 824990000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '79ec9dec-7d95-43f8-8cf3-4f6f4e117e31',\n", - " 'endTimestamp': {'epochSecond': 1624185899, 'nano': 935305000},\n", - " 'eventId': '79ec9dec-7d95-43f8-8cf3-4f6f4e117e31:8fa6498c-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '8f9643f9-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185899, 'nano': 824990000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'e37ef8f1-66da-4d6f-b7a8-2b7b807a15ef',\n", - " 'endTimestamp': {'epochSecond': 1624185906, 'nano': 50756000},\n", - " 'eventId': 'e37ef8f1-66da-4d6f-b7a8-2b7b807a15ef:934c4632-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '934c4631-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185906, 'nano': 40599000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '22c8431b-4f2d-466c-986f-3db7536509ce',\n", - " 'endTimestamp': {'epochSecond': 1624185906, 'nano': 50566000},\n", - " 'eventId': '22c8431b-4f2d-466c-986f-3db7536509ce:934bf80f-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '934b34be-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185906, 'nano': 43263000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'f7e3700f-e6f1-4afc-88eb-f3ab83ca58c7',\n", - " 'endTimestamp': {'epochSecond': 1624185907, 'nano': 52516000},\n", - " 'eventId': 'f7e3700f-e6f1-4afc-88eb-f3ab83ca58c7:93e52ae3-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '93e52ae2-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 42554000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'fcf9b609-d48b-4eb7-9113-72c0063f65b1',\n", - " 'endTimestamp': {'epochSecond': 1624185907, 'nano': 52322000},\n", - " 'eventId': 'fcf9b609-d48b-4eb7-9113-72c0063f65b1:93e4b5b0-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '93e4196f-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 45671000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '366d2588-09ef-45a3-ae88-0b930155e83e',\n", - " 'endTimestamp': {'epochSecond': 1624185907, 'nano': 948994000},\n", - " 'eventId': '366d2588-09ef-45a3-ae88-0b930155e83e:946dbbe9-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '946dbbe8-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 619288000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '366d2588-09ef-45a3-ae88-0b930155e83e',\n", - " 'endTimestamp': {'epochSecond': 1624185907, 'nano': 949096000},\n", - " 'eventId': '366d2588-09ef-45a3-ae88-0b930155e83e:946dbbea-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '946dbbe8-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 619288000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'f5aec070-b5e5-49b3-a58e-790582731807',\n", - " 'endTimestamp': {'epochSecond': 1624185907, 'nano': 948731000},\n", - " 'eventId': 'f5aec070-b5e5-49b3-a58e-790582731807:946c5c55-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '943d3600-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 629360000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'f5aec070-b5e5-49b3-a58e-790582731807',\n", - " 'endTimestamp': {'epochSecond': 1624185907, 'nano': 948869000},\n", - " 'eventId': 'f5aec070-b5e5-49b3-a58e-790582731807:946d6dc6-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '943d3600-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 629360000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '04070d56-5434-41ea-b009-bff5c140d49b',\n", - " 'endTimestamp': {'epochSecond': 1624185908, 'nano': 529073000},\n", - " 'eventId': '04070d56-5434-41ea-b009-bff5c140d49b:94c6633e-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '94c6633d-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 720896000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '04070d56-5434-41ea-b009-bff5c140d49b',\n", - " 'endTimestamp': {'epochSecond': 1624185908, 'nano': 529193000},\n", - " 'eventId': '04070d56-5434-41ea-b009-bff5c140d49b:94c6633f-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '94c6633d-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 720896000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '04070d56-5434-41ea-b009-bff5c140d49b',\n", - " 'endTimestamp': {'epochSecond': 1624185908, 'nano': 529307000},\n", - " 'eventId': '04070d56-5434-41ea-b009-bff5c140d49b:94c66340-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '94c6633d-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 720896000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '2527fc47-219f-43fd-89d4-122914ce928f',\n", - " 'endTimestamp': {'epochSecond': 1624185908, 'nano': 528504000},\n", - " 'eventId': '2527fc47-219f-43fd-89d4-122914ce928f:945a33e3-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '944bdc02-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 725559000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '2527fc47-219f-43fd-89d4-122914ce928f',\n", - " 'endTimestamp': {'epochSecond': 1624185908, 'nano': 528667000},\n", - " 'eventId': '2527fc47-219f-43fd-89d4-122914ce928f:945b1e44-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '944bdc02-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 725559000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '2527fc47-219f-43fd-89d4-122914ce928f',\n", - " 'endTimestamp': {'epochSecond': 1624185908, 'nano': 528898000},\n", - " 'eventId': '2527fc47-219f-43fd-89d4-122914ce928f:94c6151b-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '944bdc02-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 725559000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'fb053f79-4984-4f03-838f-6a7e08c98bb0',\n", - " 'endTimestamp': {'epochSecond': 1624185914, 'nano': 24365000},\n", - " 'eventId': 'fb053f79-4984-4f03-838f-6a7e08c98bb0:980d02d1-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '980d02d0-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185914, 'nano': 14475000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '4c51691c-0c52-4122-99a2-eff896ffcb71',\n", - " 'endTimestamp': {'epochSecond': 1624185914, 'nano': 24206000},\n", - " 'eventId': '4c51691c-0c52-4122-99a2-eff896ffcb71:980c8d9e-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '980bca4d-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185914, 'nano': 16745000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '18cea323-8d10-48fe-b897-f97d1af5929f',\n", - " 'endTimestamp': {'epochSecond': 1624185915, 'nano': 27994000},\n", - " 'eventId': '18cea323-8d10-48fe-b897-f97d1af5929f:98a5c072-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '98a5c071-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185915, 'nano': 18949000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'ccc5302a-b013-4440-a51e-e9c02cb6ee2d',\n", - " 'endTimestamp': {'epochSecond': 1624185915, 'nano': 26120000},\n", - " 'eventId': 'ccc5302a-b013-4440-a51e-e9c02cb6ee2d:98a5995f-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '98a4fd1e-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185915, 'nano': 20187000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '79b111a6-4a29-4ae8-9a23-d961718e859e',\n", - " 'endTimestamp': {'epochSecond': 1624185916, 'nano': 118705000},\n", - " 'eventId': '79b111a6-4a29-4ae8-9a23-d961718e859e:993ef344-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '993ef343-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185915, 'nano': 929958000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '79b111a6-4a29-4ae8-9a23-d961718e859e',\n", - " 'endTimestamp': {'epochSecond': 1624185916, 'nano': 118911000},\n", - " 'eventId': '79b111a6-4a29-4ae8-9a23-d961718e859e:993ef345-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '993ef343-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185915, 'nano': 929958000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '243c5259-0247-458a-85bd-89cb0dc50317',\n", - " 'endTimestamp': {'epochSecond': 1624185916, 'nano': 29696000},\n", - " 'eventId': '243c5259-0247-458a-85bd-89cb0dc50317:993e5700-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '993de1cf-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185916, 'nano': 22973000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '243c5259-0247-458a-85bd-89cb0dc50317',\n", - " 'endTimestamp': {'epochSecond': 1624185916, 'nano': 29771000},\n", - " 'eventId': '243c5259-0247-458a-85bd-89cb0dc50317:993ecc31-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '993de1cf-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185916, 'nano': 22973000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '294e4c48-7ea5-4068-9b71-b464bdd2cef1',\n", - " 'endTimestamp': {'epochSecond': 1624185916, 'nano': 535238000},\n", - " 'eventId': '294e4c48-7ea5-4068-9b71-b464bdd2cef1:998c01dd-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '998c01dc-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185916, 'nano': 143638000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '294e4c48-7ea5-4068-9b71-b464bdd2cef1',\n", - " 'endTimestamp': {'epochSecond': 1624185916, 'nano': 535280000},\n", - " 'eventId': '294e4c48-7ea5-4068-9b71-b464bdd2cef1:998c01de-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '998c01dc-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185916, 'nano': 143638000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '294e4c48-7ea5-4068-9b71-b464bdd2cef1',\n", - " 'endTimestamp': {'epochSecond': 1624185916, 'nano': 535328000},\n", - " 'eventId': '294e4c48-7ea5-4068-9b71-b464bdd2cef1:998c01df-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '998c01dc-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185916, 'nano': 143638000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '7dc67598-1716-4618-9c88-474f095f7c5a',\n", - " 'endTimestamp': {'epochSecond': 1624185916, 'nano': 535027000},\n", - " 'eventId': '7dc67598-1716-4618-9c88-474f095f7c5a:995365a8-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '995169d7-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185916, 'nano': 150159000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '7dc67598-1716-4618-9c88-474f095f7c5a',\n", - " 'endTimestamp': {'epochSecond': 1624185916, 'nano': 535113000},\n", - " 'eventId': '7dc67598-1716-4618-9c88-474f095f7c5a:995c3f49-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '995169d7-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185916, 'nano': 150159000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '7dc67598-1716-4618-9c88-474f095f7c5a',\n", - " 'endTimestamp': {'epochSecond': 1624185916, 'nano': 535169000},\n", - " 'eventId': '7dc67598-1716-4618-9c88-474f095f7c5a:998bdaca-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '995169d7-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185916, 'nano': 150159000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'dd7cf937-17fa-494d-aeb2-44599212bf69',\n", - " 'endTimestamp': {'epochSecond': 1624185923, 'nano': 123793000},\n", - " 'eventId': 'dd7cf937-17fa-494d-aeb2-44599212bf69:9d71a090-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '9d71a08f-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185923, 'nano': 59893000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'faadeebe-eeb9-41a6-b69a-6db7bfd35013',\n", - " 'endTimestamp': {'epochSecond': 1624185923, 'nano': 121995000},\n", - " 'eventId': 'faadeebe-eeb9-41a6-b69a-6db7bfd35013:9d708f1d-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '9d6ff2dc-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185923, 'nano': 61991000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'afd0d956-1172-4ff0-9f7e-b89638f1fa3f',\n", - " 'endTimestamp': {'epochSecond': 1624185924, 'nano': 48402000},\n", - " 'eventId': 'afd0d956-1172-4ff0-9f7e-b89638f1fa3f:9e066691-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '9e066690-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 40298000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '0534a343-5269-4571-80e3-42d0bda213d3',\n", - " 'endTimestamp': {'epochSecond': 1624185924, 'nano': 48221000},\n", - " 'eventId': '0534a343-5269-4571-80e3-42d0bda213d3:9e06186e-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '9e057c2d-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 41350000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '69451533-1158-4f7c-ac3e-974aade1150b',\n", - " 'endTimestamp': {'epochSecond': 1624185924, 'nano': 955280000},\n", - " 'eventId': '69451533-1158-4f7c-ac3e-974aade1150b:9e90cc56-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '9e90cc55-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 747686000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '69451533-1158-4f7c-ac3e-974aade1150b',\n", - " 'endTimestamp': {'epochSecond': 1624185924, 'nano': 955352000},\n", - " 'eventId': '69451533-1158-4f7c-ac3e-974aade1150b:9e90cc57-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '9e90cc55-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 747686000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'f918748b-6f66-4be8-bb57-813bbee5e3f2',\n", - " 'endTimestamp': {'epochSecond': 1624185924, 'nano': 955124000},\n", - " 'eventId': 'f918748b-6f66-4be8-bb57-813bbee5e3f2:9e905722-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '9e71847e-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 749301000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'f918748b-6f66-4be8-bb57-813bbee5e3f2',\n", - " 'endTimestamp': {'epochSecond': 1624185924, 'nano': 955208000},\n", - " 'eventId': 'f918748b-6f66-4be8-bb57-813bbee5e3f2:9e90a543-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '9e71847e-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 749301000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'ee1a0389-e1ff-42e9-a397-8eead4599d7c',\n", - " 'endTimestamp': {'epochSecond': 1624185925, 'nano': 547340000},\n", - " 'eventId': 'ee1a0389-e1ff-42e9-a397-8eead4599d7c:9eead33d-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '9eead33c-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 843104000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'ee1a0389-e1ff-42e9-a397-8eead4599d7c',\n", - " 'endTimestamp': {'epochSecond': 1624185925, 'nano': 547436000},\n", - " 'eventId': 'ee1a0389-e1ff-42e9-a397-8eead4599d7c:9eead33e-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '9eead33c-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 843104000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'ee1a0389-e1ff-42e9-a397-8eead4599d7c',\n", - " 'endTimestamp': {'epochSecond': 1624185925, 'nano': 547471000},\n", - " 'eventId': 'ee1a0389-e1ff-42e9-a397-8eead4599d7c:9eead33f-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '9eead33c-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 843104000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '83775107-a1de-476c-a179-ef26b9313676',\n", - " 'endTimestamp': {'epochSecond': 1624185925, 'nano': 546195000},\n", - " 'eventId': '83775107-a1de-476c-a179-ef26b9313676:9e8114e1-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '9e8078a0-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 847325000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '83775107-a1de-476c-a179-ef26b9313676',\n", - " 'endTimestamp': {'epochSecond': 1624185925, 'nano': 546292000},\n", - " 'eventId': '83775107-a1de-476c-a179-ef26b9313676:9eea36f8-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '9e8078a0-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 847325000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '83775107-a1de-476c-a179-ef26b9313676',\n", - " 'endTimestamp': {'epochSecond': 1624185925, 'nano': 546687000},\n", - " 'eventId': '83775107-a1de-476c-a179-ef26b9313676:9eea8519-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '9e8078a0-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 847325000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'attachedMessageIds': [],\n", - " 'batchId': '83775107-a1de-476c-a179-ef26b9313676',\n", - " 'endTimestamp': {'epochSecond': 1624185925, 'nano': 546761000},\n", - " 'eventId': '83775107-a1de-476c-a179-ef26b9313676:9eeaac2a-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '9e8078a0-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 847325000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '0fcac3db-3747-421f-acd8-4e35921a74d3',\n", - " 'endTimestamp': {'epochSecond': 1624185931, 'nano': 28943000},\n", - " 'eventId': '0fcac3db-3747-421f-acd8-4e35921a74d3:a22f9e10-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'a22f9e0f-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185931, 'nano': 19233000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'edd0d9ad-3d88-40a6-b42d-5bc7ff1c215f',\n", - " 'endTimestamp': {'epochSecond': 1624185931, 'nano': 28824000},\n", - " 'eventId': 'edd0d9ad-3d88-40a6-b42d-5bc7ff1c215f:a22edabd-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'a22e658c-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185931, 'nano': 20431000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '5254c8fd-de89-4c06-9625-acc377fbadc0',\n", - " 'endTimestamp': {'epochSecond': 1624185932, 'nano': 17683000},\n", - " 'eventId': '5254c8fd-de89-4c06-9625-acc377fbadc0:a2c686f1-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'a2c686f0-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 14200000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'e6e16bcf-97c2-4f37-94e4-45d580d650ff',\n", - " 'endTimestamp': {'epochSecond': 1624185932, 'nano': 17604000},\n", - " 'eventId': 'e6e16bcf-97c2-4f37-94e4-45d580d650ff:a2c65fde-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'a2c638cd-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 15295000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '78c6db8b-07bc-46b2-81b7-1b3ea537acf3',\n", - " 'endTimestamp': {'epochSecond': 1624185932, 'nano': 943704000},\n", - " 'eventId': '78c6db8b-07bc-46b2-81b7-1b3ea537acf3:a353d2e6-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'a353d2e5-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 621555000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '78c6db8b-07bc-46b2-81b7-1b3ea537acf3',\n", - " 'endTimestamp': {'epochSecond': 1624185932, 'nano': 943764000},\n", - " 'eventId': '78c6db8b-07bc-46b2-81b7-1b3ea537acf3:a353d2e7-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'a353d2e5-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 621555000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'f1bffe38-2fdf-413c-a845-778436c9b001',\n", - " 'endTimestamp': {'epochSecond': 1624185932, 'nano': 943413000},\n", - " 'eventId': 'f1bffe38-2fdf-413c-a845-778436c9b001:a352c172-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'a322fede-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 623385000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'f1bffe38-2fdf-413c-a845-778436c9b001',\n", - " 'endTimestamp': {'epochSecond': 1624185932, 'nano': 943502000},\n", - " 'eventId': 'f1bffe38-2fdf-413c-a845-778436c9b001:a3535db3-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'a322fede-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 623385000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '1ca7683c-b206-4cc3-a659-76da1ec9583d',\n", - " 'endTimestamp': {'epochSecond': 1624185933, 'nano': 562504000},\n", - " 'eventId': '1ca7683c-b206-4cc3-a659-76da1ec9583d:a3b21f8c-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'a3b21f8b-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 739688000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '1ca7683c-b206-4cc3-a659-76da1ec9583d',\n", - " 'endTimestamp': {'epochSecond': 1624185933, 'nano': 562554000},\n", - " 'eventId': '1ca7683c-b206-4cc3-a659-76da1ec9583d:a3b2469d-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'a3b21f8b-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 739688000},\n", - " 'successful': False,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '1ca7683c-b206-4cc3-a659-76da1ec9583d',\n", - " 'endTimestamp': {'epochSecond': 1624185933, 'nano': 562603000},\n", - " 'eventId': '1ca7683c-b206-4cc3-a659-76da1ec9583d:a3b2469e-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'a3b21f8b-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 739688000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'e9440dd3-0575-46a3-92c1-02657a8d65da',\n", - " 'endTimestamp': {'epochSecond': 1624185933, 'nano': 562214000},\n", - " 'eventId': 'e9440dd3-0575-46a3-92c1-02657a8d65da:a3354e61-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'a3350040-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 741779000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'e9440dd3-0575-46a3-92c1-02657a8d65da',\n", - " 'endTimestamp': {'epochSecond': 1624185933, 'nano': 562293000},\n", - " 'eventId': 'e9440dd3-0575-46a3-92c1-02657a8d65da:a3b13528-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'a3350040-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 741779000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'e9440dd3-0575-46a3-92c1-02657a8d65da',\n", - " 'endTimestamp': {'epochSecond': 1624185933, 'nano': 562432000},\n", - " 'eventId': 'e9440dd3-0575-46a3-92c1-02657a8d65da:a3b15c39-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'a3350040-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 741779000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n" - ] - } - ], - "source": [ - "leaves = Data(tree.get_leaves())\n", - "for event in leaves.filter(lambda record: record.get(\"eventType\") == \"Verification\"):\n", - " pprint(event)" - ] - }, - { - "cell_type": "markdown", - "id": "b1ebea69", - "metadata": {}, - "source": [ - "You can get full path to the event use `get_full_path(evet_id)` method in the colllection or each tree." - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "id": "ac6d716c", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
eventName
0[TS_1]Aggressive IOC vs two orders: second order's price is lower than first
1Case[TC_1.1]: Trader DEMO-CONN1 vs trader DEMO-CONN2 for instrument INSTR1
2Check sequence rule SessionKey{sessionAlias='demo-conn1', direction=FIRST} - STEP2: Trader \"DEMO-CONN1\" receives Execution Report. The order stands on book in status NEW
3Check messages
4Verification 'ExecutionReport' message
\n", - "
" - ], - "text/plain": [ - " eventName\n", - "0 [TS_1]Aggressive IOC vs two orders: second order's price is lower than first\n", - "1 Case[TC_1.1]: Trader DEMO-CONN1 vs trader DEMO-CONN2 for instrument INSTR1\n", - "2 Check sequence rule SessionKey{sessionAlias='demo-conn1', direction=FIRST} - STEP2: Trader \"DEMO-CONN1\" receives Execution Report. The order stands on book in status NEW\n", - "3 Check messages\n", - "4 Verification 'ExecutionReport' message" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "data = Data(tree.get_full_path(\"53c1abd6-b2f9-4378-b061-434a3315c4a2:8d722b53-d1b4-11eb-9278-591e568ad66e\"))\\\n", - " .map(lambda record: {\n", - " \"eventName\": record.get(\"eventName\")\n", - " }\n", - " )\n", - "DataFrame(data)" - ] - }, - { - "cell_type": "markdown", - "id": "ab55e7a3", - "metadata": {}, - "source": [ - "You can get the root id from all trees." - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "id": "a0159685", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "['84db48fc-d1b4-11eb-b0fb-199708acc7bc',\n", - " '814422e1-9c68-11eb-8598-691ebd7f413d',\n", - " '745f0318-d010-11eb-8e55-d3a76285d588',\n", - " '5d0e9572-d047-11eb-bddd-1e8d42132387']" - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "collection.get_roots_ids()" - ] - }, - { - "cell_type": "markdown", - "id": "182be98a", - "metadata": {}, - "source": [ - "You can get the parent\\children for event " - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "id": "b057a69b", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'type': 'event',\n", - " 'eventId': '8d722b52-d1b4-11eb-9278-591e568ad66e',\n", - " 'batchId': None,\n", - " 'isBatched': False,\n", - " 'eventName': 'Check messages',\n", - " 'eventType': 'checkMessages',\n", - " 'endTimestamp': {'nano': 625252000, 'epochSecond': 1624185896},\n", - " 'startTimestamp': {'nano': 205141000, 'epochSecond': 1624185896},\n", - " 'parentEventId': '8d6e0c9e-d1b4-11eb-9278-591e568ad66e',\n", - " 'successful': True,\n", - " 'attachedMessageIds': []}" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "collection.get_parent(\"53c1abd6-b2f9-4378-b061-434a3315c4a2:8d722b53-d1b4-11eb-9278-591e568ad66e\")" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "id": "f90502e3", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "({'type': 'event',\n", - " 'eventId': '53c1abd6-b2f9-4378-b061-434a3315c4a2:8d722b53-d1b4-11eb-9278-591e568ad66e',\n", - " 'batchId': '53c1abd6-b2f9-4378-b061-434a3315c4a2',\n", - " 'isBatched': True,\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'endTimestamp': {'nano': 625264000, 'epochSecond': 1624185896},\n", - " 'startTimestamp': {'nano': 205141000, 'epochSecond': 1624185896},\n", - " 'parentEventId': '8d722b52-d1b4-11eb-9278-591e568ad66e',\n", - " 'successful': True,\n", - " 'attachedMessageIds': []},)" - ] - }, - "execution_count": 20, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "collection.get_children(\"8d722b52-d1b4-11eb-9278-591e568ad66e\")" - ] - }, - { - "cell_type": "markdown", - "id": "2dd9add2", - "metadata": {}, - "source": [ - "### Demo for events." - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "id": "6002a278", - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': {},\n", - " 'endTimestamp': {'epochSecond': 1624185888, 'nano': 167676000},\n", - " 'eventId': '84db48fc-d1b4-11eb-b0fb-199708acc7bc',\n", - " 'eventName': \"[TS_1]Aggressive IOC vs two orders: second order's price is \"\n", - " 'lower than first',\n", - " 'eventType': '',\n", - " 'isBatched': False,\n", - " 'parentEventId': None,\n", - " 'startTimestamp': {'epochSecond': 1624185881, 'nano': 821639000},\n", - " 'successful': False,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': {},\n", - " 'endTimestamp': {'epochSecond': 1624185888, 'nano': 169710000},\n", - " 'eventId': '88a3ee80-d1b4-11eb-b0fb-199708acc7bc',\n", - " 'eventName': 'Case[TC_1.1]: Trader DEMO-CONN1 vs trader DEMO-CONN2 for '\n", - " 'instrument INSTR1',\n", - " 'eventType': '',\n", - " 'isBatched': False,\n", - " 'parentEventId': '84db48fc-d1b4-11eb-b0fb-199708acc7bc',\n", - " 'startTimestamp': {'epochSecond': 1624185888, 'nano': 169672000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'data': 'STEP1: Trader \"DEMO-CONN1\" sends request to create passive '\n", - " 'Order.',\n", - " 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185893, 'nano': 436565000},\n", - " 'eventId': '8bc787fe-d1b4-11eb-bae5-57b0c4472880',\n", - " 'eventName': 'placeOrderFIX demo-conn1 - STEP1: Trader \"DEMO-CONN1\" sends '\n", - " 'request to create passive Order.',\n", - " 'eventType': 'placeOrderFIX',\n", - " 'isBatched': False,\n", - " 'parentEventId': '88a3ee80-d1b4-11eb-b0fb-199708acc7bc',\n", - " 'startTimestamp': {'epochSecond': 1624185893, 'nano': 436316000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '6e3be13f-cab7-4653-8cb9-6e74fd95ade4',\n", - " 'body': [{'data': \"Checkpoint id '8c037f50-d1b4-11eb-ba78-1981398e00bd'\",\n", - " 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185893, 'nano': 830158000},\n", - " 'eventId': '6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c035903-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Checkpoint',\n", - " 'eventType': 'Checkpoint',\n", - " 'isBatched': True,\n", - " 'parentEventId': '8bc787fe-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185893, 'nano': 828017000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '6e3be13f-cab7-4653-8cb9-6e74fd95ade4',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185893, 'nano': 830158000},\n", - " 'eventId': '6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c1114a4-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'th2-hand-demo' direction 'FIRST' \"\n", - " \"sequence '1623852603564709030'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c035903-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185893, 'nano': 828017000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '6e3be13f-cab7-4653-8cb9-6e74fd95ade4',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185893, 'nano': 830158000},\n", - " 'eventId': '6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c1114a5-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn1' direction 'SECOND' \"\n", - " \"sequence '1624005455622140289'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c035903-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185893, 'nano': 828017000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '6e3be13f-cab7-4653-8cb9-6e74fd95ade4',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185893, 'nano': 830158000},\n", - " 'eventId': '6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c1114a6-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc1' direction 'SECOND' \"\n", - " \"sequence '1624005475721015014'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c035903-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185893, 'nano': 828017000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '6e3be13f-cab7-4653-8cb9-6e74fd95ade4',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185893, 'nano': 830158000},\n", - " 'eventId': '6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c1114a7-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc1' direction 'FIRST' \"\n", - " \"sequence '1624005475720919499'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c035903-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185893, 'nano': 828017000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '6e3be13f-cab7-4653-8cb9-6e74fd95ade4',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185893, 'nano': 830158000},\n", - " 'eventId': '6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c1114a8-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn2' direction 'FIRST' \"\n", - " \"sequence '1624005448022245399'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c035903-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185893, 'nano': 828017000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '6e3be13f-cab7-4653-8cb9-6e74fd95ade4',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185893, 'nano': 830158000},\n", - " 'eventId': '6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c1114a9-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn2' direction 'SECOND' \"\n", - " \"sequence '1624005448022426113'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c035903-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185893, 'nano': 828017000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '6e3be13f-cab7-4653-8cb9-6e74fd95ade4',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185893, 'nano': 830158000},\n", - " 'eventId': '6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c1114aa-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc2' direction 'SECOND' \"\n", - " \"sequence '1624005466840347015'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c035903-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185893, 'nano': 828017000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '6e3be13f-cab7-4653-8cb9-6e74fd95ade4',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185893, 'nano': 830158000},\n", - " 'eventId': '6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c1114ab-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc2' direction 'FIRST' \"\n", - " \"sequence '1624005466840263372'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c035903-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185893, 'nano': 828017000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '6e3be13f-cab7-4653-8cb9-6e74fd95ade4',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185893, 'nano': 830158000},\n", - " 'eventId': '6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c1114ac-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn1' direction 'FIRST' \"\n", - " \"sequence '1624005455622011522'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c035903-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185893, 'nano': 828017000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '6e3be13f-cab7-4653-8cb9-6e74fd95ade4',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185893, 'nano': 830158000},\n", - " 'eventId': '6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c1114ad-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-log' direction 'FIRST' \"\n", - " \"sequence '1624029363623063053'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c035903-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185893, 'nano': 828017000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'rows': {'AccountType': {'columns': {'fieldValue': '1'},\n", - " 'type': 'row'},\n", - " 'ClOrdID': {'columns': {'fieldValue': '9601585'},\n", - " 'type': 'row'},\n", - " 'OrdType': {'columns': {'fieldValue': '2'}, 'type': 'row'},\n", - " 'OrderCapacity': {'columns': {'fieldValue': 'A'},\n", - " 'type': 'row'},\n", - " 'OrderQty': {'columns': {'fieldValue': '30'},\n", - " 'type': 'row'},\n", - " 'Price': {'columns': {'fieldValue': '55'}, 'type': 'row'},\n", - " 'SecondaryClOrdID': {'columns': {'fieldValue': '11111'},\n", - " 'type': 'row'},\n", - " 'SecurityID': {'columns': {'fieldValue': 'INSTR1'},\n", - " 'type': 'row'},\n", - " 'SecurityIDSource': {'columns': {'fieldValue': '8'},\n", - " 'type': 'row'},\n", - " 'Side': {'columns': {'fieldValue': '1'}, 'type': 'row'},\n", - " 'TradingParty': {'rows': {'NoPartyIDs': {'rows': {'0': {'rows': {'PartyID': {'columns': {'fieldValue': 'DEMO-CONN1'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'D'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '76'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '1': {'rows': {'PartyID': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '2': {'rows': {'PartyID': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '122'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '3': {'rows': {'PartyID': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '12'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'columns': {'fieldValue': '2021-06-20T13:44:48.170589'},\n", - " 'type': 'row'}},\n", - " 'type': 'treeTable'}],\n", - " 'endTimestamp': {'epochSecond': 1624185894, 'nano': 226124000},\n", - " 'eventId': '8c3fec4f-d1b4-11eb-bae5-57b0c4472880',\n", - " 'eventName': \"Send 'NewOrderSingle' message to connectivity\",\n", - " 'eventType': 'Outgoing message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '8bc787fe-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185894, 'nano': 225931000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185894, 'nano': 256033000},\n", - " 'eventId': '8c44806c-d1b4-11eb-8e55-d3a76285d588',\n", - " 'eventName': \"Send 'NewOrderSingle' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '8bc787fe-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185894, 'nano': 255570000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '654c2724-5202-460b-8e6c-a7ee9fb02ddf',\n", - " 'body': {'data': 'The message was deleted because a new one came with the '\n", - " \"same hash '7009491514226292581' in message group \"\n", - " \"'NOS_CONN'\\n\"\n", - " ' Message not matched',\n", - " 'type': 'message'},\n", - " 'endTimestamp': {'epochSecond': 1624185894, 'nano': 867342000},\n", - " 'eventId': '654c2724-5202-460b-8e6c-a7ee9fb02ddf:8ca20288-d1b4-11eb-986f-1e8d42132387',\n", - " 'eventName': \"Remove 'NewOrderSingle' \"\n", - " \"id='demo-conn1:SECOND:1624005455622135205' \"\n", - " \"Hash='7009491514226292581' Group='NOS_CONN' \"\n", - " \"Hash['SecondaryClOrdID': 11111, 'SecurityID': INSTR1]\",\n", - " 'eventType': '',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'a3779b94-d051-11eb-986f-1e8d42132387',\n", - " 'startTimestamp': {'epochSecond': 1624185894, 'nano': 867342000},\n", - " 'successful': False,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185895, 'nano': 348430000},\n", - " 'eventId': '8ceb47f6-d1b4-11eb-a9ed-ffb57363e013',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '845d70d2-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185895, 'nano': 348344000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185895, 'nano': 360947000},\n", - " 'eventId': '8ced1c93-d1b4-11eb-a9f4-b12655548efc',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '845d70d2-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185895, 'nano': 360848000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'rows': {'AccountType': {'columns': {'fieldValue': '1'},\n", - " 'type': 'row'},\n", - " 'ClOrdID': {'columns': {'fieldValue': '9601585'},\n", - " 'type': 'row'},\n", - " 'CumQty': {'columns': {'fieldValue': '0'}, 'type': 'row'},\n", - " 'ExecID': {'columns': {'fieldValue': '2346'},\n", - " 'type': 'row'},\n", - " 'ExecType': {'columns': {'fieldValue': '0'}, 'type': 'row'},\n", - " 'LeavesQty': {'columns': {'fieldValue': '30'},\n", - " 'type': 'row'},\n", - " 'OrdStatus': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'OrdType': {'columns': {'fieldValue': '2'}, 'type': 'row'},\n", - " 'OrderCapacity': {'columns': {'fieldValue': 'A'},\n", - " 'type': 'row'},\n", - " 'OrderID': {'columns': {'fieldValue': '867'},\n", - " 'type': 'row'},\n", - " 'OrderQty': {'columns': {'fieldValue': '30'},\n", - " 'type': 'row'},\n", - " 'Price': {'columns': {'fieldValue': '55'}, 'type': 'row'},\n", - " 'SecurityID': {'columns': {'fieldValue': 'INSTR1'},\n", - " 'type': 'row'},\n", - " 'SecurityIDSource': {'columns': {'fieldValue': '8'},\n", - " 'type': 'row'},\n", - " 'Side': {'columns': {'fieldValue': '1'}, 'type': 'row'},\n", - " 'Text': {'columns': {'fieldValue': 'Simulated New Order '\n", - " 'Buy is placed'},\n", - " 'type': 'row'},\n", - " 'TradingParty': {'rows': {'NoPartyIDs': {'rows': {'0': {'rows': {'PartyID': {'columns': {'fieldValue': 'DEMO-CONN1'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'D'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '76'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '1': {'rows': {'PartyID': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '2': {'rows': {'PartyID': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '122'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '3': {'rows': {'PartyID': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '12'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'columns': {'fieldValue': '2021-06-20T10:44:55'},\n", - " 'type': 'row'},\n", - " 'header': {'rows': {'BeginString': {'columns': {'fieldValue': 'FIXT.1.1'},\n", - " 'type': 'row'},\n", - " 'BodyLength': {'columns': {'fieldValue': '310'},\n", - " 'type': 'row'},\n", - " 'MsgSeqNum': {'columns': {'fieldValue': '1291'},\n", - " 'type': 'row'},\n", - " 'MsgType': {'columns': {'fieldValue': '8'},\n", - " 'type': 'row'},\n", - " 'SenderCompID': {'columns': {'fieldValue': 'FGW'},\n", - " 'type': 'row'},\n", - " 'SendingTime': {'columns': {'fieldValue': '2021-06-20T10:44:55.346'},\n", - " 'type': 'row'},\n", - " 'TargetCompID': {'columns': {'fieldValue': 'DEMO-CONN1'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " 'trailer': {'rows': {'CheckSum': {'columns': {'fieldValue': '056'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'treeTable'}],\n", - " 'endTimestamp': {'epochSecond': 1624185895, 'nano': 935092000},\n", - " 'eventId': '8d44d930-d1b4-11eb-bae5-57b0c4472880',\n", - " 'eventName': \"Received 'ExecutionReport' response message\",\n", - " 'eventType': 'message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '8bc787fe-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185895, 'nano': 935035000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'data': 'STEP2: Trader \"DEMO-CONN1\" receives Execution Report. The '\n", - " 'order stands on book in status NEW',\n", - " 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185896, 'nano': 232493000},\n", - " 'eventId': '8d6e0c9e-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Check sequence rule SessionKey{sessionAlias='demo-conn1', \"\n", - " 'direction=FIRST} - STEP2: Trader \"DEMO-CONN1\" receives '\n", - " 'Execution Report. The order stands on book in status NEW',\n", - " 'eventType': 'checkSequenceRule',\n", - " 'isBatched': False,\n", - " 'parentEventId': '88a3ee80-d1b4-11eb-b0fb-199708acc7bc',\n", - " 'startTimestamp': {'epochSecond': 1624185896, 'nano': 205141000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'data': 'Contains comparisons', 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185896, 'nano': 625252000},\n", - " 'eventId': '8d722b52-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Check messages',\n", - " 'eventType': 'checkMessages',\n", - " 'isBatched': False,\n", - " 'parentEventId': '8d6e0c9e-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185896, 'nano': 205141000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '53c1abd6-b2f9-4378-b061-434a3315c4a2',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '9601585',\n", - " 'expected': '9601585',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2346',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '30',\n", - " 'expected': '30',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': '2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'A',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '867',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '30',\n", - " 'expected': '30',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '55',\n", - " 'expected': '55',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR1',\n", - " 'expected': 'INSTR1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'Simulated New Order Buy is placed',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {'NoPartyIDs': {'actual': '4',\n", - " 'expected': '4',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'DEMO-CONN1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': '76',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': '122',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': '12',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:44:55',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': '7',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'FIXT.1.1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '310',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1291',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:44:55.346',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'DEMO-CONN1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '056',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185896, 'nano': 625264000},\n", - " 'eventId': '53c1abd6-b2f9-4378-b061-434a3315c4a2:8d722b53-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '8d722b52-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185896, 'nano': 205141000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '7ed5fe20-9316-4e12-92a5-982364cd5637',\n", - " 'body': [{'data': 'Expected 1, Actual 1', 'type': 'message'},\n", - " {'rows': [{'actualMessage': 'ExecutionReport, demo-conn1, '\n", - " 'OrdStatus=0, ClOrdID=9601585',\n", - " 'actualMetadata': 'Metadata, demo-conn1',\n", - " 'expectedMessage': 'ExecutionReport, demo-conn1, '\n", - " 'OrdStatus=0, ClOrdID=9601585',\n", - " 'expectedMetadata': 'Metadata, demo-conn1'}],\n", - " 'type': 'table'}],\n", - " 'endTimestamp': {'epochSecond': 1624185896, 'nano': 622684000},\n", - " 'eventId': '7ed5fe20-9316-4e12-92a5-982364cd5637:8d722b51-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Check sequence (expected 1 / actual 1 , check order false)',\n", - " 'eventType': 'checkSequence',\n", - " 'isBatched': True,\n", - " 'parentEventId': '8d6e0c9e-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185896, 'nano': 205141000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'rows': {'comparison-settings': {'rows': {'ignore-fields': {'rows': {},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'},\n", - " 'message-filter': {'rows': {'SecurityID': {'columns': {'expected': 'INSTR1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL'},\n", - " 'type': 'row'},\n", - " 'header': {'rows': {'MsgType': {'columns': {'expected': 'f',\n", - " 'key': False,\n", - " 'operation': 'NOT_EQUAL'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'},\n", - " 'message-type': {'columns': {'type': 'PreFilter'},\n", - " 'type': 'row'},\n", - " 'metadata-filter': {'rows': {}, 'type': 'collection'}},\n", - " 'type': 'treeTable'}],\n", - " 'endTimestamp': {'epochSecond': 1624185896, 'nano': 233217000},\n", - " 'eventId': '8d6f6c2f-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Pre-filtering (filtered 1 / processed 1) messages',\n", - " 'eventType': 'preFiltering',\n", - " 'isBatched': False,\n", - " 'parentEventId': '8d6e0c9e-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185896, 'nano': 214108000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'e71f316c-6912-43b1-a6cb-60c328a8239b',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '9601585',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2346',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '30',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '867',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '30',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '55',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR1',\n", - " 'expected': 'INSTR1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'Simulated New Order Buy is placed',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'NoPartyIDs': {'actual': '4',\n", - " 'expected': 'null',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:44:55',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': '1',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '310',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1291',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': 'x != \"f\"',\n", - " 'key': False,\n", - " 'operation': 'NOT_EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:44:55.346',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '056',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185896, 'nano': 419542000},\n", - " 'eventId': 'e71f316c-6912-43b1-a6cb-60c328a8239b:8d71dd30-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '8d6f6c2f-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185896, 'nano': 214108000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'data': 'STEP3: Trader \"DEMO-CONN1\" sends request to create passive '\n", - " 'Order with price lower than first order.',\n", - " 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185896, 'nano': 315987000},\n", - " 'eventId': '8d7ed4f1-d1b4-11eb-bae5-57b0c4472880',\n", - " 'eventName': 'placeOrderFIX demo-conn1 - STEP3: Trader \"DEMO-CONN1\" sends '\n", - " 'request to create passive Order with price lower than first '\n", - " 'order.',\n", - " 'eventType': 'placeOrderFIX',\n", - " 'isBatched': False,\n", - " 'parentEventId': '88a3ee80-d1b4-11eb-b0fb-199708acc7bc',\n", - " 'startTimestamp': {'epochSecond': 1624185896, 'nano': 315942000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '0af2c7e5-a348-4c3b-95e4-c2d9eeab8e14',\n", - " 'body': [{'data': \"Checkpoint id '8d7fbf10-d1b4-11eb-ba78-1981398e00bd'\",\n", - " 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185896, 'nano': 321704000},\n", - " 'eventId': '0af2c7e5-a348-4c3b-95e4-c2d9eeab8e14:8d7fbfe4-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Checkpoint',\n", - " 'eventType': 'Checkpoint',\n", - " 'isBatched': True,\n", - " 'parentEventId': '8d7ed4f1-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185896, 'nano': 321503000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '0af2c7e5-a348-4c3b-95e4-c2d9eeab8e14',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185896, 'nano': 321704000},\n", - " 'eventId': '0af2c7e5-a348-4c3b-95e4-c2d9eeab8e14:8d7fbfe5-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'th2-hand-demo' direction 'FIRST' \"\n", - " \"sequence '1623852603564709030'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '0af2c7e5-a348-4c3b-95e4-c2d9eeab8e14:8d7fbfe4-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185896, 'nano': 321503000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '0af2c7e5-a348-4c3b-95e4-c2d9eeab8e14',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185896, 'nano': 321704000},\n", - " 'eventId': '0af2c7e5-a348-4c3b-95e4-c2d9eeab8e14:8d7fbfe6-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn1' direction 'SECOND' \"\n", - " \"sequence '1624005455622140290'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '0af2c7e5-a348-4c3b-95e4-c2d9eeab8e14:8d7fbfe4-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185896, 'nano': 321503000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '0af2c7e5-a348-4c3b-95e4-c2d9eeab8e14',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185896, 'nano': 321704000},\n", - " 'eventId': '0af2c7e5-a348-4c3b-95e4-c2d9eeab8e14:8d7fbfe7-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc1' direction 'SECOND' \"\n", - " \"sequence '1624005475721015014'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '0af2c7e5-a348-4c3b-95e4-c2d9eeab8e14:8d7fbfe4-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185896, 'nano': 321503000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '0af2c7e5-a348-4c3b-95e4-c2d9eeab8e14',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185896, 'nano': 321704000},\n", - " 'eventId': '0af2c7e5-a348-4c3b-95e4-c2d9eeab8e14:8d7fbfe8-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc1' direction 'FIRST' \"\n", - " \"sequence '1624005475720919500'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '0af2c7e5-a348-4c3b-95e4-c2d9eeab8e14:8d7fbfe4-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185896, 'nano': 321503000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '0af2c7e5-a348-4c3b-95e4-c2d9eeab8e14',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185896, 'nano': 321704000},\n", - " 'eventId': '0af2c7e5-a348-4c3b-95e4-c2d9eeab8e14:8d7fbfe9-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn2' direction 'FIRST' \"\n", - " \"sequence '1624005448022245399'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '0af2c7e5-a348-4c3b-95e4-c2d9eeab8e14:8d7fbfe4-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185896, 'nano': 321503000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '0af2c7e5-a348-4c3b-95e4-c2d9eeab8e14',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185896, 'nano': 321704000},\n", - " 'eventId': '0af2c7e5-a348-4c3b-95e4-c2d9eeab8e14:8d7fbfea-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn2' direction 'SECOND' \"\n", - " \"sequence '1624005448022426113'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '0af2c7e5-a348-4c3b-95e4-c2d9eeab8e14:8d7fbfe4-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185896, 'nano': 321503000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '0af2c7e5-a348-4c3b-95e4-c2d9eeab8e14',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185896, 'nano': 321704000},\n", - " 'eventId': '0af2c7e5-a348-4c3b-95e4-c2d9eeab8e14:8d7fbfeb-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc2' direction 'SECOND' \"\n", - " \"sequence '1624005466840347015'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '0af2c7e5-a348-4c3b-95e4-c2d9eeab8e14:8d7fbfe4-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185896, 'nano': 321503000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '0af2c7e5-a348-4c3b-95e4-c2d9eeab8e14',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185896, 'nano': 321704000},\n", - " 'eventId': '0af2c7e5-a348-4c3b-95e4-c2d9eeab8e14:8d7fbfec-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc2' direction 'FIRST' \"\n", - " \"sequence '1624005466840263372'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '0af2c7e5-a348-4c3b-95e4-c2d9eeab8e14:8d7fbfe4-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185896, 'nano': 321503000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '0af2c7e5-a348-4c3b-95e4-c2d9eeab8e14',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185896, 'nano': 321704000},\n", - " 'eventId': '0af2c7e5-a348-4c3b-95e4-c2d9eeab8e14:8d7fbfed-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn1' direction 'FIRST' \"\n", - " \"sequence '1624005455622011523'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '0af2c7e5-a348-4c3b-95e4-c2d9eeab8e14:8d7fbfe4-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185896, 'nano': 321503000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '0af2c7e5-a348-4c3b-95e4-c2d9eeab8e14',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185896, 'nano': 321704000},\n", - " 'eventId': '0af2c7e5-a348-4c3b-95e4-c2d9eeab8e14:8d7fbfee-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-log' direction 'FIRST' \"\n", - " \"sequence '1624029363623063053'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '0af2c7e5-a348-4c3b-95e4-c2d9eeab8e14:8d7fbfe4-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185896, 'nano': 321503000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'rows': {'AccountType': {'columns': {'fieldValue': '1'},\n", - " 'type': 'row'},\n", - " 'ClOrdID': {'columns': {'fieldValue': '2638304'},\n", - " 'type': 'row'},\n", - " 'OrdType': {'columns': {'fieldValue': '2'}, 'type': 'row'},\n", - " 'OrderCapacity': {'columns': {'fieldValue': 'A'},\n", - " 'type': 'row'},\n", - " 'OrderQty': {'columns': {'fieldValue': '10'},\n", - " 'type': 'row'},\n", - " 'Price': {'columns': {'fieldValue': '56'}, 'type': 'row'},\n", - " 'SecondaryClOrdID': {'columns': {'fieldValue': '22222'},\n", - " 'type': 'row'},\n", - " 'SecurityID': {'columns': {'fieldValue': 'INSTR1'},\n", - " 'type': 'row'},\n", - " 'SecurityIDSource': {'columns': {'fieldValue': '8'},\n", - " 'type': 'row'},\n", - " 'Side': {'columns': {'fieldValue': '1'}, 'type': 'row'},\n", - " 'TradingParty': {'rows': {'NoPartyIDs': {'rows': {'0': {'rows': {'PartyID': {'columns': {'fieldValue': 'DEMO-CONN1'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'D'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '76'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '1': {'rows': {'PartyID': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '2': {'rows': {'PartyID': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '122'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '3': {'rows': {'PartyID': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '12'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'columns': {'fieldValue': '2021-06-20T13:44:48.170620'},\n", - " 'type': 'row'}},\n", - " 'type': 'treeTable'}],\n", - " 'endTimestamp': {'epochSecond': 1624185896, 'nano': 341038000},\n", - " 'eventId': '8d82a582-d1b4-11eb-bae5-57b0c4472880',\n", - " 'eventName': \"Send 'NewOrderSingle' message to connectivity\",\n", - " 'eventType': 'Outgoing message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '8d7ed4f1-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185896, 'nano': 340175000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185896, 'nano': 364373000},\n", - " 'eventId': '8d86282d-d1b4-11eb-8e55-d3a76285d588',\n", - " 'eventName': \"Send 'NewOrderSingle' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '8d7ed4f1-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185896, 'nano': 363020000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '2595f1b7-7341-4f8d-83e1-c2936416fdcc',\n", - " 'body': {'data': 'The message was deleted because a new one came with the '\n", - " \"same hash '9109085565557408626' in message group \"\n", - " \"'NOS_CONN'\\n\"\n", - " ' Message not matched',\n", - " 'type': 'message'},\n", - " 'endTimestamp': {'epochSecond': 1624185896, 'nano': 833038000},\n", - " 'eventId': '2595f1b7-7341-4f8d-83e1-c2936416fdcc:8dcdedde-d1b4-11eb-986f-1e8d42132387',\n", - " 'eventName': \"Remove 'NewOrderSingle' \"\n", - " \"id='demo-conn1:SECOND:1624005455622135206' \"\n", - " \"Hash='9109085565557408626' Group='NOS_CONN' \"\n", - " \"Hash['SecondaryClOrdID': 22222, 'SecurityID': INSTR1]\",\n", - " 'eventType': '',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'a3779b94-d051-11eb-986f-1e8d42132387',\n", - " 'startTimestamp': {'epochSecond': 1624185896, 'nano': 833038000},\n", - " 'successful': False,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185897, 'nano': 252806000},\n", - " 'eventId': '8e0dcef7-d1b4-11eb-a9ed-ffb57363e013',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '845d70d2-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185897, 'nano': 252801000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185897, 'nano': 261069000},\n", - " 'eventId': '8e0f2e64-d1b4-11eb-a9f4-b12655548efc',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '845d70d2-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185897, 'nano': 261065000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'rows': {'AccountType': {'columns': {'fieldValue': '1'},\n", - " 'type': 'row'},\n", - " 'ClOrdID': {'columns': {'fieldValue': '2638304'},\n", - " 'type': 'row'},\n", - " 'CumQty': {'columns': {'fieldValue': '0'}, 'type': 'row'},\n", - " 'ExecID': {'columns': {'fieldValue': '2348'},\n", - " 'type': 'row'},\n", - " 'ExecType': {'columns': {'fieldValue': '0'}, 'type': 'row'},\n", - " 'LeavesQty': {'columns': {'fieldValue': '10'},\n", - " 'type': 'row'},\n", - " 'OrdStatus': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'OrdType': {'columns': {'fieldValue': '2'}, 'type': 'row'},\n", - " 'OrderCapacity': {'columns': {'fieldValue': 'A'},\n", - " 'type': 'row'},\n", - " 'OrderID': {'columns': {'fieldValue': '868'},\n", - " 'type': 'row'},\n", - " 'OrderQty': {'columns': {'fieldValue': '10'},\n", - " 'type': 'row'},\n", - " 'Price': {'columns': {'fieldValue': '56'}, 'type': 'row'},\n", - " 'SecurityID': {'columns': {'fieldValue': 'INSTR1'},\n", - " 'type': 'row'},\n", - " 'SecurityIDSource': {'columns': {'fieldValue': '8'},\n", - " 'type': 'row'},\n", - " 'Side': {'columns': {'fieldValue': '1'}, 'type': 'row'},\n", - " 'Text': {'columns': {'fieldValue': 'Simulated New Order '\n", - " 'Buy is placed'},\n", - " 'type': 'row'},\n", - " 'TradingParty': {'rows': {'NoPartyIDs': {'rows': {'0': {'rows': {'PartyID': {'columns': {'fieldValue': 'DEMO-CONN1'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'D'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '76'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '1': {'rows': {'PartyID': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '2': {'rows': {'PartyID': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '122'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '3': {'rows': {'PartyID': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '12'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'columns': {'fieldValue': '2021-06-20T10:44:57'},\n", - " 'type': 'row'},\n", - " 'header': {'rows': {'BeginString': {'columns': {'fieldValue': 'FIXT.1.1'},\n", - " 'type': 'row'},\n", - " 'BodyLength': {'columns': {'fieldValue': '310'},\n", - " 'type': 'row'},\n", - " 'MsgSeqNum': {'columns': {'fieldValue': '1292'},\n", - " 'type': 'row'},\n", - " 'MsgType': {'columns': {'fieldValue': '8'},\n", - " 'type': 'row'},\n", - " 'SenderCompID': {'columns': {'fieldValue': 'FGW'},\n", - " 'type': 'row'},\n", - " 'SendingTime': {'columns': {'fieldValue': '2021-06-20T10:44:57.250'},\n", - " 'type': 'row'},\n", - " 'TargetCompID': {'columns': {'fieldValue': 'DEMO-CONN1'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " 'trailer': {'rows': {'CheckSum': {'columns': {'fieldValue': '047'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'treeTable'}],\n", - " 'endTimestamp': {'epochSecond': 1624185897, 'nano': 932848000},\n", - " 'eventId': '8e759103-d1b4-11eb-bae5-57b0c4472880',\n", - " 'eventName': \"Received 'ExecutionReport' response message\",\n", - " 'eventType': 'message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '8d7ed4f1-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185897, 'nano': 932789000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'data': 'STEP4: Trader \"DEMO-CONN1\" receives Execution Report. The '\n", - " 'order stands on book in status NEW',\n", - " 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185898, 'nano': 46366000},\n", - " 'eventId': '8e85e54f-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Check sequence rule SessionKey{sessionAlias='demo-conn1', \"\n", - " 'direction=FIRST} - STEP4: Trader \"DEMO-CONN1\" receives '\n", - " 'Execution Report. The order stands on book in status NEW',\n", - " 'eventType': 'checkSequenceRule',\n", - " 'isBatched': False,\n", - " 'parentEventId': '88a3ee80-d1b4-11eb-b0fb-199708acc7bc',\n", - " 'startTimestamp': {'epochSecond': 1624185898, 'nano': 39168000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'data': 'Contains comparisons', 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185898, 'nano': 46700000},\n", - " 'eventId': '8e86f6c3-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Check messages',\n", - " 'eventType': 'checkMessages',\n", - " 'isBatched': False,\n", - " 'parentEventId': '8e85e54f-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185898, 'nano': 39168000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '9df66bf9-adeb-4443-aeb1-aafcdfff6b66',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '2638304',\n", - " 'expected': '2638304',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2348',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '10',\n", - " 'expected': '10',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': '2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'A',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '868',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '10',\n", - " 'expected': '10',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '56',\n", - " 'expected': '56',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR1',\n", - " 'expected': 'INSTR1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'Simulated New Order Buy is placed',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {'NoPartyIDs': {'actual': '4',\n", - " 'expected': '4',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'DEMO-CONN1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': '76',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': '122',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': '12',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:44:57',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': '7',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'FIXT.1.1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '310',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1292',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:44:57.250',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'DEMO-CONN1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '047',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185898, 'nano': 46707000},\n", - " 'eventId': '9df66bf9-adeb-4443-aeb1-aafcdfff6b66:8e86f6c4-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '8e86f6c3-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185898, 'nano': 39168000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'b7900a0c-b1d5-44a2-9fd5-5c0ab728abd8',\n", - " 'body': [{'data': 'Expected 1, Actual 1', 'type': 'message'},\n", - " {'rows': [{'actualMessage': 'ExecutionReport, demo-conn1, '\n", - " 'ClOrdID=2638304, OrdStatus=0',\n", - " 'actualMetadata': 'Metadata, demo-conn1',\n", - " 'expectedMessage': 'ExecutionReport, demo-conn1, '\n", - " 'ClOrdID=2638304, OrdStatus=0',\n", - " 'expectedMetadata': 'Metadata, demo-conn1'}],\n", - " 'type': 'table'}],\n", - " 'endTimestamp': {'epochSecond': 1624185898, 'nano': 46676000},\n", - " 'eventId': 'b7900a0c-b1d5-44a2-9fd5-5c0ab728abd8:8e86f6c2-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Check sequence (expected 1 / actual 1 , check order false)',\n", - " 'eventType': 'checkSequence',\n", - " 'isBatched': True,\n", - " 'parentEventId': '8e85e54f-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185898, 'nano': 39168000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'rows': {'comparison-settings': {'rows': {'ignore-fields': {'rows': {},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'},\n", - " 'message-filter': {'rows': {'SecurityID': {'columns': {'expected': 'INSTR1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " 'message-type': {'columns': {'type': 'PreFilter'},\n", - " 'type': 'row'},\n", - " 'metadata-filter': {'rows': {}, 'type': 'collection'}},\n", - " 'type': 'treeTable'}],\n", - " 'endTimestamp': {'epochSecond': 1624185898, 'nano': 46437000},\n", - " 'eventId': '8e868190-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Pre-filtering (filtered 1 / processed 1) messages',\n", - " 'eventType': 'preFiltering',\n", - " 'isBatched': False,\n", - " 'parentEventId': '8e85e54f-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185898, 'nano': 43152000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '064f3825-7ed0-4ae8-a5ef-a6b339d894e3',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '2638304',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2348',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '10',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '868',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '10',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '56',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR1',\n", - " 'expected': 'INSTR1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'Simulated New Order Buy is placed',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'NoPartyIDs': {'actual': '4',\n", - " 'expected': 'null',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:44:57',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': 'null',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '310',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1292',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:44:57.250',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '047',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185898, 'nano': 46525000},\n", - " 'eventId': '064f3825-7ed0-4ae8-a5ef-a6b339d894e3:8e86cfb1-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '8e868190-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185898, 'nano': 43152000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'data': 'STEP5: Trader \"DEMO-CONN2\" sends request to create '\n", - " 'aggressive IOC Order.',\n", - " 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185898, 'nano': 205329000},\n", - " 'eventId': '8e9f3914-d1b4-11eb-bae5-57b0c4472880',\n", - " 'eventName': 'placeOrderFIX demo-conn2 - STEP5: Trader \"DEMO-CONN2\" sends '\n", - " 'request to create aggressive IOC Order.',\n", - " 'eventType': 'placeOrderFIX',\n", - " 'isBatched': False,\n", - " 'parentEventId': '88a3ee80-d1b4-11eb-b0fb-199708acc7bc',\n", - " 'startTimestamp': {'epochSecond': 1624185898, 'nano': 205296000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'b702a614-df18-42b5-9e8f-3ae49e993c68',\n", - " 'body': [{'data': \"Checkpoint id '8ea15bb0-d1b4-11eb-ba78-1981398e00bd'\",\n", - " 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185898, 'nano': 219224000},\n", - " 'eventId': 'b702a614-df18-42b5-9e8f-3ae49e993c68:8ea15c95-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Checkpoint',\n", - " 'eventType': 'Checkpoint',\n", - " 'isBatched': True,\n", - " 'parentEventId': '8e9f3914-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185898, 'nano': 219128000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'b702a614-df18-42b5-9e8f-3ae49e993c68',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185898, 'nano': 219224000},\n", - " 'eventId': 'b702a614-df18-42b5-9e8f-3ae49e993c68:8ea15c96-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'th2-hand-demo' direction 'FIRST' \"\n", - " \"sequence '1623852603564709030'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'b702a614-df18-42b5-9e8f-3ae49e993c68:8ea15c95-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185898, 'nano': 219128000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'b702a614-df18-42b5-9e8f-3ae49e993c68',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185898, 'nano': 219224000},\n", - " 'eventId': 'b702a614-df18-42b5-9e8f-3ae49e993c68:8ea15c97-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn1' direction 'SECOND' \"\n", - " \"sequence '1624005455622140291'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'b702a614-df18-42b5-9e8f-3ae49e993c68:8ea15c95-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185898, 'nano': 219128000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'b702a614-df18-42b5-9e8f-3ae49e993c68',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185898, 'nano': 219224000},\n", - " 'eventId': 'b702a614-df18-42b5-9e8f-3ae49e993c68:8ea15c98-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc1' direction 'SECOND' \"\n", - " \"sequence '1624005475721015014'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'b702a614-df18-42b5-9e8f-3ae49e993c68:8ea15c95-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185898, 'nano': 219128000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'b702a614-df18-42b5-9e8f-3ae49e993c68',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185898, 'nano': 219224000},\n", - " 'eventId': 'b702a614-df18-42b5-9e8f-3ae49e993c68:8ea15c99-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc1' direction 'FIRST' \"\n", - " \"sequence '1624005475720919501'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'b702a614-df18-42b5-9e8f-3ae49e993c68:8ea15c95-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185898, 'nano': 219128000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'b702a614-df18-42b5-9e8f-3ae49e993c68',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185898, 'nano': 219224000},\n", - " 'eventId': 'b702a614-df18-42b5-9e8f-3ae49e993c68:8ea15c9a-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn2' direction 'FIRST' \"\n", - " \"sequence '1624005448022245399'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'b702a614-df18-42b5-9e8f-3ae49e993c68:8ea15c95-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185898, 'nano': 219128000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'b702a614-df18-42b5-9e8f-3ae49e993c68',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185898, 'nano': 219224000},\n", - " 'eventId': 'b702a614-df18-42b5-9e8f-3ae49e993c68:8ea15c9b-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn2' direction 'SECOND' \"\n", - " \"sequence '1624005448022426113'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'b702a614-df18-42b5-9e8f-3ae49e993c68:8ea15c95-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185898, 'nano': 219128000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'b702a614-df18-42b5-9e8f-3ae49e993c68',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185898, 'nano': 219224000},\n", - " 'eventId': 'b702a614-df18-42b5-9e8f-3ae49e993c68:8ea15c9c-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc2' direction 'SECOND' \"\n", - " \"sequence '1624005466840347015'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'b702a614-df18-42b5-9e8f-3ae49e993c68:8ea15c95-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185898, 'nano': 219128000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'b702a614-df18-42b5-9e8f-3ae49e993c68',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185898, 'nano': 219224000},\n", - " 'eventId': 'b702a614-df18-42b5-9e8f-3ae49e993c68:8ea15c9d-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc2' direction 'FIRST' \"\n", - " \"sequence '1624005466840263372'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'b702a614-df18-42b5-9e8f-3ae49e993c68:8ea15c95-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185898, 'nano': 219128000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'b702a614-df18-42b5-9e8f-3ae49e993c68',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185898, 'nano': 219224000},\n", - " 'eventId': 'b702a614-df18-42b5-9e8f-3ae49e993c68:8ea15c9e-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn1' direction 'FIRST' \"\n", - " \"sequence '1624005455622011524'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'b702a614-df18-42b5-9e8f-3ae49e993c68:8ea15c95-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185898, 'nano': 219128000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'b702a614-df18-42b5-9e8f-3ae49e993c68',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185898, 'nano': 219224000},\n", - " 'eventId': 'b702a614-df18-42b5-9e8f-3ae49e993c68:8ea15c9f-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-log' direction 'FIRST' \"\n", - " \"sequence '1624029363623063053'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'b702a614-df18-42b5-9e8f-3ae49e993c68:8ea15c95-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185898, 'nano': 219128000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'rows': {'AccountType': {'columns': {'fieldValue': '1'},\n", - " 'type': 'row'},\n", - " 'ClOrdID': {'columns': {'fieldValue': '7427734'},\n", - " 'type': 'row'},\n", - " 'OrdType': {'columns': {'fieldValue': '2'}, 'type': 'row'},\n", - " 'OrderCapacity': {'columns': {'fieldValue': 'A'},\n", - " 'type': 'row'},\n", - " 'OrderQty': {'columns': {'fieldValue': '100'},\n", - " 'type': 'row'},\n", - " 'Price': {'columns': {'fieldValue': '54'}, 'type': 'row'},\n", - " 'SecondaryClOrdID': {'columns': {'fieldValue': '33333'},\n", - " 'type': 'row'},\n", - " 'SecurityID': {'columns': {'fieldValue': 'INSTR1'},\n", - " 'type': 'row'},\n", - " 'SecurityIDSource': {'columns': {'fieldValue': '8'},\n", - " 'type': 'row'},\n", - " 'Side': {'columns': {'fieldValue': '2'}, 'type': 'row'},\n", - " 'TimeInForce': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'},\n", - " 'TradingParty': {'rows': {'NoPartyIDs': {'rows': {'0': {'rows': {'PartyID': {'columns': {'fieldValue': 'DEMO-CONN2'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'D'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '76'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '1': {'rows': {'PartyID': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '2': {'rows': {'PartyID': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '122'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '3': {'rows': {'PartyID': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '12'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'columns': {'fieldValue': '2021-06-20T13:44:48.170637'},\n", - " 'type': 'row'}},\n", - " 'type': 'treeTable'}],\n", - " 'endTimestamp': {'epochSecond': 1624185898, 'nano': 222222000},\n", - " 'eventId': '8ea1d125-d1b4-11eb-bae5-57b0c4472880',\n", - " 'eventName': \"Send 'NewOrderSingle' message to connectivity\",\n", - " 'eventType': 'Outgoing message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '8e9f3914-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185898, 'nano': 222160000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185898, 'nano': 241489000},\n", - " 'eventId': '8ea4b711-d1b4-11eb-bd0a-0d6cee9f6833',\n", - " 'eventName': \"Send 'NewOrderSingle' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '8e9f3914-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185898, 'nano': 241268000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185898, 'nano': 450612000},\n", - " 'eventId': '8ec49bd8-d1b4-11eb-a9ed-ffb57363e013',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '849a79d3-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185898, 'nano': 450127000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185898, 'nano': 457028000},\n", - " 'eventId': '8ec5ad25-d1b4-11eb-a9f4-b12655548efc',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '849a79d3-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185898, 'nano': 457023000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185898, 'nano': 468430000},\n", - " 'eventId': '8ec75af9-d1b4-11eb-a9ed-ffb57363e013',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '849a79d3-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185898, 'nano': 468426000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185898, 'nano': 468732000},\n", - " 'eventId': '8ec75ad6-d1b4-11eb-a9f4-b12655548efc',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '849a79d3-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185898, 'nano': 468728000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185898, 'nano': 533843000},\n", - " 'eventId': '8ed1456c-d1b4-11eb-91f0-77dd26d4db8e',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '849a79d3-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185898, 'nano': 533691000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185898, 'nano': 539217000},\n", - " 'eventId': '8ed22ffd-d1b4-11eb-be23-57049e5b0bd9',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '849a79d3-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185898, 'nano': 539082000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185898, 'nano': 539121000},\n", - " 'eventId': '8ed22fcd-d1b4-11eb-91f0-77dd26d4db8e',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '849a79d3-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185898, 'nano': 539108000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185898, 'nano': 546212000},\n", - " 'eventId': '8ed3416e-d1b4-11eb-be23-57049e5b0bd9',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '849a79d3-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185898, 'nano': 546200000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185898, 'nano': 619841000},\n", - " 'eventId': '8ede64ce-d1b4-11eb-91f0-77dd26d4db8e',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '849a79d3-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185898, 'nano': 619823000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185898, 'nano': 623721000},\n", - " 'eventId': '8edf013f-d1b4-11eb-be23-57049e5b0bd9',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '849a79d3-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185898, 'nano': 623706000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '614f6ff2-bfbe-4750-9dfd-58abaaf1adbc',\n", - " 'body': {'data': 'The message was deleted because a new one came with the '\n", - " \"same hash '3210110562847338001' in message group \"\n", - " \"'NOS_CONN'\\n\"\n", - " ' Message not matched',\n", - " 'type': 'message'},\n", - " 'endTimestamp': {'epochSecond': 1624185898, 'nano': 629696000},\n", - " 'eventId': '614f6ff2-bfbe-4750-9dfd-58abaaf1adbc:8ee00d2e-d1b4-11eb-986f-1e8d42132387',\n", - " 'eventName': \"Remove 'NewOrderSingle' \"\n", - " \"id='demo-conn2:SECOND:1624005448022421036' \"\n", - " \"Hash='3210110562847338001' Group='NOS_CONN' \"\n", - " \"Hash['SecondaryClOrdID': 33333, 'SecurityID': INSTR1]\",\n", - " 'eventType': '',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'a3779b94-d051-11eb-986f-1e8d42132387',\n", - " 'startTimestamp': {'epochSecond': 1624185898, 'nano': 629696000},\n", - " 'successful': False,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'rows': {'AccountType': {'columns': {'fieldValue': '1'},\n", - " 'type': 'row'},\n", - " 'ClOrdID': {'columns': {'fieldValue': '7427734'},\n", - " 'type': 'row'},\n", - " 'CumQty': {'columns': {'fieldValue': '10'}, 'type': 'row'},\n", - " 'ExecID': {'columns': {'fieldValue': '2352'},\n", - " 'type': 'row'},\n", - " 'ExecType': {'columns': {'fieldValue': 'F'}, 'type': 'row'},\n", - " 'LastPx': {'columns': {'fieldValue': '56'}, 'type': 'row'},\n", - " 'LeavesQty': {'columns': {'fieldValue': '90'},\n", - " 'type': 'row'},\n", - " 'OrdStatus': {'columns': {'fieldValue': '1'},\n", - " 'type': 'row'},\n", - " 'OrdType': {'columns': {'fieldValue': '2'}, 'type': 'row'},\n", - " 'OrderCapacity': {'columns': {'fieldValue': 'A'},\n", - " 'type': 'row'},\n", - " 'OrderID': {'columns': {'fieldValue': '869'},\n", - " 'type': 'row'},\n", - " 'OrderQty': {'columns': {'fieldValue': '100'},\n", - " 'type': 'row'},\n", - " 'Price': {'columns': {'fieldValue': '54'}, 'type': 'row'},\n", - " 'SecurityID': {'columns': {'fieldValue': 'INSTR1'},\n", - " 'type': 'row'},\n", - " 'SecurityIDSource': {'columns': {'fieldValue': '8'},\n", - " 'type': 'row'},\n", - " 'Side': {'columns': {'fieldValue': '2'}, 'type': 'row'},\n", - " 'Text': {'columns': {'fieldValue': 'The simulated order '\n", - " 'has been partially '\n", - " 'traded'},\n", - " 'type': 'row'},\n", - " 'TimeInForce': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'},\n", - " 'TradingParty': {'rows': {'NoPartyIDs': {'rows': {'0': {'rows': {'PartyID': {'columns': {'fieldValue': 'DEMO-CONN2'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'D'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '76'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '1': {'rows': {'PartyID': {'columns': {'fieldValue': 'DEMOFIRM1'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'D'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '17'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '2': {'rows': {'PartyID': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '3': {'rows': {'PartyID': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '122'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '4': {'rows': {'PartyID': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '12'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'columns': {'fieldValue': '2021-06-20T10:44:58'},\n", - " 'type': 'row'},\n", - " 'TrdMatchID': {'columns': {'fieldValue': '481'},\n", - " 'type': 'row'},\n", - " 'header': {'rows': {'BeginString': {'columns': {'fieldValue': 'FIXT.1.1'},\n", - " 'type': 'row'},\n", - " 'BodyLength': {'columns': {'fieldValue': '370'},\n", - " 'type': 'row'},\n", - " 'MsgSeqNum': {'columns': {'fieldValue': '1291'},\n", - " 'type': 'row'},\n", - " 'MsgType': {'columns': {'fieldValue': '8'},\n", - " 'type': 'row'},\n", - " 'SenderCompID': {'columns': {'fieldValue': 'FGW'},\n", - " 'type': 'row'},\n", - " 'SendingTime': {'columns': {'fieldValue': '2021-06-20T10:44:58.531'},\n", - " 'type': 'row'},\n", - " 'TargetCompID': {'columns': {'fieldValue': 'DEMO-CONN2'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " 'trailer': {'rows': {'CheckSum': {'columns': {'fieldValue': '231'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'treeTable'}],\n", - " 'endTimestamp': {'epochSecond': 1624185899, 'nano': 528525000},\n", - " 'eventId': '8f6918c6-d1b4-11eb-bae5-57b0c4472880',\n", - " 'eventName': \"Received 'ExecutionReport' response message\",\n", - " 'eventType': 'message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '8e9f3914-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185899, 'nano': 528490000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'data': 'STEP6: Trader \"DEMO-CONN1\" receives Execution Reports with '\n", - " 'ExecType=F: first at Order2 and second on Order1.',\n", - " 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185899, 'nano': 641280000},\n", - " 'eventId': '8f772330-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Check sequence rule SessionKey{sessionAlias='demo-conn1', \"\n", - " 'direction=FIRST} - STEP6: Trader \"DEMO-CONN1\" receives '\n", - " 'Execution Reports with ExecType=F: first at Order2 and second '\n", - " 'on Order1.',\n", - " 'eventType': 'checkSequenceRule',\n", - " 'isBatched': False,\n", - " 'parentEventId': '88a3ee80-d1b4-11eb-b0fb-199708acc7bc',\n", - " 'startTimestamp': {'epochSecond': 1624185899, 'nano': 620545000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'data': 'Contains comparisons', 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185899, 'nano': 719098000},\n", - " 'eventId': '8f7a5785-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Check messages',\n", - " 'eventType': 'checkMessages',\n", - " 'isBatched': False,\n", - " 'parentEventId': '8f772330-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185899, 'nano': 620545000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '6e254e16-2a86-42a7-87f9-ebca7f867630',\n", - " 'body': [{'data': 'Expected 2, Actual 2, In order', 'type': 'message'},\n", - " {'rows': [{'actualMessage': 'ExecutionReport, demo-conn1, '\n", - " 'LeavesQty=0, CumQty=10, OrdStatus=2, '\n", - " 'ClOrdID=2638304',\n", - " 'actualMetadata': 'Metadata, demo-conn1',\n", - " 'expectedMessage': 'ExecutionReport, demo-conn1, '\n", - " 'LeavesQty=0, CumQty=10, OrdStatus=2, '\n", - " 'ClOrdID=2638304',\n", - " 'expectedMetadata': 'Metadata, demo-conn1'},\n", - " {'actualMessage': 'ExecutionReport, demo-conn1, '\n", - " 'OrdStatus=2, LeavesQty=0, CumQty=30, '\n", - " 'ClOrdID=9601585',\n", - " 'actualMetadata': 'Metadata, demo-conn1',\n", - " 'expectedMessage': 'ExecutionReport, demo-conn1, '\n", - " 'OrdStatus=2, LeavesQty=0, CumQty=30, '\n", - " 'ClOrdID=9601585',\n", - " 'expectedMetadata': 'Metadata, demo-conn1'}],\n", - " 'type': 'table'}],\n", - " 'endTimestamp': {'epochSecond': 1624185899, 'nano': 719034000},\n", - " 'eventId': '6e254e16-2a86-42a7-87f9-ebca7f867630:8f7a5784-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Check sequence (expected 2 / actual 2 , check order true)',\n", - " 'eventType': 'checkSequence',\n", - " 'isBatched': True,\n", - " 'parentEventId': '8f772330-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185899, 'nano': 620545000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'f01baf75-606b-47f7-95ac-75b797efd7ed',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '2638304',\n", - " 'expected': '2638304',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '10',\n", - " 'expected': '10',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2350',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': 'F',\n", - " 'expected': 'F',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LastPx': {'actual': '56',\n", - " 'expected': '56',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '2',\n", - " 'expected': '2',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': '2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'A',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '868',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '10',\n", - " 'expected': '10',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '56',\n", - " 'expected': '56',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR1',\n", - " 'expected': 'INSTR1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'The simulated order has been fully '\n", - " 'traded',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TimeInForce': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {'NoPartyIDs': {'actual': '5',\n", - " 'expected': '5',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'DEMO-CONN1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': '76',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMOFIRM2',\n", - " 'expected': 'DEMOFIRM2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '17',\n", - " 'expected': '17',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': '122',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '4': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': '12',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:44:58',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TrdMatchID': {'actual': '481',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': '7',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'FIXT.1.1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '364',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1293',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:44:58.449',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'DEMO-CONN1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '216',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185899, 'nano': 719106000},\n", - " 'eventId': 'f01baf75-606b-47f7-95ac-75b797efd7ed:8f7a5786-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '8f7a5785-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185899, 'nano': 620545000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'f01baf75-606b-47f7-95ac-75b797efd7ed',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '9601585',\n", - " 'expected': '9601585',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '30',\n", - " 'expected': '30',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2351',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': 'F',\n", - " 'expected': 'F',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LastPx': {'actual': '55',\n", - " 'expected': '55',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '2',\n", - " 'expected': '2',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': '2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'A',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '867',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '30',\n", - " 'expected': '30',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '55',\n", - " 'expected': '55',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR1',\n", - " 'expected': 'INSTR1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'The simulated order has been fully '\n", - " 'traded',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TimeInForce': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {'NoPartyIDs': {'actual': '5',\n", - " 'expected': '5',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'DEMO-CONN1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': '76',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMOFIRM2',\n", - " 'expected': 'DEMOFIRM2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '17',\n", - " 'expected': '17',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': '122',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '4': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': '12',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:44:58',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TrdMatchID': {'actual': '482',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': '7',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'FIXT.1.1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '364',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1294',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:44:58.467',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'DEMO-CONN1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '228',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185899, 'nano': 719362000},\n", - " 'eventId': 'f01baf75-606b-47f7-95ac-75b797efd7ed:8f7a5787-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '8f7a5785-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185899, 'nano': 620545000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'rows': {'comparison-settings': {'rows': {'ignore-fields': {'rows': {},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'},\n", - " 'message-filter': {'rows': {'SecurityID': {'columns': {'expected': 'INSTR1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " 'message-type': {'columns': {'type': 'PreFilter'},\n", - " 'type': 'row'},\n", - " 'metadata-filter': {'rows': {}, 'type': 'collection'}},\n", - " 'type': 'treeTable'}],\n", - " 'endTimestamp': {'epochSecond': 1624185899, 'nano': 641344000},\n", - " 'eventId': '8f7834a1-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Pre-filtering (filtered 2 / processed 2) messages',\n", - " 'eventType': 'preFiltering',\n", - " 'isBatched': False,\n", - " 'parentEventId': '8f772330-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185899, 'nano': 627174000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '97ed6ada-667e-4d7e-b39c-90f8be81b8f3',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '2638304',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '10',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2350',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': 'F',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LastPx': {'actual': '56',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '868',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '10',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '56',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR1',\n", - " 'expected': 'INSTR1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'The simulated order has been fully '\n", - " 'traded',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TimeInForce': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'NoPartyIDs': {'actual': '5',\n", - " 'expected': 'null',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': 'DEMOFIRM2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '17',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '4': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:44:58',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TrdMatchID': {'actual': '481',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': 'null',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '364',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1293',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:44:58.449',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '216',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185899, 'nano': 642180000},\n", - " 'eventId': '97ed6ada-667e-4d7e-b39c-90f8be81b8f3:8f799432-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '8f7834a1-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185899, 'nano': 627174000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '97ed6ada-667e-4d7e-b39c-90f8be81b8f3',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '9601585',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '30',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2351',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': 'F',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LastPx': {'actual': '55',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '867',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '30',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '55',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR1',\n", - " 'expected': 'INSTR1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'The simulated order has been fully '\n", - " 'traded',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TimeInForce': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'NoPartyIDs': {'actual': '5',\n", - " 'expected': 'null',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': 'DEMOFIRM2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '17',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '4': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:44:58',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TrdMatchID': {'actual': '482',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': 'null',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '364',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1294',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:44:58.467',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '228',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185899, 'nano': 718695000},\n", - " 'eventId': '97ed6ada-667e-4d7e-b39c-90f8be81b8f3:8f7a0963-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '8f7834a1-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185899, 'nano': 627174000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'ef902404-a26a-49de-bc8b-287df10e4877',\n", - " 'body': {'fields': {'AccountType': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '2638304',\n", - " 'expected': '7427734',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '10',\n", - " 'expected': '10',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2350',\n", - " 'expected': '2352',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': 'F',\n", - " 'expected': 'F',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LastPx': {'actual': '56',\n", - " 'expected': '56',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '0',\n", - " 'expected': '90',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '2',\n", - " 'expected': '1',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': '2',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'A',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '868',\n", - " 'expected': '869',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '10',\n", - " 'expected': '100',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '56',\n", - " 'expected': '54',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR1',\n", - " 'expected': 'INSTR1',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': '8',\n", - " 'fields': {},\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '1',\n", - " 'expected': '2',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'The simulated order has been fully '\n", - " 'traded',\n", - " 'expected': 'The simulated order has been '\n", - " 'partially traded',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TimeInForce': {'actual': '0',\n", - " 'expected': '3',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {'NoPartyIDs': {'actual': '5',\n", - " 'expected': '5',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'DEMO-CONN2',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': '76',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMOFIRM2',\n", - " 'expected': 'DEMOFIRM1',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '17',\n", - " 'expected': '17',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': '122',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '4': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': '12',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:44:58',\n", - " 'expected': '2021-06-20T10:44:58',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TrdMatchID': {'actual': '481',\n", - " 'expected': '481',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': '7',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'FIXT.1.1',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '364',\n", - " 'expected': '370',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1293',\n", - " 'expected': '1291',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': '8',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': 'FGW',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:44:58.449',\n", - " 'expected': '2021-06-20T10:44:58.531',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'DEMO-CONN2',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {'CheckSum': {'actual': '216',\n", - " 'expected': '231',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'status': 0,\n", - " 'type': 'verification'},\n", - " 'endTimestamp': {'epochSecond': 1624185899, 'nano': 630975000},\n", - " 'eventId': 'ef902404-a26a-49de-bc8b-287df10e4877:8f78d608-d1b4-11eb-986f-1e8d42132387',\n", - " 'eventName': \"Match by '['TrdMatchID': 481]'\",\n", - " 'eventType': '',\n", - " 'isBatched': True,\n", - " 'parentEventId': '6e86db98-d047-11eb-986f-1e8d42132387',\n", - " 'startTimestamp': {'epochSecond': 1624185899, 'nano': 630975000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'data': 'STEP7: Trader \"DEMO-CONN2\" receives Execution Reports: '\n", - " 'first trade with Order2, next with Order1 and then '\n", - " 'cancellation',\n", - " 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185899, 'nano': 930383000},\n", - " 'eventId': '8f8701b8-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Check sequence rule SessionKey{sessionAlias='demo-conn2', \"\n", - " 'direction=FIRST} - STEP7: Trader \"DEMO-CONN2\" receives '\n", - " 'Execution Reports: first trade with Order2, next with Order1 '\n", - " 'and then cancellation',\n", - " 'eventType': 'checkSequenceRule',\n", - " 'isBatched': False,\n", - " 'parentEventId': '88a3ee80-d1b4-11eb-b0fb-199708acc7bc',\n", - " 'startTimestamp': {'epochSecond': 1624185899, 'nano': 724004000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'data': 'Contains comparisons', 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185899, 'nano': 936023000},\n", - " 'eventId': '8fa6709e-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Check messages',\n", - " 'eventType': 'checkMessages',\n", - " 'isBatched': False,\n", - " 'parentEventId': '8f8701b8-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185899, 'nano': 724004000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'adbecd61-eb28-49e3-af69-814691a9404d',\n", - " 'body': [{'data': 'Expected 3, Actual 3, In order', 'type': 'message'},\n", - " {'rows': [{'actualMessage': 'ExecutionReport, demo-conn2, '\n", - " 'OrdStatus=1, ClOrdID=7427734, '\n", - " 'LeavesQty=90, CumQty=10',\n", - " 'actualMetadata': 'Metadata, demo-conn2',\n", - " 'expectedMessage': 'ExecutionReport, demo-conn2, '\n", - " 'OrdStatus=1, ClOrdID=7427734, '\n", - " 'LeavesQty=90, CumQty=10',\n", - " 'expectedMetadata': 'Metadata, demo-conn2'},\n", - " {'actualMessage': 'ExecutionReport, demo-conn2, '\n", - " 'ClOrdID=7427734, CumQty=40, '\n", - " 'LeavesQty=60, OrdStatus=1',\n", - " 'actualMetadata': 'Metadata, demo-conn2',\n", - " 'expectedMessage': 'ExecutionReport, demo-conn2, '\n", - " 'ClOrdID=7427734, CumQty=40, '\n", - " 'LeavesQty=60, OrdStatus=1',\n", - " 'expectedMetadata': 'Metadata, demo-conn2'},\n", - " {'actualMessage': 'ExecutionReport, demo-conn2, '\n", - " 'LeavesQty=0, OrdStatus=C, CumQty=40, '\n", - " 'ClOrdID=7427734',\n", - " 'actualMetadata': 'Metadata, demo-conn2',\n", - " 'expectedMessage': 'ExecutionReport, demo-conn2, '\n", - " 'LeavesQty=0, OrdStatus=C, CumQty=40, '\n", - " 'ClOrdID=7427734',\n", - " 'expectedMetadata': 'Metadata, demo-conn2'}],\n", - " 'type': 'table'}],\n", - " 'endTimestamp': {'epochSecond': 1624185899, 'nano': 935497000},\n", - " 'eventId': 'adbecd61-eb28-49e3-af69-814691a9404d:8fa6709d-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Check sequence (expected 3 / actual 3 , check order true)',\n", - " 'eventType': 'checkSequence',\n", - " 'isBatched': True,\n", - " 'parentEventId': '8f8701b8-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185899, 'nano': 724004000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'f3042deb-f287-40a7-b4d9-97a61f4e061f',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '7427734',\n", - " 'expected': '7427734',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '10',\n", - " 'expected': '10',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2352',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': 'F',\n", - " 'expected': 'F',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LastPx': {'actual': '56',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '90',\n", - " 'expected': '90',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': '2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'A',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '869',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '100',\n", - " 'expected': '100',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '54',\n", - " 'expected': '54',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR1',\n", - " 'expected': 'INSTR1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '2',\n", - " 'expected': '2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'The simulated order has been '\n", - " 'partially traded',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TimeInForce': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {'NoPartyIDs': {'actual': '5',\n", - " 'expected': '5',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'DEMO-CONN2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': '76',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMOFIRM1',\n", - " 'expected': 'DEMOFIRM1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '17',\n", - " 'expected': '17',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': '122',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '4': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': '12',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:44:58',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TrdMatchID': {'actual': '481',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': '7',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'FIXT.1.1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '370',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1291',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:44:58.531',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'DEMO-CONN2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '231',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185899, 'nano': 936038000},\n", - " 'eventId': 'f3042deb-f287-40a7-b4d9-97a61f4e061f:8fa6709f-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '8fa6709e-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185899, 'nano': 724004000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'f3042deb-f287-40a7-b4d9-97a61f4e061f',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '7427734',\n", - " 'expected': '7427734',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '40',\n", - " 'expected': '40',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2353',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': 'F',\n", - " 'expected': 'F',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LastPx': {'actual': '55',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '60',\n", - " 'expected': '60',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': '2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'A',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '869',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '100',\n", - " 'expected': '100',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '54',\n", - " 'expected': '54',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR1',\n", - " 'expected': 'INSTR1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '2',\n", - " 'expected': '2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'The simulated order has been '\n", - " 'partially traded',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TimeInForce': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {'NoPartyIDs': {'actual': '5',\n", - " 'expected': '5',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'DEMO-CONN2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': '76',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMOFIRM1',\n", - " 'expected': 'DEMOFIRM1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '17',\n", - " 'expected': '17',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': '122',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '4': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': '12',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:44:58',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TrdMatchID': {'actual': '482',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': '7',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'FIXT.1.1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '370',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1292',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:44:58.537',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'DEMO-CONN2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '239',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185899, 'nano': 936160000},\n", - " 'eventId': 'f3042deb-f287-40a7-b4d9-97a61f4e061f:8fa670a0-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '8fa6709e-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185899, 'nano': 724004000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'f3042deb-f287-40a7-b4d9-97a61f4e061f',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '7427734',\n", - " 'expected': '7427734',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '40',\n", - " 'expected': '40',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2354',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': 'C',\n", - " 'expected': 'C',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': 'C',\n", - " 'expected': 'C',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': '2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'A',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '869',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '100',\n", - " 'expected': '100',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '54',\n", - " 'expected': '54',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR1',\n", - " 'expected': 'INSTR1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '2',\n", - " 'expected': '2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'The remaining part of simulated '\n", - " 'order has been expired',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TimeInForce': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {'NoPartyIDs': {'actual': '4',\n", - " 'expected': '4',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'DEMO-CONN2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': '76',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': '122',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': '12',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:44:58',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': '7',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'FIXT.1.1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '337',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1293',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:44:58.619',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'DEMO-CONN2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '178',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185899, 'nano': 936270000},\n", - " 'eventId': 'f3042deb-f287-40a7-b4d9-97a61f4e061f:8fa670a1-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '8fa6709e-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185899, 'nano': 724004000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'ef902404-a26a-49de-bc8b-287df10e4877',\n", - " 'body': {'fields': {'AccountType': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '9601585',\n", - " 'expected': '7427734',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '30',\n", - " 'expected': '40',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2351',\n", - " 'expected': '2353',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': 'F',\n", - " 'expected': 'F',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LastPx': {'actual': '55',\n", - " 'expected': '55',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '0',\n", - " 'expected': '60',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '2',\n", - " 'expected': '1',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': '2',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'A',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '867',\n", - " 'expected': '869',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '30',\n", - " 'expected': '100',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '55',\n", - " 'expected': '54',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR1',\n", - " 'expected': 'INSTR1',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': '8',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '1',\n", - " 'expected': '2',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'The simulated order has been fully '\n", - " 'traded',\n", - " 'expected': 'The simulated order has been '\n", - " 'partially traded',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TimeInForce': {'actual': '0',\n", - " 'expected': '3',\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {'NoPartyIDs': {'actual': '5',\n", - " 'expected': '5',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'DEMO-CONN2',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': '76',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMOFIRM2',\n", - " 'expected': 'DEMOFIRM1',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '17',\n", - " 'expected': '17',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': '122',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '4': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': '12',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:44:58',\n", - " 'expected': '2021-06-20T10:44:58',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TrdMatchID': {'actual': '482',\n", - " 'expected': '482',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': '7',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'FIXT.1.1',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '364',\n", - " 'expected': '370',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1294',\n", - " 'expected': '1292',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': '8',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': 'FGW',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:44:58.467',\n", - " 'expected': '2021-06-20T10:44:58.537',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'DEMO-CONN2',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {'CheckSum': {'actual': '228',\n", - " 'expected': '239',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'status': 0,\n", - " 'type': 'verification'},\n", - " 'endTimestamp': {'epochSecond': 1624185899, 'nano': 734412000},\n", - " 'eventId': 'ef902404-a26a-49de-bc8b-287df10e4877:8f889e1c-d1b4-11eb-986f-1e8d42132387',\n", - " 'eventName': \"Match by '['TrdMatchID': 482]'\",\n", - " 'eventType': '',\n", - " 'isBatched': True,\n", - " 'parentEventId': '6e86db98-d047-11eb-986f-1e8d42132387',\n", - " 'startTimestamp': {'epochSecond': 1624185899, 'nano': 734412000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'rows': {'comparison-settings': {'rows': {'ignore-fields': {'rows': {},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'},\n", - " 'message-filter': {'rows': {'SecurityID': {'columns': {'expected': 'INSTR1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " 'message-type': {'columns': {'type': 'PreFilter'},\n", - " 'type': 'row'},\n", - " 'metadata-filter': {'rows': {}, 'type': 'collection'}},\n", - " 'type': 'treeTable'}],\n", - " 'endTimestamp': {'epochSecond': 1624185899, 'nano': 931414000},\n", - " 'eventId': '8f9643f9-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Pre-filtering (filtered 3 / processed 3) messages',\n", - " 'eventType': 'preFiltering',\n", - " 'isBatched': False,\n", - " 'parentEventId': '8f8701b8-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185899, 'nano': 824990000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '79ec9dec-7d95-43f8-8cf3-4f6f4e117e31',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '7427734',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '10',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2352',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': 'F',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LastPx': {'actual': '56',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '90',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '869',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '100',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '54',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR1',\n", - " 'expected': 'INSTR1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'The simulated order has been '\n", - " 'partially traded',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TimeInForce': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'NoPartyIDs': {'actual': '5',\n", - " 'expected': 'null',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': 'DEMOFIRM1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '17',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '4': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:44:58',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TrdMatchID': {'actual': '481',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': 'null',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '370',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1291',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:44:58.531',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '231',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185899, 'nano': 933217000},\n", - " 'eventId': '79ec9dec-7d95-43f8-8cf3-4f6f4e117e31:8fa5381a-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '8f9643f9-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185899, 'nano': 824990000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '79ec9dec-7d95-43f8-8cf3-4f6f4e117e31',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '7427734',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '40',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2353',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': 'F',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LastPx': {'actual': '55',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '60',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '869',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '100',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '54',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR1',\n", - " 'expected': 'INSTR1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'The simulated order has been '\n", - " 'partially traded',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TimeInForce': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'NoPartyIDs': {'actual': '5',\n", - " 'expected': 'null',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': 'DEMOFIRM1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '17',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '4': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:44:58',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TrdMatchID': {'actual': '482',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': 'null',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '370',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1292',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:44:58.537',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '239',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185899, 'nano': 935174000},\n", - " 'eventId': '79ec9dec-7d95-43f8-8cf3-4f6f4e117e31:8fa5ad4b-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '8f9643f9-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185899, 'nano': 824990000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '79ec9dec-7d95-43f8-8cf3-4f6f4e117e31',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '7427734',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '40',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2354',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': 'C',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': 'C',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '869',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '100',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '54',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR1',\n", - " 'expected': 'INSTR1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'The remaining part of simulated '\n", - " 'order has been expired',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TimeInForce': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'NoPartyIDs': {'actual': '4',\n", - " 'expected': 'null',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:44:58',\n", - " 'expected': 'null',\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': 'null',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '337',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1293',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:44:58.619',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '178',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185899, 'nano': 935305000},\n", - " 'eventId': '79ec9dec-7d95-43f8-8cf3-4f6f4e117e31:8fa6498c-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '8f9643f9-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185899, 'nano': 824990000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': {},\n", - " 'endTimestamp': {'epochSecond': 1624185899, 'nano': 848973000},\n", - " 'eventId': '8f7cc07f-d1b4-11eb-b0fb-199708acc7bc',\n", - " 'eventName': 'Case[TC_1.2]: Trader DEMO-CONN1 vs trader DEMO-CONN2 for '\n", - " 'instrument INSTR2',\n", - " 'eventType': '',\n", - " 'isBatched': False,\n", - " 'parentEventId': '84db48fc-d1b4-11eb-b0fb-199708acc7bc',\n", - " 'startTimestamp': {'epochSecond': 1624185899, 'nano': 848920000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'data': 'STEP1: Trader \"DEMO-CONN1\" sends request to create passive '\n", - " 'Order.',\n", - " 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185904, 'nano': 924434000},\n", - " 'eventId': '92a07607-d1b4-11eb-bae5-57b0c4472880',\n", - " 'eventName': 'placeOrderFIX demo-conn1 - STEP1: Trader \"DEMO-CONN1\" sends '\n", - " 'request to create passive Order.',\n", - " 'eventType': 'placeOrderFIX',\n", - " 'isBatched': False,\n", - " 'parentEventId': '8f7cc07f-d1b4-11eb-b0fb-199708acc7bc',\n", - " 'startTimestamp': {'epochSecond': 1624185904, 'nano': 924389000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'bca5979c-975b-438d-95ff-0764f1e46e1a',\n", - " 'body': [{'data': \"Checkpoint id '92a13910-d1b4-11eb-ba78-1981398e00bd'\",\n", - " 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185904, 'nano': 929292000},\n", - " 'eventId': 'bca5979c-975b-438d-95ff-0764f1e46e1a:92a13912-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Checkpoint',\n", - " 'eventType': 'Checkpoint',\n", - " 'isBatched': True,\n", - " 'parentEventId': '92a07607-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185904, 'nano': 929173000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'bca5979c-975b-438d-95ff-0764f1e46e1a',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185904, 'nano': 929292000},\n", - " 'eventId': 'bca5979c-975b-438d-95ff-0764f1e46e1a:92a13913-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'th2-hand-demo' direction 'FIRST' \"\n", - " \"sequence '1623852603564709030'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'bca5979c-975b-438d-95ff-0764f1e46e1a:92a13912-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185904, 'nano': 929173000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'bca5979c-975b-438d-95ff-0764f1e46e1a',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185904, 'nano': 929292000},\n", - " 'eventId': 'bca5979c-975b-438d-95ff-0764f1e46e1a:92a13914-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn1' direction 'SECOND' \"\n", - " \"sequence '1624005455622140291'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'bca5979c-975b-438d-95ff-0764f1e46e1a:92a13912-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185904, 'nano': 929173000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'bca5979c-975b-438d-95ff-0764f1e46e1a',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185904, 'nano': 929292000},\n", - " 'eventId': 'bca5979c-975b-438d-95ff-0764f1e46e1a:92a13915-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc1' direction 'SECOND' \"\n", - " \"sequence '1624005475721015015'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'bca5979c-975b-438d-95ff-0764f1e46e1a:92a13912-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185904, 'nano': 929173000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'bca5979c-975b-438d-95ff-0764f1e46e1a',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185904, 'nano': 929292000},\n", - " 'eventId': 'bca5979c-975b-438d-95ff-0764f1e46e1a:92a13916-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc1' direction 'FIRST' \"\n", - " \"sequence '1624005475720919503'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'bca5979c-975b-438d-95ff-0764f1e46e1a:92a13912-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185904, 'nano': 929173000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'bca5979c-975b-438d-95ff-0764f1e46e1a',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185904, 'nano': 929292000},\n", - " 'eventId': 'bca5979c-975b-438d-95ff-0764f1e46e1a:92a13917-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn2' direction 'FIRST' \"\n", - " \"sequence '1624005448022245402'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'bca5979c-975b-438d-95ff-0764f1e46e1a:92a13912-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185904, 'nano': 929173000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'bca5979c-975b-438d-95ff-0764f1e46e1a',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185904, 'nano': 929292000},\n", - " 'eventId': 'bca5979c-975b-438d-95ff-0764f1e46e1a:92a13918-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn2' direction 'SECOND' \"\n", - " \"sequence '1624005448022426114'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'bca5979c-975b-438d-95ff-0764f1e46e1a:92a13912-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185904, 'nano': 929173000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'bca5979c-975b-438d-95ff-0764f1e46e1a',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185904, 'nano': 929292000},\n", - " 'eventId': 'bca5979c-975b-438d-95ff-0764f1e46e1a:92a13919-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc2' direction 'SECOND' \"\n", - " \"sequence '1624005466840347016'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'bca5979c-975b-438d-95ff-0764f1e46e1a:92a13912-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185904, 'nano': 929173000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'bca5979c-975b-438d-95ff-0764f1e46e1a',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185904, 'nano': 929292000},\n", - " 'eventId': 'bca5979c-975b-438d-95ff-0764f1e46e1a:92a1391a-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc2' direction 'FIRST' \"\n", - " \"sequence '1624005466840263375'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'bca5979c-975b-438d-95ff-0764f1e46e1a:92a13912-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185904, 'nano': 929173000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'bca5979c-975b-438d-95ff-0764f1e46e1a',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185904, 'nano': 929292000},\n", - " 'eventId': 'bca5979c-975b-438d-95ff-0764f1e46e1a:92a1391b-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn1' direction 'FIRST' \"\n", - " \"sequence '1624005455622011526'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'bca5979c-975b-438d-95ff-0764f1e46e1a:92a13912-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185904, 'nano': 929173000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'bca5979c-975b-438d-95ff-0764f1e46e1a',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185904, 'nano': 929292000},\n", - " 'eventId': 'bca5979c-975b-438d-95ff-0764f1e46e1a:92a1391c-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-log' direction 'FIRST' \"\n", - " \"sequence '1624029363623063053'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'bca5979c-975b-438d-95ff-0764f1e46e1a:92a13912-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185904, 'nano': 929173000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'rows': {'AccountType': {'columns': {'fieldValue': '1'},\n", - " 'type': 'row'},\n", - " 'ClOrdID': {'columns': {'fieldValue': '4556842'},\n", - " 'type': 'row'},\n", - " 'OrdType': {'columns': {'fieldValue': '2'}, 'type': 'row'},\n", - " 'OrderCapacity': {'columns': {'fieldValue': 'A'},\n", - " 'type': 'row'},\n", - " 'OrderQty': {'columns': {'fieldValue': '30'},\n", - " 'type': 'row'},\n", - " 'Price': {'columns': {'fieldValue': '35'}, 'type': 'row'},\n", - " 'SecondaryClOrdID': {'columns': {'fieldValue': '11111'},\n", - " 'type': 'row'},\n", - " 'SecurityID': {'columns': {'fieldValue': 'INSTR2'},\n", - " 'type': 'row'},\n", - " 'SecurityIDSource': {'columns': {'fieldValue': '8'},\n", - " 'type': 'row'},\n", - " 'Side': {'columns': {'fieldValue': '1'}, 'type': 'row'},\n", - " 'TradingParty': {'rows': {'NoPartyIDs': {'rows': {'0': {'rows': {'PartyID': {'columns': {'fieldValue': 'DEMO-CONN1'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'D'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '76'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '1': {'rows': {'PartyID': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '2': {'rows': {'PartyID': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '122'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '3': {'rows': {'PartyID': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '12'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'columns': {'fieldValue': '2021-06-20T13:44:59.850447'},\n", - " 'type': 'row'}},\n", - " 'type': 'treeTable'}],\n", - " 'endTimestamp': {'epochSecond': 1624185904, 'nano': 935657000},\n", - " 'eventId': '92a223b8-d1b4-11eb-bae5-57b0c4472880',\n", - " 'eventName': \"Send 'NewOrderSingle' message to connectivity\",\n", - " 'eventType': 'Outgoing message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '92a07607-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185904, 'nano': 935323000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185904, 'nano': 953044000},\n", - " 'eventId': '92a4e30e-d1b4-11eb-8e55-d3a76285d588',\n", - " 'eventName': \"Send 'NewOrderSingle' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '92a07607-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185904, 'nano': 953006000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185905, 'nano': 254696000},\n", - " 'eventId': '92d2d11a-d1b4-11eb-a9ed-ffb57363e013',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '845d70d2-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185905, 'nano': 254675000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185905, 'nano': 255661000},\n", - " 'eventId': '92d2f807-d1b4-11eb-a9f4-b12655548efc',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '845d70d2-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185905, 'nano': 255657000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '56e62064-7d54-46a0-a702-cf40b5a46fed',\n", - " 'body': {'data': 'The message was deleted because a new one came with the '\n", - " \"same hash '-6798959314518195988' in message group \"\n", - " \"'NOS_CONN'\\n\"\n", - " ' Message not matched',\n", - " 'type': 'message'},\n", - " 'endTimestamp': {'epochSecond': 1624185905, 'nano': 834111000},\n", - " 'eventId': '56e62064-7d54-46a0-a702-cf40b5a46fed:932b631a-d1b4-11eb-986f-1e8d42132387',\n", - " 'eventName': \"Remove 'NewOrderSingle' \"\n", - " \"id='demo-conn1:SECOND:1624005455622135207' \"\n", - " \"Hash='-6798959314518195988' Group='NOS_CONN' \"\n", - " \"Hash['SecondaryClOrdID': 11111, 'SecurityID': INSTR2]\",\n", - " 'eventType': '',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'a3779b94-d051-11eb-986f-1e8d42132387',\n", - " 'startTimestamp': {'epochSecond': 1624185905, 'nano': 834111000},\n", - " 'successful': False,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'rows': {'AccountType': {'columns': {'fieldValue': '1'},\n", - " 'type': 'row'},\n", - " 'ClOrdID': {'columns': {'fieldValue': '4556842'},\n", - " 'type': 'row'},\n", - " 'CumQty': {'columns': {'fieldValue': '0'}, 'type': 'row'},\n", - " 'ExecID': {'columns': {'fieldValue': '2355'},\n", - " 'type': 'row'},\n", - " 'ExecType': {'columns': {'fieldValue': '0'}, 'type': 'row'},\n", - " 'LeavesQty': {'columns': {'fieldValue': '30'},\n", - " 'type': 'row'},\n", - " 'OrdStatus': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'OrdType': {'columns': {'fieldValue': '2'}, 'type': 'row'},\n", - " 'OrderCapacity': {'columns': {'fieldValue': 'A'},\n", - " 'type': 'row'},\n", - " 'OrderID': {'columns': {'fieldValue': '870'},\n", - " 'type': 'row'},\n", - " 'OrderQty': {'columns': {'fieldValue': '30'},\n", - " 'type': 'row'},\n", - " 'Price': {'columns': {'fieldValue': '35'}, 'type': 'row'},\n", - " 'SecurityID': {'columns': {'fieldValue': 'INSTR2'},\n", - " 'type': 'row'},\n", - " 'SecurityIDSource': {'columns': {'fieldValue': '8'},\n", - " 'type': 'row'},\n", - " 'Side': {'columns': {'fieldValue': '1'}, 'type': 'row'},\n", - " 'Text': {'columns': {'fieldValue': 'Simulated New Order '\n", - " 'Buy is placed'},\n", - " 'type': 'row'},\n", - " 'TradingParty': {'rows': {'NoPartyIDs': {'rows': {'0': {'rows': {'PartyID': {'columns': {'fieldValue': 'DEMO-CONN1'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'D'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '76'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '1': {'rows': {'PartyID': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '2': {'rows': {'PartyID': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '122'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '3': {'rows': {'PartyID': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '12'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'columns': {'fieldValue': '2021-06-20T10:45:05'},\n", - " 'type': 'row'},\n", - " 'header': {'rows': {'BeginString': {'columns': {'fieldValue': 'FIXT.1.1'},\n", - " 'type': 'row'},\n", - " 'BodyLength': {'columns': {'fieldValue': '310'},\n", - " 'type': 'row'},\n", - " 'MsgSeqNum': {'columns': {'fieldValue': '1295'},\n", - " 'type': 'row'},\n", - " 'MsgType': {'columns': {'fieldValue': '8'},\n", - " 'type': 'row'},\n", - " 'SenderCompID': {'columns': {'fieldValue': 'FGW'},\n", - " 'type': 'row'},\n", - " 'SendingTime': {'columns': {'fieldValue': '2021-06-20T10:45:05.253'},\n", - " 'type': 'row'},\n", - " 'TargetCompID': {'columns': {'fieldValue': 'DEMO-CONN1'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " 'trailer': {'rows': {'CheckSum': {'columns': {'fieldValue': '042'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'treeTable'}],\n", - " 'endTimestamp': {'epochSecond': 1624185905, 'nano': 931093000},\n", - " 'eventId': '933a1df9-d1b4-11eb-bae5-57b0c4472880',\n", - " 'eventName': \"Received 'ExecutionReport' response message\",\n", - " 'eventType': 'message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '92a07607-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185905, 'nano': 931058000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'data': 'STEP2: Trader \"DEMO-CONN1\" receives Execution Report. The '\n", - " 'order stands on book in status NEW',\n", - " 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185906, 'nano': 50283000},\n", - " 'eventId': '934abf8d-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Check sequence rule SessionKey{sessionAlias='demo-conn1', \"\n", - " 'direction=FIRST} - STEP2: Trader \"DEMO-CONN1\" receives '\n", - " 'Execution Report. The order stands on book in status NEW',\n", - " 'eventType': 'checkSequenceRule',\n", - " 'isBatched': False,\n", - " 'parentEventId': '8f7cc07f-d1b4-11eb-b0fb-199708acc7bc',\n", - " 'startTimestamp': {'epochSecond': 1624185906, 'nano': 40599000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'data': 'Contains comparisons', 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185906, 'nano': 50751000},\n", - " 'eventId': '934c4631-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Check messages',\n", - " 'eventType': 'checkMessages',\n", - " 'isBatched': False,\n", - " 'parentEventId': '934abf8d-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185906, 'nano': 40599000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '7a49c3e2-f075-41e8-af90-f341d0256286',\n", - " 'body': [{'data': 'Expected 1, Actual 1', 'type': 'message'},\n", - " {'rows': [{'actualMessage': 'ExecutionReport, demo-conn1, '\n", - " 'ClOrdID=4556842, OrdStatus=0',\n", - " 'actualMetadata': 'Metadata, demo-conn1',\n", - " 'expectedMessage': 'ExecutionReport, demo-conn1, '\n", - " 'ClOrdID=4556842, OrdStatus=0',\n", - " 'expectedMetadata': 'Metadata, demo-conn1'}],\n", - " 'type': 'table'}],\n", - " 'endTimestamp': {'epochSecond': 1624185906, 'nano': 50705000},\n", - " 'eventId': '7a49c3e2-f075-41e8-af90-f341d0256286:934c4630-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Check sequence (expected 1 / actual 1 , check order false)',\n", - " 'eventType': 'checkSequence',\n", - " 'isBatched': True,\n", - " 'parentEventId': '934abf8d-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185906, 'nano': 40599000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'e37ef8f1-66da-4d6f-b7a8-2b7b807a15ef',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '4556842',\n", - " 'expected': '4556842',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2355',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '30',\n", - " 'expected': '30',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': '2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'A',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '870',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '30',\n", - " 'expected': '30',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '35',\n", - " 'expected': '35',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR2',\n", - " 'expected': 'INSTR2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'Simulated New Order Buy is placed',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {'NoPartyIDs': {'actual': '4',\n", - " 'expected': '4',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'DEMO-CONN1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': '76',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': '122',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': '12',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:05',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': '7',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'FIXT.1.1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '310',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1295',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:05.253',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'DEMO-CONN1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '042',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185906, 'nano': 50756000},\n", - " 'eventId': 'e37ef8f1-66da-4d6f-b7a8-2b7b807a15ef:934c4632-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '934c4631-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185906, 'nano': 40599000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'rows': {'comparison-settings': {'rows': {'ignore-fields': {'rows': {},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'},\n", - " 'message-filter': {'rows': {'SecurityID': {'columns': {'expected': 'INSTR2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL'},\n", - " 'type': 'row'},\n", - " 'header': {'rows': {'MsgType': {'columns': {'expected': 'f',\n", - " 'key': False,\n", - " 'operation': 'NOT_EQUAL'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'},\n", - " 'message-type': {'columns': {'type': 'PreFilter'},\n", - " 'type': 'row'},\n", - " 'metadata-filter': {'rows': {}, 'type': 'collection'}},\n", - " 'type': 'treeTable'}],\n", - " 'endTimestamp': {'epochSecond': 1624185906, 'nano': 50454000},\n", - " 'eventId': '934b34be-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Pre-filtering (filtered 1 / processed 1) messages',\n", - " 'eventType': 'preFiltering',\n", - " 'isBatched': False,\n", - " 'parentEventId': '934abf8d-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185906, 'nano': 43263000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '22c8431b-4f2d-466c-986f-3db7536509ce',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '4556842',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2355',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '30',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '870',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '30',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '35',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR2',\n", - " 'expected': 'INSTR2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'Simulated New Order Buy is placed',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': 'null',\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " 'fields': {'NoPartyIDs': {'actual': '4',\n", - " 'expected': 'null',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:05',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': '1',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '310',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1295',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': 'x != \"f\"',\n", - " 'key': False,\n", - " 'operation': 'NOT_EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:05.253',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '042',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185906, 'nano': 50566000},\n", - " 'eventId': '22c8431b-4f2d-466c-986f-3db7536509ce:934bf80f-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '934b34be-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185906, 'nano': 43263000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'data': 'STEP3: Trader \"DEMO-CONN1\" sends request to create passive '\n", - " 'Order with price lower than first order.',\n", - " 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185906, 'nano': 167657000},\n", - " 'eventId': '935e20ba-d1b4-11eb-bae5-57b0c4472880',\n", - " 'eventName': 'placeOrderFIX demo-conn1 - STEP3: Trader \"DEMO-CONN1\" sends '\n", - " 'request to create passive Order with price lower than first '\n", - " 'order.',\n", - " 'eventType': 'placeOrderFIX',\n", - " 'isBatched': False,\n", - " 'parentEventId': '8f7cc07f-d1b4-11eb-b0fb-199708acc7bc',\n", - " 'startTimestamp': {'epochSecond': 1624185906, 'nano': 167578000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'c87362e0-401e-4e35-a6c0-e23f1866f1db',\n", - " 'body': [{'data': \"Checkpoint id '935ee3c0-d1b4-11eb-ba78-1981398e00bd'\",\n", - " 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185906, 'nano': 172855000},\n", - " 'eventId': 'c87362e0-401e-4e35-a6c0-e23f1866f1db:935ee3d3-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Checkpoint',\n", - " 'eventType': 'Checkpoint',\n", - " 'isBatched': True,\n", - " 'parentEventId': '935e20ba-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185906, 'nano': 172712000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'c87362e0-401e-4e35-a6c0-e23f1866f1db',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185906, 'nano': 172855000},\n", - " 'eventId': 'c87362e0-401e-4e35-a6c0-e23f1866f1db:935ee3d4-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'th2-hand-demo' direction 'FIRST' \"\n", - " \"sequence '1623852603564709030'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'c87362e0-401e-4e35-a6c0-e23f1866f1db:935ee3d3-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185906, 'nano': 172712000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'c87362e0-401e-4e35-a6c0-e23f1866f1db',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185906, 'nano': 172855000},\n", - " 'eventId': 'c87362e0-401e-4e35-a6c0-e23f1866f1db:935ee3d5-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn1' direction 'SECOND' \"\n", - " \"sequence '1624005455622140292'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'c87362e0-401e-4e35-a6c0-e23f1866f1db:935ee3d3-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185906, 'nano': 172712000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'c87362e0-401e-4e35-a6c0-e23f1866f1db',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185906, 'nano': 172855000},\n", - " 'eventId': 'c87362e0-401e-4e35-a6c0-e23f1866f1db:935ee3d6-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc1' direction 'SECOND' \"\n", - " \"sequence '1624005475721015015'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'c87362e0-401e-4e35-a6c0-e23f1866f1db:935ee3d3-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185906, 'nano': 172712000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'c87362e0-401e-4e35-a6c0-e23f1866f1db',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185906, 'nano': 172855000},\n", - " 'eventId': 'c87362e0-401e-4e35-a6c0-e23f1866f1db:935ee3d7-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc1' direction 'FIRST' \"\n", - " \"sequence '1624005475720919504'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'c87362e0-401e-4e35-a6c0-e23f1866f1db:935ee3d3-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185906, 'nano': 172712000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'c87362e0-401e-4e35-a6c0-e23f1866f1db',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185906, 'nano': 172855000},\n", - " 'eventId': 'c87362e0-401e-4e35-a6c0-e23f1866f1db:935ee3d8-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn2' direction 'FIRST' \"\n", - " \"sequence '1624005448022245402'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'c87362e0-401e-4e35-a6c0-e23f1866f1db:935ee3d3-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185906, 'nano': 172712000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'c87362e0-401e-4e35-a6c0-e23f1866f1db',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185906, 'nano': 172855000},\n", - " 'eventId': 'c87362e0-401e-4e35-a6c0-e23f1866f1db:935ee3d9-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn2' direction 'SECOND' \"\n", - " \"sequence '1624005448022426114'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'c87362e0-401e-4e35-a6c0-e23f1866f1db:935ee3d3-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185906, 'nano': 172712000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'c87362e0-401e-4e35-a6c0-e23f1866f1db',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185906, 'nano': 172855000},\n", - " 'eventId': 'c87362e0-401e-4e35-a6c0-e23f1866f1db:935ee3da-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc2' direction 'SECOND' \"\n", - " \"sequence '1624005466840347016'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'c87362e0-401e-4e35-a6c0-e23f1866f1db:935ee3d3-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185906, 'nano': 172712000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'c87362e0-401e-4e35-a6c0-e23f1866f1db',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185906, 'nano': 172855000},\n", - " 'eventId': 'c87362e0-401e-4e35-a6c0-e23f1866f1db:935ee3db-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc2' direction 'FIRST' \"\n", - " \"sequence '1624005466840263375'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'c87362e0-401e-4e35-a6c0-e23f1866f1db:935ee3d3-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185906, 'nano': 172712000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'c87362e0-401e-4e35-a6c0-e23f1866f1db',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185906, 'nano': 172855000},\n", - " 'eventId': 'c87362e0-401e-4e35-a6c0-e23f1866f1db:935ee3dc-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn1' direction 'FIRST' \"\n", - " \"sequence '1624005455622011527'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'c87362e0-401e-4e35-a6c0-e23f1866f1db:935ee3d3-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185906, 'nano': 172712000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'c87362e0-401e-4e35-a6c0-e23f1866f1db',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185906, 'nano': 172855000},\n", - " 'eventId': 'c87362e0-401e-4e35-a6c0-e23f1866f1db:935ee3dd-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-log' direction 'FIRST' \"\n", - " \"sequence '1624029363623063053'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'c87362e0-401e-4e35-a6c0-e23f1866f1db:935ee3d3-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185906, 'nano': 172712000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'rows': {'AccountType': {'columns': {'fieldValue': '1'},\n", - " 'type': 'row'},\n", - " 'ClOrdID': {'columns': {'fieldValue': '5061159'},\n", - " 'type': 'row'},\n", - " 'OrdType': {'columns': {'fieldValue': '2'}, 'type': 'row'},\n", - " 'OrderCapacity': {'columns': {'fieldValue': 'A'},\n", - " 'type': 'row'},\n", - " 'OrderQty': {'columns': {'fieldValue': '10'},\n", - " 'type': 'row'},\n", - " 'Price': {'columns': {'fieldValue': '36'}, 'type': 'row'},\n", - " 'SecondaryClOrdID': {'columns': {'fieldValue': '22222'},\n", - " 'type': 'row'},\n", - " 'SecurityID': {'columns': {'fieldValue': 'INSTR2'},\n", - " 'type': 'row'},\n", - " 'SecurityIDSource': {'columns': {'fieldValue': '8'},\n", - " 'type': 'row'},\n", - " 'Side': {'columns': {'fieldValue': '1'}, 'type': 'row'},\n", - " 'TradingParty': {'rows': {'NoPartyIDs': {'rows': {'0': {'rows': {'PartyID': {'columns': {'fieldValue': 'DEMO-CONN1'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'D'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '76'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '1': {'rows': {'PartyID': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '2': {'rows': {'PartyID': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '122'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '3': {'rows': {'PartyID': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '12'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'columns': {'fieldValue': '2021-06-20T13:44:59.850481'},\n", - " 'type': 'row'}},\n", - " 'type': 'treeTable'}],\n", - " 'endTimestamp': {'epochSecond': 1624185906, 'nano': 176817000},\n", - " 'eventId': '935f804b-d1b4-11eb-bae5-57b0c4472880',\n", - " 'eventName': \"Send 'NewOrderSingle' message to connectivity\",\n", - " 'eventType': 'Outgoing message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '935e20ba-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185906, 'nano': 176600000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185906, 'nano': 196243000},\n", - " 'eventId': '93628dbf-d1b4-11eb-8e55-d3a76285d588',\n", - " 'eventName': \"Send 'NewOrderSingle' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '935e20ba-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185906, 'nano': 196239000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185906, 'nano': 252358000},\n", - " 'eventId': '936b1958-d1b4-11eb-a9f4-b12655548efc',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '845d70d2-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185906, 'nano': 252347000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185906, 'nano': 253401000},\n", - " 'eventId': '936b408b-d1b4-11eb-a9ed-ffb57363e013',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '845d70d2-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185906, 'nano': 253391000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '56e62064-7d54-46a0-a702-cf40b5a46fed',\n", - " 'body': {'data': 'The message was deleted because a new one came with the '\n", - " \"same hash '255011743932618104' in message group 'NOS_CONN'\\n\"\n", - " ' Message not matched',\n", - " 'type': 'message'},\n", - " 'endTimestamp': {'epochSecond': 1624185906, 'nano': 833542000},\n", - " 'eventId': '56e62064-7d54-46a0-a702-cf40b5a46fed:93c3ddd4-d1b4-11eb-986f-1e8d42132387',\n", - " 'eventName': \"Remove 'NewOrderSingle' \"\n", - " \"id='demo-conn1:SECOND:1624005455622135208' \"\n", - " \"Hash='255011743932618104' Group='NOS_CONN' \"\n", - " \"Hash['SecondaryClOrdID': 22222, 'SecurityID': INSTR2]\",\n", - " 'eventType': '',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'a3779b94-d051-11eb-986f-1e8d42132387',\n", - " 'startTimestamp': {'epochSecond': 1624185906, 'nano': 833542000},\n", - " 'successful': False,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'rows': {'AccountType': {'columns': {'fieldValue': '1'},\n", - " 'type': 'row'},\n", - " 'ClOrdID': {'columns': {'fieldValue': '5061159'},\n", - " 'type': 'row'},\n", - " 'CumQty': {'columns': {'fieldValue': '0'}, 'type': 'row'},\n", - " 'ExecID': {'columns': {'fieldValue': '2357'},\n", - " 'type': 'row'},\n", - " 'ExecType': {'columns': {'fieldValue': '0'}, 'type': 'row'},\n", - " 'LeavesQty': {'columns': {'fieldValue': '10'},\n", - " 'type': 'row'},\n", - " 'OrdStatus': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'OrdType': {'columns': {'fieldValue': '2'}, 'type': 'row'},\n", - " 'OrderCapacity': {'columns': {'fieldValue': 'A'},\n", - " 'type': 'row'},\n", - " 'OrderID': {'columns': {'fieldValue': '871'},\n", - " 'type': 'row'},\n", - " 'OrderQty': {'columns': {'fieldValue': '10'},\n", - " 'type': 'row'},\n", - " 'Price': {'columns': {'fieldValue': '36'}, 'type': 'row'},\n", - " 'SecurityID': {'columns': {'fieldValue': 'INSTR2'},\n", - " 'type': 'row'},\n", - " 'SecurityIDSource': {'columns': {'fieldValue': '8'},\n", - " 'type': 'row'},\n", - " 'Side': {'columns': {'fieldValue': '1'}, 'type': 'row'},\n", - " 'Text': {'columns': {'fieldValue': 'Simulated New Order '\n", - " 'Buy is placed'},\n", - " 'type': 'row'},\n", - " 'TradingParty': {'rows': {'NoPartyIDs': {'rows': {'0': {'rows': {'PartyID': {'columns': {'fieldValue': 'DEMO-CONN1'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'D'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '76'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '1': {'rows': {'PartyID': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '2': {'rows': {'PartyID': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '122'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '3': {'rows': {'PartyID': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '12'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'columns': {'fieldValue': '2021-06-20T10:45:06'},\n", - " 'type': 'row'},\n", - " 'header': {'rows': {'BeginString': {'columns': {'fieldValue': 'FIXT.1.1'},\n", - " 'type': 'row'},\n", - " 'BodyLength': {'columns': {'fieldValue': '310'},\n", - " 'type': 'row'},\n", - " 'MsgSeqNum': {'columns': {'fieldValue': '1296'},\n", - " 'type': 'row'},\n", - " 'MsgType': {'columns': {'fieldValue': '8'},\n", - " 'type': 'row'},\n", - " 'SenderCompID': {'columns': {'fieldValue': 'FGW'},\n", - " 'type': 'row'},\n", - " 'SendingTime': {'columns': {'fieldValue': '2021-06-20T10:45:06.252'},\n", - " 'type': 'row'},\n", - " 'TargetCompID': {'columns': {'fieldValue': 'DEMO-CONN1'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " 'trailer': {'rows': {'CheckSum': {'columns': {'fieldValue': '037'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'treeTable'}],\n", - " 'endTimestamp': {'epochSecond': 1624185906, 'nano': 930153000},\n", - " 'eventId': '93d28d6c-d1b4-11eb-bae5-57b0c4472880',\n", - " 'eventName': \"Received 'ExecutionReport' response message\",\n", - " 'eventType': 'message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '935e20ba-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185906, 'nano': 930121000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'data': 'STEP4: Trader \"DEMO-CONN1\" receives Execution Report. The '\n", - " 'order stands on book in status NEW',\n", - " 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185907, 'nano': 52228000},\n", - " 'eventId': '93e3a43e-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Check sequence rule SessionKey{sessionAlias='demo-conn1', \"\n", - " 'direction=FIRST} - STEP4: Trader \"DEMO-CONN1\" receives '\n", - " 'Execution Report. The order stands on book in status NEW',\n", - " 'eventType': 'checkSequenceRule',\n", - " 'isBatched': False,\n", - " 'parentEventId': '8f7cc07f-d1b4-11eb-b0fb-199708acc7bc',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 42554000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'data': 'Contains comparisons', 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185907, 'nano': 52514000},\n", - " 'eventId': '93e52ae2-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Check messages',\n", - " 'eventType': 'checkMessages',\n", - " 'isBatched': False,\n", - " 'parentEventId': '93e3a43e-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 42554000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'b8d6b125-e2e3-4699-97f6-ba523ce696ba',\n", - " 'body': [{'data': 'Expected 1, Actual 1', 'type': 'message'},\n", - " {'rows': [{'actualMessage': 'ExecutionReport, demo-conn1, '\n", - " 'OrdStatus=0, ClOrdID=5061159',\n", - " 'actualMetadata': 'Metadata, demo-conn1',\n", - " 'expectedMessage': 'ExecutionReport, demo-conn1, '\n", - " 'OrdStatus=0, ClOrdID=5061159',\n", - " 'expectedMetadata': 'Metadata, demo-conn1'}],\n", - " 'type': 'table'}],\n", - " 'endTimestamp': {'epochSecond': 1624185907, 'nano': 52486000},\n", - " 'eventId': 'b8d6b125-e2e3-4699-97f6-ba523ce696ba:93e52ae1-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Check sequence (expected 1 / actual 1 , check order false)',\n", - " 'eventType': 'checkSequence',\n", - " 'isBatched': True,\n", - " 'parentEventId': '93e3a43e-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 42554000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'f7e3700f-e6f1-4afc-88eb-f3ab83ca58c7',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '5061159',\n", - " 'expected': '5061159',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2357',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '10',\n", - " 'expected': '10',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': '2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'A',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '871',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '10',\n", - " 'expected': '10',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '36',\n", - " 'expected': '36',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR2',\n", - " 'expected': 'INSTR2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'Simulated New Order Buy is placed',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {'NoPartyIDs': {'actual': '4',\n", - " 'expected': '4',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'DEMO-CONN1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': '76',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': '122',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': '12',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:06',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': '7',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'FIXT.1.1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '310',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1296',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:06.252',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'DEMO-CONN1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '037',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185907, 'nano': 52516000},\n", - " 'eventId': 'f7e3700f-e6f1-4afc-88eb-f3ab83ca58c7:93e52ae3-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '93e52ae2-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 42554000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'rows': {'comparison-settings': {'rows': {'ignore-fields': {'rows': {},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'},\n", - " 'message-filter': {'rows': {'SecurityID': {'columns': {'expected': 'INSTR2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " 'message-type': {'columns': {'type': 'PreFilter'},\n", - " 'type': 'row'},\n", - " 'metadata-filter': {'rows': {}, 'type': 'collection'}},\n", - " 'type': 'treeTable'}],\n", - " 'endTimestamp': {'epochSecond': 1624185907, 'nano': 52269000},\n", - " 'eventId': '93e4196f-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Pre-filtering (filtered 1 / processed 1) messages',\n", - " 'eventType': 'preFiltering',\n", - " 'isBatched': False,\n", - " 'parentEventId': '93e3a43e-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 45671000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'fcf9b609-d48b-4eb7-9113-72c0063f65b1',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '5061159',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2357',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '10',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '871',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '10',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '36',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR2',\n", - " 'expected': 'INSTR2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'Simulated New Order Buy is placed',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'NoPartyIDs': {'actual': '4',\n", - " 'expected': 'null',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:06',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': 'null',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '310',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1296',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:06.252',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '037',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185907, 'nano': 52322000},\n", - " 'eventId': 'fcf9b609-d48b-4eb7-9113-72c0063f65b1:93e4b5b0-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '93e4196f-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 45671000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'data': 'STEP5: Trader \"DEMO-CONN2\" sends request to create '\n", - " 'aggressive IOC Order.',\n", - " 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185907, 'nano': 223578000},\n", - " 'eventId': '93ff42bd-d1b4-11eb-bae5-57b0c4472880',\n", - " 'eventName': 'placeOrderFIX demo-conn2 - STEP5: Trader \"DEMO-CONN2\" sends '\n", - " 'request to create aggressive IOC Order.',\n", - " 'eventType': 'placeOrderFIX',\n", - " 'isBatched': False,\n", - " 'parentEventId': '8f7cc07f-d1b4-11eb-b0fb-199708acc7bc',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 223541000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'f8a54b0b-59f9-4462-b270-eff0d9057a36',\n", - " 'body': [{'data': \"Checkpoint id '93ffb7a0-d1b4-11eb-ba78-1981398e00bd'\",\n", - " 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185907, 'nano': 226750000},\n", - " 'eventId': 'f8a54b0b-59f9-4462-b270-eff0d9057a36:93ffb7c4-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Checkpoint',\n", - " 'eventType': 'Checkpoint',\n", - " 'isBatched': True,\n", - " 'parentEventId': '93ff42bd-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 226531000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'f8a54b0b-59f9-4462-b270-eff0d9057a36',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185907, 'nano': 226750000},\n", - " 'eventId': 'f8a54b0b-59f9-4462-b270-eff0d9057a36:93ffb7c5-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'th2-hand-demo' direction 'FIRST' \"\n", - " \"sequence '1623852603564709030'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'f8a54b0b-59f9-4462-b270-eff0d9057a36:93ffb7c4-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 226531000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'f8a54b0b-59f9-4462-b270-eff0d9057a36',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185907, 'nano': 226750000},\n", - " 'eventId': 'f8a54b0b-59f9-4462-b270-eff0d9057a36:93ffb7c6-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn1' direction 'SECOND' \"\n", - " \"sequence '1624005455622140293'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'f8a54b0b-59f9-4462-b270-eff0d9057a36:93ffb7c4-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 226531000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'f8a54b0b-59f9-4462-b270-eff0d9057a36',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185907, 'nano': 226750000},\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " 'eventId': 'f8a54b0b-59f9-4462-b270-eff0d9057a36:93ffded7-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc1' direction 'SECOND' \"\n", - " \"sequence '1624005475721015015'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'f8a54b0b-59f9-4462-b270-eff0d9057a36:93ffb7c4-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 226531000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'f8a54b0b-59f9-4462-b270-eff0d9057a36',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185907, 'nano': 226750000},\n", - " 'eventId': 'f8a54b0b-59f9-4462-b270-eff0d9057a36:93ffded8-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc1' direction 'FIRST' \"\n", - " \"sequence '1624005475720919505'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'f8a54b0b-59f9-4462-b270-eff0d9057a36:93ffb7c4-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 226531000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'f8a54b0b-59f9-4462-b270-eff0d9057a36',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185907, 'nano': 226750000},\n", - " 'eventId': 'f8a54b0b-59f9-4462-b270-eff0d9057a36:93ffded9-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn2' direction 'FIRST' \"\n", - " \"sequence '1624005448022245402'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'f8a54b0b-59f9-4462-b270-eff0d9057a36:93ffb7c4-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 226531000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'f8a54b0b-59f9-4462-b270-eff0d9057a36',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185907, 'nano': 226750000},\n", - " 'eventId': 'f8a54b0b-59f9-4462-b270-eff0d9057a36:93ffdeda-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn2' direction 'SECOND' \"\n", - " \"sequence '1624005448022426114'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'f8a54b0b-59f9-4462-b270-eff0d9057a36:93ffb7c4-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 226531000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'f8a54b0b-59f9-4462-b270-eff0d9057a36',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185907, 'nano': 226750000},\n", - " 'eventId': 'f8a54b0b-59f9-4462-b270-eff0d9057a36:93ffdedb-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc2' direction 'SECOND' \"\n", - " \"sequence '1624005466840347016'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'f8a54b0b-59f9-4462-b270-eff0d9057a36:93ffb7c4-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 226531000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'f8a54b0b-59f9-4462-b270-eff0d9057a36',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185907, 'nano': 226750000},\n", - " 'eventId': 'f8a54b0b-59f9-4462-b270-eff0d9057a36:93ffdedc-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc2' direction 'FIRST' \"\n", - " \"sequence '1624005466840263375'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'f8a54b0b-59f9-4462-b270-eff0d9057a36:93ffb7c4-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 226531000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'f8a54b0b-59f9-4462-b270-eff0d9057a36',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185907, 'nano': 226750000},\n", - " 'eventId': 'f8a54b0b-59f9-4462-b270-eff0d9057a36:93ffdedd-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn1' direction 'FIRST' \"\n", - " \"sequence '1624005455622011528'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'f8a54b0b-59f9-4462-b270-eff0d9057a36:93ffb7c4-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 226531000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'f8a54b0b-59f9-4462-b270-eff0d9057a36',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185907, 'nano': 226750000},\n", - " 'eventId': 'f8a54b0b-59f9-4462-b270-eff0d9057a36:93ffdede-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-log' direction 'FIRST' \"\n", - " \"sequence '1624029363623063053'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'f8a54b0b-59f9-4462-b270-eff0d9057a36:93ffb7c4-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 226531000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'rows': {'AccountType': {'columns': {'fieldValue': '1'},\n", - " 'type': 'row'},\n", - " 'ClOrdID': {'columns': {'fieldValue': '6989279'},\n", - " 'type': 'row'},\n", - " 'OrdType': {'columns': {'fieldValue': '2'}, 'type': 'row'},\n", - " 'OrderCapacity': {'columns': {'fieldValue': 'A'},\n", - " 'type': 'row'},\n", - " 'OrderQty': {'columns': {'fieldValue': '100'},\n", - " 'type': 'row'},\n", - " 'Price': {'columns': {'fieldValue': '34'}, 'type': 'row'},\n", - " 'SecondaryClOrdID': {'columns': {'fieldValue': '33333'},\n", - " 'type': 'row'},\n", - " 'SecurityID': {'columns': {'fieldValue': 'INSTR2'},\n", - " 'type': 'row'},\n", - " 'SecurityIDSource': {'columns': {'fieldValue': '8'},\n", - " 'type': 'row'},\n", - " 'Side': {'columns': {'fieldValue': '2'}, 'type': 'row'},\n", - " 'TimeInForce': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'},\n", - " 'TradingParty': {'rows': {'NoPartyIDs': {'rows': {'0': {'rows': {'PartyID': {'columns': {'fieldValue': 'DEMO-CONN2'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'D'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '76'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '1': {'rows': {'PartyID': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '2': {'rows': {'PartyID': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '122'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '3': {'rows': {'PartyID': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '12'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'columns': {'fieldValue': '2021-06-20T13:44:59.850501'},\n", - " 'type': 'row'}},\n", - " 'type': 'treeTable'}],\n", - " 'endTimestamp': {'epochSecond': 1624185907, 'nano': 232329000},\n", - " 'eventId': '9400a24e-d1b4-11eb-bae5-57b0c4472880',\n", - " 'eventName': \"Send 'NewOrderSingle' message to connectivity\",\n", - " 'eventType': 'Outgoing message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '93ff42bd-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 232268000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185907, 'nano': 266056000},\n", - " 'eventId': '9405d222-d1b4-11eb-bd0a-0d6cee9f6833',\n", - " 'eventName': \"Send 'NewOrderSingle' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '93ff42bd-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 266031000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185907, 'nano': 446828000},\n", - " 'eventId': '94214a1c-d1b4-11eb-a9ed-ffb57363e013',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '849a79d3-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 446815000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185907, 'nano': 457021000},\n", - " 'eventId': '9422f7cd-d1b4-11eb-a9ed-ffb57363e013',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '849a79d3-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 457015000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185907, 'nano': 464444000},\n", - " 'eventId': '94240919-d1b4-11eb-a9f4-b12655548efc',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '849a79d3-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 464441000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185907, 'nano': 480888000},\n", - " 'eventId': '9426799f-d1b4-11eb-91f0-77dd26d4db8e',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '849a79d3-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 480859000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185907, 'nano': 483008000},\n", - " 'eventId': '9426c7f0-d1b4-11eb-be23-57049e5b0bd9',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '849a79d3-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 482986000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185907, 'nano': 484499000},\n", - " 'eventId': '942715e0-d1b4-11eb-91f0-77dd26d4db8e',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '849a79d3-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 484485000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185907, 'nano': 490227000},\n", - " 'eventId': '942800ba-d1b4-11eb-a9f4-b12655548efc',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '849a79d3-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 490223000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185907, 'nano': 532327000},\n", - " 'eventId': '942e6911-d1b4-11eb-be23-57049e5b0bd9',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '849a79d3-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 532305000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185907, 'nano': 534552000},\n", - " 'eventId': '942eb732-d1b4-11eb-be23-57049e5b0bd9',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '849a79d3-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 534542000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'rows': {'AccountType': {'columns': {'fieldValue': '1'},\n", - " 'type': 'row'},\n", - " 'ClOrdID': {'columns': {'fieldValue': '6989279'},\n", - " 'type': 'row'},\n", - " 'CumQty': {'columns': {'fieldValue': '10'}, 'type': 'row'},\n", - " 'ExecID': {'columns': {'fieldValue': '2361'},\n", - " 'type': 'row'},\n", - " 'ExecType': {'columns': {'fieldValue': 'F'}, 'type': 'row'},\n", - " 'LastPx': {'columns': {'fieldValue': '36'}, 'type': 'row'},\n", - " 'LeavesQty': {'columns': {'fieldValue': '90'},\n", - " 'type': 'row'},\n", - " 'OrdStatus': {'columns': {'fieldValue': '1'},\n", - " 'type': 'row'},\n", - " 'OrdType': {'columns': {'fieldValue': '2'}, 'type': 'row'},\n", - " 'OrderCapacity': {'columns': {'fieldValue': 'A'},\n", - " 'type': 'row'},\n", - " 'OrderID': {'columns': {'fieldValue': '872'},\n", - " 'type': 'row'},\n", - " 'OrderQty': {'columns': {'fieldValue': '100'},\n", - " 'type': 'row'},\n", - " 'Price': {'columns': {'fieldValue': '34'}, 'type': 'row'},\n", - " 'SecurityID': {'columns': {'fieldValue': 'INSTR2'},\n", - " 'type': 'row'},\n", - " 'SecurityIDSource': {'columns': {'fieldValue': '8'},\n", - " 'type': 'row'},\n", - " 'Side': {'columns': {'fieldValue': '2'}, 'type': 'row'},\n", - " 'Text': {'columns': {'fieldValue': 'The simulated order '\n", - " 'has been partially '\n", - " 'traded'},\n", - " 'type': 'row'},\n", - " 'TimeInForce': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'},\n", - " 'TradingParty': {'rows': {'NoPartyIDs': {'rows': {'0': {'rows': {'PartyID': {'columns': {'fieldValue': 'DEMO-CONN2'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'D'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '76'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '1': {'rows': {'PartyID': {'columns': {'fieldValue': 'DEMOFIRM1'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'D'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '17'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '2': {'rows': {'PartyID': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '3': {'rows': {'PartyID': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '122'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '4': {'rows': {'PartyID': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '12'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'columns': {'fieldValue': '2021-06-20T10:45:07'},\n", - " 'type': 'row'},\n", - " 'TrdMatchID': {'columns': {'fieldValue': '483'},\n", - " 'type': 'row'},\n", - " 'header': {'rows': {'BeginString': {'columns': {'fieldValue': 'FIXT.1.1'},\n", - " 'type': 'row'},\n", - " 'BodyLength': {'columns': {'fieldValue': '370'},\n", - " 'type': 'row'},\n", - " 'MsgSeqNum': {'columns': {'fieldValue': '1294'},\n", - " 'type': 'row'},\n", - " 'MsgType': {'columns': {'fieldValue': '8'},\n", - " 'type': 'row'},\n", - " 'SenderCompID': {'columns': {'fieldValue': 'FGW'},\n", - " 'type': 'row'},\n", - " 'SendingTime': {'columns': {'fieldValue': '2021-06-20T10:45:07.480'},\n", - " 'type': 'row'},\n", - " 'TargetCompID': {'columns': {'fieldValue': 'DEMO-CONN2'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " 'trailer': {'rows': {'CheckSum': {'columns': {'fieldValue': '236'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'treeTable'}],\n", - " 'endTimestamp': {'epochSecond': 1624185907, 'nano': 535070000},\n", - " 'eventId': '942ede3f-d1b4-11eb-bae5-57b0c4472880',\n", - " 'eventName': \"Received 'ExecutionReport' response message\",\n", - " 'eventType': 'message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '93ff42bd-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 535024000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185907, 'nano': 537120000},\n", - " 'eventId': '942f2c31-d1b4-11eb-91f0-77dd26d4db8e',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '849a79d3-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 537103000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'data': 'STEP6: Trader \"DEMO-CONN1\" receives Execution Reports with '\n", - " 'ExecType=F: first at Order2 and second on Order1.',\n", - " 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185907, 'nano': 947942000},\n", - " 'eventId': '943baf5f-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Check sequence rule SessionKey{sessionAlias='demo-conn1', \"\n", - " 'direction=FIRST} - STEP6: Trader \"DEMO-CONN1\" receives '\n", - " 'Execution Reports with ExecType=F: first at Order2 and second '\n", - " 'on Order1.',\n", - " 'eventType': 'checkSequenceRule',\n", - " 'isBatched': False,\n", - " 'parentEventId': '8f7cc07f-d1b4-11eb-b0fb-199708acc7bc',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 619288000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'data': 'Contains comparisons', 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185907, 'nano': 948990000},\n", - " 'eventId': '946dbbe8-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Check messages',\n", - " 'eventType': 'checkMessages',\n", - " 'isBatched': False,\n", - " 'parentEventId': '943baf5f-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 619288000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '366d2588-09ef-45a3-ae88-0b930155e83e',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '5061159',\n", - " 'expected': '5061159',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '10',\n", - " 'expected': '10',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2359',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': 'F',\n", - " 'expected': 'F',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LastPx': {'actual': '36',\n", - " 'expected': '36',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '2',\n", - " 'expected': '2',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': '2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'A',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '871',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '10',\n", - " 'expected': '10',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '36',\n", - " 'expected': '36',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR2',\n", - " 'expected': 'INSTR2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'The simulated order has been fully '\n", - " 'traded',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TimeInForce': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {'NoPartyIDs': {'actual': '5',\n", - " 'expected': '5',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'DEMO-CONN1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': '76',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMOFIRM2',\n", - " 'expected': 'DEMOFIRM2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '17',\n", - " 'expected': '17',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': '122',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '4': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': '12',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:07',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TrdMatchID': {'actual': '483',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': '7',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'FIXT.1.1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '364',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1297',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:07.445',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'DEMO-CONN1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '209',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185907, 'nano': 948994000},\n", - " 'eventId': '366d2588-09ef-45a3-ae88-0b930155e83e:946dbbe9-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '946dbbe8-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 619288000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '366d2588-09ef-45a3-ae88-0b930155e83e',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '4556842',\n", - " 'expected': '4556842',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '30',\n", - " 'expected': '30',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2360',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': 'F',\n", - " 'expected': 'F',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LastPx': {'actual': '35',\n", - " 'expected': '35',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '2',\n", - " 'expected': '2',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': '2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'A',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '870',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '30',\n", - " 'expected': '30',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '35',\n", - " 'expected': '35',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR2',\n", - " 'expected': 'INSTR2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'The simulated order has been fully '\n", - " 'traded',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TimeInForce': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {'NoPartyIDs': {'actual': '5',\n", - " 'expected': '5',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'DEMO-CONN1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': '76',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMOFIRM2',\n", - " 'expected': 'DEMOFIRM2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '17',\n", - " 'expected': '17',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': '122',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '4': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': '12',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:07',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TrdMatchID': {'actual': '484',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': '7',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'FIXT.1.1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '364',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1298',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:07.456',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'DEMO-CONN1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '213',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185907, 'nano': 949096000},\n", - " 'eventId': '366d2588-09ef-45a3-ae88-0b930155e83e:946dbbea-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '946dbbe8-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 619288000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '7e7891b2-7885-4a5b-9e44-3cf1e5bddfa0',\n", - " 'body': [{'data': 'Expected 2, Actual 2, In order', 'type': 'message'},\n", - " {'rows': [{'actualMessage': 'ExecutionReport, demo-conn1, '\n", - " 'LeavesQty=0, OrdStatus=2, CumQty=10, '\n", - " 'ClOrdID=5061159',\n", - " 'actualMetadata': 'Metadata, demo-conn1',\n", - " 'expectedMessage': 'ExecutionReport, demo-conn1, '\n", - " 'LeavesQty=0, OrdStatus=2, CumQty=10, '\n", - " 'ClOrdID=5061159',\n", - " 'expectedMetadata': 'Metadata, demo-conn1'},\n", - " {'actualMessage': 'ExecutionReport, demo-conn1, CumQty=30, '\n", - " 'OrdStatus=2, LeavesQty=0, '\n", - " 'ClOrdID=4556842',\n", - " 'actualMetadata': 'Metadata, demo-conn1',\n", - " 'expectedMessage': 'ExecutionReport, demo-conn1, '\n", - " 'CumQty=30, OrdStatus=2, LeavesQty=0, '\n", - " 'ClOrdID=4556842',\n", - " 'expectedMetadata': 'Metadata, demo-conn1'}],\n", - " 'type': 'table'}],\n", - " 'endTimestamp': {'epochSecond': 1624185907, 'nano': 948955000},\n", - " 'eventId': '7e7891b2-7885-4a5b-9e44-3cf1e5bddfa0:946dbbe7-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Check sequence (expected 2 / actual 2 , check order true)',\n", - " 'eventType': 'checkSequence',\n", - " 'isBatched': True,\n", - " 'parentEventId': '943baf5f-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 619288000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'rows': {'comparison-settings': {'rows': {'ignore-fields': {'rows': {},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'},\n", - " 'message-filter': {'rows': {'SecurityID': {'columns': {'expected': 'INSTR2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " 'message-type': {'columns': {'type': 'PreFilter'},\n", - " 'type': 'row'},\n", - " 'metadata-filter': {'rows': {}, 'type': 'collection'}},\n", - " 'type': 'treeTable'}],\n", - " 'endTimestamp': {'epochSecond': 1624185907, 'nano': 947989000},\n", - " 'eventId': '943d3600-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Pre-filtering (filtered 2 / processed 2) messages',\n", - " 'eventType': 'preFiltering',\n", - " 'isBatched': False,\n", - " 'parentEventId': '943baf5f-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 629360000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'f5aec070-b5e5-49b3-a58e-790582731807',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '5061159',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '10',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2359',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': 'F',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LastPx': {'actual': '36',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '871',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '10',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '36',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR2',\n", - " 'expected': 'INSTR2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'The simulated order has been fully '\n", - " 'traded',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TimeInForce': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'NoPartyIDs': {'actual': '5',\n", - " 'expected': 'null',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': 'DEMOFIRM2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '17',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " '3': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '4': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:07',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TrdMatchID': {'actual': '483',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': 'null',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '364',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1297',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:07.445',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '209',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185907, 'nano': 948731000},\n", - " 'eventId': 'f5aec070-b5e5-49b3-a58e-790582731807:946c5c55-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '943d3600-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 629360000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'f5aec070-b5e5-49b3-a58e-790582731807',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '4556842',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '30',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2360',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': 'F',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LastPx': {'actual': '35',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '870',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '30',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '35',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR2',\n", - " 'expected': 'INSTR2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'The simulated order has been fully '\n", - " 'traded',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TimeInForce': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'NoPartyIDs': {'actual': '5',\n", - " 'expected': 'null',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': 'DEMOFIRM2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '17',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '4': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:07',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TrdMatchID': {'actual': '484',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': 'null',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '364',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1298',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:07.456',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '213',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185907, 'nano': 948869000},\n", - " 'eventId': 'f5aec070-b5e5-49b3-a58e-790582731807:946d6dc6-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '943d3600-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 629360000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'd0540e4c-f3a6-4f78-801e-47c114b061ae',\n", - " 'body': {'data': 'The message was deleted because a new one came with the '\n", - " \"same hash '2022982225733544569' in message group \"\n", - " \"'NOS_CONN'\\n\"\n", - " ' Message not matched',\n", - " 'type': 'message'},\n", - " 'endTimestamp': {'epochSecond': 1624185907, 'nano': 641254000},\n", - " 'eventId': 'd0540e4c-f3a6-4f78-801e-47c114b061ae:943f24a8-d1b4-11eb-986f-1e8d42132387',\n", - " 'eventName': \"Remove 'NewOrderSingle' \"\n", - " \"id='demo-conn2:SECOND:1624005448022421037' \"\n", - " \"Hash='2022982225733544569' Group='NOS_CONN' \"\n", - " \"Hash['SecondaryClOrdID': 33333, 'SecurityID': INSTR2]\",\n", - " 'eventType': '',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'a3779b94-d051-11eb-986f-1e8d42132387',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 641254000},\n", - " 'successful': False,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'data': 'STEP7: Trader \"DEMO-CONN2\" receives Execution Reports: '\n", - " 'first trade with Order2, next with Order1 and then '\n", - " 'cancellation',\n", - " 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185908, 'nano': 528297000},\n", - " 'eventId': '944b18b1-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Check sequence rule SessionKey{sessionAlias='demo-conn2', \"\n", - " 'direction=FIRST} - STEP7: Trader \"DEMO-CONN2\" receives '\n", - " 'Execution Reports: first trade with Order2, next with Order1 '\n", - " 'and then cancellation',\n", - " 'eventType': 'checkSequenceRule',\n", - " 'isBatched': False,\n", - " 'parentEventId': '8f7cc07f-d1b4-11eb-b0fb-199708acc7bc',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 720896000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'data': 'Contains comparisons', 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185908, 'nano': 529063000},\n", - " 'eventId': '94c6633d-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Check messages',\n", - " 'eventType': 'checkMessages',\n", - " 'isBatched': False,\n", - " 'parentEventId': '944b18b1-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 720896000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '04070d56-5434-41ea-b009-bff5c140d49b',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '6989279',\n", - " 'expected': '6989279',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '10',\n", - " 'expected': '10',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2361',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': 'F',\n", - " 'expected': 'F',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LastPx': {'actual': '36',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '90',\n", - " 'expected': '90',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': '2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'A',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '872',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '100',\n", - " 'expected': '100',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '34',\n", - " 'expected': '34',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR2',\n", - " 'expected': 'INSTR2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '2',\n", - " 'expected': '2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'The simulated order has been '\n", - " 'partially traded',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TimeInForce': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {'NoPartyIDs': {'actual': '5',\n", - " 'expected': '5',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'DEMO-CONN2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': '76',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMOFIRM1',\n", - " 'expected': 'DEMOFIRM1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '17',\n", - " 'expected': '17',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': '122',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '4': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': '12',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:07',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TrdMatchID': {'actual': '483',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': '7',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'FIXT.1.1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '370',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1294',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:07.480',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'DEMO-CONN2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '236',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185908, 'nano': 529073000},\n", - " 'eventId': '04070d56-5434-41ea-b009-bff5c140d49b:94c6633e-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '94c6633d-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 720896000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '04070d56-5434-41ea-b009-bff5c140d49b',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '6989279',\n", - " 'expected': '6989279',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '40',\n", - " 'expected': '40',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2362',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': 'F',\n", - " 'expected': 'F',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LastPx': {'actual': '35',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '60',\n", - " 'expected': '60',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': '2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'A',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '872',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '100',\n", - " 'expected': '100',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '34',\n", - " 'expected': '34',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR2',\n", - " 'expected': 'INSTR2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '2',\n", - " 'expected': '2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'The simulated order has been '\n", - " 'partially traded',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TimeInForce': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {'NoPartyIDs': {'actual': '5',\n", - " 'expected': '5',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'DEMO-CONN2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': '76',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMOFIRM1',\n", - " 'expected': 'DEMOFIRM1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '17',\n", - " 'expected': '17',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': '122',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '4': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': '12',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:07',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TrdMatchID': {'actual': '484',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': '7',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'FIXT.1.1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '370',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1295',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:07.483',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'DEMO-CONN2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '241',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185908, 'nano': 529193000},\n", - " 'eventId': '04070d56-5434-41ea-b009-bff5c140d49b:94c6633f-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '94c6633d-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 720896000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '04070d56-5434-41ea-b009-bff5c140d49b',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '6989279',\n", - " 'expected': '6989279',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '40',\n", - " 'expected': '40',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2363',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': 'C',\n", - " 'expected': 'C',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': 'C',\n", - " 'expected': 'C',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': '2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'A',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '872',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '100',\n", - " 'expected': '100',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '34',\n", - " 'expected': '34',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR2',\n", - " 'expected': 'INSTR2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '2',\n", - " 'expected': '2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'The remaining part of simulated '\n", - " 'order has been expired',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TimeInForce': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {'NoPartyIDs': {'actual': '4',\n", - " 'expected': '4',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'DEMO-CONN2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': '76',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': '122',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': '12',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:07',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': '7',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'FIXT.1.1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '337',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1296',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:07.536',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'DEMO-CONN2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '178',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185908, 'nano': 529307000},\n", - " 'eventId': '04070d56-5434-41ea-b009-bff5c140d49b:94c66340-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '94c6633d-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 720896000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '4a5a57db-b664-42f4-9b64-9e7893a40a3e',\n", - " 'body': [{'data': 'Expected 3, Actual 3, In order', 'type': 'message'},\n", - " {'rows': [{'actualMessage': 'ExecutionReport, demo-conn2, '\n", - " 'LeavesQty=90, OrdStatus=1, '\n", - " 'ClOrdID=6989279, CumQty=10',\n", - " 'actualMetadata': 'Metadata, demo-conn2',\n", - " 'expectedMessage': 'ExecutionReport, demo-conn2, '\n", - " 'LeavesQty=90, OrdStatus=1, '\n", - " 'ClOrdID=6989279, CumQty=10',\n", - " 'expectedMetadata': 'Metadata, demo-conn2'},\n", - " {'actualMessage': 'ExecutionReport, demo-conn2, '\n", - " 'OrdStatus=1, ClOrdID=6989279, '\n", - " 'CumQty=40, LeavesQty=60',\n", - " 'actualMetadata': 'Metadata, demo-conn2',\n", - " 'expectedMessage': 'ExecutionReport, demo-conn2, '\n", - " 'OrdStatus=1, ClOrdID=6989279, '\n", - " 'CumQty=40, LeavesQty=60',\n", - " 'expectedMetadata': 'Metadata, demo-conn2'},\n", - " {'actualMessage': 'ExecutionReport, demo-conn2, '\n", - " 'OrdStatus=C, ClOrdID=6989279, '\n", - " 'CumQty=40, LeavesQty=0',\n", - " 'actualMetadata': 'Metadata, demo-conn2',\n", - " 'expectedMessage': 'ExecutionReport, demo-conn2, '\n", - " 'OrdStatus=C, ClOrdID=6989279, '\n", - " 'CumQty=40, LeavesQty=0',\n", - " 'expectedMetadata': 'Metadata, demo-conn2'}],\n", - " 'type': 'table'}],\n", - " 'endTimestamp': {'epochSecond': 1624185908, 'nano': 529009000},\n", - " 'eventId': '4a5a57db-b664-42f4-9b64-9e7893a40a3e:94c63c2c-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Check sequence (expected 3 / actual 3 , check order true)',\n", - " 'eventType': 'checkSequence',\n", - " 'isBatched': True,\n", - " 'parentEventId': '944b18b1-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 720896000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'rows': {'comparison-settings': {'rows': {'ignore-fields': {'rows': {},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'},\n", - " 'message-filter': {'rows': {'SecurityID': {'columns': {'expected': 'INSTR2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " 'message-type': {'columns': {'type': 'PreFilter'},\n", - " 'type': 'row'},\n", - " 'metadata-filter': {'rows': {}, 'type': 'collection'}},\n", - " 'type': 'treeTable'}],\n", - " 'endTimestamp': {'epochSecond': 1624185908, 'nano': 528363000},\n", - " 'eventId': '944bdc02-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Pre-filtering (filtered 3 / processed 3) messages',\n", - " 'eventType': 'preFiltering',\n", - " 'isBatched': False,\n", - " 'parentEventId': '944b18b1-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 725559000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '2527fc47-219f-43fd-89d4-122914ce928f',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '6989279',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '10',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2361',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': 'F',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LastPx': {'actual': '36',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '90',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '872',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '100',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '34',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR2',\n", - " 'expected': 'INSTR2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'The simulated order has been '\n", - " 'partially traded',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TimeInForce': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'NoPartyIDs': {'actual': '5',\n", - " 'expected': 'null',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': 'DEMOFIRM1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '17',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '4': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:07',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TrdMatchID': {'actual': '483',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': 'null',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '370',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1294',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:07.480',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '236',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185908, 'nano': 528504000},\n", - " 'eventId': '2527fc47-219f-43fd-89d4-122914ce928f:945a33e3-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '944bdc02-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 725559000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '2527fc47-219f-43fd-89d4-122914ce928f',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '6989279',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '40',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2362',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': 'F',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LastPx': {'actual': '35',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '60',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '872',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '100',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '34',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR2',\n", - " 'expected': 'INSTR2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'The simulated order has been '\n", - " 'partially traded',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TimeInForce': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'NoPartyIDs': {'actual': '5',\n", - " 'expected': 'null',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': 'DEMOFIRM1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '17',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '4': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:07',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TrdMatchID': {'actual': '484',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': 'null',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '370',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1295',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:07.483',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '241',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185908, 'nano': 528667000},\n", - " 'eventId': '2527fc47-219f-43fd-89d4-122914ce928f:945b1e44-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '944bdc02-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 725559000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '2527fc47-219f-43fd-89d4-122914ce928f',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '6989279',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '40',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2363',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': 'C',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': 'C',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '872',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '100',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '34',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR2',\n", - " 'expected': 'INSTR2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'The remaining part of simulated '\n", - " 'order has been expired',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TimeInForce': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'NoPartyIDs': {'actual': '4',\n", - " 'expected': 'null',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:07',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': 'null',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '337',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1296',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:07.536',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '178',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185908, 'nano': 528898000},\n", - " 'eventId': '2527fc47-219f-43fd-89d4-122914ce928f:94c6151b-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '944bdc02-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 725559000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': {},\n", - " 'endTimestamp': {'epochSecond': 1624185907, 'nano': 896046000},\n", - " 'eventId': '9465ea7a-d1b4-11eb-b0fb-199708acc7bc',\n", - " 'eventName': 'Case[TC_1.3]: Trader DEMO-CONN1 vs trader DEMO-CONN2 for '\n", - " 'instrument INSTR3',\n", - " 'eventType': '',\n", - " 'isBatched': False,\n", - " 'parentEventId': '84db48fc-d1b4-11eb-b0fb-199708acc7bc',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 895991000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '91277a82-2260-4799-b82f-1df49494f8a6',\n", - " 'body': {'fields': {'AccountType': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '6989279',\n", - " 'expected': '5061159',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '10',\n", - " 'expected': '10',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2361',\n", - " 'expected': '2359',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': 'F',\n", - " 'expected': 'F',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LastPx': {'actual': '36',\n", - " 'expected': '36',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '90',\n", - " 'expected': '0',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '1',\n", - " 'expected': '2',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': '2',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'A',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '872',\n", - " 'expected': '871',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '100',\n", - " 'expected': '10',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '34',\n", - " 'expected': '36',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR2',\n", - " 'expected': 'INSTR2',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': '8',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '2',\n", - " 'expected': '1',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'The simulated order has been '\n", - " 'partially traded',\n", - " 'expected': 'The simulated order has been fully '\n", - " 'traded',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TimeInForce': {'actual': '3',\n", - " 'expected': '0',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': '1',\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " 'fields': {'NoPartyIDs': {'actual': '5',\n", - " 'expected': '5',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'DEMO-CONN1',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': '76',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMOFIRM1',\n", - " 'expected': 'DEMOFIRM2',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '17',\n", - " 'expected': '17',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': '122',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '4': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': '12',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:07',\n", - " 'expected': '2021-06-20T10:45:07',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TrdMatchID': {'actual': '483',\n", - " 'expected': '483',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': '7',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'FIXT.1.1',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '370',\n", - " 'expected': '364',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1294',\n", - " 'expected': '1297',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': '8',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': 'FGW',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:07.480',\n", - " 'expected': '2021-06-20T10:45:07.445',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'DEMO-CONN1',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {'CheckSum': {'actual': '236',\n", - " 'expected': '209',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'status': 0,\n", - " 'type': 'verification'},\n", - " 'endTimestamp': {'epochSecond': 1624185907, 'nano': 961484000},\n", - " 'eventId': '91277a82-2260-4799-b82f-1df49494f8a6:946ff858-d1b4-11eb-986f-1e8d42132387',\n", - " 'eventName': \"Match by '['TrdMatchID': 483]'\",\n", - " 'eventType': '',\n", - " 'isBatched': True,\n", - " 'parentEventId': '6e86db98-d047-11eb-986f-1e8d42132387',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 961484000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '91277a82-2260-4799-b82f-1df49494f8a6',\n", - " 'body': {'fields': {'AccountType': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '6989279',\n", - " 'expected': '4556842',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '40',\n", - " 'expected': '30',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2362',\n", - " 'expected': '2360',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': 'F',\n", - " 'expected': 'F',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LastPx': {'actual': '35',\n", - " 'expected': '35',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '60',\n", - " 'expected': '0',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '1',\n", - " 'expected': '2',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': '2',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'A',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '872',\n", - " 'expected': '870',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '100',\n", - " 'expected': '30',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '34',\n", - " 'expected': '35',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR2',\n", - " 'expected': 'INSTR2',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': '8',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '2',\n", - " 'expected': '1',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'The simulated order has been '\n", - " 'partially traded',\n", - " 'expected': 'The simulated order has been fully '\n", - " 'traded',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TimeInForce': {'actual': '3',\n", - " 'expected': '0',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {'NoPartyIDs': {'actual': '5',\n", - " 'expected': '5',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'DEMO-CONN1',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': '76',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMOFIRM1',\n", - " 'expected': 'DEMOFIRM2',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '17',\n", - " 'expected': '17',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': '122',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '4': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': '12',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:07',\n", - " 'expected': '2021-06-20T10:45:07',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TrdMatchID': {'actual': '484',\n", - " 'expected': '484',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': '7',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'FIXT.1.1',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '370',\n", - " 'expected': '364',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1295',\n", - " 'expected': '1298',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': '8',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': 'FGW',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:07.483',\n", - " 'expected': '2021-06-20T10:45:07.456',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'DEMO-CONN1',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {'CheckSum': {'actual': '241',\n", - " 'expected': '213',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'status': 0,\n", - " 'type': 'verification'},\n", - " 'endTimestamp': {'epochSecond': 1624185907, 'nano': 975041000},\n", - " 'eventId': '91277a82-2260-4799-b82f-1df49494f8a6:94720864-d1b4-11eb-986f-1e8d42132387',\n", - " 'eventName': \"Match by '['TrdMatchID': 484]'\",\n", - " 'eventType': '',\n", - " 'isBatched': True,\n", - " 'parentEventId': '6e86db98-d047-11eb-986f-1e8d42132387',\n", - " 'startTimestamp': {'epochSecond': 1624185907, 'nano': 975041000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'data': 'STEP1: Trader \"DEMO-CONN1\" sends request to create passive '\n", - " 'Order.',\n", - " 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185912, 'nano': 940359000},\n", - " 'eventId': '97679b10-d1b4-11eb-bae5-57b0c4472880',\n", - " 'eventName': 'placeOrderFIX demo-conn1 - STEP1: Trader \"DEMO-CONN1\" sends '\n", - " 'request to create passive Order.',\n", - " 'eventType': 'placeOrderFIX',\n", - " 'isBatched': False,\n", - " 'parentEventId': '9465ea7a-d1b4-11eb-b0fb-199708acc7bc',\n", - " 'startTimestamp': {'epochSecond': 1624185912, 'nano': 940322000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '1f870c59-9889-4a0e-8e22-897b4535effc',\n", - " 'body': [{'data': \"Checkpoint id '97683700-d1b4-11eb-ba78-1981398e00bd'\",\n", - " 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185912, 'nano': 944579000},\n", - " 'eventId': '1f870c59-9889-4a0e-8e22-897b4535effc:97683741-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Checkpoint',\n", - " 'eventType': 'Checkpoint',\n", - " 'isBatched': True,\n", - " 'parentEventId': '97679b10-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185912, 'nano': 944392000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '1f870c59-9889-4a0e-8e22-897b4535effc',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185912, 'nano': 944579000},\n", - " 'eventId': '1f870c59-9889-4a0e-8e22-897b4535effc:97683742-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'th2-hand-demo' direction 'FIRST' \"\n", - " \"sequence '1623852603564709030'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '1f870c59-9889-4a0e-8e22-897b4535effc:97683741-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185912, 'nano': 944392000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '1f870c59-9889-4a0e-8e22-897b4535effc',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185912, 'nano': 944579000},\n", - " 'eventId': '1f870c59-9889-4a0e-8e22-897b4535effc:97683743-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn1' direction 'SECOND' \"\n", - " \"sequence '1624005455622140293'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '1f870c59-9889-4a0e-8e22-897b4535effc:97683741-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185912, 'nano': 944392000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '1f870c59-9889-4a0e-8e22-897b4535effc',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185912, 'nano': 944579000},\n", - " 'eventId': '1f870c59-9889-4a0e-8e22-897b4535effc:97683744-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc1' direction 'SECOND' \"\n", - " \"sequence '1624005475721015015'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '1f870c59-9889-4a0e-8e22-897b4535effc:97683741-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185912, 'nano': 944392000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '1f870c59-9889-4a0e-8e22-897b4535effc',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185912, 'nano': 944579000},\n", - " 'eventId': '1f870c59-9889-4a0e-8e22-897b4535effc:97683745-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc1' direction 'FIRST' \"\n", - " \"sequence '1624005475720919507'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '1f870c59-9889-4a0e-8e22-897b4535effc:97683741-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185912, 'nano': 944392000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '1f870c59-9889-4a0e-8e22-897b4535effc',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185912, 'nano': 944579000},\n", - " 'eventId': '1f870c59-9889-4a0e-8e22-897b4535effc:97683746-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn2' direction 'FIRST' \"\n", - " \"sequence '1624005448022245405'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '1f870c59-9889-4a0e-8e22-897b4535effc:97683741-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185912, 'nano': 944392000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '1f870c59-9889-4a0e-8e22-897b4535effc',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185912, 'nano': 944579000},\n", - " 'eventId': '1f870c59-9889-4a0e-8e22-897b4535effc:97683747-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn2' direction 'SECOND' \"\n", - " \"sequence '1624005448022426115'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '1f870c59-9889-4a0e-8e22-897b4535effc:97683741-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185912, 'nano': 944392000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '1f870c59-9889-4a0e-8e22-897b4535effc',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185912, 'nano': 944579000},\n", - " 'eventId': '1f870c59-9889-4a0e-8e22-897b4535effc:97683748-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc2' direction 'SECOND' \"\n", - " \"sequence '1624005466840347016'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '1f870c59-9889-4a0e-8e22-897b4535effc:97683741-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185912, 'nano': 944392000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '1f870c59-9889-4a0e-8e22-897b4535effc',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185912, 'nano': 944579000},\n", - " 'eventId': '1f870c59-9889-4a0e-8e22-897b4535effc:97683749-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc2' direction 'FIRST' \"\n", - " \"sequence '1624005466840263378'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '1f870c59-9889-4a0e-8e22-897b4535effc:97683741-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185912, 'nano': 944392000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '1f870c59-9889-4a0e-8e22-897b4535effc',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185912, 'nano': 944579000},\n", - " 'eventId': '1f870c59-9889-4a0e-8e22-897b4535effc:9768374a-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn1' direction 'FIRST' \"\n", - " \"sequence '1624005455622011530'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '1f870c59-9889-4a0e-8e22-897b4535effc:97683741-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185912, 'nano': 944392000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '1f870c59-9889-4a0e-8e22-897b4535effc',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185912, 'nano': 944579000},\n", - " 'eventId': '1f870c59-9889-4a0e-8e22-897b4535effc:9768374b-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-log' direction 'FIRST' \"\n", - " \"sequence '1624029363623063053'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '1f870c59-9889-4a0e-8e22-897b4535effc:97683741-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185912, 'nano': 944392000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'rows': {'AccountType': {'columns': {'fieldValue': '1'},\n", - " 'type': 'row'},\n", - " 'ClOrdID': {'columns': {'fieldValue': '3774265'},\n", - " 'type': 'row'},\n", - " 'OrdType': {'columns': {'fieldValue': '2'}, 'type': 'row'},\n", - " 'OrderCapacity': {'columns': {'fieldValue': 'A'},\n", - " 'type': 'row'},\n", - " 'OrderQty': {'columns': {'fieldValue': '30'},\n", - " 'type': 'row'},\n", - " 'Price': {'columns': {'fieldValue': '75'}, 'type': 'row'},\n", - " 'SecondaryClOrdID': {'columns': {'fieldValue': '11111'},\n", - " 'type': 'row'},\n", - " 'SecurityID': {'columns': {'fieldValue': 'INSTR3'},\n", - " 'type': 'row'},\n", - " 'SecurityIDSource': {'columns': {'fieldValue': '8'},\n", - " 'type': 'row'},\n", - " 'Side': {'columns': {'fieldValue': '1'}, 'type': 'row'},\n", - " 'TradingParty': {'rows': {'NoPartyIDs': {'rows': {'0': {'rows': {'PartyID': {'columns': {'fieldValue': 'DEMO-CONN1'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'D'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '76'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '1': {'rows': {'PartyID': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '2': {'rows': {'PartyID': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '122'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '3': {'rows': {'PartyID': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '12'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'columns': {'fieldValue': '2021-06-20T13:45:07.898136'},\n", - " 'type': 'row'}},\n", - " 'type': 'treeTable'}],\n", - " 'endTimestamp': {'epochSecond': 1624185912, 'nano': 953658000},\n", - " 'eventId': '976996e1-d1b4-11eb-bae5-57b0c4472880',\n", - " 'eventName': \"Send 'NewOrderSingle' message to connectivity\",\n", - " 'eventType': 'Outgoing message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '97679b10-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185912, 'nano': 953202000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185912, 'nano': 967864000},\n", - " 'eventId': '976bb9f0-d1b4-11eb-8e55-d3a76285d588',\n", - " 'eventName': \"Send 'NewOrderSingle' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '97679b10-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185912, 'nano': 967853000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185913, 'nano': 267034000},\n", - " 'eventId': '979980ee-d1b4-11eb-a9ed-ffb57363e013',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '845d70d2-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185913, 'nano': 267031000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185913, 'nano': 268658000},\n", - " 'eventId': '9799a7db-d1b4-11eb-a9f4-b12655548efc',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '845d70d2-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185913, 'nano': 268430000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '5d924f7a-ad45-494e-aa12-e95789d1d8f3',\n", - " 'body': {'data': 'The message was deleted because a new one came with the '\n", - " \"same hash '-8710003674304438575' in message group \"\n", - " \"'NOS_CONN'\\n\"\n", - " ' Message not matched',\n", - " 'type': 'message'},\n", - " 'endTimestamp': {'epochSecond': 1624185913, 'nano': 833802000},\n", - " 'eventId': '5d924f7a-ad45-494e-aa12-e95789d1d8f3:97f00720-d1b4-11eb-986f-1e8d42132387',\n", - " 'eventName': \"Remove 'NewOrderSingle' \"\n", - " \"id='demo-conn1:SECOND:1624005455622135209' \"\n", - " \"Hash='-8710003674304438575' Group='NOS_CONN' \"\n", - " \"Hash['SecondaryClOrdID': 11111, 'SecurityID': INSTR3]\",\n", - " 'eventType': '',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'a3779b94-d051-11eb-986f-1e8d42132387',\n", - " 'startTimestamp': {'epochSecond': 1624185913, 'nano': 833802000},\n", - " 'successful': False,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'rows': {'AccountType': {'columns': {'fieldValue': '1'},\n", - " 'type': 'row'},\n", - " 'ClOrdID': {'columns': {'fieldValue': '3774265'},\n", - " 'type': 'row'},\n", - " 'CumQty': {'columns': {'fieldValue': '0'}, 'type': 'row'},\n", - " 'ExecID': {'columns': {'fieldValue': '2364'},\n", - " 'type': 'row'},\n", - " 'ExecType': {'columns': {'fieldValue': '0'}, 'type': 'row'},\n", - " 'LeavesQty': {'columns': {'fieldValue': '30'},\n", - " 'type': 'row'},\n", - " 'OrdStatus': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'OrdType': {'columns': {'fieldValue': '2'}, 'type': 'row'},\n", - " 'OrderCapacity': {'columns': {'fieldValue': 'A'},\n", - " 'type': 'row'},\n", - " 'OrderID': {'columns': {'fieldValue': '873'},\n", - " 'type': 'row'},\n", - " 'OrderQty': {'columns': {'fieldValue': '30'},\n", - " 'type': 'row'},\n", - " 'Price': {'columns': {'fieldValue': '75'}, 'type': 'row'},\n", - " 'SecurityID': {'columns': {'fieldValue': 'INSTR3'},\n", - " 'type': 'row'},\n", - " 'SecurityIDSource': {'columns': {'fieldValue': '8'},\n", - " 'type': 'row'},\n", - " 'Side': {'columns': {'fieldValue': '1'}, 'type': 'row'},\n", - " 'Text': {'columns': {'fieldValue': 'Simulated New Order '\n", - " 'Buy is placed'},\n", - " 'type': 'row'},\n", - " 'TradingParty': {'rows': {'NoPartyIDs': {'rows': {'0': {'rows': {'PartyID': {'columns': {'fieldValue': 'DEMO-CONN1'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'D'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '76'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '1': {'rows': {'PartyID': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '2': {'rows': {'PartyID': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '122'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '3': {'rows': {'PartyID': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '12'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'columns': {'fieldValue': '2021-06-20T10:45:13'},\n", - " 'type': 'row'},\n", - " 'header': {'rows': {'BeginString': {'columns': {'fieldValue': 'FIXT.1.1'},\n", - " 'type': 'row'},\n", - " 'BodyLength': {'columns': {'fieldValue': '310'},\n", - " 'type': 'row'},\n", - " 'MsgSeqNum': {'columns': {'fieldValue': '1299'},\n", - " 'type': 'row'},\n", - " 'MsgType': {'columns': {'fieldValue': '8'},\n", - " 'type': 'row'},\n", - " 'SenderCompID': {'columns': {'fieldValue': 'FGW'},\n", - " 'type': 'row'},\n", - " 'SendingTime': {'columns': {'fieldValue': '2021-06-20T10:45:13.264'},\n", - " 'type': 'row'},\n", - " 'TargetCompID': {'columns': {'fieldValue': 'DEMO-CONN1'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " 'trailer': {'rows': {'CheckSum': {'columns': {'fieldValue': '054'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'treeTable'}],\n", - " 'endTimestamp': {'epochSecond': 1624185913, 'nano': 933880000},\n", - " 'eventId': '97ff2022-d1b4-11eb-bae5-57b0c4472880',\n", - " 'eventName': \"Received 'ExecutionReport' response message\",\n", - " 'eventType': 'message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '97679b10-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185913, 'nano': 933852000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'data': 'STEP2: Trader \"DEMO-CONN1\" receives Execution Report. The '\n", - " 'order stands on book in status NEW',\n", - " 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185914, 'nano': 24078000},\n", - " 'eventId': '980b7c2c-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Check sequence rule SessionKey{sessionAlias='demo-conn1', \"\n", - " 'direction=FIRST} - STEP2: Trader \"DEMO-CONN1\" receives '\n", - " 'Execution Report. The order stands on book in status NEW',\n", - " 'eventType': 'checkSequenceRule',\n", - " 'isBatched': False,\n", - " 'parentEventId': '9465ea7a-d1b4-11eb-b0fb-199708acc7bc',\n", - " 'startTimestamp': {'epochSecond': 1624185914, 'nano': 14475000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'data': 'Contains comparisons', 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185914, 'nano': 24360000},\n", - " 'eventId': '980d02d0-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Check messages',\n", - " 'eventType': 'checkMessages',\n", - " 'isBatched': False,\n", - " 'parentEventId': '980b7c2c-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185914, 'nano': 14475000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '79c770eb-0e05-4f18-9bb8-db872b29039a',\n", - " 'body': [{'data': 'Expected 1, Actual 1', 'type': 'message'},\n", - " {'rows': [{'actualMessage': 'ExecutionReport, demo-conn1, '\n", - " 'ClOrdID=3774265, OrdStatus=0',\n", - " 'actualMetadata': 'Metadata, demo-conn1',\n", - " 'expectedMessage': 'ExecutionReport, demo-conn1, '\n", - " 'ClOrdID=3774265, OrdStatus=0',\n", - " 'expectedMetadata': 'Metadata, demo-conn1'}],\n", - " 'type': 'table'}],\n", - " 'endTimestamp': {'epochSecond': 1624185914, 'nano': 24330000},\n", - " 'eventId': '79c770eb-0e05-4f18-9bb8-db872b29039a:980cdbbf-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Check sequence (expected 1 / actual 1 , check order false)',\n", - " 'eventType': 'checkSequence',\n", - " 'isBatched': True,\n", - " 'parentEventId': '980b7c2c-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185914, 'nano': 14475000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'fb053f79-4984-4f03-838f-6a7e08c98bb0',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '3774265',\n", - " 'expected': '3774265',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2364',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '30',\n", - " 'expected': '30',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': '2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'A',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '873',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '30',\n", - " 'expected': '30',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '75',\n", - " 'expected': '75',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR3',\n", - " 'expected': 'INSTR3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'Simulated New Order Buy is placed',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {'NoPartyIDs': {'actual': '4',\n", - " 'expected': '4',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'DEMO-CONN1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': '76',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': '122',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': '12',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:13',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': '7',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'FIXT.1.1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '310',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1299',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " 'MsgType': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:13.264',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'DEMO-CONN1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '054',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185914, 'nano': 24365000},\n", - " 'eventId': 'fb053f79-4984-4f03-838f-6a7e08c98bb0:980d02d1-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '980d02d0-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185914, 'nano': 14475000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'rows': {'comparison-settings': {'rows': {'ignore-fields': {'rows': {},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'},\n", - " 'message-filter': {'rows': {'SecurityID': {'columns': {'expected': 'INSTR3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL'},\n", - " 'type': 'row'},\n", - " 'header': {'rows': {'MsgType': {'columns': {'expected': 'f',\n", - " 'key': False,\n", - " 'operation': 'NOT_EQUAL'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'},\n", - " 'message-type': {'columns': {'type': 'PreFilter'},\n", - " 'type': 'row'},\n", - " 'metadata-filter': {'rows': {}, 'type': 'collection'}},\n", - " 'type': 'treeTable'}],\n", - " 'endTimestamp': {'epochSecond': 1624185914, 'nano': 24125000},\n", - " 'eventId': '980bca4d-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Pre-filtering (filtered 1 / processed 1) messages',\n", - " 'eventType': 'preFiltering',\n", - " 'isBatched': False,\n", - " 'parentEventId': '980b7c2c-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185914, 'nano': 16745000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '4c51691c-0c52-4122-99a2-eff896ffcb71',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '3774265',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2364',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '30',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '873',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '30',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '75',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR3',\n", - " 'expected': 'INSTR3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'Simulated New Order Buy is placed',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'NoPartyIDs': {'actual': '4',\n", - " 'expected': 'null',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:13',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': '1',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '310',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1299',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': 'x != \"f\"',\n", - " 'key': False,\n", - " 'operation': 'NOT_EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:13.264',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '054',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185914, 'nano': 24206000},\n", - " 'eventId': '4c51691c-0c52-4122-99a2-eff896ffcb71:980c8d9e-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '980bca4d-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185914, 'nano': 16745000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'data': 'STEP3: Trader \"DEMO-CONN1\" sends request to create passive '\n", - " 'Order with price lower than first order.',\n", - " 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185914, 'nano': 98120000},\n", - " 'eventId': '98184d73-d1b4-11eb-bae5-57b0c4472880',\n", - " 'eventName': 'placeOrderFIX demo-conn1 - STEP3: Trader \"DEMO-CONN1\" sends '\n", - " 'request to create passive Order with price lower than first '\n", - " 'order.',\n", - " 'eventType': 'placeOrderFIX',\n", - " 'isBatched': False,\n", - " 'parentEventId': '9465ea7a-d1b4-11eb-b0fb-199708acc7bc',\n", - " 'startTimestamp': {'epochSecond': 1624185914, 'nano': 98078000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '0bca6c95-0d84-4f01-aefb-62ad9975d35d',\n", - " 'body': [{'data': \"Checkpoint id '981a7000-d1b4-11eb-ba78-1981398e00bd'\",\n", - " 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185914, 'nano': 112512000},\n", - " 'eventId': '0bca6c95-0d84-4f01-aefb-62ad9975d35d:981a7052-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Checkpoint',\n", - " 'eventType': 'Checkpoint',\n", - " 'isBatched': True,\n", - " 'parentEventId': '98184d73-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185914, 'nano': 112399000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '0bca6c95-0d84-4f01-aefb-62ad9975d35d',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185914, 'nano': 112512000},\n", - " 'eventId': '0bca6c95-0d84-4f01-aefb-62ad9975d35d:981a7053-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'th2-hand-demo' direction 'FIRST' \"\n", - " \"sequence '1623852603564709030'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '0bca6c95-0d84-4f01-aefb-62ad9975d35d:981a7052-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185914, 'nano': 112399000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '0bca6c95-0d84-4f01-aefb-62ad9975d35d',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185914, 'nano': 112512000},\n", - " 'eventId': '0bca6c95-0d84-4f01-aefb-62ad9975d35d:981a7054-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn1' direction 'SECOND' \"\n", - " \"sequence '1624005455622140294'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '0bca6c95-0d84-4f01-aefb-62ad9975d35d:981a7052-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185914, 'nano': 112399000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '0bca6c95-0d84-4f01-aefb-62ad9975d35d',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185914, 'nano': 112512000},\n", - " 'eventId': '0bca6c95-0d84-4f01-aefb-62ad9975d35d:981a7055-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc1' direction 'SECOND' \"\n", - " \"sequence '1624005475721015015'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '0bca6c95-0d84-4f01-aefb-62ad9975d35d:981a7052-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185914, 'nano': 112399000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '0bca6c95-0d84-4f01-aefb-62ad9975d35d',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185914, 'nano': 112512000},\n", - " 'eventId': '0bca6c95-0d84-4f01-aefb-62ad9975d35d:981a7056-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc1' direction 'FIRST' \"\n", - " \"sequence '1624005475720919508'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '0bca6c95-0d84-4f01-aefb-62ad9975d35d:981a7052-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185914, 'nano': 112399000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '0bca6c95-0d84-4f01-aefb-62ad9975d35d',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185914, 'nano': 112512000},\n", - " 'eventId': '0bca6c95-0d84-4f01-aefb-62ad9975d35d:981a7057-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn2' direction 'FIRST' \"\n", - " \"sequence '1624005448022245405'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '0bca6c95-0d84-4f01-aefb-62ad9975d35d:981a7052-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185914, 'nano': 112399000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '0bca6c95-0d84-4f01-aefb-62ad9975d35d',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185914, 'nano': 112512000},\n", - " 'eventId': '0bca6c95-0d84-4f01-aefb-62ad9975d35d:981a7058-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn2' direction 'SECOND' \"\n", - " \"sequence '1624005448022426115'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '0bca6c95-0d84-4f01-aefb-62ad9975d35d:981a7052-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185914, 'nano': 112399000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '0bca6c95-0d84-4f01-aefb-62ad9975d35d',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185914, 'nano': 112512000},\n", - " 'eventId': '0bca6c95-0d84-4f01-aefb-62ad9975d35d:981a7059-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc2' direction 'SECOND' \"\n", - " \"sequence '1624005466840347016'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '0bca6c95-0d84-4f01-aefb-62ad9975d35d:981a7052-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185914, 'nano': 112399000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '0bca6c95-0d84-4f01-aefb-62ad9975d35d',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185914, 'nano': 112512000},\n", - " 'eventId': '0bca6c95-0d84-4f01-aefb-62ad9975d35d:981a705a-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc2' direction 'FIRST' \"\n", - " \"sequence '1624005466840263378'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '0bca6c95-0d84-4f01-aefb-62ad9975d35d:981a7052-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185914, 'nano': 112399000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '0bca6c95-0d84-4f01-aefb-62ad9975d35d',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185914, 'nano': 112512000},\n", - " 'eventId': '0bca6c95-0d84-4f01-aefb-62ad9975d35d:981a705b-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn1' direction 'FIRST' \"\n", - " \"sequence '1624005455622011531'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '0bca6c95-0d84-4f01-aefb-62ad9975d35d:981a7052-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185914, 'nano': 112399000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '0bca6c95-0d84-4f01-aefb-62ad9975d35d',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185914, 'nano': 112512000},\n", - " 'eventId': '0bca6c95-0d84-4f01-aefb-62ad9975d35d:981a705c-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-log' direction 'FIRST' \"\n", - " \"sequence '1624029363623063053'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '0bca6c95-0d84-4f01-aefb-62ad9975d35d:981a7052-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185914, 'nano': 112399000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'rows': {'AccountType': {'columns': {'fieldValue': '1'},\n", - " 'type': 'row'},\n", - " 'ClOrdID': {'columns': {'fieldValue': '6061277'},\n", - " 'type': 'row'},\n", - " 'OrdType': {'columns': {'fieldValue': '2'}, 'type': 'row'},\n", - " 'OrderCapacity': {'columns': {'fieldValue': 'A'},\n", - " 'type': 'row'},\n", - " 'OrderQty': {'columns': {'fieldValue': '10'},\n", - " 'type': 'row'},\n", - " 'Price': {'columns': {'fieldValue': '76'}, 'type': 'row'},\n", - " 'SecondaryClOrdID': {'columns': {'fieldValue': '22222'},\n", - " 'type': 'row'},\n", - " 'SecurityID': {'columns': {'fieldValue': 'INSTR3'},\n", - " 'type': 'row'},\n", - " 'SecurityIDSource': {'columns': {'fieldValue': '8'},\n", - " 'type': 'row'},\n", - " 'Side': {'columns': {'fieldValue': '1'}, 'type': 'row'},\n", - " 'TradingParty': {'rows': {'NoPartyIDs': {'rows': {'0': {'rows': {'PartyID': {'columns': {'fieldValue': 'DEMO-CONN1'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'D'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '76'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '1': {'rows': {'PartyID': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '2': {'rows': {'PartyID': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '122'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '3': {'rows': {'PartyID': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '12'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'columns': {'fieldValue': '2021-06-20T13:45:07.898194'},\n", - " 'type': 'row'}},\n", - " 'type': 'treeTable'}],\n", - " 'endTimestamp': {'epochSecond': 1624185914, 'nano': 119769000},\n", - " 'eventId': '981b81c4-d1b4-11eb-bae5-57b0c4472880',\n", - " 'eventName': \"Send 'NewOrderSingle' message to connectivity\",\n", - " 'eventType': 'Outgoing message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '98184d73-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185914, 'nano': 119697000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185914, 'nano': 156945000},\n", - " 'eventId': '98212741-d1b4-11eb-8e55-d3a76285d588',\n", - " 'eventName': \"Send 'NewOrderSingle' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '98184d73-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185914, 'nano': 156941000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185914, 'nano': 253814000},\n", - " 'eventId': '982ff48f-d1b4-11eb-a9ed-ffb57363e013',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '845d70d2-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185914, 'nano': 253810000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185914, 'nano': 260873000},\n", - " 'eventId': '983105dc-d1b4-11eb-a9f4-b12655548efc',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '845d70d2-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185914, 'nano': 260868000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '5421e1d4-bd2b-4a25-95e0-580d5c8e6750',\n", - " 'body': {'data': 'The message was deleted because a new one came with the '\n", - " \"same hash '-25247830425272190' in message group 'NOS_CONN'\\n\"\n", - " ' Message not matched',\n", - " 'type': 'message'},\n", - " 'endTimestamp': {'epochSecond': 1624185914, 'nano': 839072000},\n", - " 'eventId': '5421e1d4-bd2b-4a25-95e0-580d5c8e6750:98896b4a-d1b4-11eb-986f-1e8d42132387',\n", - " 'eventName': \"Remove 'NewOrderSingle' \"\n", - " \"id='demo-conn1:SECOND:1624005455622135210' \"\n", - " \"Hash='-25247830425272190' Group='NOS_CONN' \"\n", - " \"Hash['SecondaryClOrdID': 22222, 'SecurityID': INSTR3]\",\n", - " 'eventType': '',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'a3779b94-d051-11eb-986f-1e8d42132387',\n", - " 'startTimestamp': {'epochSecond': 1624185914, 'nano': 839072000},\n", - " 'successful': False,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'rows': {'AccountType': {'columns': {'fieldValue': '1'},\n", - " 'type': 'row'},\n", - " 'ClOrdID': {'columns': {'fieldValue': '6061277'},\n", - " 'type': 'row'},\n", - " 'CumQty': {'columns': {'fieldValue': '0'}, 'type': 'row'},\n", - " 'ExecID': {'columns': {'fieldValue': '2366'},\n", - " 'type': 'row'},\n", - " 'ExecType': {'columns': {'fieldValue': '0'}, 'type': 'row'},\n", - " 'LeavesQty': {'columns': {'fieldValue': '10'},\n", - " 'type': 'row'},\n", - " 'OrdStatus': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'OrdType': {'columns': {'fieldValue': '2'}, 'type': 'row'},\n", - " 'OrderCapacity': {'columns': {'fieldValue': 'A'},\n", - " 'type': 'row'},\n", - " 'OrderID': {'columns': {'fieldValue': '874'},\n", - " 'type': 'row'},\n", - " 'OrderQty': {'columns': {'fieldValue': '10'},\n", - " 'type': 'row'},\n", - " 'Price': {'columns': {'fieldValue': '76'}, 'type': 'row'},\n", - " 'SecurityID': {'columns': {'fieldValue': 'INSTR3'},\n", - " 'type': 'row'},\n", - " 'SecurityIDSource': {'columns': {'fieldValue': '8'},\n", - " 'type': 'row'},\n", - " 'Side': {'columns': {'fieldValue': '1'}, 'type': 'row'},\n", - " 'Text': {'columns': {'fieldValue': 'Simulated New Order '\n", - " 'Buy is placed'},\n", - " 'type': 'row'},\n", - " 'TradingParty': {'rows': {'NoPartyIDs': {'rows': {'0': {'rows': {'PartyID': {'columns': {'fieldValue': 'DEMO-CONN1'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'D'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '76'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '1': {'rows': {'PartyID': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '2': {'rows': {'PartyID': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '122'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '3': {'rows': {'PartyID': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '12'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'columns': {'fieldValue': '2021-06-20T10:45:14'},\n", - " 'type': 'row'},\n", - " 'header': {'rows': {'BeginString': {'columns': {'fieldValue': 'FIXT.1.1'},\n", - " 'type': 'row'},\n", - " 'BodyLength': {'columns': {'fieldValue': '310'},\n", - " 'type': 'row'},\n", - " 'MsgSeqNum': {'columns': {'fieldValue': '1300'},\n", - " 'type': 'row'},\n", - " 'MsgType': {'columns': {'fieldValue': '8'},\n", - " 'type': 'row'},\n", - " 'SenderCompID': {'columns': {'fieldValue': 'FGW'},\n", - " 'type': 'row'},\n", - " 'SendingTime': {'columns': {'fieldValue': '2021-06-20T10:45:14.253'},\n", - " 'type': 'row'},\n", - " 'TargetCompID': {'columns': {'fieldValue': 'DEMO-CONN1'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " 'trailer': {'rows': {'CheckSum': {'columns': {'fieldValue': '032'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'treeTable'}],\n", - " 'endTimestamp': {'epochSecond': 1624185914, 'nano': 932702000},\n", - " 'eventId': '98978f95-d1b4-11eb-bae5-57b0c4472880',\n", - " 'eventName': \"Received 'ExecutionReport' response message\",\n", - " 'eventType': 'message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '98184d73-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185914, 'nano': 932660000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'data': 'STEP4: Trader \"DEMO-CONN1\" receives Execution Report. The '\n", - " 'order stands on book in status NEW',\n", - " 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185915, 'nano': 26017000},\n", - " 'eventId': '98a4aefd-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Check sequence rule SessionKey{sessionAlias='demo-conn1', \"\n", - " 'direction=FIRST} - STEP4: Trader \"DEMO-CONN1\" receives '\n", - " 'Execution Report. The order stands on book in status NEW',\n", - " 'eventType': 'checkSequenceRule',\n", - " 'isBatched': False,\n", - " 'parentEventId': '9465ea7a-d1b4-11eb-b0fb-199708acc7bc',\n", - " 'startTimestamp': {'epochSecond': 1624185915, 'nano': 18949000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'data': 'Contains comparisons', 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185915, 'nano': 27982000},\n", - " 'eventId': '98a5c071-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Check messages',\n", - " 'eventType': 'checkMessages',\n", - " 'isBatched': False,\n", - " 'parentEventId': '98a4aefd-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185915, 'nano': 18949000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '18cea323-8d10-48fe-b897-f97d1af5929f',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '6061277',\n", - " 'expected': '6061277',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2366',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '10',\n", - " 'expected': '10',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': '2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'A',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '874',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '10',\n", - " 'expected': '10',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '76',\n", - " 'expected': '76',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR3',\n", - " 'expected': 'INSTR3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'Simulated New Order Buy is placed',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {'NoPartyIDs': {'actual': '4',\n", - " 'expected': '4',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'DEMO-CONN1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': '76',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': '122',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': '12',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:14',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': '7',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'FIXT.1.1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '310',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1300',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:14.253',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'DEMO-CONN1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '032',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185915, 'nano': 27994000},\n", - " 'eventId': '18cea323-8d10-48fe-b897-f97d1af5929f:98a5c072-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '98a5c071-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185915, 'nano': 18949000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '2272d73d-2929-428d-a776-e103a946a242',\n", - " 'body': [{'data': 'Expected 1, Actual 1', 'type': 'message'},\n", - " {'rows': [{'actualMessage': 'ExecutionReport, demo-conn1, '\n", - " 'ClOrdID=6061277, OrdStatus=0',\n", - " 'actualMetadata': 'Metadata, demo-conn1',\n", - " 'expectedMessage': 'ExecutionReport, demo-conn1, '\n", - " 'ClOrdID=6061277, OrdStatus=0',\n", - " 'expectedMetadata': 'Metadata, demo-conn1'}],\n", - " 'type': 'table'}],\n", - " 'endTimestamp': {'epochSecond': 1624185915, 'nano': 26235000},\n", - " 'eventId': '2272d73d-2929-428d-a776-e103a946a242:98a5c070-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Check sequence (expected 1 / actual 1 , check order false)',\n", - " 'eventType': 'checkSequence',\n", - " 'isBatched': True,\n", - " 'parentEventId': '98a4aefd-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185915, 'nano': 18949000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'rows': {'comparison-settings': {'rows': {'ignore-fields': {'rows': {},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'},\n", - " 'message-filter': {'rows': {'SecurityID': {'columns': {'expected': 'INSTR3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " 'message-type': {'columns': {'type': 'PreFilter'},\n", - " 'type': 'row'},\n", - " 'metadata-filter': {'rows': {}, 'type': 'collection'}},\n", - " 'type': 'treeTable'}],\n", - " 'endTimestamp': {'epochSecond': 1624185915, 'nano': 26066000},\n", - " 'eventId': '98a4fd1e-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Pre-filtering (filtered 1 / processed 1) messages',\n", - " 'eventType': 'preFiltering',\n", - " 'isBatched': False,\n", - " 'parentEventId': '98a4aefd-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185915, 'nano': 20187000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'ccc5302a-b013-4440-a51e-e9c02cb6ee2d',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '6061277',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2366',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '10',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '874',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '10',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '76',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR3',\n", - " 'expected': 'INSTR3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'Simulated New Order Buy is placed',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'NoPartyIDs': {'actual': '4',\n", - " 'expected': 'null',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:14',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': 'null',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '310',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1300',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:14.253',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '032',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185915, 'nano': 26120000},\n", - " 'eventId': 'ccc5302a-b013-4440-a51e-e9c02cb6ee2d:98a5995f-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '98a4fd1e-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185915, 'nano': 20187000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'data': 'STEP5: Trader \"DEMO-CONN2\" sends request to create '\n", - " 'aggressive IOC Order.',\n", - " 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185915, 'nano': 96128000},\n", - " 'eventId': '98b095d6-d1b4-11eb-bae5-57b0c4472880',\n", - " 'eventName': 'placeOrderFIX demo-conn2 - STEP5: Trader \"DEMO-CONN2\" sends '\n", - " 'request to create aggressive IOC Order.',\n", - " 'eventType': 'placeOrderFIX',\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " 'isBatched': False,\n", - " 'parentEventId': '9465ea7a-d1b4-11eb-b0fb-199708acc7bc',\n", - " 'startTimestamp': {'epochSecond': 1624185915, 'nano': 96046000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '086e595c-0989-4f3d-8573-8af4b2f30a31',\n", - " 'body': [{'data': \"Checkpoint id '98b417f0-d1b4-11eb-ba78-1981398e00bd'\",\n", - " 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185915, 'nano': 119589000},\n", - " 'eventId': '086e595c-0989-4f3d-8573-8af4b2f30a31:98b41853-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Checkpoint',\n", - " 'eventType': 'Checkpoint',\n", - " 'isBatched': True,\n", - " 'parentEventId': '98b095d6-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185915, 'nano': 119489000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '086e595c-0989-4f3d-8573-8af4b2f30a31',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185915, 'nano': 119589000},\n", - " 'eventId': '086e595c-0989-4f3d-8573-8af4b2f30a31:98b41854-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'th2-hand-demo' direction 'FIRST' \"\n", - " \"sequence '1623852603564709030'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '086e595c-0989-4f3d-8573-8af4b2f30a31:98b41853-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185915, 'nano': 119489000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '086e595c-0989-4f3d-8573-8af4b2f30a31',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185915, 'nano': 119589000},\n", - " 'eventId': '086e595c-0989-4f3d-8573-8af4b2f30a31:98b41855-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn1' direction 'SECOND' \"\n", - " \"sequence '1624005455622140295'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '086e595c-0989-4f3d-8573-8af4b2f30a31:98b41853-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185915, 'nano': 119489000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '086e595c-0989-4f3d-8573-8af4b2f30a31',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185915, 'nano': 119589000},\n", - " 'eventId': '086e595c-0989-4f3d-8573-8af4b2f30a31:98b41856-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc1' direction 'SECOND' \"\n", - " \"sequence '1624005475721015015'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '086e595c-0989-4f3d-8573-8af4b2f30a31:98b41853-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185915, 'nano': 119489000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '086e595c-0989-4f3d-8573-8af4b2f30a31',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185915, 'nano': 119589000},\n", - " 'eventId': '086e595c-0989-4f3d-8573-8af4b2f30a31:98b41857-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc1' direction 'FIRST' \"\n", - " \"sequence '1624005475720919509'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '086e595c-0989-4f3d-8573-8af4b2f30a31:98b41853-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185915, 'nano': 119489000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '086e595c-0989-4f3d-8573-8af4b2f30a31',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185915, 'nano': 119589000},\n", - " 'eventId': '086e595c-0989-4f3d-8573-8af4b2f30a31:98b41858-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn2' direction 'FIRST' \"\n", - " \"sequence '1624005448022245405'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '086e595c-0989-4f3d-8573-8af4b2f30a31:98b41853-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185915, 'nano': 119489000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '086e595c-0989-4f3d-8573-8af4b2f30a31',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185915, 'nano': 119589000},\n", - " 'eventId': '086e595c-0989-4f3d-8573-8af4b2f30a31:98b41859-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn2' direction 'SECOND' \"\n", - " \"sequence '1624005448022426115'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '086e595c-0989-4f3d-8573-8af4b2f30a31:98b41853-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185915, 'nano': 119489000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '086e595c-0989-4f3d-8573-8af4b2f30a31',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185915, 'nano': 119589000},\n", - " 'eventId': '086e595c-0989-4f3d-8573-8af4b2f30a31:98b4185a-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc2' direction 'SECOND' \"\n", - " \"sequence '1624005466840347016'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '086e595c-0989-4f3d-8573-8af4b2f30a31:98b41853-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185915, 'nano': 119489000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '086e595c-0989-4f3d-8573-8af4b2f30a31',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185915, 'nano': 119589000},\n", - " 'eventId': '086e595c-0989-4f3d-8573-8af4b2f30a31:98b4185b-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc2' direction 'FIRST' \"\n", - " \"sequence '1624005466840263378'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '086e595c-0989-4f3d-8573-8af4b2f30a31:98b41853-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185915, 'nano': 119489000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '086e595c-0989-4f3d-8573-8af4b2f30a31',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185915, 'nano': 119589000},\n", - " 'eventId': '086e595c-0989-4f3d-8573-8af4b2f30a31:98b4185c-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn1' direction 'FIRST' \"\n", - " \"sequence '1624005455622011532'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '086e595c-0989-4f3d-8573-8af4b2f30a31:98b41853-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185915, 'nano': 119489000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '086e595c-0989-4f3d-8573-8af4b2f30a31',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185915, 'nano': 119589000},\n", - " 'eventId': '086e595c-0989-4f3d-8573-8af4b2f30a31:98b4185d-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-log' direction 'FIRST' \"\n", - " \"sequence '1624029363623063053'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '086e595c-0989-4f3d-8573-8af4b2f30a31:98b41853-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185915, 'nano': 119489000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'rows': {'AccountType': {'columns': {'fieldValue': '1'},\n", - " 'type': 'row'},\n", - " 'ClOrdID': {'columns': {'fieldValue': '1975411'},\n", - " 'type': 'row'},\n", - " 'OrdType': {'columns': {'fieldValue': '2'}, 'type': 'row'},\n", - " 'OrderCapacity': {'columns': {'fieldValue': 'A'},\n", - " 'type': 'row'},\n", - " 'OrderQty': {'columns': {'fieldValue': '100'},\n", - " 'type': 'row'},\n", - " 'Price': {'columns': {'fieldValue': '74'}, 'type': 'row'},\n", - " 'SecondaryClOrdID': {'columns': {'fieldValue': '33333'},\n", - " 'type': 'row'},\n", - " 'SecurityID': {'columns': {'fieldValue': 'INSTR3'},\n", - " 'type': 'row'},\n", - " 'SecurityIDSource': {'columns': {'fieldValue': '8'},\n", - " 'type': 'row'},\n", - " 'Side': {'columns': {'fieldValue': '2'}, 'type': 'row'},\n", - " 'TimeInForce': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'},\n", - " 'TradingParty': {'rows': {'NoPartyIDs': {'rows': {'0': {'rows': {'PartyID': {'columns': {'fieldValue': 'DEMO-CONN2'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'D'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '76'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '1': {'rows': {'PartyID': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '2': {'rows': {'PartyID': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '122'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '3': {'rows': {'PartyID': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '12'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'columns': {'fieldValue': '2021-06-20T13:45:07.898232'},\n", - " 'type': 'row'}},\n", - " 'type': 'treeTable'}],\n", - " 'endTimestamp': {'epochSecond': 1624185915, 'nano': 121897000},\n", - " 'eventId': '98b46667-d1b4-11eb-bae5-57b0c4472880',\n", - " 'eventName': \"Send 'NewOrderSingle' message to connectivity\",\n", - " 'eventType': 'Outgoing message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '98b095d6-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185915, 'nano': 121827000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185915, 'nano': 139523000},\n", - " 'eventId': '98b72533-d1b4-11eb-bd0a-0d6cee9f6833',\n", - " 'eventName': \"Send 'NewOrderSingle' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '98b095d6-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185915, 'nano': 139418000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185915, 'nano': 449896000},\n", - " 'eventId': '98e6732d-d1b4-11eb-a9f4-b12655548efc',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '849a79d3-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185915, 'nano': 449891000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185915, 'nano': 455004000},\n", - " 'eventId': '98e75d8e-d1b4-11eb-a9f4-b12655548efc',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '849a79d3-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185915, 'nano': 455000000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185915, 'nano': 457013000},\n", - " 'eventId': '98e7abd0-d1b4-11eb-a9ed-ffb57363e013',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '849a79d3-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185915, 'nano': 457001000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185915, 'nano': 461583000},\n", - " 'eventId': '98e84811-d1b4-11eb-a9ed-ffb57363e013',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '849a79d3-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185915, 'nano': 461579000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185915, 'nano': 471527000},\n", - " 'eventId': '98e9ce12-d1b4-11eb-91f0-77dd26d4db8e',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '849a79d3-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185915, 'nano': 471498000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185915, 'nano': 475524000},\n", - " 'eventId': '98ea6a53-d1b4-11eb-91f0-77dd26d4db8e',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '849a79d3-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185915, 'nano': 475513000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185915, 'nano': 476027000},\n", - " 'eventId': '98ea9193-d1b4-11eb-be23-57049e5b0bd9',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '849a79d3-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185915, 'nano': 476001000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185915, 'nano': 528021000},\n", - " 'eventId': '98f25994-d1b4-11eb-91f0-77dd26d4db8e',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '849a79d3-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185915, 'nano': 527994000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185915, 'nano': 549371000},\n", - " 'eventId': '98f5b524-d1b4-11eb-be23-57049e5b0bd9',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '849a79d3-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185915, 'nano': 549343000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'rows': {'AccountType': {'columns': {'fieldValue': '1'},\n", - " 'type': 'row'},\n", - " 'ClOrdID': {'columns': {'fieldValue': '1975411'},\n", - " 'type': 'row'},\n", - " 'CumQty': {'columns': {'fieldValue': '10'}, 'type': 'row'},\n", - " 'ExecID': {'columns': {'fieldValue': '2370'},\n", - " 'type': 'row'},\n", - " 'ExecType': {'columns': {'fieldValue': 'F'}, 'type': 'row'},\n", - " 'LastPx': {'columns': {'fieldValue': '76'}, 'type': 'row'},\n", - " 'LeavesQty': {'columns': {'fieldValue': '90'},\n", - " 'type': 'row'},\n", - " 'OrdStatus': {'columns': {'fieldValue': '1'},\n", - " 'type': 'row'},\n", - " 'OrdType': {'columns': {'fieldValue': '2'}, 'type': 'row'},\n", - " 'OrderCapacity': {'columns': {'fieldValue': 'A'},\n", - " 'type': 'row'},\n", - " 'OrderID': {'columns': {'fieldValue': '875'},\n", - " 'type': 'row'},\n", - " 'OrderQty': {'columns': {'fieldValue': '100'},\n", - " 'type': 'row'},\n", - " 'Price': {'columns': {'fieldValue': '74'}, 'type': 'row'},\n", - " 'SecurityID': {'columns': {'fieldValue': 'INSTR3'},\n", - " 'type': 'row'},\n", - " 'SecurityIDSource': {'columns': {'fieldValue': '8'},\n", - " 'type': 'row'},\n", - " 'Side': {'columns': {'fieldValue': '2'}, 'type': 'row'},\n", - " 'Text': {'columns': {'fieldValue': 'The simulated order '\n", - " 'has been partially '\n", - " 'traded'},\n", - " 'type': 'row'},\n", - " 'TimeInForce': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'},\n", - " 'TradingParty': {'rows': {'NoPartyIDs': {'rows': {'0': {'rows': {'PartyID': {'columns': {'fieldValue': 'DEMO-CONN2'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'D'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '76'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '1': {'rows': {'PartyID': {'columns': {'fieldValue': 'DEMOFIRM1'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'D'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '17'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '2': {'rows': {'PartyID': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '3': {'rows': {'PartyID': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '122'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '4': {'rows': {'PartyID': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '12'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'columns': {'fieldValue': '2021-06-20T10:45:15'},\n", - " 'type': 'row'},\n", - " 'TrdMatchID': {'columns': {'fieldValue': '485'},\n", - " 'type': 'row'},\n", - " 'header': {'rows': {'BeginString': {'columns': {'fieldValue': 'FIXT.1.1'},\n", - " 'type': 'row'},\n", - " 'BodyLength': {'columns': {'fieldValue': '370'},\n", - " 'type': 'row'},\n", - " 'MsgSeqNum': {'columns': {'fieldValue': '1297'},\n", - " 'type': 'row'},\n", - " 'MsgType': {'columns': {'fieldValue': '8'},\n", - " 'type': 'row'},\n", - " 'SenderCompID': {'columns': {'fieldValue': 'FGW'},\n", - " 'type': 'row'},\n", - " 'SendingTime': {'columns': {'fieldValue': '2021-06-20T10:45:15.468'},\n", - " 'type': 'row'},\n", - " 'TargetCompID': {'columns': {'fieldValue': 'DEMO-CONN2'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " 'trailer': {'rows': {'CheckSum': {'columns': {'fieldValue': '235'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'treeTable'}],\n", - " 'endTimestamp': {'epochSecond': 1624185915, 'nano': 550922000},\n", - " 'eventId': '98f5dc38-d1b4-11eb-bae5-57b0c4472880',\n", - " 'eventName': \"Received 'ExecutionReport' response message\",\n", - " 'eventType': 'message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '98b095d6-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185915, 'nano': 550552000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185915, 'nano': 555404000},\n", - " 'eventId': '98f69f85-d1b4-11eb-be23-57049e5b0bd9',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '849a79d3-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185915, 'nano': 555390000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '5421e1d4-bd2b-4a25-95e0-580d5c8e6750',\n", - " 'body': {'data': 'The message was deleted because a new one came with the '\n", - " \"same hash '-2705192066397611092' in message group \"\n", - " \"'NOS_CONN'\\n\"\n", - " ' Message not matched',\n", - " 'type': 'message'},\n", - " 'endTimestamp': {'epochSecond': 1624185915, 'nano': 638586000},\n", - " 'eventId': '5421e1d4-bd2b-4a25-95e0-580d5c8e6750:99036d50-d1b4-11eb-986f-1e8d42132387',\n", - " 'eventName': \"Remove 'NewOrderSingle' \"\n", - " \"id='demo-conn2:SECOND:1624005448022421038' \"\n", - " \"Hash='-2705192066397611092' Group='NOS_CONN' \"\n", - " \"Hash['SecondaryClOrdID': 33333, 'SecurityID': INSTR3]\",\n", - " 'eventType': '',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'a3779b94-d051-11eb-986f-1e8d42132387',\n", - " 'startTimestamp': {'epochSecond': 1624185915, 'nano': 638586000},\n", - " 'successful': False,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'data': 'STEP6: Trader \"DEMO-CONN1\" receives Execution Reports with '\n", - " 'ExecType=F: first at Order2 and second on Order1.',\n", - " 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185916, 'nano': 29604000},\n", - " 'eventId': '992fb0fe-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Check sequence rule SessionKey{sessionAlias='demo-conn1', \"\n", - " 'direction=FIRST} - STEP6: Trader \"DEMO-CONN1\" receives '\n", - " 'Execution Reports with ExecType=F: first at Order2 and second '\n", - " 'on Order1.',\n", - " 'eventType': 'checkSequenceRule',\n", - " 'isBatched': False,\n", - " 'parentEventId': '9465ea7a-d1b4-11eb-b0fb-199708acc7bc',\n", - " 'startTimestamp': {'epochSecond': 1624185915, 'nano': 929958000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'data': 'Contains comparisons', 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185916, 'nano': 118694000},\n", - " 'eventId': '993ef343-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Check messages',\n", - " 'eventType': 'checkMessages',\n", - " 'isBatched': False,\n", - " 'parentEventId': '992fb0fe-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185915, 'nano': 929958000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '79b111a6-4a29-4ae8-9a23-d961718e859e',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '6061277',\n", - " 'expected': '6061277',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '10',\n", - " 'expected': '10',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2368',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': 'F',\n", - " 'expected': 'F',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LastPx': {'actual': '76',\n", - " 'expected': '76',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '2',\n", - " 'expected': '2',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': '2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'A',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '874',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '10',\n", - " 'expected': '10',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '76',\n", - " 'expected': '76',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR3',\n", - " 'expected': 'INSTR3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'The simulated order has been fully '\n", - " 'traded',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TimeInForce': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {'NoPartyIDs': {'actual': '5',\n", - " 'expected': '5',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'DEMO-CONN1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': '76',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMOFIRM2',\n", - " 'expected': 'DEMOFIRM2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '17',\n", - " 'expected': '17',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': '122',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '4': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': '12',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:15',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TrdMatchID': {'actual': '485',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': '7',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'FIXT.1.1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '364',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1301',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:15.456',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'DEMO-CONN1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '211',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185916, 'nano': 118705000},\n", - " 'eventId': '79b111a6-4a29-4ae8-9a23-d961718e859e:993ef344-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '993ef343-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185915, 'nano': 929958000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '79b111a6-4a29-4ae8-9a23-d961718e859e',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '3774265',\n", - " 'expected': '3774265',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '30',\n", - " 'expected': '30',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2369',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': 'F',\n", - " 'expected': 'F',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LastPx': {'actual': '75',\n", - " 'expected': '75',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '2',\n", - " 'expected': '2',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': '2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'A',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '873',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '30',\n", - " 'expected': '30',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '75',\n", - " 'expected': '75',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR3',\n", - " 'expected': 'INSTR3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'The simulated order has been fully '\n", - " 'traded',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TimeInForce': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {'NoPartyIDs': {'actual': '5',\n", - " 'expected': '5',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'DEMO-CONN1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': '76',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMOFIRM2',\n", - " 'expected': 'DEMOFIRM2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '17',\n", - " 'expected': '17',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': '122',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '4': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': '12',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:15',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TrdMatchID': {'actual': '486',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': '7',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'FIXT.1.1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '364',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1302',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:15.460',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'DEMO-CONN1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '215',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185916, 'nano': 118911000},\n", - " 'eventId': '79b111a6-4a29-4ae8-9a23-d961718e859e:993ef345-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '993ef343-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185915, 'nano': 929958000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'f0ecdbc8-c66b-4b28-8587-791fc40c2d2b',\n", - " 'body': [{'data': 'Expected 2, Actual 2, In order', 'type': 'message'},\n", - " {'rows': [{'actualMessage': 'ExecutionReport, demo-conn1, '\n", - " 'OrdStatus=2, LeavesQty=0, '\n", - " 'ClOrdID=6061277, CumQty=10',\n", - " 'actualMetadata': 'Metadata, demo-conn1',\n", - " 'expectedMessage': 'ExecutionReport, demo-conn1, '\n", - " 'OrdStatus=2, LeavesQty=0, '\n", - " 'ClOrdID=6061277, CumQty=10',\n", - " 'expectedMetadata': 'Metadata, demo-conn1'},\n", - " {'actualMessage': 'ExecutionReport, demo-conn1, '\n", - " 'ClOrdID=3774265, LeavesQty=0, '\n", - " 'OrdStatus=2, CumQty=30',\n", - " 'actualMetadata': 'Metadata, demo-conn1',\n", - " 'expectedMessage': 'ExecutionReport, demo-conn1, '\n", - " 'ClOrdID=3774265, LeavesQty=0, '\n", - " 'OrdStatus=2, CumQty=30',\n", - " 'expectedMetadata': 'Metadata, demo-conn1'}],\n", - " 'type': 'table'}],\n", - " 'endTimestamp': {'epochSecond': 1624185916, 'nano': 118528000},\n", - " 'eventId': 'f0ecdbc8-c66b-4b28-8587-791fc40c2d2b:993ef342-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Check sequence (expected 2 / actual 2 , check order true)',\n", - " 'eventType': 'checkSequence',\n", - " 'isBatched': True,\n", - " 'parentEventId': '992fb0fe-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185915, 'nano': 929958000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '1ae1119d-679c-4938-ad5f-d9492016061b',\n", - " 'body': {'fields': {'AccountType': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '1975411',\n", - " 'expected': '6061277',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '10',\n", - " 'expected': '10',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2370',\n", - " 'expected': '2368',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': 'F',\n", - " 'expected': 'F',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LastPx': {'actual': '76',\n", - " 'expected': '76',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '90',\n", - " 'expected': '0',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '1',\n", - " 'expected': '2',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': '2',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'A',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '875',\n", - " 'expected': '874',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '100',\n", - " 'expected': '10',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '74',\n", - " 'expected': '76',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR3',\n", - " 'expected': 'INSTR3',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': '8',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '2',\n", - " 'expected': '1',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'The simulated order has been '\n", - " 'partially traded',\n", - " 'expected': 'The simulated order has been fully '\n", - " 'traded',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TimeInForce': {'actual': '3',\n", - " 'expected': '0',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {'NoPartyIDs': {'actual': '5',\n", - " 'expected': '5',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'DEMO-CONN1',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': '76',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMOFIRM1',\n", - " 'expected': 'DEMOFIRM2',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '17',\n", - " 'expected': '17',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': '122',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '4': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': '12',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:15',\n", - " 'expected': '2021-06-20T10:45:15',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TrdMatchID': {'actual': '485',\n", - " 'expected': '485',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': '7',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'FIXT.1.1',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '370',\n", - " 'expected': '364',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1297',\n", - " 'expected': '1301',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': '8',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': 'FGW',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:15.468',\n", - " 'expected': '2021-06-20T10:45:15.456',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'DEMO-CONN1',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {'CheckSum': {'actual': '235',\n", - " 'expected': '211',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'status': 0,\n", - " 'type': 'verification'},\n", - " 'endTimestamp': {'epochSecond': 1624185915, 'nano': 944994000},\n", - " 'eventId': '1ae1119d-679c-4938-ad5f-d9492016061b:99322852-d1b4-11eb-986f-1e8d42132387',\n", - " 'eventName': \"Match by '['TrdMatchID': 485]'\",\n", - " 'eventType': '',\n", - " 'isBatched': True,\n", - " 'parentEventId': '6e86db98-d047-11eb-986f-1e8d42132387',\n", - " 'startTimestamp': {'epochSecond': 1624185915, 'nano': 944994000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '1ae1119d-679c-4938-ad5f-d9492016061b',\n", - " 'body': {'fields': {'AccountType': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '1975411',\n", - " 'expected': '3774265',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '40',\n", - " 'expected': '30',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2371',\n", - " 'expected': '2369',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': 'F',\n", - " 'expected': 'F',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LastPx': {'actual': '75',\n", - " 'expected': '75',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '60',\n", - " 'expected': '0',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '1',\n", - " 'expected': '2',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': '2',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'A',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '875',\n", - " 'expected': '873',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '100',\n", - " 'expected': '30',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '74',\n", - " 'expected': '75',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR3',\n", - " 'expected': 'INSTR3',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': '8',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '2',\n", - " 'expected': '1',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'The simulated order has been '\n", - " 'partially traded',\n", - " 'expected': 'The simulated order has been fully '\n", - " 'traded',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TimeInForce': {'actual': '3',\n", - " 'expected': '0',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {'NoPartyIDs': {'actual': '5',\n", - " 'expected': '5',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'DEMO-CONN1',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': '76',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMOFIRM1',\n", - " 'expected': 'DEMOFIRM2',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '17',\n", - " 'expected': '17',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': '122',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '4': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': '12',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:15',\n", - " 'expected': '2021-06-20T10:45:15',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TrdMatchID': {'actual': '486',\n", - " 'expected': '486',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': '7',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'FIXT.1.1',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '370',\n", - " 'expected': '364',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1298',\n", - " 'expected': '1302',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': '8',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': 'FGW',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:15.469',\n", - " 'expected': '2021-06-20T10:45:15.460',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'DEMO-CONN1',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {'CheckSum': {'actual': '238',\n", - " 'expected': '215',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'status': 0,\n", - " 'type': 'verification'},\n", - " 'endTimestamp': {'epochSecond': 1624185915, 'nano': 972905000},\n", - " 'eventId': '1ae1119d-679c-4938-ad5f-d9492016061b:99366aac-d1b4-11eb-986f-1e8d42132387',\n", - " 'eventName': \"Match by '['TrdMatchID': 486]'\",\n", - " 'eventType': '',\n", - " 'isBatched': True,\n", - " 'parentEventId': '6e86db98-d047-11eb-986f-1e8d42132387',\n", - " 'startTimestamp': {'epochSecond': 1624185915, 'nano': 972905000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'rows': {'comparison-settings': {'rows': {'ignore-fields': {'rows': {},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'},\n", - " 'message-filter': {'rows': {'SecurityID': {'columns': {'expected': 'INSTR3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " 'message-type': {'columns': {'type': 'PreFilter'},\n", - " 'type': 'row'},\n", - " 'metadata-filter': {'rows': {}, 'type': 'collection'}},\n", - " 'type': 'treeTable'}],\n", - " 'endTimestamp': {'epochSecond': 1624185916, 'nano': 29642000},\n", - " 'eventId': '993de1cf-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Pre-filtering (filtered 2 / processed 2) messages',\n", - " 'eventType': 'preFiltering',\n", - " 'isBatched': False,\n", - " 'parentEventId': '992fb0fe-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185916, 'nano': 22973000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '243c5259-0247-458a-85bd-89cb0dc50317',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '6061277',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '10',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2368',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': 'F',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LastPx': {'actual': '76',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '874',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '10',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '76',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR3',\n", - " 'expected': 'INSTR3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'The simulated order has been fully '\n", - " 'traded',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TimeInForce': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'NoPartyIDs': {'actual': '5',\n", - " 'expected': 'null',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': 'DEMOFIRM2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '17',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '4': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:15',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TrdMatchID': {'actual': '485',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': 'null',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '364',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1301',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:15.456',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '211',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185916, 'nano': 29696000},\n", - " 'eventId': '243c5259-0247-458a-85bd-89cb0dc50317:993e5700-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '993de1cf-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185916, 'nano': 22973000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '243c5259-0247-458a-85bd-89cb0dc50317',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '3774265',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '30',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2369',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': 'F',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LastPx': {'actual': '75',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '873',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '30',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '75',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR3',\n", - " 'expected': 'INSTR3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'The simulated order has been fully '\n", - " 'traded',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TimeInForce': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'NoPartyIDs': {'actual': '5',\n", - " 'expected': 'null',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': 'DEMOFIRM2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '17',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '4': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:15',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TrdMatchID': {'actual': '486',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': 'null',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '364',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1302',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:15.460',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '215',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185916, 'nano': 29771000},\n", - " 'eventId': '243c5259-0247-458a-85bd-89cb0dc50317:993ecc31-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '993de1cf-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185916, 'nano': 22973000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'data': 'STEP7: Trader \"DEMO-CONN2\" receives Execution Reports: '\n", - " 'first trade with Order2, next with Order1 and then '\n", - " 'cancellation',\n", - " 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185916, 'nano': 534937000},\n", - " 'eventId': '99505866-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Check sequence rule SessionKey{sessionAlias='demo-conn2', \"\n", - " 'direction=FIRST} - STEP7: Trader \"DEMO-CONN2\" receives '\n", - " 'Execution Reports: first trade with Order2, next with Order1 '\n", - " 'and then cancellation',\n", - " 'eventType': 'checkSequenceRule',\n", - " 'isBatched': False,\n", - " 'parentEventId': '9465ea7a-d1b4-11eb-b0fb-199708acc7bc',\n", - " 'startTimestamp': {'epochSecond': 1624185916, 'nano': 143638000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'data': 'Contains comparisons', 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185916, 'nano': 535235000},\n", - " 'eventId': '998c01dc-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Check messages',\n", - " 'eventType': 'checkMessages',\n", - " 'isBatched': False,\n", - " 'parentEventId': '99505866-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185916, 'nano': 143638000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '294e4c48-7ea5-4068-9b71-b464bdd2cef1',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '1975411',\n", - " 'expected': '1975411',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '10',\n", - " 'expected': '10',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2370',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': 'F',\n", - " 'expected': 'F',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LastPx': {'actual': '76',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '90',\n", - " 'expected': '90',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': '2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'A',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '875',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " 'OrderQty': {'actual': '100',\n", - " 'expected': '100',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '74',\n", - " 'expected': '74',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR3',\n", - " 'expected': 'INSTR3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '2',\n", - " 'expected': '2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'The simulated order has been '\n", - " 'partially traded',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TimeInForce': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {'NoPartyIDs': {'actual': '5',\n", - " 'expected': '5',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'DEMO-CONN2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': '76',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMOFIRM1',\n", - " 'expected': 'DEMOFIRM1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '17',\n", - " 'expected': '17',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': '122',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '4': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': '12',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:15',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TrdMatchID': {'actual': '485',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': '7',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'FIXT.1.1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '370',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1297',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:15.468',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'DEMO-CONN2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '235',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185916, 'nano': 535238000},\n", - " 'eventId': '294e4c48-7ea5-4068-9b71-b464bdd2cef1:998c01dd-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '998c01dc-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185916, 'nano': 143638000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '294e4c48-7ea5-4068-9b71-b464bdd2cef1',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '1975411',\n", - " 'expected': '1975411',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '40',\n", - " 'expected': '40',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2371',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': 'F',\n", - " 'expected': 'F',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LastPx': {'actual': '75',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '60',\n", - " 'expected': '60',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': '2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'A',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '875',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '100',\n", - " 'expected': '100',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '74',\n", - " 'expected': '74',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR3',\n", - " 'expected': 'INSTR3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '2',\n", - " 'expected': '2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'The simulated order has been '\n", - " 'partially traded',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TimeInForce': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {'NoPartyIDs': {'actual': '5',\n", - " 'expected': '5',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'DEMO-CONN2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': '76',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMOFIRM1',\n", - " 'expected': 'DEMOFIRM1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '17',\n", - " 'expected': '17',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': '122',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '4': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': '12',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:15',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TrdMatchID': {'actual': '486',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': '7',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'FIXT.1.1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '370',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1298',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:15.469',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'DEMO-CONN2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '238',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185916, 'nano': 535280000},\n", - " 'eventId': '294e4c48-7ea5-4068-9b71-b464bdd2cef1:998c01de-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '998c01dc-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185916, 'nano': 143638000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '294e4c48-7ea5-4068-9b71-b464bdd2cef1',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '1975411',\n", - " 'expected': '1975411',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '40',\n", - " 'expected': '40',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2372',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': 'C',\n", - " 'expected': 'C',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': 'C',\n", - " 'expected': 'C',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': '2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'A',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '875',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '100',\n", - " 'expected': '100',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '74',\n", - " 'expected': '74',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR3',\n", - " 'expected': 'INSTR3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '2',\n", - " 'expected': '2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'The remaining part of simulated '\n", - " 'order has been expired',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TimeInForce': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {'NoPartyIDs': {'actual': '4',\n", - " 'expected': '4',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'DEMO-CONN2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': '76',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': '122',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': '12',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:15',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': '7',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'FIXT.1.1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '337',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1299',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:15.527',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'DEMO-CONN2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '165',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185916, 'nano': 535328000},\n", - " 'eventId': '294e4c48-7ea5-4068-9b71-b464bdd2cef1:998c01df-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '998c01dc-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185916, 'nano': 143638000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'e9add0fe-c565-4112-84a1-fbaa321456b1',\n", - " 'body': [{'data': 'Expected 3, Actual 3, In order', 'type': 'message'},\n", - " {'rows': [{'actualMessage': 'ExecutionReport, demo-conn2, '\n", - " 'LeavesQty=90, OrdStatus=1, '\n", - " 'ClOrdID=1975411, CumQty=10',\n", - " 'actualMetadata': 'Metadata, demo-conn2',\n", - " 'expectedMessage': 'ExecutionReport, demo-conn2, '\n", - " 'LeavesQty=90, OrdStatus=1, '\n", - " 'ClOrdID=1975411, CumQty=10',\n", - " 'expectedMetadata': 'Metadata, demo-conn2'},\n", - " {'actualMessage': 'ExecutionReport, demo-conn2, CumQty=40, '\n", - " 'ClOrdID=1975411, LeavesQty=60, '\n", - " 'OrdStatus=1',\n", - " 'actualMetadata': 'Metadata, demo-conn2',\n", - " 'expectedMessage': 'ExecutionReport, demo-conn2, '\n", - " 'CumQty=40, ClOrdID=1975411, '\n", - " 'LeavesQty=60, OrdStatus=1',\n", - " 'expectedMetadata': 'Metadata, demo-conn2'},\n", - " {'actualMessage': 'ExecutionReport, demo-conn2, '\n", - " 'ClOrdID=1975411, OrdStatus=C, '\n", - " 'LeavesQty=0, CumQty=40',\n", - " 'actualMetadata': 'Metadata, demo-conn2',\n", - " 'expectedMessage': 'ExecutionReport, demo-conn2, '\n", - " 'ClOrdID=1975411, OrdStatus=C, '\n", - " 'LeavesQty=0, CumQty=40',\n", - " 'expectedMetadata': 'Metadata, demo-conn2'}],\n", - " 'type': 'table'}],\n", - " 'endTimestamp': {'epochSecond': 1624185916, 'nano': 535212000},\n", - " 'eventId': 'e9add0fe-c565-4112-84a1-fbaa321456b1:998c01db-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Check sequence (expected 3 / actual 3 , check order true)',\n", - " 'eventType': 'checkSequence',\n", - " 'isBatched': True,\n", - " 'parentEventId': '99505866-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185916, 'nano': 143638000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'rows': {'comparison-settings': {'rows': {'ignore-fields': {'rows': {},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'},\n", - " 'message-filter': {'rows': {'SecurityID': {'columns': {'expected': 'INSTR3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " 'message-type': {'columns': {'type': 'PreFilter'},\n", - " 'type': 'row'},\n", - " 'metadata-filter': {'rows': {}, 'type': 'collection'}},\n", - " 'type': 'treeTable'}],\n", - " 'endTimestamp': {'epochSecond': 1624185916, 'nano': 534977000},\n", - " 'eventId': '995169d7-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Pre-filtering (filtered 3 / processed 3) messages',\n", - " 'eventType': 'preFiltering',\n", - " 'isBatched': False,\n", - " 'parentEventId': '99505866-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185916, 'nano': 150159000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '7dc67598-1716-4618-9c88-474f095f7c5a',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '1975411',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '10',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2370',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': 'F',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LastPx': {'actual': '76',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '90',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '875',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '100',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '74',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR3',\n", - " 'expected': 'INSTR3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'The simulated order has been '\n", - " 'partially traded',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TimeInForce': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'NoPartyIDs': {'actual': '5',\n", - " 'expected': 'null',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': 'DEMOFIRM1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '17',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '4': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:15',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TrdMatchID': {'actual': '485',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': 'null',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '370',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1297',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:15.468',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '235',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185916, 'nano': 535027000},\n", - " 'eventId': '7dc67598-1716-4618-9c88-474f095f7c5a:995365a8-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '995169d7-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185916, 'nano': 150159000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '7dc67598-1716-4618-9c88-474f095f7c5a',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '1975411',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '40',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2371',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': 'F',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LastPx': {'actual': '75',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '60',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '875',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '100',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '74',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR3',\n", - " 'expected': 'INSTR3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'The simulated order has been '\n", - " 'partially traded',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TimeInForce': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'NoPartyIDs': {'actual': '5',\n", - " 'expected': 'null',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': 'DEMOFIRM1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '17',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '4': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:15',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TrdMatchID': {'actual': '486',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': 'null',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " 'BodyLength': {'actual': '370',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1298',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:15.469',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '238',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185916, 'nano': 535113000},\n", - " 'eventId': '7dc67598-1716-4618-9c88-474f095f7c5a:995c3f49-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '995169d7-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185916, 'nano': 150159000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '7dc67598-1716-4618-9c88-474f095f7c5a',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '1975411',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '40',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2372',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': 'C',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': 'C',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '875',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '100',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '74',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR3',\n", - " 'expected': 'INSTR3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'The remaining part of simulated '\n", - " 'order has been expired',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TimeInForce': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'NoPartyIDs': {'actual': '4',\n", - " 'expected': 'null',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:15',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': 'null',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '337',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1299',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:15.527',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '165',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185916, 'nano': 535169000},\n", - " 'eventId': '7dc67598-1716-4618-9c88-474f095f7c5a:998bdaca-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '995169d7-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185916, 'nano': 150159000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': {},\n", - " 'endTimestamp': {'epochSecond': 1624185916, 'nano': 172538000},\n", - " 'eventId': '9954d104-d1b4-11eb-b0fb-199708acc7bc',\n", - " 'eventName': 'Case[TC_1.4]: Trader DEMO-CONN1 vs trader DEMO-CONN2 for '\n", - " 'instrument INSTR4',\n", - " 'eventType': '',\n", - " 'isBatched': False,\n", - " 'parentEventId': '84db48fc-d1b4-11eb-b0fb-199708acc7bc',\n", - " 'startTimestamp': {'epochSecond': 1624185916, 'nano': 172487000},\n", - " 'successful': False,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'data': 'STEP1: Trader \"DEMO-CONN1\" sends request to create passive '\n", - " 'Order.',\n", - " 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185921, 'nano': 231287000},\n", - " 'eventId': '9c58b649-d1b4-11eb-bae5-57b0c4472880',\n", - " 'eventName': 'placeOrderFIX demo-conn1 - STEP1: Trader \"DEMO-CONN1\" sends '\n", - " 'request to create passive Order.',\n", - " 'eventType': 'placeOrderFIX',\n", - " 'isBatched': False,\n", - " 'parentEventId': '9954d104-d1b4-11eb-b0fb-199708acc7bc',\n", - " 'startTimestamp': {'epochSecond': 1624185921, 'nano': 231222000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '77739bdd-7658-4d9f-aa71-ac16a5ec9f3c',\n", - " 'body': [{'data': \"Checkpoint id '9c597940-d1b4-11eb-ba78-1981398e00bd'\",\n", - " 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185921, 'nano': 237064000},\n", - " 'eventId': '77739bdd-7658-4d9f-aa71-ac16a5ec9f3c:9c5979c0-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Checkpoint',\n", - " 'eventType': 'Checkpoint',\n", - " 'isBatched': True,\n", - " 'parentEventId': '9c58b649-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185921, 'nano': 236901000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '77739bdd-7658-4d9f-aa71-ac16a5ec9f3c',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185921, 'nano': 237064000},\n", - " 'eventId': '77739bdd-7658-4d9f-aa71-ac16a5ec9f3c:9c59a0d1-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'th2-hand-demo' direction 'FIRST' \"\n", - " \"sequence '1623852603564709030'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '77739bdd-7658-4d9f-aa71-ac16a5ec9f3c:9c5979c0-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185921, 'nano': 236901000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '77739bdd-7658-4d9f-aa71-ac16a5ec9f3c',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185921, 'nano': 237064000},\n", - " 'eventId': '77739bdd-7658-4d9f-aa71-ac16a5ec9f3c:9c59a0d2-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn1' direction 'SECOND' \"\n", - " \"sequence '1624005455622140295'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '77739bdd-7658-4d9f-aa71-ac16a5ec9f3c:9c5979c0-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185921, 'nano': 236901000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '77739bdd-7658-4d9f-aa71-ac16a5ec9f3c',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185921, 'nano': 237064000},\n", - " 'eventId': '77739bdd-7658-4d9f-aa71-ac16a5ec9f3c:9c59a0d3-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc1' direction 'SECOND' \"\n", - " \"sequence '1624005475721015015'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '77739bdd-7658-4d9f-aa71-ac16a5ec9f3c:9c5979c0-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185921, 'nano': 236901000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '77739bdd-7658-4d9f-aa71-ac16a5ec9f3c',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185921, 'nano': 237064000},\n", - " 'eventId': '77739bdd-7658-4d9f-aa71-ac16a5ec9f3c:9c59a0d4-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc1' direction 'FIRST' \"\n", - " \"sequence '1624005475720919511'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '77739bdd-7658-4d9f-aa71-ac16a5ec9f3c:9c5979c0-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185921, 'nano': 236901000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '77739bdd-7658-4d9f-aa71-ac16a5ec9f3c',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185921, 'nano': 237064000},\n", - " 'eventId': '77739bdd-7658-4d9f-aa71-ac16a5ec9f3c:9c59a0d5-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn2' direction 'FIRST' \"\n", - " \"sequence '1624005448022245408'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '77739bdd-7658-4d9f-aa71-ac16a5ec9f3c:9c5979c0-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185921, 'nano': 236901000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '77739bdd-7658-4d9f-aa71-ac16a5ec9f3c',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185921, 'nano': 237064000},\n", - " 'eventId': '77739bdd-7658-4d9f-aa71-ac16a5ec9f3c:9c59a0d6-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn2' direction 'SECOND' \"\n", - " \"sequence '1624005448022426116'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '77739bdd-7658-4d9f-aa71-ac16a5ec9f3c:9c5979c0-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185921, 'nano': 236901000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '77739bdd-7658-4d9f-aa71-ac16a5ec9f3c',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185921, 'nano': 237064000},\n", - " 'eventId': '77739bdd-7658-4d9f-aa71-ac16a5ec9f3c:9c59a0d7-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc2' direction 'SECOND' \"\n", - " \"sequence '1624005466840347016'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '77739bdd-7658-4d9f-aa71-ac16a5ec9f3c:9c5979c0-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185921, 'nano': 236901000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '77739bdd-7658-4d9f-aa71-ac16a5ec9f3c',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185921, 'nano': 237064000},\n", - " 'eventId': '77739bdd-7658-4d9f-aa71-ac16a5ec9f3c:9c59a0d8-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc2' direction 'FIRST' \"\n", - " \"sequence '1624005466840263381'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '77739bdd-7658-4d9f-aa71-ac16a5ec9f3c:9c5979c0-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185921, 'nano': 236901000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '77739bdd-7658-4d9f-aa71-ac16a5ec9f3c',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185921, 'nano': 237064000},\n", - " 'eventId': '77739bdd-7658-4d9f-aa71-ac16a5ec9f3c:9c59a0d9-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn1' direction 'FIRST' \"\n", - " \"sequence '1624005455622011534'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '77739bdd-7658-4d9f-aa71-ac16a5ec9f3c:9c5979c0-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185921, 'nano': 236901000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '77739bdd-7658-4d9f-aa71-ac16a5ec9f3c',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185921, 'nano': 237064000},\n", - " 'eventId': '77739bdd-7658-4d9f-aa71-ac16a5ec9f3c:9c59a0da-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-log' direction 'FIRST' \"\n", - " \"sequence '1624029363623063053'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '77739bdd-7658-4d9f-aa71-ac16a5ec9f3c:9c5979c0-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185921, 'nano': 236901000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'rows': {'AccountType': {'columns': {'fieldValue': '1'},\n", - " 'type': 'row'},\n", - " 'ClOrdID': {'columns': {'fieldValue': '2255277'},\n", - " 'type': 'row'},\n", - " 'OrdType': {'columns': {'fieldValue': '2'}, 'type': 'row'},\n", - " 'OrderCapacity': {'columns': {'fieldValue': 'A'},\n", - " 'type': 'row'},\n", - " 'OrderQty': {'columns': {'fieldValue': '30'},\n", - " 'type': 'row'},\n", - " 'Price': {'columns': {'fieldValue': '45'}, 'type': 'row'},\n", - " 'SecondaryClOrdID': {'columns': {'fieldValue': '11111'},\n", - " 'type': 'row'},\n", - " 'SecurityID': {'columns': {'fieldValue': 'INSTR4'},\n", - " 'type': 'row'},\n", - " 'SecurityIDSource': {'columns': {'fieldValue': '8'},\n", - " 'type': 'row'},\n", - " 'Side': {'columns': {'fieldValue': '1'}, 'type': 'row'},\n", - " 'TradingParty': {'rows': {'NoPartyIDs': {'rows': {'0': {'rows': {'PartyID': {'columns': {'fieldValue': 'DEMO-CONN1'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'D'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '76'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '1': {'rows': {'PartyID': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '2': {'rows': {'PartyID': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '122'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '3': {'rows': {'PartyID': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '12'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'columns': {'fieldValue': '2021-06-20T13:45:16.174177'},\n", - " 'type': 'row'}},\n", - " 'type': 'treeTable'}],\n", - " 'endTimestamp': {'epochSecond': 1624185921, 'nano': 251567000},\n", - " 'eventId': '9c5bc38a-d1b4-11eb-bae5-57b0c4472880',\n", - " 'eventName': \"Send 'NewOrderSingle' message to connectivity\",\n", - " 'eventType': 'Outgoing message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '9c58b649-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185921, 'nano': 251483000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185921, 'nano': 274513000},\n", - " 'eventId': '9c5f4622-d1b4-11eb-8e55-d3a76285d588',\n", - " 'eventName': \"Send 'NewOrderSingle' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '9c58b649-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185921, 'nano': 274500000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '02e38401-a682-45dd-a3bc-0f7fe58271a4',\n", - " 'body': {'data': 'The message was deleted because a new one came with the '\n", - " \"same hash '9142400804910536496' in message group \"\n", - " \"'NOS_CONN'\\n\"\n", - " ' Message not matched',\n", - " 'type': 'message'},\n", - " 'endTimestamp': {'epochSecond': 1624185921, 'nano': 849531000},\n", - " 'eventId': '02e38401-a682-45dd-a3bc-0f7fe58271a4:9cb720ea-d1b4-11eb-986f-1e8d42132387',\n", - " 'eventName': \"Remove 'NewOrderSingle' \"\n", - " \"id='demo-conn1:SECOND:1624005455622135211' \"\n", - " \"Hash='9142400804910536496' Group='NOS_CONN' \"\n", - " \"Hash['SecondaryClOrdID': 11111, 'SecurityID': INSTR4]\",\n", - " 'eventType': '',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'a3779b94-d051-11eb-986f-1e8d42132387',\n", - " 'startTimestamp': {'epochSecond': 1624185921, 'nano': 849531000},\n", - " 'successful': False,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185922, 'nano': 264035000},\n", - " 'eventId': '9cf6561f-d1b4-11eb-a9f4-b12655548efc',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '845d70d2-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185922, 'nano': 264032000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185922, 'nano': 265144000},\n", - " 'eventId': '9cf67d52-d1b4-11eb-a9ed-ffb57363e013',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '845d70d2-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185922, 'nano': 265135000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'rows': {'AccountType': {'columns': {'fieldValue': '1'},\n", - " 'type': 'row'},\n", - " 'ClOrdID': {'columns': {'fieldValue': '2255277'},\n", - " 'type': 'row'},\n", - " 'CumQty': {'columns': {'fieldValue': '0'}, 'type': 'row'},\n", - " 'ExecID': {'columns': {'fieldValue': '2373'},\n", - " 'type': 'row'},\n", - " 'ExecType': {'columns': {'fieldValue': '0'}, 'type': 'row'},\n", - " 'LeavesQty': {'columns': {'fieldValue': '30'},\n", - " 'type': 'row'},\n", - " 'OrdStatus': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'OrdType': {'columns': {'fieldValue': '2'}, 'type': 'row'},\n", - " 'OrderCapacity': {'columns': {'fieldValue': 'A'},\n", - " 'type': 'row'},\n", - " 'OrderID': {'columns': {'fieldValue': '876'},\n", - " 'type': 'row'},\n", - " 'OrderQty': {'columns': {'fieldValue': '30'},\n", - " 'type': 'row'},\n", - " 'Price': {'columns': {'fieldValue': '45'}, 'type': 'row'},\n", - " 'SecurityID': {'columns': {'fieldValue': 'INSTR4'},\n", - " 'type': 'row'},\n", - " 'SecurityIDSource': {'columns': {'fieldValue': '8'},\n", - " 'type': 'row'},\n", - " 'Side': {'columns': {'fieldValue': '1'}, 'type': 'row'},\n", - " 'Text': {'columns': {'fieldValue': 'Simulated New Order '\n", - " 'Buy is placed'},\n", - " 'type': 'row'},\n", - " 'TradingParty': {'rows': {'NoPartyIDs': {'rows': {'0': {'rows': {'PartyID': {'columns': {'fieldValue': 'DEMO-CONN1'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'D'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '76'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '1': {'rows': {'PartyID': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '2': {'rows': {'PartyID': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '122'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '3': {'rows': {'PartyID': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '12'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'columns': {'fieldValue': '2021-06-20T10:45:22'},\n", - " 'type': 'row'},\n", - " 'header': {'rows': {'BeginString': {'columns': {'fieldValue': 'FIXT.1.1'},\n", - " 'type': 'row'},\n", - " 'BodyLength': {'columns': {'fieldValue': '310'},\n", - " 'type': 'row'},\n", - " 'MsgSeqNum': {'columns': {'fieldValue': '1303'},\n", - " 'type': 'row'},\n", - " 'MsgType': {'columns': {'fieldValue': '8'},\n", - " 'type': 'row'},\n", - " 'SenderCompID': {'columns': {'fieldValue': 'FGW'},\n", - " 'type': 'row'},\n", - " 'SendingTime': {'columns': {'fieldValue': '2021-06-20T10:45:22.263'},\n", - " 'type': 'row'},\n", - " 'TargetCompID': {'columns': {'fieldValue': 'DEMO-CONN1'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " 'trailer': {'rows': {'CheckSum': {'columns': {'fieldValue': '036'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'treeTable'}],\n", - " 'endTimestamp': {'epochSecond': 1624185922, 'nano': 973425000},\n", - " 'eventId': '9d62852b-d1b4-11eb-bae5-57b0c4472880',\n", - " 'eventName': \"Received 'ExecutionReport' response message\",\n", - " 'eventType': 'message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '9c58b649-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185922, 'nano': 973357000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " 'body': [{'data': 'STEP2: Trader \"DEMO-CONN1\" receives Execution Report. The '\n", - " 'order stands on book in status NEW',\n", - " 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185923, 'nano': 72842000},\n", - " 'eventId': '9d6fa4bb-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Check sequence rule SessionKey{sessionAlias='demo-conn1', \"\n", - " 'direction=FIRST} - STEP2: Trader \"DEMO-CONN1\" receives '\n", - " 'Execution Report. The order stands on book in status NEW',\n", - " 'eventType': 'checkSequenceRule',\n", - " 'isBatched': False,\n", - " 'parentEventId': '9954d104-d1b4-11eb-b0fb-199708acc7bc',\n", - " 'startTimestamp': {'epochSecond': 1624185923, 'nano': 59893000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'data': 'Contains comparisons', 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185923, 'nano': 123771000},\n", - " 'eventId': '9d71a08f-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Check messages',\n", - " 'eventType': 'checkMessages',\n", - " 'isBatched': False,\n", - " 'parentEventId': '9d6fa4bb-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185923, 'nano': 59893000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '34b92870-14fa-4cb4-a634-c507950a7986',\n", - " 'body': [{'data': 'Expected 1, Actual 1', 'type': 'message'},\n", - " {'rows': [{'actualMessage': 'ExecutionReport, demo-conn1, '\n", - " 'OrdStatus=0, ClOrdID=2255277',\n", - " 'actualMetadata': 'Metadata, demo-conn1',\n", - " 'expectedMessage': 'ExecutionReport, demo-conn1, '\n", - " 'OrdStatus=0, ClOrdID=2255277',\n", - " 'expectedMetadata': 'Metadata, demo-conn1'}],\n", - " 'type': 'table'}],\n", - " 'endTimestamp': {'epochSecond': 1624185923, 'nano': 123027000},\n", - " 'eventId': '34b92870-14fa-4cb4-a634-c507950a7986:9d71a08e-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Check sequence (expected 1 / actual 1 , check order false)',\n", - " 'eventType': 'checkSequence',\n", - " 'isBatched': True,\n", - " 'parentEventId': '9d6fa4bb-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185923, 'nano': 59893000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'dd7cf937-17fa-494d-aeb2-44599212bf69',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '2255277',\n", - " 'expected': '2255277',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2373',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '30',\n", - " 'expected': '30',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': '2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'A',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '876',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '30',\n", - " 'expected': '30',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '45',\n", - " 'expected': '45',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR4',\n", - " 'expected': 'INSTR4',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'Simulated New Order Buy is placed',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {'NoPartyIDs': {'actual': '4',\n", - " 'expected': '4',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'DEMO-CONN1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': '76',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': '122',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': '12',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:22',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': '7',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'FIXT.1.1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '310',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1303',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:22.263',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'DEMO-CONN1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '036',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185923, 'nano': 123793000},\n", - " 'eventId': 'dd7cf937-17fa-494d-aeb2-44599212bf69:9d71a090-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '9d71a08f-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185923, 'nano': 59893000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'rows': {'comparison-settings': {'rows': {'ignore-fields': {'rows': {},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'},\n", - " 'message-filter': {'rows': {'SecurityID': {'columns': {'expected': 'INSTR4',\n", - " 'key': False,\n", - " 'operation': 'EQUAL'},\n", - " 'type': 'row'},\n", - " 'header': {'rows': {'MsgType': {'columns': {'expected': 'f',\n", - " 'key': False,\n", - " 'operation': 'NOT_EQUAL'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'},\n", - " 'message-type': {'columns': {'type': 'PreFilter'},\n", - " 'type': 'row'},\n", - " 'metadata-filter': {'rows': {}, 'type': 'collection'}},\n", - " 'type': 'treeTable'}],\n", - " 'endTimestamp': {'epochSecond': 1624185923, 'nano': 118598000},\n", - " 'eventId': '9d6ff2dc-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Pre-filtering (filtered 1 / processed 1) messages',\n", - " 'eventType': 'preFiltering',\n", - " 'isBatched': False,\n", - " 'parentEventId': '9d6fa4bb-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185923, 'nano': 61991000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'faadeebe-eeb9-41a6-b69a-6db7bfd35013',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '2255277',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2373',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '30',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '876',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '30',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '45',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR4',\n", - " 'expected': 'INSTR4',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'Simulated New Order Buy is placed',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'NoPartyIDs': {'actual': '4',\n", - " 'expected': 'null',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:22',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': '1',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '310',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1303',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': 'x != \"f\"',\n", - " 'key': False,\n", - " 'operation': 'NOT_EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:22.263',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '036',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185923, 'nano': 121995000},\n", - " 'eventId': 'faadeebe-eeb9-41a6-b69a-6db7bfd35013:9d708f1d-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '9d6ff2dc-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185923, 'nano': 61991000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'data': 'STEP3: Trader \"DEMO-CONN1\" sends request to create passive '\n", - " 'Order with price lower than first order.',\n", - " 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185923, 'nano': 178008000},\n", - " 'eventId': '9d81a5ec-d1b4-11eb-bae5-57b0c4472880',\n", - " 'eventName': 'placeOrderFIX demo-conn1 - STEP3: Trader \"DEMO-CONN1\" sends '\n", - " 'request to create passive Order with price lower than first '\n", - " 'order.',\n", - " 'eventType': 'placeOrderFIX',\n", - " 'isBatched': False,\n", - " 'parentEventId': '9954d104-d1b4-11eb-b0fb-199708acc7bc',\n", - " 'startTimestamp': {'epochSecond': 1624185923, 'nano': 177971000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'c489ca45-3242-4d5e-9f31-2b34249792d1',\n", - " 'body': [{'data': \"Checkpoint id '9d828ff0-d1b4-11eb-ba78-1981398e00bd'\",\n", - " 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185923, 'nano': 183105000},\n", - " 'eventId': 'c489ca45-3242-4d5e-9f31-2b34249792d1:9d829081-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Checkpoint',\n", - " 'eventType': 'Checkpoint',\n", - " 'isBatched': True,\n", - " 'parentEventId': '9d81a5ec-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185923, 'nano': 183010000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'c489ca45-3242-4d5e-9f31-2b34249792d1',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185923, 'nano': 183105000},\n", - " 'eventId': 'c489ca45-3242-4d5e-9f31-2b34249792d1:9d829082-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'th2-hand-demo' direction 'FIRST' \"\n", - " \"sequence '1623852603564709030'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'c489ca45-3242-4d5e-9f31-2b34249792d1:9d829081-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185923, 'nano': 183010000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'c489ca45-3242-4d5e-9f31-2b34249792d1',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185923, 'nano': 183105000},\n", - " 'eventId': 'c489ca45-3242-4d5e-9f31-2b34249792d1:9d829083-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn1' direction 'SECOND' \"\n", - " \"sequence '1624005455622140296'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'c489ca45-3242-4d5e-9f31-2b34249792d1:9d829081-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185923, 'nano': 183010000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'c489ca45-3242-4d5e-9f31-2b34249792d1',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185923, 'nano': 183105000},\n", - " 'eventId': 'c489ca45-3242-4d5e-9f31-2b34249792d1:9d829084-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc1' direction 'SECOND' \"\n", - " \"sequence '1624005475721015015'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'c489ca45-3242-4d5e-9f31-2b34249792d1:9d829081-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185923, 'nano': 183010000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'c489ca45-3242-4d5e-9f31-2b34249792d1',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185923, 'nano': 183105000},\n", - " 'eventId': 'c489ca45-3242-4d5e-9f31-2b34249792d1:9d829085-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc1' direction 'FIRST' \"\n", - " \"sequence '1624005475720919512'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'c489ca45-3242-4d5e-9f31-2b34249792d1:9d829081-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185923, 'nano': 183010000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'c489ca45-3242-4d5e-9f31-2b34249792d1',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185923, 'nano': 183105000},\n", - " 'eventId': 'c489ca45-3242-4d5e-9f31-2b34249792d1:9d829086-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn2' direction 'FIRST' \"\n", - " \"sequence '1624005448022245408'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'c489ca45-3242-4d5e-9f31-2b34249792d1:9d829081-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185923, 'nano': 183010000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'c489ca45-3242-4d5e-9f31-2b34249792d1',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185923, 'nano': 183105000},\n", - " 'eventId': 'c489ca45-3242-4d5e-9f31-2b34249792d1:9d829087-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn2' direction 'SECOND' \"\n", - " \"sequence '1624005448022426116'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'c489ca45-3242-4d5e-9f31-2b34249792d1:9d829081-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185923, 'nano': 183010000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'c489ca45-3242-4d5e-9f31-2b34249792d1',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185923, 'nano': 183105000},\n", - " 'eventId': 'c489ca45-3242-4d5e-9f31-2b34249792d1:9d829088-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc2' direction 'SECOND' \"\n", - " \"sequence '1624005466840347016'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'c489ca45-3242-4d5e-9f31-2b34249792d1:9d829081-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185923, 'nano': 183010000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'c489ca45-3242-4d5e-9f31-2b34249792d1',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185923, 'nano': 183105000},\n", - " 'eventId': 'c489ca45-3242-4d5e-9f31-2b34249792d1:9d829089-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc2' direction 'FIRST' \"\n", - " \"sequence '1624005466840263381'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'c489ca45-3242-4d5e-9f31-2b34249792d1:9d829081-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185923, 'nano': 183010000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'c489ca45-3242-4d5e-9f31-2b34249792d1',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185923, 'nano': 183105000},\n", - " 'eventId': 'c489ca45-3242-4d5e-9f31-2b34249792d1:9d82908a-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn1' direction 'FIRST' \"\n", - " \"sequence '1624005455622011535'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'c489ca45-3242-4d5e-9f31-2b34249792d1:9d829081-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185923, 'nano': 183010000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'c489ca45-3242-4d5e-9f31-2b34249792d1',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185923, 'nano': 183105000},\n", - " 'eventId': 'c489ca45-3242-4d5e-9f31-2b34249792d1:9d82908b-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-log' direction 'FIRST' \"\n", - " \"sequence '1624029363623063053'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'c489ca45-3242-4d5e-9f31-2b34249792d1:9d829081-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185923, 'nano': 183010000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'rows': {'AccountType': {'columns': {'fieldValue': '1'},\n", - " 'type': 'row'},\n", - " 'ClOrdID': {'columns': {'fieldValue': '8442881'},\n", - " 'type': 'row'},\n", - " 'OrdType': {'columns': {'fieldValue': '2'}, 'type': 'row'},\n", - " 'OrderCapacity': {'columns': {'fieldValue': 'A'},\n", - " 'type': 'row'},\n", - " 'OrderQty': {'columns': {'fieldValue': '10'},\n", - " 'type': 'row'},\n", - " 'Price': {'columns': {'fieldValue': '46'}, 'type': 'row'},\n", - " 'SecondaryClOrdID': {'columns': {'fieldValue': '22222'},\n", - " 'type': 'row'},\n", - " 'SecurityID': {'columns': {'fieldValue': 'INSTR4'},\n", - " 'type': 'row'},\n", - " 'SecurityIDSource': {'columns': {'fieldValue': '8'},\n", - " 'type': 'row'},\n", - " 'Side': {'columns': {'fieldValue': '1'}, 'type': 'row'},\n", - " 'TradingParty': {'rows': {'NoPartyIDs': {'rows': {'0': {'rows': {'PartyID': {'columns': {'fieldValue': 'DEMO-CONN1'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'D'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '76'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '1': {'rows': {'PartyID': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '2': {'rows': {'PartyID': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '122'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '3': {'rows': {'PartyID': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '12'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'columns': {'fieldValue': '2021-06-20T13:45:16.174221'},\n", - " 'type': 'row'}},\n", - " 'type': 'treeTable'}],\n", - " 'endTimestamp': {'epochSecond': 1624185923, 'nano': 192868000},\n", - " 'eventId': '9d83efdd-d1b4-11eb-bae5-57b0c4472880',\n", - " 'eventName': \"Send 'NewOrderSingle' message to connectivity\",\n", - " 'eventType': 'Outgoing message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '9d81a5ec-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185923, 'nano': 192817000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185923, 'nano': 217206000},\n", - " 'eventId': '9d87c093-d1b4-11eb-8e55-d3a76285d588',\n", - " 'eventName': \"Send 'NewOrderSingle' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '9d81a5ec-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185923, 'nano': 217203000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185923, 'nano': 247787000},\n", - " 'eventId': '9d8c54b3-d1b4-11eb-a9ed-ffb57363e013',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '845d70d2-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185923, 'nano': 247782000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185923, 'nano': 254615000},\n", - " 'eventId': '9d8d6600-d1b4-11eb-a9f4-b12655548efc',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '845d70d2-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185923, 'nano': 254607000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '05e0bfdf-50c9-4d98-9d41-b07d460abf89',\n", - " 'body': {'data': 'The message was deleted because a new one came with the '\n", - " \"same hash '5003206531323649912' in message group \"\n", - " \"'NOS_CONN'\\n\"\n", - " ' Message not matched',\n", - " 'type': 'message'},\n", - " 'endTimestamp': {'epochSecond': 1624185923, 'nano': 861903000},\n", - " 'eventId': '05e0bfdf-50c9-4d98-9d41-b07d460abf89:9dea377c-d1b4-11eb-986f-1e8d42132387',\n", - " 'eventName': \"Remove 'NewOrderSingle' \"\n", - " \"id='demo-conn1:SECOND:1624005455622135212' \"\n", - " \"Hash='5003206531323649912' Group='NOS_CONN' \"\n", - " \"Hash['SecondaryClOrdID': 22222, 'SecurityID': INSTR4]\",\n", - " 'eventType': '',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'a3779b94-d051-11eb-986f-1e8d42132387',\n", - " 'startTimestamp': {'epochSecond': 1624185923, 'nano': 861903000},\n", - " 'successful': False,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'rows': {'AccountType': {'columns': {'fieldValue': '1'},\n", - " 'type': 'row'},\n", - " 'ClOrdID': {'columns': {'fieldValue': '8442881'},\n", - " 'type': 'row'},\n", - " 'CumQty': {'columns': {'fieldValue': '0'}, 'type': 'row'},\n", - " 'ExecID': {'columns': {'fieldValue': '2375'},\n", - " 'type': 'row'},\n", - " 'ExecType': {'columns': {'fieldValue': '0'}, 'type': 'row'},\n", - " 'LeavesQty': {'columns': {'fieldValue': '10'},\n", - " 'type': 'row'},\n", - " 'OrdStatus': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'OrdType': {'columns': {'fieldValue': '2'}, 'type': 'row'},\n", - " 'OrderCapacity': {'columns': {'fieldValue': 'A'},\n", - " 'type': 'row'},\n", - " 'OrderID': {'columns': {'fieldValue': '877'},\n", - " 'type': 'row'},\n", - " 'OrderQty': {'columns': {'fieldValue': '10'},\n", - " 'type': 'row'},\n", - " 'Price': {'columns': {'fieldValue': '46'}, 'type': 'row'},\n", - " 'SecurityID': {'columns': {'fieldValue': 'INSTR4'},\n", - " 'type': 'row'},\n", - " 'SecurityIDSource': {'columns': {'fieldValue': '8'},\n", - " 'type': 'row'},\n", - " 'Side': {'columns': {'fieldValue': '1'}, 'type': 'row'},\n", - " 'Text': {'columns': {'fieldValue': 'Simulated New Order '\n", - " 'Buy is placed'},\n", - " 'type': 'row'},\n", - " 'TradingParty': {'rows': {'NoPartyIDs': {'rows': {'0': {'rows': {'PartyID': {'columns': {'fieldValue': 'DEMO-CONN1'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'D'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '76'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '1': {'rows': {'PartyID': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '2': {'rows': {'PartyID': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '122'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '3': {'rows': {'PartyID': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '12'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'columns': {'fieldValue': '2021-06-20T10:45:23'},\n", - " 'type': 'row'},\n", - " 'header': {'rows': {'BeginString': {'columns': {'fieldValue': 'FIXT.1.1'},\n", - " 'type': 'row'},\n", - " 'BodyLength': {'columns': {'fieldValue': '310'},\n", - " 'type': 'row'},\n", - " 'MsgSeqNum': {'columns': {'fieldValue': '1304'},\n", - " 'type': 'row'},\n", - " 'MsgType': {'columns': {'fieldValue': '8'},\n", - " 'type': 'row'},\n", - " 'SenderCompID': {'columns': {'fieldValue': 'FGW'},\n", - " 'type': 'row'},\n", - " 'SendingTime': {'columns': {'fieldValue': '2021-06-20T10:45:23.246'},\n", - " 'type': 'row'},\n", - " 'TargetCompID': {'columns': {'fieldValue': 'DEMO-CONN1'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " 'trailer': {'rows': {'CheckSum': {'columns': {'fieldValue': '045'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'treeTable'}],\n", - " 'endTimestamp': {'epochSecond': 1624185923, 'nano': 944097000},\n", - " 'eventId': '9df6aede-d1b4-11eb-bae5-57b0c4472880',\n", - " 'eventName': \"Received 'ExecutionReport' response message\",\n", - " 'eventType': 'message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '9d81a5ec-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185923, 'nano': 944057000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'data': 'STEP4: Trader \"DEMO-CONN1\" receives Execution Report. The '\n", - " 'order stands on book in status NEW',\n", - " 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185924, 'nano': 48015000},\n", - " 'eventId': '9e05551c-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Check sequence rule SessionKey{sessionAlias='demo-conn1', \"\n", - " 'direction=FIRST} - STEP4: Trader \"DEMO-CONN1\" receives '\n", - " 'Execution Report. The order stands on book in status NEW',\n", - " 'eventType': 'checkSequenceRule',\n", - " 'isBatched': False,\n", - " 'parentEventId': '9954d104-d1b4-11eb-b0fb-199708acc7bc',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 40298000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'data': 'Contains comparisons', 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185924, 'nano': 48397000},\n", - " 'eventId': '9e066690-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Check messages',\n", - " 'eventType': 'checkMessages',\n", - " 'isBatched': False,\n", - " 'parentEventId': '9e05551c-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 40298000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '3cd0d522-a8c7-4e92-b53d-9228ea0c5382',\n", - " 'body': [{'data': 'Expected 1, Actual 1', 'type': 'message'},\n", - " {'rows': [{'actualMessage': 'ExecutionReport, demo-conn1, '\n", - " 'OrdStatus=0, ClOrdID=8442881',\n", - " 'actualMetadata': 'Metadata, demo-conn1',\n", - " 'expectedMessage': 'ExecutionReport, demo-conn1, '\n", - " 'OrdStatus=0, ClOrdID=8442881',\n", - " 'expectedMetadata': 'Metadata, demo-conn1'}],\n", - " 'type': 'table'}],\n", - " 'endTimestamp': {'epochSecond': 1624185924, 'nano': 48319000},\n", - " 'eventId': '3cd0d522-a8c7-4e92-b53d-9228ea0c5382:9e06668f-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Check sequence (expected 1 / actual 1 , check order false)',\n", - " 'eventType': 'checkSequence',\n", - " 'isBatched': True,\n", - " 'parentEventId': '9e05551c-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 40298000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'afd0d956-1172-4ff0-9f7e-b89638f1fa3f',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '8442881',\n", - " 'expected': '8442881',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2375',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '10',\n", - " 'expected': '10',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': '2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'A',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '877',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '10',\n", - " 'expected': '10',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '46',\n", - " 'expected': '46',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR4',\n", - " 'expected': 'INSTR4',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'Simulated New Order Buy is placed',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {'NoPartyIDs': {'actual': '4',\n", - " 'expected': '4',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'DEMO-CONN1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': '76',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': '122',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': '12',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:23',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': '7',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'FIXT.1.1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '310',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1304',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:23.246',\n", - " 'expected': '*',\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'DEMO-CONN1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '045',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185924, 'nano': 48402000},\n", - " 'eventId': 'afd0d956-1172-4ff0-9f7e-b89638f1fa3f:9e066691-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '9e066690-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 40298000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'rows': {'comparison-settings': {'rows': {'ignore-fields': {'rows': {},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'},\n", - " 'message-filter': {'rows': {'SecurityID': {'columns': {'expected': 'INSTR4',\n", - " 'key': False,\n", - " 'operation': 'EQUAL'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " 'message-type': {'columns': {'type': 'PreFilter'},\n", - " 'type': 'row'},\n", - " 'metadata-filter': {'rows': {}, 'type': 'collection'}},\n", - " 'type': 'treeTable'}],\n", - " 'endTimestamp': {'epochSecond': 1624185924, 'nano': 48097000},\n", - " 'eventId': '9e057c2d-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Pre-filtering (filtered 1 / processed 1) messages',\n", - " 'eventType': 'preFiltering',\n", - " 'isBatched': False,\n", - " 'parentEventId': '9e05551c-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 41350000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '0534a343-5269-4571-80e3-42d0bda213d3',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '8442881',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2375',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '10',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '877',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '10',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '46',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR4',\n", - " 'expected': 'INSTR4',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'Simulated New Order Buy is placed',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'NoPartyIDs': {'actual': '4',\n", - " 'expected': 'null',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:23',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': 'null',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '310',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1304',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:23.246',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '045',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185924, 'nano': 48221000},\n", - " 'eventId': '0534a343-5269-4571-80e3-42d0bda213d3:9e06186e-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '9e057c2d-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 41350000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'data': 'STEP5: Trader \"DEMO-CONN2\" sends request to create '\n", - " 'aggressive IOC Order.',\n", - " 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185924, 'nano': 125333000},\n", - " 'eventId': '9e124d2f-d1b4-11eb-bae5-57b0c4472880',\n", - " 'eventName': 'placeOrderFIX demo-conn2 - STEP5: Trader \"DEMO-CONN2\" sends '\n", - " 'request to create aggressive IOC Order.',\n", - " 'eventType': 'placeOrderFIX',\n", - " 'isBatched': False,\n", - " 'parentEventId': '9954d104-d1b4-11eb-b0fb-199708acc7bc',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 125303000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '246dc777-e3d6-46c8-8160-f60c7bb97df7',\n", - " 'body': [{'data': \"Checkpoint id '9e133730-d1b4-11eb-ba78-1981398e00bd'\",\n", - " 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185924, 'nano': 131551000},\n", - " 'eventId': '246dc777-e3d6-46c8-8160-f60c7bb97df7:9e1337d2-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Checkpoint',\n", - " 'eventType': 'Checkpoint',\n", - " 'isBatched': True,\n", - " 'parentEventId': '9e124d2f-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 131423000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '246dc777-e3d6-46c8-8160-f60c7bb97df7',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185924, 'nano': 131551000},\n", - " 'eventId': '246dc777-e3d6-46c8-8160-f60c7bb97df7:9e1337d3-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'th2-hand-demo' direction 'FIRST' \"\n", - " \"sequence '1623852603564709030'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '246dc777-e3d6-46c8-8160-f60c7bb97df7:9e1337d2-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 131423000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '246dc777-e3d6-46c8-8160-f60c7bb97df7',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185924, 'nano': 131551000},\n", - " 'eventId': '246dc777-e3d6-46c8-8160-f60c7bb97df7:9e1337d4-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn1' direction 'SECOND' \"\n", - " \"sequence '1624005455622140297'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '246dc777-e3d6-46c8-8160-f60c7bb97df7:9e1337d2-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 131423000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '246dc777-e3d6-46c8-8160-f60c7bb97df7',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185924, 'nano': 131551000},\n", - " 'eventId': '246dc777-e3d6-46c8-8160-f60c7bb97df7:9e1337d5-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc1' direction 'SECOND' \"\n", - " \"sequence '1624005475721015015'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '246dc777-e3d6-46c8-8160-f60c7bb97df7:9e1337d2-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 131423000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '246dc777-e3d6-46c8-8160-f60c7bb97df7',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185924, 'nano': 131551000},\n", - " 'eventId': '246dc777-e3d6-46c8-8160-f60c7bb97df7:9e1337d6-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc1' direction 'FIRST' \"\n", - " \"sequence '1624005475720919513'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '246dc777-e3d6-46c8-8160-f60c7bb97df7:9e1337d2-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 131423000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '246dc777-e3d6-46c8-8160-f60c7bb97df7',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185924, 'nano': 131551000},\n", - " 'eventId': '246dc777-e3d6-46c8-8160-f60c7bb97df7:9e1337d7-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn2' direction 'FIRST' \"\n", - " \"sequence '1624005448022245408'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '246dc777-e3d6-46c8-8160-f60c7bb97df7:9e1337d2-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 131423000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '246dc777-e3d6-46c8-8160-f60c7bb97df7',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185924, 'nano': 131551000},\n", - " 'eventId': '246dc777-e3d6-46c8-8160-f60c7bb97df7:9e1337d8-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn2' direction 'SECOND' \"\n", - " \"sequence '1624005448022426116'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '246dc777-e3d6-46c8-8160-f60c7bb97df7:9e1337d2-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 131423000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '246dc777-e3d6-46c8-8160-f60c7bb97df7',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185924, 'nano': 131551000},\n", - " 'eventId': '246dc777-e3d6-46c8-8160-f60c7bb97df7:9e1337d9-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc2' direction 'SECOND' \"\n", - " \"sequence '1624005466840347016'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '246dc777-e3d6-46c8-8160-f60c7bb97df7:9e1337d2-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 131423000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '246dc777-e3d6-46c8-8160-f60c7bb97df7',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185924, 'nano': 131551000},\n", - " 'eventId': '246dc777-e3d6-46c8-8160-f60c7bb97df7:9e1337da-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc2' direction 'FIRST' \"\n", - " \"sequence '1624005466840263381'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '246dc777-e3d6-46c8-8160-f60c7bb97df7:9e1337d2-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 131423000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '246dc777-e3d6-46c8-8160-f60c7bb97df7',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185924, 'nano': 131551000},\n", - " 'eventId': '246dc777-e3d6-46c8-8160-f60c7bb97df7:9e1337db-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn1' direction 'FIRST' \"\n", - " \"sequence '1624005455622011536'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '246dc777-e3d6-46c8-8160-f60c7bb97df7:9e1337d2-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 131423000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '246dc777-e3d6-46c8-8160-f60c7bb97df7',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185924, 'nano': 131551000},\n", - " 'eventId': '246dc777-e3d6-46c8-8160-f60c7bb97df7:9e1337dc-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-log' direction 'FIRST' \"\n", - " \"sequence '1624029363623063053'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '246dc777-e3d6-46c8-8160-f60c7bb97df7:9e1337d2-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 131423000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'rows': {'AccountType': {'columns': {'fieldValue': '1'},\n", - " 'type': 'row'},\n", - " 'ClOrdID': {'columns': {'fieldValue': '3896411'},\n", - " 'type': 'row'},\n", - " 'OrdType': {'columns': {'fieldValue': '2'}, 'type': 'row'},\n", - " 'OrderCapacity': {'columns': {'fieldValue': 'A'},\n", - " 'type': 'row'},\n", - " 'OrderQty': {'columns': {'fieldValue': '100'},\n", - " 'type': 'row'},\n", - " 'Price': {'columns': {'fieldValue': '44'}, 'type': 'row'},\n", - " 'SecondaryClOrdID': {'columns': {'fieldValue': '33333'},\n", - " 'type': 'row'},\n", - " 'SecurityID': {'columns': {'fieldValue': 'INSTR4'},\n", - " 'type': 'row'},\n", - " 'SecurityIDSource': {'columns': {'fieldValue': '8'},\n", - " 'type': 'row'},\n", - " 'Side': {'columns': {'fieldValue': '2'}, 'type': 'row'},\n", - " 'TimeInForce': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'},\n", - " 'TradingParty': {'rows': {'NoPartyIDs': {'rows': {'0': {'rows': {'PartyID': {'columns': {'fieldValue': 'DEMO-CONN2'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'D'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '76'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '1': {'rows': {'PartyID': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '2': {'rows': {'PartyID': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '122'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '3': {'rows': {'PartyID': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '12'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'columns': {'fieldValue': '2021-06-20T13:45:16.174242'},\n", - " 'type': 'row'}},\n", - " 'type': 'treeTable'}],\n", - " 'endTimestamp': {'epochSecond': 1624185924, 'nano': 140136000},\n", - " 'eventId': '9e149720-d1b4-11eb-bae5-57b0c4472880',\n", - " 'eventName': \"Send 'NewOrderSingle' message to connectivity\",\n", - " 'eventType': 'Outgoing message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '9e124d2f-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 140083000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185924, 'nano': 165785000},\n", - " 'eventId': '9e186754-d1b4-11eb-bd0a-0d6cee9f6833',\n", - " 'eventName': \"Send 'NewOrderSingle' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '9e124d2f-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 165763000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185924, 'nano': 499704000},\n", - " 'eventId': '9e4b5ef4-d1b4-11eb-a9ed-ffb57363e013',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '849a79d3-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 499700000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185924, 'nano': 503958000},\n", - " 'eventId': '9e4bfb35-d1b4-11eb-a9ed-ffb57363e013',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '849a79d3-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 503955000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185924, 'nano': 504837000},\n", - " 'eventId': '9e4c2221-d1b4-11eb-a9f4-b12655548efc',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '849a79d3-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 504829000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185924, 'nano': 512123000},\n", - " 'eventId': '9e4d5a56-d1b4-11eb-be23-57049e5b0bd9',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '849a79d3-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 512091000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185924, 'nano': 513946000},\n", - " 'eventId': '9e4d8135-d1b4-11eb-91f0-77dd26d4db8e',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '849a79d3-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 513895000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185924, 'nano': 525008000},\n", - " 'eventId': '9e4f2ee6-d1b4-11eb-91f0-77dd26d4db8e',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '849a79d3-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 524986000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185924, 'nano': 566529000},\n", - " 'eventId': '9e559802-d1b4-11eb-a9f4-b12655548efc',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '849a79d3-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 566524000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185924, 'nano': 633760000},\n", - " 'eventId': '9e5fd0e7-d1b4-11eb-be23-57049e5b0bd9',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '849a79d3-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 633732000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185924, 'nano': 635467000},\n", - " 'eventId': '9e601f08-d1b4-11eb-be23-57049e5b0bd9',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '849a79d3-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 635452000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185924, 'nano': 646670000},\n", - " 'eventId': '9e61cc87-d1b4-11eb-91f0-77dd26d4db8e',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '849a79d3-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 646634000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185924, 'nano': 647477000},\n", - " 'eventId': '9e61f398-d1b4-11eb-91f0-77dd26d4db8e',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '849a79d3-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 647467000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '05e0bfdf-50c9-4d98-9d41-b07d460abf89',\n", - " 'body': {'data': 'The message was deleted because a new one came with the '\n", - " \"same hash '-3810261582785232455' in message group \"\n", - " \"'NOS_CONN'\\n\"\n", - " ' Message not matched',\n", - " 'type': 'message'},\n", - " 'endTimestamp': {'epochSecond': 1624185924, 'nano': 650306000},\n", - " 'eventId': '05e0bfdf-50c9-4d98-9d41-b07d460abf89:9e62c2aa-d1b4-11eb-986f-1e8d42132387',\n", - " 'eventName': \"Remove 'NewOrderSingle' \"\n", - " \"id='demo-conn2:SECOND:1624005448022421039' \"\n", - " \"Hash='-3810261582785232455' Group='NOS_CONN' \"\n", - " \"Hash['SecondaryClOrdID': 33333, 'SecurityID': INSTR4]\",\n", - " 'eventType': '',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'a3779b94-d051-11eb-986f-1e8d42132387',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 650306000},\n", - " 'successful': False,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'rows': {'AccountType': {'columns': {'fieldValue': '1'},\n", - " 'type': 'row'},\n", - " 'ClOrdID': {'columns': {'fieldValue': '3896411'},\n", - " 'type': 'row'},\n", - " 'CumQty': {'columns': {'fieldValue': '10'}, 'type': 'row'},\n", - " 'ExecID': {'columns': {'fieldValue': '2379'},\n", - " 'type': 'row'},\n", - " 'ExecType': {'columns': {'fieldValue': 'F'}, 'type': 'row'},\n", - " 'LastPx': {'columns': {'fieldValue': '46'}, 'type': 'row'},\n", - " 'LeavesQty': {'columns': {'fieldValue': '90'},\n", - " 'type': 'row'},\n", - " 'OrdStatus': {'columns': {'fieldValue': '1'},\n", - " 'type': 'row'},\n", - " 'OrdType': {'columns': {'fieldValue': '2'}, 'type': 'row'},\n", - " 'OrderCapacity': {'columns': {'fieldValue': 'A'},\n", - " 'type': 'row'},\n", - " 'OrderID': {'columns': {'fieldValue': '878'},\n", - " 'type': 'row'},\n", - " 'OrderQty': {'columns': {'fieldValue': '100'},\n", - " 'type': 'row'},\n", - " 'Price': {'columns': {'fieldValue': '44'}, 'type': 'row'},\n", - " 'SecurityID': {'columns': {'fieldValue': 'INSTR4'},\n", - " 'type': 'row'},\n", - " 'SecurityIDSource': {'columns': {'fieldValue': '8'},\n", - " 'type': 'row'},\n", - " 'Side': {'columns': {'fieldValue': '2'}, 'type': 'row'},\n", - " 'Text': {'columns': {'fieldValue': 'The simulated order '\n", - " 'has been partially '\n", - " 'traded'},\n", - " 'type': 'row'},\n", - " 'TimeInForce': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'},\n", - " 'TradingParty': {'rows': {'NoPartyIDs': {'rows': {'0': {'rows': {'PartyID': {'columns': {'fieldValue': 'DEMO-CONN2'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'D'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '76'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '1': {'rows': {'PartyID': {'columns': {'fieldValue': 'DEMOFIRM1'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'D'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '17'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '2': {'rows': {'PartyID': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '3': {'rows': {'PartyID': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '122'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '4': {'rows': {'PartyID': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '12'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'columns': {'fieldValue': '2021-06-20T10:45:24'},\n", - " 'type': 'row'},\n", - " 'TrdMatchID': {'columns': {'fieldValue': '487'},\n", - " 'type': 'row'},\n", - " 'header': {'rows': {'BeginString': {'columns': {'fieldValue': 'FIXT.1.1'},\n", - " 'type': 'row'},\n", - " 'BodyLength': {'columns': {'fieldValue': '370'},\n", - " 'type': 'row'},\n", - " 'MsgSeqNum': {'columns': {'fieldValue': '1300'},\n", - " 'type': 'row'},\n", - " 'MsgType': {'columns': {'fieldValue': '8'},\n", - " 'type': 'row'},\n", - " 'SenderCompID': {'columns': {'fieldValue': 'FGW'},\n", - " 'type': 'row'},\n", - " 'SendingTime': {'columns': {'fieldValue': '2021-06-20T10:45:24.511'},\n", - " 'type': 'row'},\n", - " 'TargetCompID': {'columns': {'fieldValue': 'DEMO-CONN2'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " 'trailer': {'rows': {'CheckSum': {'columns': {'fieldValue': '222'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'treeTable'}],\n", - " 'endTimestamp': {'epochSecond': 1624185924, 'nano': 653870000},\n", - " 'eventId': '9e62de31-d1b4-11eb-bae5-57b0c4472880',\n", - " 'eventName': \"Received 'ExecutionReport' response message\",\n", - " 'eventType': 'message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '9e124d2f-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 653825000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'data': 'STEP6: Trader \"DEMO-CONN1\" receives Execution Reports with '\n", - " 'ExecType=F: first at Order2 and second on Order1.',\n", - " 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185924, 'nano': 954984000},\n", - " 'eventId': '9e71365d-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Check sequence rule SessionKey{sessionAlias='demo-conn1', \"\n", - " 'direction=FIRST} - STEP6: Trader \"DEMO-CONN1\" receives '\n", - " 'Execution Reports with ExecType=F: first at Order2 and second '\n", - " 'on Order1.',\n", - " 'eventType': 'checkSequenceRule',\n", - " 'isBatched': False,\n", - " 'parentEventId': '9954d104-d1b4-11eb-b0fb-199708acc7bc',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 747686000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'data': 'Contains comparisons', 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185924, 'nano': 955278000},\n", - " 'eventId': '9e90cc55-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Check messages',\n", - " 'eventType': 'checkMessages',\n", - " 'isBatched': False,\n", - " 'parentEventId': '9e71365d-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 747686000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '056b70da-11cf-4992-a2d9-7d29b034f2a9',\n", - " 'body': [{'data': 'Expected 2, Actual 2, In order', 'type': 'message'},\n", - " {'rows': [{'actualMessage': 'ExecutionReport, demo-conn1, CumQty=10, '\n", - " 'ClOrdID=8442881, LeavesQty=0, '\n", - " 'OrdStatus=2',\n", - " 'actualMetadata': 'Metadata, demo-conn1',\n", - " 'expectedMessage': 'ExecutionReport, demo-conn1, '\n", - " 'CumQty=10, ClOrdID=8442881, '\n", - " 'LeavesQty=0, OrdStatus=2',\n", - " 'expectedMetadata': 'Metadata, demo-conn1'},\n", - " {'actualMessage': 'ExecutionReport, demo-conn1, CumQty=30, '\n", - " 'LeavesQty=0, OrdStatus=2, '\n", - " 'ClOrdID=2255277',\n", - " 'actualMetadata': 'Metadata, demo-conn1',\n", - " 'expectedMessage': 'ExecutionReport, demo-conn1, '\n", - " 'CumQty=30, LeavesQty=0, OrdStatus=2, '\n", - " 'ClOrdID=2255277',\n", - " 'expectedMetadata': 'Metadata, demo-conn1'}],\n", - " 'type': 'table'}],\n", - " 'endTimestamp': {'epochSecond': 1624185924, 'nano': 955253000},\n", - " 'eventId': '056b70da-11cf-4992-a2d9-7d29b034f2a9:9e90cc54-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Check sequence (expected 2 / actual 2 , check order true)',\n", - " 'eventType': 'checkSequence',\n", - " 'isBatched': True,\n", - " 'parentEventId': '9e71365d-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 747686000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '69451533-1158-4f7c-ac3e-974aade1150b',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '8442881',\n", - " 'expected': '8442881',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '10',\n", - " 'expected': '10',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2377',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': 'F',\n", - " 'expected': 'F',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LastPx': {'actual': '46',\n", - " 'expected': '46',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '2',\n", - " 'expected': '2',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': '2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'A',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '877',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '10',\n", - " 'expected': '10',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '46',\n", - " 'expected': '46',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR4',\n", - " 'expected': 'INSTR4',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'The simulated order has been fully '\n", - " 'traded',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TimeInForce': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {'NoPartyIDs': {'actual': '5',\n", - " 'expected': '5',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'DEMO-CONN1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': '76',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMOFIRM2',\n", - " 'expected': 'DEMOFIRM2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '17',\n", - " 'expected': '17',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': '122',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '4': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': '12',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:24',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TrdMatchID': {'actual': '487',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': '7',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'FIXT.1.1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '364',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1305',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:24.498',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'DEMO-CONN1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '227',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185924, 'nano': 955280000},\n", - " 'eventId': '69451533-1158-4f7c-ac3e-974aade1150b:9e90cc56-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '9e90cc55-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 747686000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '69451533-1158-4f7c-ac3e-974aade1150b',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '2255277',\n", - " 'expected': '2255277',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '30',\n", - " 'expected': '30',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2378',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': 'F',\n", - " 'expected': 'F',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LastPx': {'actual': '45',\n", - " 'expected': '45',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '2',\n", - " 'expected': '2',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': '2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'A',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '876',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '30',\n", - " 'expected': '30',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '45',\n", - " 'expected': '45',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR4',\n", - " 'expected': 'INSTR4',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'The simulated order has been fully '\n", - " 'traded',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TimeInForce': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {'NoPartyIDs': {'actual': '5',\n", - " 'expected': '5',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'DEMO-CONN1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': '76',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMOFIRM2',\n", - " 'expected': 'DEMOFIRM2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '17',\n", - " 'expected': '17',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': '122',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '4': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': '12',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:24',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TrdMatchID': {'actual': '488',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': '7',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'FIXT.1.1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '364',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1306',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:24.503',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'DEMO-CONN1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '213',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185924, 'nano': 955352000},\n", - " 'eventId': '69451533-1158-4f7c-ac3e-974aade1150b:9e90cc57-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '9e90cc55-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 747686000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'rows': {'comparison-settings': {'rows': {'ignore-fields': {'rows': {},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'},\n", - " 'message-filter': {'rows': {'SecurityID': {'columns': {'expected': 'INSTR4',\n", - " 'key': False,\n", - " 'operation': 'EQUAL'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " 'message-type': {'columns': {'type': 'PreFilter'},\n", - " 'type': 'row'},\n", - " 'metadata-filter': {'rows': {}, 'type': 'collection'}},\n", - " 'type': 'treeTable'}],\n", - " 'endTimestamp': {'epochSecond': 1624185924, 'nano': 955039000},\n", - " 'eventId': '9e71847e-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Pre-filtering (filtered 2 / processed 2) messages',\n", - " 'eventType': 'preFiltering',\n", - " 'isBatched': False,\n", - " 'parentEventId': '9e71365d-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 749301000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'f918748b-6f66-4be8-bb57-813bbee5e3f2',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '8442881',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '10',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2377',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': 'F',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LastPx': {'actual': '46',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '877',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '10',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '46',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR4',\n", - " 'expected': 'INSTR4',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'The simulated order has been fully '\n", - " 'traded',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TimeInForce': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'NoPartyIDs': {'actual': '5',\n", - " 'expected': 'null',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': 'DEMOFIRM2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '17',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '4': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:24',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TrdMatchID': {'actual': '487',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': 'null',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '364',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1305',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:24.498',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '227',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185924, 'nano': 955124000},\n", - " 'eventId': 'f918748b-6f66-4be8-bb57-813bbee5e3f2:9e905722-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '9e71847e-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 749301000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'f918748b-6f66-4be8-bb57-813bbee5e3f2',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '2255277',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '30',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2378',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': 'F',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LastPx': {'actual': '45',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '876',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '30',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '45',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR4',\n", - " 'expected': 'INSTR4',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'The simulated order has been fully '\n", - " 'traded',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TimeInForce': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'NoPartyIDs': {'actual': '5',\n", - " 'expected': 'null',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': 'DEMOFIRM2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '17',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '4': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:24',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TrdMatchID': {'actual': '488',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': 'null',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '364',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1306',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:24.503',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '213',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185924, 'nano': 955208000},\n", - " 'eventId': 'f918748b-6f66-4be8-bb57-813bbee5e3f2:9e90a543-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '9e71847e-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 749301000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'data': 'STEP7: Trader \"DEMO-CONN2\" receives Execution Reports: '\n", - " 'first trade with Order2, next with Order1 and then '\n", - " 'cancellation',\n", - " 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185925, 'nano': 545028000},\n", - " 'eventId': '9e7fdc5f-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Check sequence rule SessionKey{sessionAlias='demo-conn2', \"\n", - " 'direction=FIRST} - STEP7: Trader \"DEMO-CONN2\" receives '\n", - " 'Execution Reports: first trade with Order2, next with Order1 '\n", - " 'and then cancellation',\n", - " 'eventType': 'checkSequenceRule',\n", - " 'isBatched': False,\n", - " 'parentEventId': '9954d104-d1b4-11eb-b0fb-199708acc7bc',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 843104000},\n", - " 'successful': False,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'data': 'Contains comparisons', 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185925, 'nano': 547334000},\n", - " 'eventId': '9eead33c-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Check messages',\n", - " 'eventType': 'checkMessages',\n", - " 'isBatched': False,\n", - " 'parentEventId': '9e7fdc5f-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 843104000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'a792bd7f-a942-4dfc-85ff-bee3f679690a',\n", - " 'body': [{'data': 'Expected 3, Actual 4, In order', 'type': 'message'},\n", - " {'rows': [{'actualMessage': 'ExecutionReport, demo-conn2, '\n", - " 'LeavesQty=90, CumQty=10, OrdStatus=1, '\n", - " 'ClOrdID=3896411',\n", - " 'actualMetadata': 'Metadata, demo-conn2',\n", - " 'expectedMessage': 'ExecutionReport, demo-conn2, '\n", - " 'LeavesQty=90, CumQty=10, OrdStatus=1, '\n", - " 'ClOrdID=3896411',\n", - " 'expectedMetadata': 'Metadata, demo-conn2'},\n", - " {'actualMessage': 'ExecutionReport, demo-conn2, '\n", - " 'ClOrdID=3896411, CumQty=40, '\n", - " 'OrdStatus=1, LeavesQty=60',\n", - " 'actualMetadata': 'Metadata, demo-conn2',\n", - " 'expectedMessage': 'ExecutionReport, demo-conn2, '\n", - " 'ClOrdID=3896411, CumQty=40, '\n", - " 'OrdStatus=1, LeavesQty=60',\n", - " 'expectedMetadata': 'Metadata, demo-conn2'},\n", - " {'actualMessage': 'ExecutionReport, demo-conn2',\n", - " 'actualMetadata': '',\n", - " 'expectedMessage': '',\n", - " 'expectedMetadata': ''},\n", - " {'actualMessage': 'ExecutionReport, demo-conn2, '\n", - " 'ClOrdID=3896411, CumQty=40, '\n", - " 'LeavesQty=0, OrdStatus=C',\n", - " 'actualMetadata': 'Metadata, demo-conn2',\n", - " 'expectedMessage': 'ExecutionReport, demo-conn2, '\n", - " 'ClOrdID=3896411, CumQty=40, '\n", - " 'LeavesQty=0, OrdStatus=C',\n", - " 'expectedMetadata': 'Metadata, demo-conn2'}],\n", - " 'type': 'table'}],\n", - " 'endTimestamp': {'epochSecond': 1624185925, 'nano': 546815000},\n", - " 'eventId': 'a792bd7f-a942-4dfc-85ff-bee3f679690a:9eead33b-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Check sequence (expected 3 / actual 4 , check order true)',\n", - " 'eventType': 'checkSequence',\n", - " 'isBatched': True,\n", - " 'parentEventId': '9e7fdc5f-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 843104000},\n", - " 'successful': False,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'ee1a0389-e1ff-42e9-a397-8eead4599d7c',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '3896411',\n", - " 'expected': '3896411',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '10',\n", - " 'expected': '10',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2379',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': 'F',\n", - " 'expected': 'F',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LastPx': {'actual': '46',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '90',\n", - " 'expected': '90',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': '2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'A',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '878',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '100',\n", - " 'expected': '100',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '44',\n", - " 'expected': '44',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR4',\n", - " 'expected': 'INSTR4',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '2',\n", - " 'expected': '2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'The simulated order has been '\n", - " 'partially traded',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TimeInForce': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {'NoPartyIDs': {'actual': '5',\n", - " 'expected': '5',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'DEMO-CONN2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': '76',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMOFIRM1',\n", - " 'expected': 'DEMOFIRM1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '17',\n", - " 'expected': '17',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': '122',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '4': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': '12',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:24',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TrdMatchID': {'actual': '487',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': '7',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'FIXT.1.1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '370',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1300',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:24.511',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'DEMO-CONN2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '222',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185925, 'nano': 547340000},\n", - " 'eventId': 'ee1a0389-e1ff-42e9-a397-8eead4599d7c:9eead33d-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '9eead33c-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 843104000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'ee1a0389-e1ff-42e9-a397-8eead4599d7c',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '3896411',\n", - " 'expected': '3896411',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '40',\n", - " 'expected': '40',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2380',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': 'F',\n", - " 'expected': 'F',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LastPx': {'actual': '45',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '60',\n", - " 'expected': '60',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': '2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'A',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '878',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '100',\n", - " 'expected': '100',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '44',\n", - " 'expected': '44',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR4',\n", - " 'expected': 'INSTR4',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '2',\n", - " 'expected': '2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'The simulated order has been '\n", - " 'partially traded',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TimeInForce': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {'NoPartyIDs': {'actual': '5',\n", - " 'expected': '5',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'DEMO-CONN2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': '76',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMOFIRM1',\n", - " 'expected': 'DEMOFIRM1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '17',\n", - " 'expected': '17',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': '122',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '4': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': '12',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:24',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TrdMatchID': {'actual': '488',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': '7',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'FIXT.1.1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '370',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1301',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:24.513',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'DEMO-CONN2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '217',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185925, 'nano': 547436000},\n", - " 'eventId': 'ee1a0389-e1ff-42e9-a397-8eead4599d7c:9eead33e-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '9eead33c-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 843104000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'ee1a0389-e1ff-42e9-a397-8eead4599d7c',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '3896411',\n", - " 'expected': '3896411',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '40',\n", - " 'expected': '40',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2382',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': 'C',\n", - " 'expected': 'C',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': 'C',\n", - " 'expected': 'C',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': '2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'A',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '878',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '100',\n", - " 'expected': '100',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '44',\n", - " 'expected': '44',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR4',\n", - " 'expected': 'INSTR4',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '2',\n", - " 'expected': '2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'The remaining part of simulated '\n", - " 'order has been expired',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TimeInForce': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {'NoPartyIDs': {'actual': '4',\n", - " 'expected': '4',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'DEMO-CONN2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': '76',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': '122',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': '12',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:24',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': '7',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'FIXT.1.1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '337',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1303',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:24.637',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'DEMO-CONN2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '159',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185925, 'nano': 547471000},\n", - " 'eventId': 'ee1a0389-e1ff-42e9-a397-8eead4599d7c:9eead33f-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '9eead33c-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 843104000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'rows': {'comparison-settings': {'rows': {'ignore-fields': {'rows': {},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'},\n", - " 'message-filter': {'rows': {'SecurityID': {'columns': {'expected': 'INSTR4',\n", - " 'key': False,\n", - " 'operation': 'EQUAL'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " 'message-type': {'columns': {'type': 'PreFilter'},\n", - " 'type': 'row'},\n", - " 'metadata-filter': {'rows': {}, 'type': 'collection'}},\n", - " 'type': 'treeTable'}],\n", - " 'endTimestamp': {'epochSecond': 1624185925, 'nano': 545064000},\n", - " 'eventId': '9e8078a0-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Pre-filtering (filtered 4 / processed 4) messages',\n", - " 'eventType': 'preFiltering',\n", - " 'isBatched': False,\n", - " 'parentEventId': '9e7fdc5f-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 847325000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '83775107-a1de-476c-a179-ef26b9313676',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '3896411',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '10',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2379',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': 'F',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LastPx': {'actual': '46',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '90',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '878',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '100',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '44',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR4',\n", - " 'expected': 'INSTR4',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'The simulated order has been '\n", - " 'partially traded',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TimeInForce': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'NoPartyIDs': {'actual': '5',\n", - " 'expected': 'null',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': 'DEMOFIRM1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '17',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '4': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:24',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TrdMatchID': {'actual': '487',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': 'null',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '370',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1300',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:24.511',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '222',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185925, 'nano': 546195000},\n", - " 'eventId': '83775107-a1de-476c-a179-ef26b9313676:9e8114e1-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '9e8078a0-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 847325000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '83775107-a1de-476c-a179-ef26b9313676',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '3896411',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '40',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2380',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': 'F',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LastPx': {'actual': '45',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '60',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '878',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '100',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '44',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR4',\n", - " 'expected': 'INSTR4',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'The simulated order has been '\n", - " 'partially traded',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TimeInForce': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'NoPartyIDs': {'actual': '5',\n", - " 'expected': 'null',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': 'DEMOFIRM1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '17',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '4': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:24',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TrdMatchID': {'actual': '488',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': 'null',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '370',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1301',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:24.513',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '217',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185925, 'nano': 546292000},\n", - " 'eventId': '83775107-a1de-476c-a179-ef26b9313676:9eea36f8-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '9e8078a0-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 847325000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '83775107-a1de-476c-a179-ef26b9313676',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '3896411',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '40',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2381',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': 'F',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LastPx': {'actual': '45',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '60',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '878',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '100',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '44',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR4',\n", - " 'expected': 'INSTR4',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'Extra Execution Report',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TimeInForce': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'NoPartyIDs': {'actual': '5',\n", - " 'expected': 'null',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': 'DEMOFIRM1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '17',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '4': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:24',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TrdMatchID': {'actual': '488',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': 'null',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '347',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1302',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:24.636',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '121',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185925, 'nano': 546687000},\n", - " 'eventId': '83775107-a1de-476c-a179-ef26b9313676:9eea8519-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '9e8078a0-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 847325000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '83775107-a1de-476c-a179-ef26b9313676',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '3896411',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '40',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2382',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': 'C',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': 'C',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '878',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '100',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '44',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR4',\n", - " 'expected': 'INSTR4',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'The remaining part of simulated '\n", - " 'order has been expired',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TimeInForce': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'NoPartyIDs': {'actual': '4',\n", - " 'expected': 'null',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:24',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': 'null',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '337',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1303',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:24.637',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '159',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185925, 'nano': 546761000},\n", - " 'eventId': '83775107-a1de-476c-a179-ef26b9313676:9eeaac2a-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': '9e8078a0-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 847325000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': {},\n", - " 'endTimestamp': {'epochSecond': 1624185924, 'nano': 885837000},\n", - " 'eventId': '9e865b48-d1b4-11eb-b0fb-199708acc7bc',\n", - " 'eventName': 'Case[TC_1.5]: Trader DEMO-CONN1 vs trader DEMO-CONN2 for '\n", - " 'instrument INSTR5',\n", - " 'eventType': '',\n", - " 'isBatched': False,\n", - " 'parentEventId': '84db48fc-d1b4-11eb-b0fb-199708acc7bc',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 885771000},\n", - " 'successful': False,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '69484544-8283-4ffe-ad9e-a4aa34f3966c',\n", - " 'body': {'fields': {'AccountType': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '3896411',\n", - " 'expected': '8442881',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '10',\n", - " 'expected': '10',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2379',\n", - " 'expected': '2377',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': 'F',\n", - " 'expected': 'F',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LastPx': {'actual': '46',\n", - " 'expected': '46',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '90',\n", - " 'expected': '0',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '1',\n", - " 'expected': '2',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': '2',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'A',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '878',\n", - " 'expected': '877',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '100',\n", - " 'expected': '10',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '44',\n", - " 'expected': '46',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR4',\n", - " 'expected': 'INSTR4',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': '8',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '2',\n", - " 'expected': '1',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'The simulated order has been '\n", - " 'partially traded',\n", - " 'expected': 'The simulated order has been fully '\n", - " 'traded',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TimeInForce': {'actual': '3',\n", - " 'expected': '0',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {'NoPartyIDs': {'actual': '5',\n", - " 'expected': '5',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'DEMO-CONN1',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': '76',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMOFIRM1',\n", - " 'expected': 'DEMOFIRM2',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '17',\n", - " 'expected': '17',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': '122',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '4': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': '12',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:24',\n", - " 'expected': '2021-06-20T10:45:24',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TrdMatchID': {'actual': '487',\n", - " 'expected': '487',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': '7',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'FIXT.1.1',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '370',\n", - " 'expected': '364',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1300',\n", - " 'expected': '1305',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': '8',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': 'FGW',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:24.511',\n", - " 'expected': '2021-06-20T10:45:24.498',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'DEMO-CONN1',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {'CheckSum': {'actual': '222',\n", - " 'expected': '227',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'status': 0,\n", - " 'type': 'verification'},\n", - " 'endTimestamp': {'epochSecond': 1624185924, 'nano': 970047000},\n", - " 'eventId': '69484544-8283-4ffe-ad9e-a4aa34f3966c:9e934498-d1b4-11eb-986f-1e8d42132387',\n", - " 'eventName': \"Match by '['TrdMatchID': 487]'\",\n", - " 'eventType': '',\n", - " 'isBatched': True,\n", - " 'parentEventId': '6e86db98-d047-11eb-986f-1e8d42132387',\n", - " 'startTimestamp': {'epochSecond': 1624185924, 'nano': 970047000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '69484544-8283-4ffe-ad9e-a4aa34f3966c',\n", - " 'body': {'fields': {'AccountType': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '2255277',\n", - " 'expected': '3896411',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '30',\n", - " 'expected': '40',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2378',\n", - " 'expected': '2380',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': 'F',\n", - " 'expected': 'F',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LastPx': {'actual': '45',\n", - " 'expected': '45',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '0',\n", - " 'expected': '60',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '2',\n", - " 'expected': '1',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': '2',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'A',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '876',\n", - " 'expected': '878',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '30',\n", - " 'expected': '100',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '45',\n", - " 'expected': '44',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR4',\n", - " 'expected': 'INSTR4',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': '8',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '1',\n", - " 'expected': '2',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'The simulated order has been fully '\n", - " 'traded',\n", - " 'expected': 'The simulated order has been '\n", - " 'partially traded',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TimeInForce': {'actual': '0',\n", - " 'expected': '3',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {'NoPartyIDs': {'actual': '5',\n", - " 'expected': '5',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'DEMO-CONN2',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': '76',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMOFIRM2',\n", - " 'expected': 'DEMOFIRM1',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '17',\n", - " 'expected': '17',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': '122',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '4': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': '12',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:24',\n", - " 'expected': '2021-06-20T10:45:24',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TrdMatchID': {'actual': '488',\n", - " 'expected': '488',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': '7',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'FIXT.1.1',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '364',\n", - " 'expected': '370',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1306',\n", - " 'expected': '1301',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': '8',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': 'FGW',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:24.503',\n", - " 'expected': '2021-06-20T10:45:24.513',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'DEMO-CONN2',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {'CheckSum': {'actual': '213',\n", - " 'expected': '217',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'status': 0,\n", - " 'type': 'verification'},\n", - " 'endTimestamp': {'epochSecond': 1624185925, 'nano': 564498000},\n", - " 'eventId': '69484544-8283-4ffe-ad9e-a4aa34f3966c:9eedf8fc-d1b4-11eb-986f-1e8d42132387',\n", - " 'eventName': \"Match by '['TrdMatchID': 488]'\",\n", - " 'eventType': '',\n", - " 'isBatched': True,\n", - " 'parentEventId': '6e86db98-d047-11eb-986f-1e8d42132387',\n", - " 'startTimestamp': {'epochSecond': 1624185925, 'nano': 564498000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'data': 'STEP1: Trader \"DEMO-CONN1\" sends request to create passive '\n", - " 'Order.',\n", - " 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185929, 'nano': 949740000},\n", - " 'eventId': 'a18af932-d1b4-11eb-bae5-57b0c4472880',\n", - " 'eventName': 'placeOrderFIX demo-conn1 - STEP1: Trader \"DEMO-CONN1\" sends '\n", - " 'request to create passive Order.',\n", - " 'eventType': 'placeOrderFIX',\n", - " 'isBatched': False,\n", - " 'parentEventId': '9e865b48-d1b4-11eb-b0fb-199708acc7bc',\n", - " 'startTimestamp': {'epochSecond': 1624185929, 'nano': 949701000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'b4f8d811-c4a2-4819-98b0-fcf8f0c9d0b6',\n", - " 'body': [{'data': \"Checkpoint id 'a18c0a40-d1b4-11eb-ba78-1981398e00bd'\",\n", - " 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185929, 'nano': 956273000},\n", - " 'eventId': 'b4f8d811-c4a2-4819-98b0-fcf8f0c9d0b6:a18be3f0-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Checkpoint',\n", - " 'eventType': 'Checkpoint',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'a18af932-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185929, 'nano': 955520000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'b4f8d811-c4a2-4819-98b0-fcf8f0c9d0b6',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185929, 'nano': 956273000},\n", - " 'eventId': 'b4f8d811-c4a2-4819-98b0-fcf8f0c9d0b6:a18c0b01-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'th2-hand-demo' direction 'FIRST' \"\n", - " \"sequence '1623852603564709030'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'b4f8d811-c4a2-4819-98b0-fcf8f0c9d0b6:a18be3f0-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185929, 'nano': 955520000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'b4f8d811-c4a2-4819-98b0-fcf8f0c9d0b6',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185929, 'nano': 956273000},\n", - " 'eventId': 'b4f8d811-c4a2-4819-98b0-fcf8f0c9d0b6:a18c0b02-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn1' direction 'SECOND' \"\n", - " \"sequence '1624005455622140297'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'b4f8d811-c4a2-4819-98b0-fcf8f0c9d0b6:a18be3f0-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185929, 'nano': 955520000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'b4f8d811-c4a2-4819-98b0-fcf8f0c9d0b6',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185929, 'nano': 956273000},\n", - " 'eventId': 'b4f8d811-c4a2-4819-98b0-fcf8f0c9d0b6:a18c0b03-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc1' direction 'SECOND' \"\n", - " \"sequence '1624005475721015015'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'b4f8d811-c4a2-4819-98b0-fcf8f0c9d0b6:a18be3f0-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185929, 'nano': 955520000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'b4f8d811-c4a2-4819-98b0-fcf8f0c9d0b6',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185929, 'nano': 956273000},\n", - " 'eventId': 'b4f8d811-c4a2-4819-98b0-fcf8f0c9d0b6:a18c0b04-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc1' direction 'FIRST' \"\n", - " \"sequence '1624005475720919515'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'b4f8d811-c4a2-4819-98b0-fcf8f0c9d0b6:a18be3f0-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185929, 'nano': 955520000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'b4f8d811-c4a2-4819-98b0-fcf8f0c9d0b6',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185929, 'nano': 956273000},\n", - " 'eventId': 'b4f8d811-c4a2-4819-98b0-fcf8f0c9d0b6:a18c0b05-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn2' direction 'FIRST' \"\n", - " \"sequence '1624005448022245412'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'b4f8d811-c4a2-4819-98b0-fcf8f0c9d0b6:a18be3f0-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185929, 'nano': 955520000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'b4f8d811-c4a2-4819-98b0-fcf8f0c9d0b6',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185929, 'nano': 956273000},\n", - " 'eventId': 'b4f8d811-c4a2-4819-98b0-fcf8f0c9d0b6:a18c0b06-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn2' direction 'SECOND' \"\n", - " \"sequence '1624005448022426117'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'b4f8d811-c4a2-4819-98b0-fcf8f0c9d0b6:a18be3f0-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185929, 'nano': 955520000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'b4f8d811-c4a2-4819-98b0-fcf8f0c9d0b6',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185929, 'nano': 956273000},\n", - " 'eventId': 'b4f8d811-c4a2-4819-98b0-fcf8f0c9d0b6:a18c0b07-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc2' direction 'SECOND' \"\n", - " \"sequence '1624005466840347016'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'b4f8d811-c4a2-4819-98b0-fcf8f0c9d0b6:a18be3f0-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185929, 'nano': 955520000},\n", - " 'successful': True,\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'b4f8d811-c4a2-4819-98b0-fcf8f0c9d0b6',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185929, 'nano': 956273000},\n", - " 'eventId': 'b4f8d811-c4a2-4819-98b0-fcf8f0c9d0b6:a18c0b08-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc2' direction 'FIRST' \"\n", - " \"sequence '1624005466840263384'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'b4f8d811-c4a2-4819-98b0-fcf8f0c9d0b6:a18be3f0-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185929, 'nano': 955520000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'b4f8d811-c4a2-4819-98b0-fcf8f0c9d0b6',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185929, 'nano': 956273000},\n", - " 'eventId': 'b4f8d811-c4a2-4819-98b0-fcf8f0c9d0b6:a18c0b09-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn1' direction 'FIRST' \"\n", - " \"sequence '1624005455622011538'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'b4f8d811-c4a2-4819-98b0-fcf8f0c9d0b6:a18be3f0-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185929, 'nano': 955520000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'b4f8d811-c4a2-4819-98b0-fcf8f0c9d0b6',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185929, 'nano': 956273000},\n", - " 'eventId': 'b4f8d811-c4a2-4819-98b0-fcf8f0c9d0b6:a18c0b0a-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-log' direction 'FIRST' \"\n", - " \"sequence '1624029363623063053'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'b4f8d811-c4a2-4819-98b0-fcf8f0c9d0b6:a18be3f0-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185929, 'nano': 955520000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'rows': {'AccountType': {'columns': {'fieldValue': '1'},\n", - " 'type': 'row'},\n", - " 'ClOrdID': {'columns': {'fieldValue': '9972216'},\n", - " 'type': 'row'},\n", - " 'OrdType': {'columns': {'fieldValue': '2'}, 'type': 'row'},\n", - " 'OrderCapacity': {'columns': {'fieldValue': 'A'},\n", - " 'type': 'row'},\n", - " 'OrderQty': {'columns': {'fieldValue': '30'},\n", - " 'type': 'row'},\n", - " 'Price': {'columns': {'fieldValue': '65'}, 'type': 'row'},\n", - " 'SecondaryClOrdID': {'columns': {'fieldValue': '11111'},\n", - " 'type': 'row'},\n", - " 'SecurityID': {'columns': {'fieldValue': 'INSTR5'},\n", - " 'type': 'row'},\n", - " 'SecurityIDSource': {'columns': {'fieldValue': '8'},\n", - " 'type': 'row'},\n", - " 'Side': {'columns': {'fieldValue': '1'}, 'type': 'row'},\n", - " 'TradingParty': {'rows': {'NoPartyIDs': {'rows': {'0': {'rows': {'PartyID': {'columns': {'fieldValue': 'DEMO-CONN1'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'D'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '76'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '1': {'rows': {'PartyID': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '2': {'rows': {'PartyID': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '122'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '3': {'rows': {'PartyID': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '12'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'columns': {'fieldValue': '2021-06-20T13:45:24.887460'},\n", - " 'type': 'row'}},\n", - " 'type': 'treeTable'}],\n", - " 'endTimestamp': {'epochSecond': 1624185929, 'nano': 968179000},\n", - " 'eventId': 'a18db853-d1b4-11eb-bae5-57b0c4472880',\n", - " 'eventName': \"Send 'NewOrderSingle' message to connectivity\",\n", - " 'eventType': 'Outgoing message',\n", - " 'isBatched': False,\n", - " 'parentEventId': 'a18af932-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185929, 'nano': 967964000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185929, 'nano': 994508000},\n", - " 'eventId': 'a191d724-d1b4-11eb-8e55-d3a76285d588',\n", - " 'eventName': \"Send 'NewOrderSingle' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': 'a18af932-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185929, 'nano': 994504000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185930, 'nano': 286298000},\n", - " 'eventId': 'a1be65a6-d1b4-11eb-a9ed-ffb57363e013',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '845d70d2-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185930, 'nano': 286294000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185930, 'nano': 292666000},\n", - " 'eventId': 'a1bf4fe3-d1b4-11eb-a9f4-b12655548efc',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '845d70d2-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185930, 'nano': 292528000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '6b8ad27d-ff8b-4e8d-8068-2d74e30f709d',\n", - " 'body': {'data': 'The message was deleted because a new one came with the '\n", - " \"same hash '-7539913357818383607' in message group \"\n", - " \"'NOS_CONN'\\n\"\n", - " ' Message not matched',\n", - " 'type': 'message'},\n", - " 'endTimestamp': {'epochSecond': 1624185930, 'nano': 858824000},\n", - " 'eventId': '6b8ad27d-ff8b-4e8d-8068-2d74e30f709d:a215d41e-d1b4-11eb-986f-1e8d42132387',\n", - " 'eventName': \"Remove 'NewOrderSingle' \"\n", - " \"id='demo-conn1:SECOND:1624005455622135213' \"\n", - " \"Hash='-7539913357818383607' Group='NOS_CONN' \"\n", - " \"Hash['SecondaryClOrdID': 11111, 'SecurityID': INSTR5]\",\n", - " 'eventType': '',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'a3779b94-d051-11eb-986f-1e8d42132387',\n", - " 'startTimestamp': {'epochSecond': 1624185930, 'nano': 858824000},\n", - " 'successful': False,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'rows': {'AccountType': {'columns': {'fieldValue': '1'},\n", - " 'type': 'row'},\n", - " 'ClOrdID': {'columns': {'fieldValue': '9972216'},\n", - " 'type': 'row'},\n", - " 'CumQty': {'columns': {'fieldValue': '0'}, 'type': 'row'},\n", - " 'ExecID': {'columns': {'fieldValue': '2383'},\n", - " 'type': 'row'},\n", - " 'ExecType': {'columns': {'fieldValue': '0'}, 'type': 'row'},\n", - " 'LeavesQty': {'columns': {'fieldValue': '30'},\n", - " 'type': 'row'},\n", - " 'OrdStatus': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'OrdType': {'columns': {'fieldValue': '2'}, 'type': 'row'},\n", - " 'OrderCapacity': {'columns': {'fieldValue': 'A'},\n", - " 'type': 'row'},\n", - " 'OrderID': {'columns': {'fieldValue': '879'},\n", - " 'type': 'row'},\n", - " 'OrderQty': {'columns': {'fieldValue': '30'},\n", - " 'type': 'row'},\n", - " 'Price': {'columns': {'fieldValue': '65'}, 'type': 'row'},\n", - " 'SecurityID': {'columns': {'fieldValue': 'INSTR5'},\n", - " 'type': 'row'},\n", - " 'SecurityIDSource': {'columns': {'fieldValue': '8'},\n", - " 'type': 'row'},\n", - " 'Side': {'columns': {'fieldValue': '1'}, 'type': 'row'},\n", - " 'Text': {'columns': {'fieldValue': 'Simulated New Order '\n", - " 'Buy is placed'},\n", - " 'type': 'row'},\n", - " 'TradingParty': {'rows': {'NoPartyIDs': {'rows': {'0': {'rows': {'PartyID': {'columns': {'fieldValue': 'DEMO-CONN1'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'D'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '76'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '1': {'rows': {'PartyID': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '2': {'rows': {'PartyID': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '122'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '3': {'rows': {'PartyID': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '12'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'columns': {'fieldValue': '2021-06-20T10:45:30'},\n", - " 'type': 'row'},\n", - " 'header': {'rows': {'BeginString': {'columns': {'fieldValue': 'FIXT.1.1'},\n", - " 'type': 'row'},\n", - " 'BodyLength': {'columns': {'fieldValue': '310'},\n", - " 'type': 'row'},\n", - " 'MsgSeqNum': {'columns': {'fieldValue': '1307'},\n", - " 'type': 'row'},\n", - " 'MsgType': {'columns': {'fieldValue': '8'},\n", - " 'type': 'row'},\n", - " 'SenderCompID': {'columns': {'fieldValue': 'FGW'},\n", - " 'type': 'row'},\n", - " 'SendingTime': {'columns': {'fieldValue': '2021-06-20T10:45:30.284'},\n", - " 'type': 'row'},\n", - " 'TargetCompID': {'columns': {'fieldValue': 'DEMO-CONN1'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " 'trailer': {'rows': {'CheckSum': {'columns': {'fieldValue': '054'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'treeTable'}],\n", - " 'endTimestamp': {'epochSecond': 1624185930, 'nano': 940050000},\n", - " 'eventId': 'a2223024-d1b4-11eb-bae5-57b0c4472880',\n", - " 'eventName': \"Received 'ExecutionReport' response message\",\n", - " 'eventType': 'message',\n", - " 'isBatched': False,\n", - " 'parentEventId': 'a18af932-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185930, 'nano': 940017000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'data': 'STEP2: Trader \"DEMO-CONN1\" receives Execution Report. The '\n", - " 'order stands on book in status NEW',\n", - " 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185931, 'nano': 28690000},\n", - " 'eventId': 'a22e3e7b-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Check sequence rule SessionKey{sessionAlias='demo-conn1', \"\n", - " 'direction=FIRST} - STEP2: Trader \"DEMO-CONN1\" receives '\n", - " 'Execution Report. The order stands on book in status NEW',\n", - " 'eventType': 'checkSequenceRule',\n", - " 'isBatched': False,\n", - " 'parentEventId': '9e865b48-d1b4-11eb-b0fb-199708acc7bc',\n", - " 'startTimestamp': {'epochSecond': 1624185931, 'nano': 19233000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'data': 'Contains comparisons', 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185931, 'nano': 28941000},\n", - " 'eventId': 'a22f9e0f-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Check messages',\n", - " 'eventType': 'checkMessages',\n", - " 'isBatched': False,\n", - " 'parentEventId': 'a22e3e7b-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185931, 'nano': 19233000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '0fcac3db-3747-421f-acd8-4e35921a74d3',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '9972216',\n", - " 'expected': '9972216',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2383',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '30',\n", - " 'expected': '30',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': '2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'A',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '879',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '30',\n", - " 'expected': '30',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '65',\n", - " 'expected': '65',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR5',\n", - " 'expected': 'INSTR5',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'Simulated New Order Buy is placed',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {'NoPartyIDs': {'actual': '4',\n", - " 'expected': '4',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'DEMO-CONN1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': '76',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': '122',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': '12',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:30',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': '7',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'FIXT.1.1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '310',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1307',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:30.284',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'DEMO-CONN1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '054',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185931, 'nano': 28943000},\n", - " 'eventId': '0fcac3db-3747-421f-acd8-4e35921a74d3:a22f9e10-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'a22f9e0f-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185931, 'nano': 19233000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '3815fbc9-bc3d-44af-9876-ad186b529a4d',\n", - " 'body': [{'data': 'Expected 1, Actual 1', 'type': 'message'},\n", - " {'rows': [{'actualMessage': 'ExecutionReport, demo-conn1, '\n", - " 'OrdStatus=0, ClOrdID=9972216',\n", - " 'actualMetadata': 'Metadata, demo-conn1',\n", - " 'expectedMessage': 'ExecutionReport, demo-conn1, '\n", - " 'OrdStatus=0, ClOrdID=9972216',\n", - " 'expectedMetadata': 'Metadata, demo-conn1'}],\n", - " 'type': 'table'}],\n", - " 'endTimestamp': {'epochSecond': 1624185931, 'nano': 28892000},\n", - " 'eventId': '3815fbc9-bc3d-44af-9876-ad186b529a4d:a22f9e0e-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Check sequence (expected 1 / actual 1 , check order false)',\n", - " 'eventType': 'checkSequence',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'a22e3e7b-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185931, 'nano': 19233000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'rows': {'comparison-settings': {'rows': {'ignore-fields': {'rows': {},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'},\n", - " 'message-filter': {'rows': {'SecurityID': {'columns': {'expected': 'INSTR5',\n", - " 'key': False,\n", - " 'operation': 'EQUAL'},\n", - " 'type': 'row'},\n", - " 'header': {'rows': {'MsgType': {'columns': {'expected': 'f',\n", - " 'key': False,\n", - " 'operation': 'NOT_EQUAL'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'},\n", - " 'message-type': {'columns': {'type': 'PreFilter'},\n", - " 'type': 'row'},\n", - " 'metadata-filter': {'rows': {}, 'type': 'collection'}},\n", - " 'type': 'treeTable'}],\n", - " 'endTimestamp': {'epochSecond': 1624185931, 'nano': 28728000},\n", - " 'eventId': 'a22e658c-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Pre-filtering (filtered 1 / processed 1) messages',\n", - " 'eventType': 'preFiltering',\n", - " 'isBatched': False,\n", - " 'parentEventId': 'a22e3e7b-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185931, 'nano': 20431000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'edd0d9ad-3d88-40a6-b42d-5bc7ff1c215f',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '9972216',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2383',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '30',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '879',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '30',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '65',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR5',\n", - " 'expected': 'INSTR5',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'Simulated New Order Buy is placed',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'NoPartyIDs': {'actual': '4',\n", - " 'expected': 'null',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:30',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': '1',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '310',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1307',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': 'x != \"f\"',\n", - " 'key': False,\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " 'operation': 'NOT_EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:30.284',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '054',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185931, 'nano': 28824000},\n", - " 'eventId': 'edd0d9ad-3d88-40a6-b42d-5bc7ff1c215f:a22edabd-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'a22e658c-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185931, 'nano': 20431000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'data': 'STEP3: Trader \"DEMO-CONN1\" sends request to create passive '\n", - " 'Order with price lower than first order.',\n", - " 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185931, 'nano': 147057000},\n", - " 'eventId': 'a241c615-d1b4-11eb-bae5-57b0c4472880',\n", - " 'eventName': 'placeOrderFIX demo-conn1 - STEP3: Trader \"DEMO-CONN1\" sends '\n", - " 'request to create passive Order with price lower than first '\n", - " 'order.',\n", - " 'eventType': 'placeOrderFIX',\n", - " 'isBatched': False,\n", - " 'parentEventId': '9e865b48-d1b4-11eb-b0fb-199708acc7bc',\n", - " 'startTimestamp': {'epochSecond': 1624185931, 'nano': 147030000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'f6aa500b-1cd3-43c8-83a5-c901cd202ad5',\n", - " 'body': [{'data': \"Checkpoint id 'a2445dc0-d1b4-11eb-ba78-1981398e00bd'\",\n", - " 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185931, 'nano': 164120000},\n", - " 'eventId': 'f6aa500b-1cd3-43c8-83a5-c901cd202ad5:a2445e91-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Checkpoint',\n", - " 'eventType': 'Checkpoint',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'a241c615-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185931, 'nano': 164041000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'f6aa500b-1cd3-43c8-83a5-c901cd202ad5',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185931, 'nano': 164120000},\n", - " 'eventId': 'f6aa500b-1cd3-43c8-83a5-c901cd202ad5:a2445e92-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'th2-hand-demo' direction 'FIRST' \"\n", - " \"sequence '1623852603564709030'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'f6aa500b-1cd3-43c8-83a5-c901cd202ad5:a2445e91-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185931, 'nano': 164041000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'f6aa500b-1cd3-43c8-83a5-c901cd202ad5',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185931, 'nano': 164120000},\n", - " 'eventId': 'f6aa500b-1cd3-43c8-83a5-c901cd202ad5:a2445e93-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn1' direction 'SECOND' \"\n", - " \"sequence '1624005455622140298'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'f6aa500b-1cd3-43c8-83a5-c901cd202ad5:a2445e91-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185931, 'nano': 164041000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'f6aa500b-1cd3-43c8-83a5-c901cd202ad5',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185931, 'nano': 164120000},\n", - " 'eventId': 'f6aa500b-1cd3-43c8-83a5-c901cd202ad5:a2445e94-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc1' direction 'SECOND' \"\n", - " \"sequence '1624005475721015015'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'f6aa500b-1cd3-43c8-83a5-c901cd202ad5:a2445e91-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185931, 'nano': 164041000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'f6aa500b-1cd3-43c8-83a5-c901cd202ad5',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185931, 'nano': 164120000},\n", - " 'eventId': 'f6aa500b-1cd3-43c8-83a5-c901cd202ad5:a2445e95-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc1' direction 'FIRST' \"\n", - " \"sequence '1624005475720919516'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'f6aa500b-1cd3-43c8-83a5-c901cd202ad5:a2445e91-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185931, 'nano': 164041000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'f6aa500b-1cd3-43c8-83a5-c901cd202ad5',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185931, 'nano': 164120000},\n", - " 'eventId': 'f6aa500b-1cd3-43c8-83a5-c901cd202ad5:a2445e96-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn2' direction 'FIRST' \"\n", - " \"sequence '1624005448022245412'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'f6aa500b-1cd3-43c8-83a5-c901cd202ad5:a2445e91-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185931, 'nano': 164041000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'f6aa500b-1cd3-43c8-83a5-c901cd202ad5',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185931, 'nano': 164120000},\n", - " 'eventId': 'f6aa500b-1cd3-43c8-83a5-c901cd202ad5:a2445e97-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn2' direction 'SECOND' \"\n", - " \"sequence '1624005448022426117'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'f6aa500b-1cd3-43c8-83a5-c901cd202ad5:a2445e91-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185931, 'nano': 164041000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'f6aa500b-1cd3-43c8-83a5-c901cd202ad5',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185931, 'nano': 164120000},\n", - " 'eventId': 'f6aa500b-1cd3-43c8-83a5-c901cd202ad5:a2445e98-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc2' direction 'SECOND' \"\n", - " \"sequence '1624005466840347016'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'f6aa500b-1cd3-43c8-83a5-c901cd202ad5:a2445e91-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185931, 'nano': 164041000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'f6aa500b-1cd3-43c8-83a5-c901cd202ad5',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185931, 'nano': 164120000},\n", - " 'eventId': 'f6aa500b-1cd3-43c8-83a5-c901cd202ad5:a2445e99-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc2' direction 'FIRST' \"\n", - " \"sequence '1624005466840263384'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'f6aa500b-1cd3-43c8-83a5-c901cd202ad5:a2445e91-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185931, 'nano': 164041000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'f6aa500b-1cd3-43c8-83a5-c901cd202ad5',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185931, 'nano': 164120000},\n", - " 'eventId': 'f6aa500b-1cd3-43c8-83a5-c901cd202ad5:a2445e9a-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn1' direction 'FIRST' \"\n", - " \"sequence '1624005455622011539'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'f6aa500b-1cd3-43c8-83a5-c901cd202ad5:a2445e91-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185931, 'nano': 164041000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'f6aa500b-1cd3-43c8-83a5-c901cd202ad5',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185931, 'nano': 164120000},\n", - " 'eventId': 'f6aa500b-1cd3-43c8-83a5-c901cd202ad5:a2445e9b-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-log' direction 'FIRST' \"\n", - " \"sequence '1624029363623063053'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'f6aa500b-1cd3-43c8-83a5-c901cd202ad5:a2445e91-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185931, 'nano': 164041000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'rows': {'AccountType': {'columns': {'fieldValue': '1'},\n", - " 'type': 'row'},\n", - " 'ClOrdID': {'columns': {'fieldValue': '7280757'},\n", - " 'type': 'row'},\n", - " 'OrdType': {'columns': {'fieldValue': '2'}, 'type': 'row'},\n", - " 'OrderCapacity': {'columns': {'fieldValue': 'A'},\n", - " 'type': 'row'},\n", - " 'OrderQty': {'columns': {'fieldValue': '10'},\n", - " 'type': 'row'},\n", - " 'Price': {'columns': {'fieldValue': '66'}, 'type': 'row'},\n", - " 'SecondaryClOrdID': {'columns': {'fieldValue': '22222'},\n", - " 'type': 'row'},\n", - " 'SecurityID': {'columns': {'fieldValue': 'INSTR5'},\n", - " 'type': 'row'},\n", - " 'SecurityIDSource': {'columns': {'fieldValue': '8'},\n", - " 'type': 'row'},\n", - " 'Side': {'columns': {'fieldValue': '1'}, 'type': 'row'},\n", - " 'TradingParty': {'rows': {'NoPartyIDs': {'rows': {'0': {'rows': {'PartyID': {'columns': {'fieldValue': 'DEMO-CONN1'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'D'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '76'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '1': {'rows': {'PartyID': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '2': {'rows': {'PartyID': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '122'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '3': {'rows': {'PartyID': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '12'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'columns': {'fieldValue': '2021-06-20T13:45:24.887511'},\n", - " 'type': 'row'}},\n", - " 'type': 'treeTable'}],\n", - " 'endTimestamp': {'epochSecond': 1624185931, 'nano': 172587000},\n", - " 'eventId': 'a24596a6-d1b4-11eb-bae5-57b0c4472880',\n", - " 'eventName': \"Send 'NewOrderSingle' message to connectivity\",\n", - " 'eventType': 'Outgoing message',\n", - " 'isBatched': False,\n", - " 'parentEventId': 'a241c615-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185931, 'nano': 172517000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185931, 'nano': 188067000},\n", - " 'eventId': 'a24807c5-d1b4-11eb-8e55-d3a76285d588',\n", - " 'eventName': \"Send 'NewOrderSingle' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': 'a241c615-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185931, 'nano': 188064000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185931, 'nano': 288380000},\n", - " 'eventId': 'a2574a47-d1b4-11eb-a9ed-ffb57363e013',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '845d70d2-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185931, 'nano': 288376000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185931, 'nano': 290332000},\n", - " 'eventId': 'a2579844-d1b4-11eb-a9f4-b12655548efc',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '845d70d2-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185931, 'nano': 290329000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '6b8ad27d-ff8b-4e8d-8068-2d74e30f709d',\n", - " 'body': {'data': 'The message was deleted because a new one came with the '\n", - " \"same hash '-3631733169209459363' in message group \"\n", - " \"'NOS_CONN'\\n\"\n", - " ' Message not matched',\n", - " 'type': 'message'},\n", - " 'endTimestamp': {'epochSecond': 1624185931, 'nano': 842004000},\n", - " 'eventId': '6b8ad27d-ff8b-4e8d-8068-2d74e30f709d:a2abd928-d1b4-11eb-986f-1e8d42132387',\n", - " 'eventName': \"Remove 'NewOrderSingle' \"\n", - " \"id='demo-conn1:SECOND:1624005455622135214' \"\n", - " \"Hash='-3631733169209459363' Group='NOS_CONN' \"\n", - " \"Hash['SecondaryClOrdID': 22222, 'SecurityID': INSTR5]\",\n", - " 'eventType': '',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'a3779b94-d051-11eb-986f-1e8d42132387',\n", - " 'startTimestamp': {'epochSecond': 1624185931, 'nano': 842004000},\n", - " 'successful': False,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'rows': {'AccountType': {'columns': {'fieldValue': '1'},\n", - " 'type': 'row'},\n", - " 'ClOrdID': {'columns': {'fieldValue': '7280757'},\n", - " 'type': 'row'},\n", - " 'CumQty': {'columns': {'fieldValue': '0'}, 'type': 'row'},\n", - " 'ExecID': {'columns': {'fieldValue': '2385'},\n", - " 'type': 'row'},\n", - " 'ExecType': {'columns': {'fieldValue': '0'}, 'type': 'row'},\n", - " 'LeavesQty': {'columns': {'fieldValue': '10'},\n", - " 'type': 'row'},\n", - " 'OrdStatus': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'OrdType': {'columns': {'fieldValue': '2'}, 'type': 'row'},\n", - " 'OrderCapacity': {'columns': {'fieldValue': 'A'},\n", - " 'type': 'row'},\n", - " 'OrderID': {'columns': {'fieldValue': '880'},\n", - " 'type': 'row'},\n", - " 'OrderQty': {'columns': {'fieldValue': '10'},\n", - " 'type': 'row'},\n", - " 'Price': {'columns': {'fieldValue': '66'}, 'type': 'row'},\n", - " 'SecurityID': {'columns': {'fieldValue': 'INSTR5'},\n", - " 'type': 'row'},\n", - " 'SecurityIDSource': {'columns': {'fieldValue': '8'},\n", - " 'type': 'row'},\n", - " 'Side': {'columns': {'fieldValue': '1'}, 'type': 'row'},\n", - " 'Text': {'columns': {'fieldValue': 'Simulated New Order '\n", - " 'Buy is placed'},\n", - " 'type': 'row'},\n", - " 'TradingParty': {'rows': {'NoPartyIDs': {'rows': {'0': {'rows': {'PartyID': {'columns': {'fieldValue': 'DEMO-CONN1'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'D'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '76'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '1': {'rows': {'PartyID': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '2': {'rows': {'PartyID': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '122'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '3': {'rows': {'PartyID': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '12'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'columns': {'fieldValue': '2021-06-20T10:45:31'},\n", - " 'type': 'row'},\n", - " 'header': {'rows': {'BeginString': {'columns': {'fieldValue': 'FIXT.1.1'},\n", - " 'type': 'row'},\n", - " 'BodyLength': {'columns': {'fieldValue': '310'},\n", - " 'type': 'row'},\n", - " 'MsgSeqNum': {'columns': {'fieldValue': '1308'},\n", - " 'type': 'row'},\n", - " 'MsgType': {'columns': {'fieldValue': '8'},\n", - " 'type': 'row'},\n", - " 'SenderCompID': {'columns': {'fieldValue': 'FGW'},\n", - " 'type': 'row'},\n", - " 'SendingTime': {'columns': {'fieldValue': '2021-06-20T10:45:31.287'},\n", - " 'type': 'row'},\n", - " 'TargetCompID': {'columns': {'fieldValue': 'DEMO-CONN1'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " 'trailer': {'rows': {'CheckSum': {'columns': {'fieldValue': '051'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'treeTable'}],\n", - " 'endTimestamp': {'epochSecond': 1624185931, 'nano': 942027000},\n", - " 'eventId': 'a2baedb7-d1b4-11eb-bae5-57b0c4472880',\n", - " 'eventName': \"Received 'ExecutionReport' response message\",\n", - " 'eventType': 'message',\n", - " 'isBatched': False,\n", - " 'parentEventId': 'a241c615-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185931, 'nano': 941980000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'data': 'STEP4: Trader \"DEMO-CONN1\" receives Execution Report. The '\n", - " 'order stands on book in status NEW',\n", - " 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185932, 'nano': 17542000},\n", - " 'eventId': 'a2c611bc-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Check sequence rule SessionKey{sessionAlias='demo-conn1', \"\n", - " 'direction=FIRST} - STEP4: Trader \"DEMO-CONN1\" receives '\n", - " 'Execution Report. The order stands on book in status NEW',\n", - " 'eventType': 'checkSequenceRule',\n", - " 'isBatched': False,\n", - " 'parentEventId': '9e865b48-d1b4-11eb-b0fb-199708acc7bc',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 14200000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'data': 'Contains comparisons', 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185932, 'nano': 17681000},\n", - " 'eventId': 'a2c686f0-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Check messages',\n", - " 'eventType': 'checkMessages',\n", - " 'isBatched': False,\n", - " 'parentEventId': 'a2c611bc-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 14200000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '5254c8fd-de89-4c06-9625-acc377fbadc0',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '7280757',\n", - " 'expected': '7280757',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2385',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '10',\n", - " 'expected': '10',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': '2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'A',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '880',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '10',\n", - " 'expected': '10',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '66',\n", - " 'expected': '66',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR5',\n", - " 'expected': 'INSTR5',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'Simulated New Order Buy is placed',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {'NoPartyIDs': {'actual': '4',\n", - " 'expected': '4',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'DEMO-CONN1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': '76',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': '122',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': '12',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:31',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': '7',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'FIXT.1.1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '310',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1308',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:31.287',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'DEMO-CONN1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '051',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185932, 'nano': 17683000},\n", - " 'eventId': '5254c8fd-de89-4c06-9625-acc377fbadc0:a2c686f1-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'a2c686f0-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 14200000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '75c21988-3841-47dc-b13c-1890143cf797',\n", - " 'body': [{'data': 'Expected 1, Actual 1', 'type': 'message'},\n", - " {'rows': [{'actualMessage': 'ExecutionReport, demo-conn1, '\n", - " 'ClOrdID=7280757, OrdStatus=0',\n", - " 'actualMetadata': 'Metadata, demo-conn1',\n", - " 'expectedMessage': 'ExecutionReport, demo-conn1, '\n", - " 'ClOrdID=7280757, OrdStatus=0',\n", - " 'expectedMetadata': 'Metadata, demo-conn1'}],\n", - " 'type': 'table'}],\n", - " 'endTimestamp': {'epochSecond': 1624185932, 'nano': 17665000},\n", - " 'eventId': '75c21988-3841-47dc-b13c-1890143cf797:a2c686ef-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Check sequence (expected 1 / actual 1 , check order false)',\n", - " 'eventType': 'checkSequence',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'a2c611bc-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 14200000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'rows': {'comparison-settings': {'rows': {'ignore-fields': {'rows': {},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'},\n", - " 'message-filter': {'rows': {'SecurityID': {'columns': {'expected': 'INSTR5',\n", - " 'key': False,\n", - " 'operation': 'EQUAL'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " 'message-type': {'columns': {'type': 'PreFilter'},\n", - " 'type': 'row'},\n", - " 'metadata-filter': {'rows': {}, 'type': 'collection'}},\n", - " 'type': 'treeTable'}],\n", - " 'endTimestamp': {'epochSecond': 1624185932, 'nano': 17571000},\n", - " 'eventId': 'a2c638cd-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Pre-filtering (filtered 1 / processed 1) messages',\n", - " 'eventType': 'preFiltering',\n", - " 'isBatched': False,\n", - " 'parentEventId': 'a2c611bc-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 15295000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'e6e16bcf-97c2-4f37-94e4-45d580d650ff',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '7280757',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2385',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '10',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '880',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '10',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '66',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR5',\n", - " 'expected': 'INSTR5',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'Simulated New Order Buy is placed',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'NoPartyIDs': {'actual': '4',\n", - " 'expected': 'null',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:31',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': 'null',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '310',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1308',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:31.287',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '051',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185932, 'nano': 17604000},\n", - " 'eventId': 'e6e16bcf-97c2-4f37-94e4-45d580d650ff:a2c65fde-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'a2c638cd-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 15295000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'data': 'STEP5: Trader \"DEMO-CONN2\" sends request to create '\n", - " 'aggressive IOC Order.',\n", - " 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185932, 'nano': 126674000},\n", - " 'eventId': 'a2d72848-d1b4-11eb-bae5-57b0c4472880',\n", - " 'eventName': 'placeOrderFIX demo-conn2 - STEP5: Trader \"DEMO-CONN2\" sends '\n", - " 'request to create aggressive IOC Order.',\n", - " 'eventType': 'placeOrderFIX',\n", - " 'isBatched': False,\n", - " 'parentEventId': '9e865b48-d1b4-11eb-b0fb-199708acc7bc',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 126623000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '4db96126-683f-4659-aa21-dd1c389b5d08',\n", - " 'body': [{'data': \"Checkpoint id 'a2d77600-d1b4-11eb-ba78-1981398e00bd'\",\n", - " 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185932, 'nano': 128694000},\n", - " 'eventId': '4db96126-683f-4659-aa21-dd1c389b5d08:a2d776e2-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Checkpoint',\n", - " 'eventType': 'Checkpoint',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'a2d72848-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 128621000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '4db96126-683f-4659-aa21-dd1c389b5d08',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185932, 'nano': 128694000},\n", - " 'eventId': '4db96126-683f-4659-aa21-dd1c389b5d08:a2d776e3-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'th2-hand-demo' direction 'FIRST' \"\n", - " \"sequence '1623852603564709030'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '4db96126-683f-4659-aa21-dd1c389b5d08:a2d776e2-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 128621000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '4db96126-683f-4659-aa21-dd1c389b5d08',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185932, 'nano': 128694000},\n", - " 'eventId': '4db96126-683f-4659-aa21-dd1c389b5d08:a2d776e4-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn1' direction 'SECOND' \"\n", - " \"sequence '1624005455622140299'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '4db96126-683f-4659-aa21-dd1c389b5d08:a2d776e2-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 128621000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '4db96126-683f-4659-aa21-dd1c389b5d08',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185932, 'nano': 128694000},\n", - " 'eventId': '4db96126-683f-4659-aa21-dd1c389b5d08:a2d776e5-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc1' direction 'SECOND' \"\n", - " \"sequence '1624005475721015015'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '4db96126-683f-4659-aa21-dd1c389b5d08:a2d776e2-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 128621000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '4db96126-683f-4659-aa21-dd1c389b5d08',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185932, 'nano': 128694000},\n", - " 'eventId': '4db96126-683f-4659-aa21-dd1c389b5d08:a2d776e6-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc1' direction 'FIRST' \"\n", - " \"sequence '1624005475720919517'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '4db96126-683f-4659-aa21-dd1c389b5d08:a2d776e2-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 128621000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '4db96126-683f-4659-aa21-dd1c389b5d08',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185932, 'nano': 128694000},\n", - " 'eventId': '4db96126-683f-4659-aa21-dd1c389b5d08:a2d776e7-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn2' direction 'FIRST' \"\n", - " \"sequence '1624005448022245412'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '4db96126-683f-4659-aa21-dd1c389b5d08:a2d776e2-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 128621000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '4db96126-683f-4659-aa21-dd1c389b5d08',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185932, 'nano': 128694000},\n", - " 'eventId': '4db96126-683f-4659-aa21-dd1c389b5d08:a2d776e8-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn2' direction 'SECOND' \"\n", - " \"sequence '1624005448022426117'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '4db96126-683f-4659-aa21-dd1c389b5d08:a2d776e2-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 128621000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '4db96126-683f-4659-aa21-dd1c389b5d08',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185932, 'nano': 128694000},\n", - " 'eventId': '4db96126-683f-4659-aa21-dd1c389b5d08:a2d776e9-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc2' direction 'SECOND' \"\n", - " \"sequence '1624005466840347016'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '4db96126-683f-4659-aa21-dd1c389b5d08:a2d776e2-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 128621000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '4db96126-683f-4659-aa21-dd1c389b5d08',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185932, 'nano': 128694000},\n", - " 'eventId': '4db96126-683f-4659-aa21-dd1c389b5d08:a2d776ea-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc2' direction 'FIRST' \"\n", - " \"sequence '1624005466840263384'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '4db96126-683f-4659-aa21-dd1c389b5d08:a2d776e2-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 128621000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '4db96126-683f-4659-aa21-dd1c389b5d08',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185932, 'nano': 128694000},\n", - " 'eventId': '4db96126-683f-4659-aa21-dd1c389b5d08:a2d776eb-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn1' direction 'FIRST' \"\n", - " \"sequence '1624005455622011540'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '4db96126-683f-4659-aa21-dd1c389b5d08:a2d776e2-d1b4-11eb-9278-591e568ad66e',\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 128621000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '4db96126-683f-4659-aa21-dd1c389b5d08',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185932, 'nano': 128694000},\n", - " 'eventId': '4db96126-683f-4659-aa21-dd1c389b5d08:a2d776ec-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-log' direction 'FIRST' \"\n", - " \"sequence '1624029363623063053'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '4db96126-683f-4659-aa21-dd1c389b5d08:a2d776e2-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 128621000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'rows': {'AccountType': {'columns': {'fieldValue': '1'},\n", - " 'type': 'row'},\n", - " 'ClOrdID': {'columns': {'fieldValue': '3291690'},\n", - " 'type': 'row'},\n", - " 'OrdType': {'columns': {'fieldValue': '2'}, 'type': 'row'},\n", - " 'OrderCapacity': {'columns': {'fieldValue': 'A'},\n", - " 'type': 'row'},\n", - " 'OrderQty': {'columns': {'fieldValue': '100'},\n", - " 'type': 'row'},\n", - " 'Price': {'columns': {'fieldValue': '64'}, 'type': 'row'},\n", - " 'SecondaryClOrdID': {'columns': {'fieldValue': '33333'},\n", - " 'type': 'row'},\n", - " 'SecurityID': {'columns': {'fieldValue': 'INSTR5'},\n", - " 'type': 'row'},\n", - " 'SecurityIDSource': {'columns': {'fieldValue': '8'},\n", - " 'type': 'row'},\n", - " 'Side': {'columns': {'fieldValue': '2'}, 'type': 'row'},\n", - " 'TimeInForce': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'},\n", - " 'TradingParty': {'rows': {'NoPartyIDs': {'rows': {'0': {'rows': {'PartyID': {'columns': {'fieldValue': 'DEMO-CONN2'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'D'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '76'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '1': {'rows': {'PartyID': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '2': {'rows': {'PartyID': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '122'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '3': {'rows': {'PartyID': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '12'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'columns': {'fieldValue': '2021-06-20T13:45:24.887547'},\n", - " 'type': 'row'}},\n", - " 'type': 'treeTable'}],\n", - " 'endTimestamp': {'epochSecond': 1624185932, 'nano': 140746000},\n", - " 'eventId': 'a2d94b29-d1b4-11eb-bae5-57b0c4472880',\n", - " 'eventName': \"Send 'NewOrderSingle' message to connectivity\",\n", - " 'eventType': 'Outgoing message',\n", - " 'isBatched': False,\n", - " 'parentEventId': 'a2d72848-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 140705000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185932, 'nano': 152910000},\n", - " 'eventId': 'a2db1f85-d1b4-11eb-bd0a-0d6cee9f6833',\n", - " 'eventName': \"Send 'NewOrderSingle' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': 'a2d72848-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 152877000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185932, 'nano': 463377000},\n", - " 'eventId': 'a30a94b8-d1b4-11eb-a9ed-ffb57363e013',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '849a79d3-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 463373000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185932, 'nano': 465660000},\n", - " 'eventId': 'a30ae2d9-d1b4-11eb-a9ed-ffb57363e013',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '849a79d3-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 465657000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185932, 'nano': 484719000},\n", - " 'eventId': 'a30dc8e5-d1b4-11eb-a9f4-b12655548efc',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '849a79d3-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 484715000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185932, 'nano': 486495000},\n", - " 'eventId': 'a30e1706-d1b4-11eb-a9f4-b12655548efc',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '849a79d3-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 486493000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185932, 'nano': 486940000},\n", - " 'eventId': 'a30e1689-d1b4-11eb-91f0-77dd26d4db8e',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '849a79d3-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 486886000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185932, 'nano': 524679000},\n", - " 'eventId': 'a313e2ea-d1b4-11eb-91f0-77dd26d4db8e',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '849a79d3-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 524665000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185932, 'nano': 528571000},\n", - " 'eventId': 'a3147f2b-d1b4-11eb-91f0-77dd26d4db8e',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '849a79d3-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 528551000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'rows': {'AccountType': {'columns': {'fieldValue': '1'},\n", - " 'type': 'row'},\n", - " 'ClOrdID': {'columns': {'fieldValue': '3291690'},\n", - " 'type': 'row'},\n", - " 'CumQty': {'columns': {'fieldValue': '10'}, 'type': 'row'},\n", - " 'ExecID': {'columns': {'fieldValue': '2389'},\n", - " 'type': 'row'},\n", - " 'ExecType': {'columns': {'fieldValue': 'F'}, 'type': 'row'},\n", - " 'LastPx': {'columns': {'fieldValue': '66'}, 'type': 'row'},\n", - " 'LeavesQty': {'columns': {'fieldValue': '90'},\n", - " 'type': 'row'},\n", - " 'OrdStatus': {'columns': {'fieldValue': '1'},\n", - " 'type': 'row'},\n", - " 'OrdType': {'columns': {'fieldValue': '2'}, 'type': 'row'},\n", - " 'OrderCapacity': {'columns': {'fieldValue': 'A'},\n", - " 'type': 'row'},\n", - " 'OrderID': {'columns': {'fieldValue': '881'},\n", - " 'type': 'row'},\n", - " 'OrderQty': {'columns': {'fieldValue': '100'},\n", - " 'type': 'row'},\n", - " 'Price': {'columns': {'fieldValue': '64'}, 'type': 'row'},\n", - " 'SecurityID': {'columns': {'fieldValue': 'INSTR5'},\n", - " 'type': 'row'},\n", - " 'SecurityIDSource': {'columns': {'fieldValue': '8'},\n", - " 'type': 'row'},\n", - " 'Side': {'columns': {'fieldValue': '2'}, 'type': 'row'},\n", - " 'Text': {'columns': {'fieldValue': 'The simulated order '\n", - " 'has been partially '\n", - " 'traded'},\n", - " 'type': 'row'},\n", - " 'TimeInForce': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'},\n", - " 'TradingParty': {'rows': {'NoPartyIDs': {'rows': {'0': {'rows': {'PartyID': {'columns': {'fieldValue': 'DEMO-CONN2'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'D'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '76'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '1': {'rows': {'PartyID': {'columns': {'fieldValue': 'DEMOFIRM1'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'D'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '17'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '2': {'rows': {'PartyID': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '3': {'rows': {'PartyID': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '122'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '4': {'rows': {'PartyID': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '12'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'columns': {'fieldValue': '2021-06-20T10:45:32'},\n", - " 'type': 'row'},\n", - " 'TrdMatchID': {'columns': {'fieldValue': '489'},\n", - " 'type': 'row'},\n", - " 'header': {'rows': {'BeginString': {'columns': {'fieldValue': 'FIXT.1.1'},\n", - " 'type': 'row'},\n", - " 'BodyLength': {'columns': {'fieldValue': '370'},\n", - " 'type': 'row'},\n", - " 'MsgSeqNum': {'columns': {'fieldValue': '1304'},\n", - " 'type': 'row'},\n", - " 'MsgType': {'columns': {'fieldValue': '8'},\n", - " 'type': 'row'},\n", - " 'SenderCompID': {'columns': {'fieldValue': 'FGW'},\n", - " 'type': 'row'},\n", - " 'SendingTime': {'columns': {'fieldValue': '2021-06-20T10:45:32.485'},\n", - " 'type': 'row'},\n", - " 'TargetCompID': {'columns': {'fieldValue': 'DEMO-CONN2'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " 'trailer': {'rows': {'CheckSum': {'columns': {'fieldValue': '234'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'treeTable'}],\n", - " 'endTimestamp': {'epochSecond': 1624185932, 'nano': 531072000},\n", - " 'eventId': 'a314f49a-d1b4-11eb-bae5-57b0c4472880',\n", - " 'eventName': \"Received 'ExecutionReport' response message\",\n", - " 'eventType': 'message',\n", - " 'isBatched': False,\n", - " 'parentEventId': 'a2d72848-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 531032000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185932, 'nano': 532453000},\n", - " 'eventId': 'a3151b99-d1b4-11eb-be23-57049e5b0bd9',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '849a79d3-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 532426000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185932, 'nano': 538560000},\n", - " 'eventId': 'a31605fa-d1b4-11eb-be23-57049e5b0bd9',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '849a79d3-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 538546000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185932, 'nano': 543489000},\n", - " 'eventId': 'a316c94b-d1b4-11eb-be23-57049e5b0bd9',\n", - " 'eventName': \"Send 'ExecutionReport' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '849a79d3-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 543476000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'data': 'STEP6: Trader \"DEMO-CONN1\" receives Execution Reports with '\n", - " 'ExecType=F: first at Order2 and second on Order1.',\n", - " 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185932, 'nano': 943317000},\n", - " 'eventId': 'a322b0bd-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Check sequence rule SessionKey{sessionAlias='demo-conn1', \"\n", - " 'direction=FIRST} - STEP6: Trader \"DEMO-CONN1\" receives '\n", - " 'Execution Reports with ExecType=F: first at Order2 and second '\n", - " 'on Order1.',\n", - " 'eventType': 'checkSequenceRule',\n", - " 'isBatched': False,\n", - " 'parentEventId': '9e865b48-d1b4-11eb-b0fb-199708acc7bc',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 621555000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'data': 'Contains comparisons', 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185932, 'nano': 943700000},\n", - " 'eventId': 'a353d2e5-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Check messages',\n", - " 'eventType': 'checkMessages',\n", - " 'isBatched': False,\n", - " 'parentEventId': 'a322b0bd-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 621555000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '0d85eaf3-2ce0-407e-ac5e-1bf4657cd314',\n", - " 'body': [{'data': 'Expected 2, Actual 2, In order', 'type': 'message'},\n", - " {'rows': [{'actualMessage': 'ExecutionReport, demo-conn1, '\n", - " 'OrdStatus=2, ClOrdID=7280757, '\n", - " 'LeavesQty=0, CumQty=10',\n", - " 'actualMetadata': 'Metadata, demo-conn1',\n", - " 'expectedMessage': 'ExecutionReport, demo-conn1, '\n", - " 'OrdStatus=2, ClOrdID=7280757, '\n", - " 'LeavesQty=0, CumQty=10',\n", - " 'expectedMetadata': 'Metadata, demo-conn1'},\n", - " {'actualMessage': 'ExecutionReport, demo-conn1, '\n", - " 'LeavesQty=0, CumQty=30, '\n", - " 'ClOrdID=9972216, OrdStatus=2',\n", - " 'actualMetadata': 'Metadata, demo-conn1',\n", - " 'expectedMessage': 'ExecutionReport, demo-conn1, '\n", - " 'LeavesQty=0, CumQty=30, '\n", - " 'ClOrdID=9972216, OrdStatus=2',\n", - " 'expectedMetadata': 'Metadata, demo-conn1'}],\n", - " 'type': 'table'}],\n", - " 'endTimestamp': {'epochSecond': 1624185932, 'nano': 943673000},\n", - " 'eventId': '0d85eaf3-2ce0-407e-ac5e-1bf4657cd314:a353d2e4-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Check sequence (expected 2 / actual 2 , check order true)',\n", - " 'eventType': 'checkSequence',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'a322b0bd-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 621555000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '78c6db8b-07bc-46b2-81b7-1b3ea537acf3',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '7280757',\n", - " 'expected': '7280757',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '10',\n", - " 'expected': '10',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2387',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': 'F',\n", - " 'expected': 'F',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LastPx': {'actual': '66',\n", - " 'expected': '66',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '2',\n", - " 'expected': '2',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': '2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'A',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '880',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '10',\n", - " 'expected': '10',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '66',\n", - " 'expected': '66',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR5',\n", - " 'expected': 'INSTR5',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'The simulated order has been fully '\n", - " 'traded',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TimeInForce': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {'NoPartyIDs': {'actual': '5',\n", - " 'expected': '5',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'DEMO-CONN1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': '76',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMOFIRM2',\n", - " 'expected': 'DEMOFIRM2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '17',\n", - " 'expected': '17',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': '122',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '4': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': '12',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:32',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TrdMatchID': {'actual': '489',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': '7',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'FIXT.1.1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '364',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1309',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:32.462',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'DEMO-CONN1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '223',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185932, 'nano': 943704000},\n", - " 'eventId': '78c6db8b-07bc-46b2-81b7-1b3ea537acf3:a353d2e6-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'a353d2e5-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 621555000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '78c6db8b-07bc-46b2-81b7-1b3ea537acf3',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '9972216',\n", - " 'expected': '9972216',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '30',\n", - " 'expected': '30',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2388',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': 'F',\n", - " 'expected': 'F',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LastPx': {'actual': '65',\n", - " 'expected': '65',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '2',\n", - " 'expected': '2',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': '2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'A',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '879',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '30',\n", - " 'expected': '30',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '65',\n", - " 'expected': '65',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR5',\n", - " 'expected': 'INSTR5',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'The simulated order has been fully '\n", - " 'traded',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TimeInForce': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {'NoPartyIDs': {'actual': '5',\n", - " 'expected': '5',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'DEMO-CONN1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': '76',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMOFIRM2',\n", - " 'expected': 'DEMOFIRM2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '17',\n", - " 'expected': '17',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': '122',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '4': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': '12',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:32',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TrdMatchID': {'actual': '490',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': '7',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'FIXT.1.1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '364',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1310',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:32.464',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'DEMO-CONN1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '220',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185932, 'nano': 943764000},\n", - " 'eventId': '78c6db8b-07bc-46b2-81b7-1b3ea537acf3:a353d2e7-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'a353d2e5-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 621555000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'rows': {'comparison-settings': {'rows': {'ignore-fields': {'rows': {},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'},\n", - " 'message-filter': {'rows': {'SecurityID': {'columns': {'expected': 'INSTR5',\n", - " 'key': False,\n", - " 'operation': 'EQUAL'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " 'message-type': {'columns': {'type': 'PreFilter'},\n", - " 'type': 'row'},\n", - " 'metadata-filter': {'rows': {}, 'type': 'collection'}},\n", - " 'type': 'treeTable'}],\n", - " 'endTimestamp': {'epochSecond': 1624185932, 'nano': 943360000},\n", - " 'eventId': 'a322fede-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Pre-filtering (filtered 2 / processed 2) messages',\n", - " 'eventType': 'preFiltering',\n", - " 'isBatched': False,\n", - " 'parentEventId': 'a322b0bd-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 623385000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'f1bffe38-2fdf-413c-a845-778436c9b001',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '7280757',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '10',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2387',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': 'F',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LastPx': {'actual': '66',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '880',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '10',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '66',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR5',\n", - " 'expected': 'INSTR5',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'The simulated order has been fully '\n", - " 'traded',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TimeInForce': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'NoPartyIDs': {'actual': '5',\n", - " 'expected': 'null',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': 'DEMOFIRM2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '17',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '4': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:32',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TrdMatchID': {'actual': '489',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': 'null',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '364',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1309',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:32.462',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '223',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185932, 'nano': 943413000},\n", - " 'eventId': 'f1bffe38-2fdf-413c-a845-778436c9b001:a352c172-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'a322fede-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 623385000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'f1bffe38-2fdf-413c-a845-778436c9b001',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '9972216',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '30',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2388',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': 'F',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LastPx': {'actual': '65',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '879',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '30',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '65',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR5',\n", - " 'expected': 'INSTR5',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'The simulated order has been fully '\n", - " 'traded',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TimeInForce': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'NoPartyIDs': {'actual': '5',\n", - " 'expected': 'null',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': 'DEMOFIRM2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '17',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '4': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:32',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TrdMatchID': {'actual': '490',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': 'null',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '364',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1310',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:32.464',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '220',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185932, 'nano': 943502000},\n", - " 'eventId': 'f1bffe38-2fdf-413c-a845-778436c9b001:a3535db3-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'a322fede-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 623385000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '38ca8816-62ac-45eb-a5c1-73c16699a2ec',\n", - " 'body': {'data': 'The message was deleted because a new one came with the '\n", - " \"same hash '-3378881774735559571' in message group \"\n", - " \"'NOS_CONN'\\n\"\n", - " ' Message not matched',\n", - " 'type': 'message'},\n", - " 'endTimestamp': {'epochSecond': 1624185932, 'nano': 639735000},\n", - " 'eventId': '38ca8816-62ac-45eb-a5c1-73c16699a2ec:a3259272-d1b4-11eb-986f-1e8d42132387',\n", - " 'eventName': \"Remove 'NewOrderSingle' \"\n", - " \"id='demo-conn2:SECOND:1624005448022421040' \"\n", - " \"Hash='-3378881774735559571' Group='NOS_CONN' \"\n", - " \"Hash['SecondaryClOrdID': 33333, 'SecurityID': INSTR5]\",\n", - " 'eventType': '',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'a3779b94-d051-11eb-986f-1e8d42132387',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 639735000},\n", - " 'successful': False,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'data': 'STEP7: Trader \"DEMO-CONN2\" receives Execution Reports: '\n", - " 'first trade with Order2, next with Order1 and then '\n", - " 'cancellation',\n", - " 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185933, 'nano': 562123000},\n", - " 'eventId': 'a334b21f-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Check sequence rule SessionKey{sessionAlias='demo-conn2', \"\n", - " 'direction=FIRST} - STEP7: Trader \"DEMO-CONN2\" receives '\n", - " 'Execution Reports: first trade with Order2, next with Order1 '\n", - " 'and then cancellation',\n", - " 'eventType': 'checkSequenceRule',\n", - " 'isBatched': False,\n", - " 'parentEventId': '9e865b48-d1b4-11eb-b0fb-199708acc7bc',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 739688000},\n", - " 'successful': False,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'data': 'Contains comparisons', 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185933, 'nano': 562495000},\n", - " 'eventId': 'a3b21f8b-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Check messages',\n", - " 'eventType': 'checkMessages',\n", - " 'isBatched': False,\n", - " 'parentEventId': 'a334b21f-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 739688000},\n", - " 'successful': False,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '1ca7683c-b206-4cc3-a659-76da1ec9583d',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '3291690',\n", - " 'expected': '3291690',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '10',\n", - " 'expected': '10',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2389',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': 'F',\n", - " 'expected': 'F',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LastPx': {'actual': '66',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '90',\n", - " 'expected': '90',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': '2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'A',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '881',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '100',\n", - " 'expected': '100',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '64',\n", - " 'expected': '64',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR5',\n", - " 'expected': 'INSTR5',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '2',\n", - " 'expected': '2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'The simulated order has been '\n", - " 'partially traded',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TimeInForce': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {'NoPartyIDs': {'actual': '5',\n", - " 'expected': '5',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'DEMO-CONN2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': '76',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMOFIRM1',\n", - " 'expected': 'DEMOFIRM1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '17',\n", - " 'expected': '17',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': '122',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '4': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': '12',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:32',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TrdMatchID': {'actual': '489',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': '7',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'FIXT.1.1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '370',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1304',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:32.485',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'DEMO-CONN2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '234',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185933, 'nano': 562504000},\n", - " 'eventId': '1ca7683c-b206-4cc3-a659-76da1ec9583d:a3b21f8c-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'a3b21f8b-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 739688000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '1ca7683c-b206-4cc3-a659-76da1ec9583d',\n", - " 'body': [{'fields': {'AccountType': {'actual': '2',\n", - " 'expected': '1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'FAILED',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '3291690',\n", - " 'expected': '3291690',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '40',\n", - " 'expected': '40',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2390',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': 'F',\n", - " 'expected': 'F',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LastPx': {'actual': '65',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '60',\n", - " 'expected': '60',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': '2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'P',\n", - " 'expected': 'A',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'FAILED',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '881',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '100',\n", - " 'expected': '100',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '64',\n", - " 'expected': '64',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR5',\n", - " 'expected': 'INSTR5',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '2',\n", - " 'expected': '2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'Execution Report with incorrect '\n", - " 'value in OrdStatus tag',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TimeInForce': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {'NoPartyIDs': {'actual': '5',\n", - " 'expected': '5',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'DEMO-CONN2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': '76',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMOFIRM1',\n", - " 'expected': 'DEMOFIRM1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '17',\n", - " 'expected': '17',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': '122',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '4': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': '12',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:32',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TrdMatchID': {'actual': '490',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': '7',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'FIXT.1.1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '379',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1305',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:32.523',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'DEMO-CONN2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '121',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185933, 'nano': 562554000},\n", - " 'eventId': '1ca7683c-b206-4cc3-a659-76da1ec9583d:a3b2469d-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'a3b21f8b-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 739688000},\n", - " 'successful': False,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '1ca7683c-b206-4cc3-a659-76da1ec9583d',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '3291690',\n", - " 'expected': '3291690',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '40',\n", - " 'expected': '40',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2391',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': 'C',\n", - " 'expected': 'C',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': 'C',\n", - " 'expected': 'C',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': '2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'A',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '881',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '100',\n", - " 'expected': '100',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '64',\n", - " 'expected': '64',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR5',\n", - " 'expected': 'INSTR5',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '2',\n", - " 'expected': '2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'The remaining part of simulated '\n", - " 'order has been expired',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TimeInForce': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {'NoPartyIDs': {'actual': '4',\n", - " 'expected': '4',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'DEMO-CONN2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': '76',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': '122',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': '12',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:32',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': '7',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'FIXT.1.1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '337',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1306',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:32.527',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'DEMO-CONN2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '153',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185933, 'nano': 562603000},\n", - " 'eventId': '1ca7683c-b206-4cc3-a659-76da1ec9583d:a3b2469e-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'a3b21f8b-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 739688000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'aeaa6efe-3e45-43ae-95f2-199906dbcd4a',\n", - " 'body': [{'data': 'Expected 3, Actual 3, In order', 'type': 'message'},\n", - " {'rows': [{'actualMessage': 'ExecutionReport, demo-conn2, '\n", - " 'OrdStatus=1, CumQty=10, '\n", - " 'ClOrdID=3291690, LeavesQty=90',\n", - " 'actualMetadata': 'Metadata, demo-conn2',\n", - " 'expectedMessage': 'ExecutionReport, demo-conn2, '\n", - " 'OrdStatus=1, CumQty=10, '\n", - " 'ClOrdID=3291690, LeavesQty=90',\n", - " 'expectedMetadata': 'Metadata, demo-conn2'},\n", - " {'actualMessage': 'ExecutionReport, demo-conn2, '\n", - " 'ClOrdID=3291690, CumQty=40, '\n", - " 'LeavesQty=60, OrdStatus=1',\n", - " 'actualMetadata': 'Metadata, demo-conn2',\n", - " 'expectedMessage': 'ExecutionReport, demo-conn2, '\n", - " 'ClOrdID=3291690, CumQty=40, '\n", - " 'LeavesQty=60, OrdStatus=1',\n", - " 'expectedMetadata': 'Metadata, demo-conn2'},\n", - " {'actualMessage': 'ExecutionReport, demo-conn2, '\n", - " 'LeavesQty=0, CumQty=40, OrdStatus=C, '\n", - " 'ClOrdID=3291690',\n", - " 'actualMetadata': 'Metadata, demo-conn2',\n", - " 'expectedMessage': 'ExecutionReport, demo-conn2, '\n", - " 'LeavesQty=0, CumQty=40, OrdStatus=C, '\n", - " 'ClOrdID=3291690',\n", - " 'expectedMetadata': 'Metadata, demo-conn2'}],\n", - " 'type': 'table'}],\n", - " 'endTimestamp': {'epochSecond': 1624185933, 'nano': 562474000},\n", - " 'eventId': 'aeaa6efe-3e45-43ae-95f2-199906dbcd4a:a3b21f8a-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Check sequence (expected 3 / actual 3 , check order true)',\n", - " 'eventType': 'checkSequence',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'a334b21f-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 739688000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'rows': {'comparison-settings': {'rows': {'ignore-fields': {'rows': {},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'},\n", - " 'message-filter': {'rows': {'SecurityID': {'columns': {'expected': 'INSTR5',\n", - " 'key': False,\n", - " 'operation': 'EQUAL'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " 'message-type': {'columns': {'type': 'PreFilter'},\n", - " 'type': 'row'},\n", - " 'metadata-filter': {'rows': {}, 'type': 'collection'}},\n", - " 'type': 'treeTable'}],\n", - " 'endTimestamp': {'epochSecond': 1624185933, 'nano': 562171000},\n", - " 'eventId': 'a3350040-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Pre-filtering (filtered 3 / processed 3) messages',\n", - " 'eventType': 'preFiltering',\n", - " 'isBatched': False,\n", - " 'parentEventId': 'a334b21f-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 741779000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'attachedMessageIds': [],\n", - " 'batchId': 'e9440dd3-0575-46a3-92c1-02657a8d65da',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '3291690',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '10',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2389',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': 'F',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LastPx': {'actual': '66',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '90',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '881',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '100',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '64',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR5',\n", - " 'expected': 'INSTR5',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'The simulated order has been '\n", - " 'partially traded',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TimeInForce': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'NoPartyIDs': {'actual': '5',\n", - " 'expected': 'null',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': 'DEMOFIRM1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '17',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '4': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:32',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TrdMatchID': {'actual': '489',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': 'null',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '370',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1304',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:32.485',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '234',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185933, 'nano': 562214000},\n", - " 'eventId': 'e9440dd3-0575-46a3-92c1-02657a8d65da:a3354e61-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'a3350040-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 741779000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'e9440dd3-0575-46a3-92c1-02657a8d65da',\n", - " 'body': [{'fields': {'AccountType': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '3291690',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '40',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2390',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': 'F',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LastPx': {'actual': '65',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '60',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '881',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '100',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '64',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR5',\n", - " 'expected': 'INSTR5',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'Execution Report with incorrect '\n", - " 'value in OrdStatus tag',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TimeInForce': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'NoPartyIDs': {'actual': '5',\n", - " 'expected': 'null',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': 'DEMOFIRM1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '17',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '4': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:32',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TrdMatchID': {'actual': '490',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': 'null',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '379',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1305',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:32.523',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '121',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185933, 'nano': 562293000},\n", - " 'eventId': 'e9440dd3-0575-46a3-92c1-02657a8d65da:a3b13528-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'a3350040-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 741779000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': 'e9440dd3-0575-46a3-92c1-02657a8d65da',\n", - " 'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '3291690',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '40',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2391',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': 'C',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': 'C',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '881',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '100',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '64',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR5',\n", - " 'expected': 'INSTR5',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'The remaining part of simulated '\n", - " 'order has been expired',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TimeInForce': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': 'null',\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " 'fields': {'NoPartyIDs': {'actual': '4',\n", - " 'expected': 'null',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:32',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': 'null',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '337',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1306',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:32.527',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '153',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'endTimestamp': {'epochSecond': 1624185933, 'nano': 562432000},\n", - " 'eventId': 'e9440dd3-0575-46a3-92c1-02657a8d65da:a3b15c39-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'eventType': 'Verification',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'a3350040-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 741779000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': {},\n", - " 'endTimestamp': {'epochSecond': 1624185932, 'nano': 778839000},\n", - " 'eventId': 'a33aba58-d1b4-11eb-b0fb-199708acc7bc',\n", - " 'eventName': 'Case[TC_1.6]: Trader DEMO-CONN1 vs trader DEMO-CONN2 for '\n", - " 'instrument INSTR6',\n", - " 'eventType': '',\n", - " 'isBatched': False,\n", - " 'parentEventId': '84db48fc-d1b4-11eb-b0fb-199708acc7bc',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 778780000},\n", - " 'successful': False,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '2c55e9dc-f840-44ca-a1fa-8485d634bb9d',\n", - " 'body': {'fields': {'AccountType': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '3291690',\n", - " 'expected': '7280757',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '10',\n", - " 'expected': '10',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2389',\n", - " 'expected': '2387',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': 'F',\n", - " 'expected': 'F',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LastPx': {'actual': '66',\n", - " 'expected': '66',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '90',\n", - " 'expected': '0',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '1',\n", - " 'expected': '2',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': '2',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'A',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '881',\n", - " 'expected': '880',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '100',\n", - " 'expected': '10',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '64',\n", - " 'expected': '66',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR5',\n", - " 'expected': 'INSTR5',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': '8',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '2',\n", - " 'expected': '1',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'The simulated order has been '\n", - " 'partially traded',\n", - " 'expected': 'The simulated order has been fully '\n", - " 'traded',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TimeInForce': {'actual': '3',\n", - " 'expected': '0',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {'NoPartyIDs': {'actual': '5',\n", - " 'expected': '5',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'DEMO-CONN1',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': '76',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMOFIRM1',\n", - " 'expected': 'DEMOFIRM2',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '17',\n", - " 'expected': '17',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': '122',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '4': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': '12',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:32',\n", - " 'expected': '2021-06-20T10:45:32',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TrdMatchID': {'actual': '489',\n", - " 'expected': '489',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': '7',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'FIXT.1.1',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '370',\n", - " 'expected': '364',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1304',\n", - " 'expected': '1309',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': '8',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': 'FGW',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:32.485',\n", - " 'expected': '2021-06-20T10:45:32.462',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN2',\n", - " 'expected': 'DEMO-CONN1',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {'CheckSum': {'actual': '234',\n", - " 'expected': '223',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'status': 0,\n", - " 'type': 'verification'},\n", - " 'endTimestamp': {'epochSecond': 1624185932, 'nano': 984822000},\n", - " 'eventId': '2c55e9dc-f840-44ca-a1fa-8485d634bb9d:a35a3b12-d1b4-11eb-986f-1e8d42132387',\n", - " 'eventName': \"Match by '['TrdMatchID': 489]'\",\n", - " 'eventType': '',\n", - " 'isBatched': True,\n", - " 'parentEventId': '6e86db98-d047-11eb-986f-1e8d42132387',\n", - " 'startTimestamp': {'epochSecond': 1624185932, 'nano': 984822000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '96e78748-647e-4ba6-96fb-ce2253858c5b',\n", - " 'body': {'fields': {'AccountType': {'actual': '1',\n", - " 'expected': '2',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'FAILED',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '9972216',\n", - " 'expected': '3291690',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '30',\n", - " 'expected': '40',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2388',\n", - " 'expected': '2390',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': 'F',\n", - " 'expected': 'F',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LastPx': {'actual': '65',\n", - " 'expected': '65',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '0',\n", - " 'expected': '60',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '2',\n", - " 'expected': '1',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': '2',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'P',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'FAILED',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '879',\n", - " 'expected': '881',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '30',\n", - " 'expected': '100',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '65',\n", - " 'expected': '64',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR5',\n", - " 'expected': 'INSTR5',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': '8',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '1',\n", - " 'expected': '2',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'The simulated order has been fully '\n", - " 'traded',\n", - " 'expected': 'Execution Report with incorrect '\n", - " 'value in OrdStatus tag',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TimeInForce': {'actual': '0',\n", - " 'expected': '3',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {'NoPartyIDs': {'actual': '5',\n", - " 'expected': '5',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'DEMO-CONN2',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': '76',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMOFIRM2',\n", - " 'expected': 'DEMOFIRM1',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '17',\n", - " 'expected': '17',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': '122',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '4': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': '12',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:45:32',\n", - " 'expected': '2021-06-20T10:45:32',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TrdMatchID': {'actual': '490',\n", - " 'expected': '490',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': '7',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'FIXT.1.1',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '364',\n", - " 'expected': '379',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1310',\n", - " 'expected': '1305',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': '8',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': 'FGW',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:45:32.464',\n", - " 'expected': '2021-06-20T10:45:32.523',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'DEMO-CONN2',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {'CheckSum': {'actual': '220',\n", - " 'expected': '121',\n", - " 'fields': {},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'status': 1,\n", - " 'type': 'verification'},\n", - " 'endTimestamp': {'epochSecond': 1624185933, 'nano': 591826000},\n", - " 'eventId': '96e78748-647e-4ba6-96fb-ce2253858c5b:a3b6ddc2-d1b4-11eb-986f-1e8d42132387',\n", - " 'eventName': \"Match by '['TrdMatchID': 490]'\",\n", - " 'eventType': '',\n", - " 'isBatched': True,\n", - " 'parentEventId': '818e2b06-d047-11eb-986f-1e8d42132387',\n", - " 'startTimestamp': {'epochSecond': 1624185933, 'nano': 591826000},\n", - " 'successful': False,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'data': 'STEP1: Trader \"DEMO-CONN1\" sends request to create passive '\n", - " 'Order.',\n", - " 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185937, 'nano': 843746000},\n", - " 'eventId': 'a63f809b-d1b4-11eb-bae5-57b0c4472880',\n", - " 'eventName': 'placeOrderFIX demo-conn1 - STEP1: Trader \"DEMO-CONN1\" sends '\n", - " 'request to create passive Order.',\n", - " 'eventType': 'placeOrderFIX',\n", - " 'isBatched': False,\n", - " 'parentEventId': 'a33aba58-d1b4-11eb-b0fb-199708acc7bc',\n", - " 'startTimestamp': {'epochSecond': 1624185937, 'nano': 843702000},\n", - " 'successful': False,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '9a245d03-7d76-454e-92c0-1c315e7e7a80',\n", - " 'body': [{'data': \"Checkpoint id 'a6401c70-d1b4-11eb-ba78-1981398e00bd'\",\n", - " 'type': 'message'}],\n", - " 'endTimestamp': {'epochSecond': 1624185937, 'nano': 847501000},\n", - " 'eventId': '9a245d03-7d76-454e-92c0-1c315e7e7a80:a6401d6f-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': 'Checkpoint',\n", - " 'eventType': 'Checkpoint',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'a63f809b-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185937, 'nano': 847411000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '9a245d03-7d76-454e-92c0-1c315e7e7a80',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185937, 'nano': 847501000},\n", - " 'eventId': '9a245d03-7d76-454e-92c0-1c315e7e7a80:a6401d70-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'th2-hand-demo' direction 'FIRST' \"\n", - " \"sequence '1623852603564709030'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '9a245d03-7d76-454e-92c0-1c315e7e7a80:a6401d6f-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185937, 'nano': 847411000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '9a245d03-7d76-454e-92c0-1c315e7e7a80',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185937, 'nano': 847501000},\n", - " 'eventId': '9a245d03-7d76-454e-92c0-1c315e7e7a80:a6401d71-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn1' direction 'SECOND' \"\n", - " \"sequence '1624005455622140299'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '9a245d03-7d76-454e-92c0-1c315e7e7a80:a6401d6f-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185937, 'nano': 847411000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '9a245d03-7d76-454e-92c0-1c315e7e7a80',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185937, 'nano': 847501000},\n", - " 'eventId': '9a245d03-7d76-454e-92c0-1c315e7e7a80:a6401d72-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc1' direction 'SECOND' \"\n", - " \"sequence '1624005475721015016'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '9a245d03-7d76-454e-92c0-1c315e7e7a80:a6401d6f-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185937, 'nano': 847411000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '9a245d03-7d76-454e-92c0-1c315e7e7a80',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185937, 'nano': 847501000},\n", - " 'eventId': '9a245d03-7d76-454e-92c0-1c315e7e7a80:a6401d73-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc1' direction 'FIRST' \"\n", - " \"sequence '1624005475720919519'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '9a245d03-7d76-454e-92c0-1c315e7e7a80:a6401d6f-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185937, 'nano': 847411000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '9a245d03-7d76-454e-92c0-1c315e7e7a80',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185937, 'nano': 847501000},\n", - " 'eventId': '9a245d03-7d76-454e-92c0-1c315e7e7a80:a6401d74-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn2' direction 'FIRST' \"\n", - " \"sequence '1624005448022245415'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '9a245d03-7d76-454e-92c0-1c315e7e7a80:a6401d6f-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185937, 'nano': 847411000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '9a245d03-7d76-454e-92c0-1c315e7e7a80',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185937, 'nano': 847501000},\n", - " 'eventId': '9a245d03-7d76-454e-92c0-1c315e7e7a80:a6401d75-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn2' direction 'SECOND' \"\n", - " \"sequence '1624005448022426118'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '9a245d03-7d76-454e-92c0-1c315e7e7a80:a6401d6f-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185937, 'nano': 847411000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '9a245d03-7d76-454e-92c0-1c315e7e7a80',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185937, 'nano': 847501000},\n", - " 'eventId': '9a245d03-7d76-454e-92c0-1c315e7e7a80:a6401d76-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc2' direction 'SECOND' \"\n", - " \"sequence '1624005466840347017'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '9a245d03-7d76-454e-92c0-1c315e7e7a80:a6401d6f-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185937, 'nano': 847411000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '9a245d03-7d76-454e-92c0-1c315e7e7a80',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185937, 'nano': 847501000},\n", - " 'eventId': '9a245d03-7d76-454e-92c0-1c315e7e7a80:a6401d77-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-dc2' direction 'FIRST' \"\n", - " \"sequence '1624005466840263387'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '9a245d03-7d76-454e-92c0-1c315e7e7a80:a6401d6f-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185937, 'nano': 847411000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '9a245d03-7d76-454e-92c0-1c315e7e7a80',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185937, 'nano': 847501000},\n", - " 'eventId': '9a245d03-7d76-454e-92c0-1c315e7e7a80:a6401d78-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-conn1' direction 'FIRST' \"\n", - " \"sequence '1624005455622011542'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '9a245d03-7d76-454e-92c0-1c315e7e7a80:a6401d6f-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185937, 'nano': 847411000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '9a245d03-7d76-454e-92c0-1c315e7e7a80',\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185937, 'nano': 847501000},\n", - " 'eventId': '9a245d03-7d76-454e-92c0-1c315e7e7a80:a6401d79-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Checkpoint for session alias 'demo-log' direction 'FIRST' \"\n", - " \"sequence '1624029363623063053'\",\n", - " 'eventType': 'Checkpoint for session',\n", - " 'isBatched': True,\n", - " 'parentEventId': '9a245d03-7d76-454e-92c0-1c315e7e7a80:a6401d6f-d1b4-11eb-9278-591e568ad66e',\n", - " 'startTimestamp': {'epochSecond': 1624185937, 'nano': 847411000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'rows': {'AccountType': {'columns': {'fieldValue': '1'},\n", - " 'type': 'row'},\n", - " 'ClOrdID': {'columns': {'fieldValue': '2202035'},\n", - " 'type': 'row'},\n", - " 'OrdType': {'columns': {'fieldValue': '2'}, 'type': 'row'},\n", - " 'OrderCapacity': {'columns': {'fieldValue': 'A'},\n", - " 'type': 'row'},\n", - " 'OrderQty': {'columns': {'fieldValue': '30'},\n", - " 'type': 'row'},\n", - " 'Price': {'columns': {'fieldValue': '65'}, 'type': 'row'},\n", - " 'SecondaryClOrdID': {'columns': {'fieldValue': '11111'},\n", - " 'type': 'row'},\n", - " 'SecurityID': {'columns': {'fieldValue': 'INSTR6'},\n", - " 'type': 'row'},\n", - " 'SecurityIDSource': {'columns': {'fieldValue': '8'},\n", - " 'type': 'row'},\n", - " 'Side': {'columns': {'fieldValue': '1'}, 'type': 'row'},\n", - " 'TradingParty': {'rows': {'NoPartyIDs': {'rows': {'0': {'rows': {'PartyID': {'columns': {'fieldValue': 'DEMO-CONN1'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'D'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '76'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '1': {'rows': {'PartyID': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '2': {'rows': {'PartyID': {'columns': {'fieldValue': '0'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '122'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " '3': {'rows': {'PartyID': {'columns': {'fieldValue': '3'},\n", - " 'type': 'row'},\n", - " 'PartyIDSource': {'columns': {'fieldValue': 'P'},\n", - " 'type': 'row'},\n", - " 'PartyRole': {'columns': {'fieldValue': '12'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'columns': {'fieldValue': '2021-06-20T13:45:32.780477'},\n", - " 'type': 'row'}},\n", - " 'type': 'treeTable'}],\n", - " 'endTimestamp': {'epochSecond': 1624185937, 'nano': 856191000},\n", - " 'eventId': 'a6417c6c-d1b4-11eb-bae5-57b0c4472880',\n", - " 'eventName': \"Send 'NewOrderSingle' message to connectivity\",\n", - " 'eventType': 'Outgoing message',\n", - " 'isBatched': False,\n", - " 'parentEventId': 'a63f809b-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185937, 'nano': 856119000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185937, 'nano': 907287000},\n", - " 'eventId': 'a64944b6-d1b4-11eb-8e55-d3a76285d588',\n", - " 'eventName': \"Send 'NewOrderSingle' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': 'a63f809b-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185937, 'nano': 907284000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185938, 'nano': 291778000},\n", - " 'eventId': 'a683dcfa-d1b4-11eb-a9ed-ffb57363e013',\n", - " 'eventName': \"Send 'BusinessMessageReject' message\",\n", - " 'eventType': 'Send message',\n", - " 'isBatched': False,\n", - " 'parentEventId': '845d70d2-9c68-11eb-8598-691ebd7f413d',\n", - " 'startTimestamp': {'epochSecond': 1624185938, 'nano': 291772000},\n", - " 'successful': True,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185938, 'nano': 295181000},\n", - " 'eventId': 'a68478f7-d1b4-11eb-8e55-d3a76285d588',\n", - " 'eventName': 'Rejecting invalid message: quickfix.FieldException: Required '\n", - " 'tag missing, field=45: '\n", - " '8=FIXT.1.1\\x019=112\\x0135=j\\x0134=1311\\x0149=FGW\\x0152=20210620-10:45:38.290\\x0156=DEMO-CONN1\\x0158=Unknown '\n", - " 'SecurityID\\x01371=48\\x01372=D\\x01379=2202035\\x01380=2\\x0110=252\\x01',\n", - " 'eventType': 'Service event',\n", - " 'isBatched': False,\n", - " 'parentEventId': '7656664a-d010-11eb-8e55-d3a76285d588',\n", - " 'startTimestamp': {'epochSecond': 1624185938, 'nano': 295169000},\n", - " 'successful': False,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [],\n", - " 'endTimestamp': {'epochSecond': 1624185938, 'nano': 297405000},\n", - " 'eventId': 'a684c718-d1b4-11eb-8e55-d3a76285d588',\n", - " 'eventName': 'Reject sent for Message 1311: Required tag missing (Required '\n", - " 'tag missing, field=45):45',\n", - " 'eventType': 'Service event',\n", - " 'isBatched': False,\n", - " 'parentEventId': '7656664a-d010-11eb-8e55-d3a76285d588',\n", - " 'startTimestamp': {'epochSecond': 1624185938, 'nano': 297401000},\n", - " 'successful': False,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': '17d3cf1b-977a-48d6-ae6d-eac7b9dc438d',\n", - " 'body': {'data': 'The message was deleted because a new one came with the '\n", - " \"same hash '-1652240969129971924' in message group \"\n", - " \"'NOS_CONN'\\n\"\n", - " ' Message not matched',\n", - " 'type': 'message'},\n", - " 'endTimestamp': {'epochSecond': 1624185938, 'nano': 838473000},\n", - " 'eventId': '17d3cf1b-977a-48d6-ae6d-eac7b9dc438d:a6d76ddc-d1b4-11eb-986f-1e8d42132387',\n", - " 'eventName': \"Remove 'NewOrderSingle' \"\n", - " \"id='demo-conn1:SECOND:1624005455622135215' \"\n", - " \"Hash='-1652240969129971924' Group='NOS_CONN' \"\n", - " \"Hash['SecondaryClOrdID': 11111, 'SecurityID': INSTR6]\",\n", - " 'eventType': '',\n", - " 'isBatched': True,\n", - " 'parentEventId': 'a3779b94-d051-11eb-986f-1e8d42132387',\n", - " 'startTimestamp': {'epochSecond': 1624185938, 'nano': 838473000},\n", - " 'successful': False,\n", - " 'type': 'event'}\n", - "{'attachedMessageIds': [],\n", - " 'batchId': None,\n", - " 'body': [{'rows': {'BusinessRejectReason': {'columns': {'fieldValue': '2'},\n", - " 'type': 'row'},\n", - " 'BusinessRejectRefID': {'columns': {'fieldValue': '2202035'},\n", - " 'type': 'row'},\n", - " 'RefMsgType': {'columns': {'fieldValue': 'D'},\n", - " 'type': 'row'},\n", - " 'RefTagID': {'columns': {'fieldValue': '48'},\n", - " 'type': 'row'},\n", - " 'Text': {'columns': {'fieldValue': 'Unknown SecurityID'},\n", - " 'type': 'row'},\n", - " 'header': {'rows': {'BeginString': {'columns': {'fieldValue': 'FIXT.1.1'},\n", - " 'type': 'row'},\n", - " 'BodyLength': {'columns': {'fieldValue': '112'},\n", - " 'type': 'row'},\n", - " 'MsgSeqNum': {'columns': {'fieldValue': '1311'},\n", - " 'type': 'row'},\n", - " 'MsgType': {'columns': {'fieldValue': 'j'},\n", - " 'type': 'row'},\n", - " 'SenderCompID': {'columns': {'fieldValue': 'FGW'},\n", - " 'type': 'row'},\n", - " 'SendingTime': {'columns': {'fieldValue': '2021-06-20T10:45:38.290'},\n", - " 'type': 'row'},\n", - " 'TargetCompID': {'columns': {'fieldValue': 'DEMO-CONN1'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'},\n", - " 'trailer': {'rows': {'CheckSum': {'columns': {'fieldValue': '252'},\n", - " 'type': 'row'}},\n", - " 'type': 'collection'}},\n", - " 'type': 'treeTable'}],\n", - " 'endTimestamp': {'epochSecond': 1624185938, 'nano': 949522000},\n", - " 'eventId': 'a6e843bd-d1b4-11eb-bae5-57b0c4472880',\n", - " 'eventName': \"Received 'BusinessMessageReject' response message\",\n", - " 'eventType': 'message',\n", - " 'isBatched': False,\n", - " 'parentEventId': 'a63f809b-d1b4-11eb-bae5-57b0c4472880',\n", - " 'startTimestamp': {'epochSecond': 1624185938, 'nano': 949485000},\n", - " 'successful': False,\n", - " 'type': 'event'}\n" - ] - } - ], - "source": [ - "working_data: Data = data_source.command(\n", - " http.GetEvents(\n", - " start_timestamp=START_TIME,\n", - " end_timestamp=END_TIME,\n", - " attached_messages=True,\n", - " cache=True\n", - " )\n", - ")\n", - "\n", - "for i in working_data:\n", - " pprint(i)" - ] - }, - { - "cell_type": "markdown", - "id": "3afb8130", - "metadata": {}, - "source": [ - "### Demo for filter, map and sift." - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "id": "b5b4728c", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '9601585',\n", - " 'expected': '9601585',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2346',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '30',\n", - " 'expected': '30',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': '2',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'A',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '867',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '30',\n", - " 'expected': '30',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '55',\n", - " 'expected': '55',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR1',\n", - " 'expected': 'INSTR1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '1',\n", - " 'expected': '1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'Simulated New Order Buy is placed',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': '1',\n", - " 'fields': {'NoPartyIDs': {'actual': '4',\n", - " 'expected': '4',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'DEMO-CONN1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'D',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': '76',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': '0',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': '122',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': '3',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': '3',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'P',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': '12',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:44:55',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': '7',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'FIXT.1.1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '310',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1291',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': '8',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:44:55.346',\n", - " 'expected': '*',\n", - " 'key': False,\n", - " 'operation': 'NOT_EMPTY',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'DEMO-CONN1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '056',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'eventId': '53c1abd6-b2f9-4378-b061-434a3315c4a2:8d722b53-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'parentEventId': '8d722b52-d1b4-11eb-9278-591e568ad66e',\n", - " 'status': 'SUCCESSFUL',\n", - " 'super_type': 'Verification'}\n", - "{'body': [{'fields': {'AccountType': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ClOrdID': {'actual': '9601585',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'CumQty': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecID': {'actual': '2346',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'ExecType': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'LeavesQty': {'actual': '30',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdStatus': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrdType': {'actual': '2',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderCapacity': {'actual': 'A',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderID': {'actual': '867',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'OrderQty': {'actual': '30',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Price': {'actual': '55',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SecurityID': {'actual': 'INSTR1',\n", - " 'expected': 'INSTR1',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SecurityIDSource': {'actual': '8',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Side': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'Text': {'actual': 'Simulated New Order Buy is placed',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TradingParty': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'NoPartyIDs': {'actual': '4',\n", - " 'expected': 'null',\n", - " 'fields': {'0': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'D',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '76',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '1': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '2': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '0',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '122',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " '3': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'fields': {'PartyID': {'actual': '3',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyIDSource': {'actual': 'P',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'PartyRole': {'actual': '12',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'},\n", - " 'TransactTime': {'actual': '2021-06-20T10:44:55',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'header': {'actual': '7',\n", - " 'expected': '1',\n", - " 'fields': {'BeginString': {'actual': 'FIXT.1.1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'BodyLength': {'actual': '310',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgSeqNum': {'actual': '1291',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'MsgType': {'actual': '8',\n", - " 'expected': 'x != \"f\"',\n", - " 'key': False,\n", - " 'operation': 'NOT_EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'},\n", - " 'SenderCompID': {'actual': 'FGW',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'SendingTime': {'actual': '2021-06-20T10:44:55.346',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'},\n", - " 'TargetCompID': {'actual': 'DEMO-CONN1',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'type': 'collection'},\n", - " 'trailer': {'actual': '1',\n", - " 'expected': 'null',\n", - " 'fields': {'CheckSum': {'actual': '056',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}},\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'collection'}},\n", - " 'type': 'verification'}],\n", - " 'eventId': 'e71f316c-6912-43b1-a6cb-60c328a8239b:8d71dd30-d1b4-11eb-9278-591e568ad66e',\n", - " 'eventName': \"Verification 'ExecutionReport' message\",\n", - " 'parentEventId': '8d6f6c2f-d1b4-11eb-9278-591e568ad66e',\n", - " 'status': 'SUCCESSFUL',\n", - " 'super_type': 'Verification'}\n" - ] - } - ], - "source": [ - "data: Data = working_data \\\n", - " .map(extract_basic) \\\n", - " .filter(lambda record: record.get(\"super_type\") == \"Verification\")\\\n", - " .sift(limit=2)\n", - "\n", - "for i in data:\n", - " pprint(i)" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "id": "9cb1aab5", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'body': {},\n", - " 'eventId': '88a3ee80-d1b4-11eb-b0fb-199708acc7bc',\n", - " 'eventName': 'Case[TC_1.1]: Trader DEMO-CONN1 vs trader DEMO-CONN2 for '\n", - " 'instrument INSTR1',\n", - " 'parentEventId': '84db48fc-d1b4-11eb-b0fb-199708acc7bc',\n", - " 'status': 'SUCCESSFUL',\n", - " 'super_type': ''}\n", - "{'body': [{'data': 'STEP1: Trader \"DEMO-CONN1\" sends request to create passive '\n", - " 'Order.',\n", - " 'type': 'message'}],\n", - " 'eventId': '8bc787fe-d1b4-11eb-bae5-57b0c4472880',\n", - " 'eventName': 'placeOrderFIX demo-conn1 - STEP1: Trader \"DEMO-CONN1\" sends '\n", - " 'request to create passive Order.',\n", - " 'parentEventId': '88a3ee80-d1b4-11eb-b0fb-199708acc7bc',\n", - " 'status': 'SUCCESSFUL',\n", - " 'super_type': 'placeOrderFIX'}\n" - ] - } - ], - "source": [ - "data = working_data \\\n", - " .map(extract_basic) \\\n", - " .filter(lambda record: record.get(\"parentEventId\"))\\\n", - " .filter(is_test_case_ancestor)\\\n", - " .sift(limit=2)\n", - "\n", - "for i in data:\n", - " pprint(i)" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "id": "55838f0e", - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'CumQty': {'actual': '30',\n", - " 'expected': '30',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}}\n", - "{'CumQty': {'actual': '10',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}}\n", - "{'CumQty': {'actual': '30',\n", - " 'expected': 'null',\n", - " 'key': False,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'NA',\n", - " 'type': 'field'}}\n", - "{'CumQty': {'actual': '10',\n", - " 'expected': '10',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}}\n", - "{'CumQty': {'actual': '40',\n", - " 'expected': '40',\n", - " 'key': True,\n", - " 'operation': 'EQUAL',\n", - " 'status': 'PASSED',\n", - " 'type': 'field'}}\n" - ] - } - ], - "source": [ - "def transform_output(record):\n", - " body = record.get(\"body\")\n", - " if body:\n", - " cumqty = body[0].get(\"fields\", {}).get(\"CumQty\")\n", - " \n", - " new_obj = {\n", - " \"CumQty\": cumqty\n", - " } \n", - " return new_obj\n", - "\n", - "data = working_data \\\n", - " .map(extract_basic) \\\n", - " .filter(lambda record: record.get(\"super_type\") == \"Verification\")\\\n", - " .map(transform_output)\\\n", - " .sift(limit=5, skip=5)\n", - "\n", - "for i in data:\n", - " pprint(i)" - ] - }, - { - "cell_type": "markdown", - "id": "df98deed", - "metadata": {}, - "source": [ - "### Demo for messages." - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "id": "d54002a6", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'attachedEventIds': [],\n", - " 'body': {'fields': {'messages': {'listValue': {'values': [{'messageValue': {'fields': {'ActionName': {'simpleValue': 'winOpen'},\n", - " 'appFile': {'simpleValue': 'MiniFIX.exe'},\n", - " 'workDir': {'simpleValue': 'C:\\\\Program '\n", - " 'Files '\n", - " '(x86)\\\\MiniFIX\\\\'}}}},\n", - " {'messageValue': {'fields': {'ActionName': {'simpleValue': 'winSearchElement'},\n", - " 'id': {'simpleValue': 'mainWindowElId'},\n", - " 'locators': {'listValue': {'values': [{'messageValue': {'fields': {'locator': {'simpleValue': 'root'}}}}]}}}}}]}}},\n", - " 'metadata': {'id': {'connectionId': {'sessionAlias': 'th2-hand-demo'},\n", - " 'direction': 'SECOND',\n", - " 'sequence': '1623751720263566001',\n", - " 'subsequence': [1]},\n", - " 'messageType': 'th2-hand',\n", - " 'timestamp': '2021-06-15T10:10:42.751818Z'}},\n", - " 'bodyBase64': 'eyJtZXNzYWdlcyI6W3siQWN0aW9uTmFtZSI6Indpbk9wZW4iLCJ3b3JrRGlyIjoiQzpcXFByb2dyYW0gRmlsZXMgKHg4NilcXE1pbmlGSVhcXCIsImFwcEZpbGUiOiJNaW5pRklYLmV4ZSJ9LHsiQWN0aW9uTmFtZSI6IndpblNlYXJjaEVsZW1lbnQiLCJsb2NhdG9ycyI6W3sibG9jYXRvciI6InJvb3QifV0sImlkIjoibWFpbldpbmRvd0VsSWQifV19',\n", - " 'direction': 'OUT',\n", - " 'messageId': 'th2-hand-demo:second:1623751720263566001',\n", - " 'messageType': 'th2-hand',\n", - " 'sessionId': 'th2-hand-demo',\n", - " 'timestamp': {'epochSecond': 1623751842, 'nano': 751818000},\n", - " 'type': 'message'}\n", - "{'attachedEventIds': [],\n", - " 'body': {'fields': {'th2-hand-1': {'messageValue': {'fields': {'ErrorText': {'simpleValue': ''}}}},\n", - " 'th2-hand-2': {'messageValue': {'fields': {'TextOut': {'simpleValue': ''}}}},\n", - " 'th2-hand-3': {'messageValue': {'fields': {'ScriptOutputCode': {'simpleValue': 'SUCCESS'}}}},\n", - " 'th2-hand-4': {'messageValue': {'fields': {'RhSessionId': {'simpleValue': '/Sesa2c385c3-c0e9-41d6-b856-9ec5bde8e2b5'}}}}},\n", - " 'metadata': {'id': {'connectionId': {'sessionAlias': 'th2-hand-demo'},\n", - " 'sequence': '1623751720263566002',\n", - " 'subsequence': [1, 2, 3, 4]},\n", - " 'messageType': 'th2-hand/th2-hand/th2-hand/th2-hand',\n", - " 'timestamp': '2021-06-15T10:11:03.797784Z'}},\n", - " 'bodyBase64': 'eyJTY3JpcHRPdXRwdXRDb2RlIjoiU1VDQ0VTUyIsIkVycm9yVGV4dCI6IiIsIlRleHRPdXQiOiIiLCJSaFNlc3Npb25JZCI6Ii9TZXNhMmMzODVjMy1jMGU5LTQxZDYtYjg1Ni05ZWM1YmRlOGUyYjUifQ==',\n", - " 'direction': 'IN',\n", - " 'messageId': 'th2-hand-demo:first:1623751720263566002',\n", - " 'messageType': 'th2-hand/th2-hand/th2-hand/th2-hand',\n", - " 'sessionId': 'th2-hand-demo',\n", - " 'timestamp': {'epochSecond': 1623751863, 'nano': 797784000},\n", - " 'type': 'message'}\n", - "{'attachedEventIds': [],\n", - " 'body': {'fields': {'messages': {'listValue': {'values': [{'messageValue': {'fields': {'ActionName': {'simpleValue': 'winClick'},\n", - " 'locators': {'listValue': {'values': [{'messageValue': {'fields': {'locator': {'simpleValue': 'cachedId'},\n", - " 'matcher': {'simpleValue': 'mainWindowElId'}}}},\n", - " {'messageValue': {'fields': {'locator': {'simpleValue': 'accessibilityId'},\n", - " 'matcher': {'simpleValue': '5004'}}}},\n", - " {'messageValue': {'fields': {'locator': {'simpleValue': 'name'},\n", - " 'matcher': {'simpleValue': 'Session'}}}}]}}}}},\n", - " {'messageValue': {'fields': {'ActionName': {'simpleValue': 'winSendText'},\n", - " 'clearBefore': {'simpleValue': 'true'},\n", - " 'locators': {'listValue': {'values': [{'messageValue': {'fields': {'locator': {'simpleValue': 'cachedId'},\n", - " 'matcher': {'simpleValue': 'mainWindowElId'}}}},\n", - " {'messageValue': {'fields': {'locator': {'simpleValue': 'accessibilityId'},\n", - " 'matcher': {'simpleValue': '28'}}}}]}},\n", - " 'text': {'simpleValue': 'DEMO-CONN2'}}}},\n", - " {'messageValue': {'fields': {'ActionName': {'simpleValue': 'winSendText'},\n", - " 'clearBefore': {'simpleValue': 'true'},\n", - " 'locators': {'listValue': {'values': [{'messageValue': {'fields': {'locator': {'simpleValue': 'cachedId'},\n", - " 'matcher': {'simpleValue': 'mainWindowElId'}}}},\n", - " {'messageValue': {'fields': {'locator': {'simpleValue': 'accessibilityId'},\n", - " 'matcher': {'simpleValue': '29'}}}}]}},\n", - " 'text': {'simpleValue': 'FGW'}}}},\n", - " {'messageValue': {'fields': {'ActionName': {'simpleValue': 'winSendText'},\n", - " 'clearBefore': {'simpleValue': 'true'},\n", - " 'locators': {'listValue': {'values': [{'messageValue': {'fields': {'locator': {'simpleValue': 'cachedId'},\n", - " 'matcher': {'simpleValue': 'mainWindowElId'}}}},\n", - " {'messageValue': {'fields': {'locator': {'simpleValue': 'accessibilityId'},\n", - " 'matcher': {'simpleValue': '32'}}}}]}},\n", - " 'text': {'simpleValue': 'FIXT.1.1'}}}},\n", - " {'messageValue': {'fields': {'ActionName': {'simpleValue': 'winClick'},\n", - " 'locators': {'listValue': {'values': [{'messageValue': {'fields': {'locator': {'simpleValue': 'cachedId'},\n", - " 'matcher': {'simpleValue': 'mainWindowElId'}}}},\n", - " {'messageValue': {'fields': {'locator': {'simpleValue': 'accessibilityId'},\n", - " 'matcher': {'simpleValue': '5052'}}}},\n", - " {'messageValue': {'fields': {'locator': {'simpleValue': 'accessibilityId'},\n", - " 'matcher': {'simpleValue': '5053'}}}},\n", - " {'messageValue': {'fields': {'locator': {'simpleValue': 'name'},\n", - " 'matcher': {'simpleValue': 'Connect'}}}}]}}}}},\n", - " {'messageValue': {'fields': {'ActionName': {'simpleValue': 'winSendText'},\n", - " 'clearBefore': {'simpleValue': 'true'},\n", - " 'isDirectText': {'simpleValue': 'true'},\n", - " 'locators': {'listValue': {'values': [{'messageValue': {'fields': {'locator': {'simpleValue': 'cachedId'},\n", - " 'matcher': {'simpleValue': 'mainWindowElId'}}}},\n", - " {'messageValue': {'fields': {'locator': {'simpleValue': 'accessibilityId'},\n", - " 'matcher': {'simpleValue': '1001'}}}}]}},\n", - " 'text': {'simpleValue': 'th2-kube-demo:31388'}}}},\n", - " {'messageValue': {'fields': {'ActionName': {'simpleValue': 'winClick'},\n", - " 'locators': {'listValue': {'values': [{'messageValue': {'fields': {'locator': {'simpleValue': 'cachedId'},\n", - " 'matcher': {'simpleValue': 'mainWindowElId'}}}},\n", - " {'messageValue': {'fields': {'locator': {'simpleValue': 'accessibilityId'},\n", - " 'matcher': {'simpleValue': '1'}}}}]}}}}}]}}},\n", - " 'metadata': {'id': {'connectionId': {'sessionAlias': 'th2-hand-demo'},\n", - " 'direction': 'SECOND',\n", - " 'sequence': '1623751720263566003',\n", - " 'subsequence': [1]},\n", - " 'messageType': 'th2-hand',\n", - " 'timestamp': '2021-06-15T10:11:03.867895Z'}},\n", - " 'bodyBase64': 'eyJtZXNzYWdlcyI6W3siQWN0aW9uTmFtZSI6IndpbkNsaWNrIiwibG9jYXRvcnMiOlt7ImxvY2F0b3IiOiJjYWNoZWRJZCIsIm1hdGNoZXIiOiJtYWluV2luZG93RWxJZCJ9LHsibG9jYXRvciI6ImFjY2Vzc2liaWxpdHlJZCIsIm1hdGNoZXIiOiI1MDA0In0seyJsb2NhdG9yIjoibmFtZSIsIm1hdGNoZXIiOiJTZXNzaW9uIn1dfSx7IkFjdGlvbk5hbWUiOiJ3aW5TZW5kVGV4dCIsImxvY2F0b3JzIjpbeyJsb2NhdG9yIjoiY2FjaGVkSWQiLCJtYXRjaGVyIjoibWFpbldpbmRvd0VsSWQifSx7ImxvY2F0b3IiOiJhY2Nlc3NpYmlsaXR5SWQiLCJtYXRjaGVyIjoiMjgifV0sInRleHQiOiJERU1PLUNPTk4yIiwiY2xlYXJCZWZvcmUiOiJ0cnVlIn0seyJBY3Rpb25OYW1lIjoid2luU2VuZFRleHQiLCJsb2NhdG9ycyI6W3sibG9jYXRvciI6ImNhY2hlZElkIiwibWF0Y2hlciI6Im1haW5XaW5kb3dFbElkIn0seyJsb2NhdG9yIjoiYWNjZXNzaWJpbGl0eUlkIiwibWF0Y2hlciI6IjI5In1dLCJ0ZXh0IjoiRkdXIiwiY2xlYXJCZWZvcmUiOiJ0cnVlIn0seyJBY3Rpb25OYW1lIjoid2luU2VuZFRleHQiLCJsb2NhdG9ycyI6W3sibG9jYXRvciI6ImNhY2hlZElkIiwibWF0Y2hlciI6Im1haW5XaW5kb3dFbElkIn0seyJsb2NhdG9yIjoiYWNjZXNzaWJpbGl0eUlkIiwibWF0Y2hlciI6IjMyIn1dLCJ0ZXh0IjoiRklYVC4xLjEiLCJjbGVhckJlZm9yZSI6InRydWUifSx7IkFjdGlvbk5hbWUiOiJ3aW5DbGljayIsImxvY2F0b3JzIjpbeyJsb2NhdG9yIjoiY2FjaGVkSWQiLCJtYXRjaGVyIjoibWFpbldpbmRvd0VsSWQifSx7ImxvY2F0b3IiOiJhY2Nlc3NpYmlsaXR5SWQiLCJtYXRjaGVyIjoiNTA1MiJ9LHsibG9jYXRvciI6ImFjY2Vzc2liaWxpdHlJZCIsIm1hdGNoZXIiOiI1MDUzIn0seyJsb2NhdG9yIjoibmFtZSIsIm1hdGNoZXIiOiJDb25uZWN0In1dfSx7IkFjdGlvbk5hbWUiOiJ3aW5TZW5kVGV4dCIsImxvY2F0b3JzIjpbeyJsb2NhdG9yIjoiY2FjaGVkSWQiLCJtYXRjaGVyIjoibWFpbldpbmRvd0VsSWQifSx7ImxvY2F0b3IiOiJhY2Nlc3NpYmlsaXR5SWQiLCJtYXRjaGVyIjoiMTAwMSJ9XSwidGV4dCI6InRoMi1rdWJlLWRlbW86MzEzODgiLCJjbGVhckJlZm9yZSI6InRydWUiLCJpc0RpcmVjdFRleHQiOiJ0cnVlIn0seyJBY3Rpb25OYW1lIjoid2luQ2xpY2siLCJsb2NhdG9ycyI6W3sibG9jYXRvciI6ImNhY2hlZElkIiwibWF0Y2hlciI6Im1haW5XaW5kb3dFbElkIn0seyJsb2NhdG9yIjoiYWNjZXNzaWJpbGl0eUlkIiwibWF0Y2hlciI6IjEifV19XX0=',\n", - " 'direction': 'OUT',\n", - " 'messageId': 'th2-hand-demo:second:1623751720263566003',\n", - " 'messageType': 'th2-hand',\n", - " 'sessionId': 'th2-hand-demo',\n", - " 'timestamp': {'epochSecond': 1623751863, 'nano': 867895000},\n", - " 'type': 'message'}\n", - "{'attachedEventIds': [],\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " 'body': {'fields': {'th2-hand-1': {'messageValue': {'fields': {'ErrorText': {'simpleValue': ''}}}},\n", - " 'th2-hand-2': {'messageValue': {'fields': {'TextOut': {'simpleValue': ''}}}},\n", - " 'th2-hand-3': {'messageValue': {'fields': {'ScriptOutputCode': {'simpleValue': 'SUCCESS'}}}},\n", - " 'th2-hand-4': {'messageValue': {'fields': {'RhSessionId': {'simpleValue': '/Sesa2c385c3-c0e9-41d6-b856-9ec5bde8e2b5'}}}}},\n", - " 'metadata': {'id': {'connectionId': {'sessionAlias': 'th2-hand-demo'},\n", - " 'sequence': '1623751720263566004',\n", - " 'subsequence': [1, 2, 3, 4]},\n", - " 'messageType': 'th2-hand/th2-hand/th2-hand/th2-hand',\n", - " 'timestamp': '2021-06-15T10:11:13.870751Z'}},\n", - " 'bodyBase64': 'eyJTY3JpcHRPdXRwdXRDb2RlIjoiU1VDQ0VTUyIsIkVycm9yVGV4dCI6IiIsIlRleHRPdXQiOiIiLCJSaFNlc3Npb25JZCI6Ii9TZXNhMmMzODVjMy1jMGU5LTQxZDYtYjg1Ni05ZWM1YmRlOGUyYjUifQ==',\n", - " 'direction': 'IN',\n", - " 'messageId': 'th2-hand-demo:first:1623751720263566004',\n", - " 'messageType': 'th2-hand/th2-hand/th2-hand/th2-hand',\n", - " 'sessionId': 'th2-hand-demo',\n", - " 'timestamp': {'epochSecond': 1623751873, 'nano': 870751000},\n", - " 'type': 'message'}\n", - "{'attachedEventIds': [],\n", - " 'body': {'fields': {'messages': {'listValue': {'values': [{'messageValue': {'fields': {'ActionName': {'simpleValue': 'winClick'},\n", - " 'locators': {'listValue': {'values': [{'messageValue': {'fields': {'locator': {'simpleValue': 'cachedId'},\n", - " 'matcher': {'simpleValue': 'mainWindowElId'}}}},\n", - " {'messageValue': {'fields': {'locator': {'simpleValue': 'accessibilityId'},\n", - " 'matcher': {'simpleValue': '5004'}}}},\n", - " {'messageValue': {'fields': {'locator': {'simpleValue': 'name'},\n", - " 'matcher': {'simpleValue': 'Transactions'}}}}]}}}}},\n", - " {'messageValue': {'fields': {'ActionName': {'simpleValue': 'winSendText'},\n", - " 'isDirectText': {'simpleValue': 'NewOrderSingle'},\n", - " 'locators': {'listValue': {'values': [{'messageValue': {'fields': {'locator': {'simpleValue': 'accessibilityId'},\n", - " 'matcher': {'simpleValue': '25'}}}}]}},\n", - " 'text': {'simpleValue': 'NewOrderSingle'}}}},\n", - " {'messageValue': {'fields': {'ActionName': {'simpleValue': 'winSendText'},\n", - " 'isDirectText': {'simpleValue': 'true'},\n", - " 'locators': {'listValue': {'values': [{'messageValue': {'fields': {'locator': {'simpleValue': 'accessibilityId'},\n", - " 'matcher': {'simpleValue': '27'}}}},\n", - " {'messageValue': {'fields': {'locator': {'simpleValue': 'name'},\n", - " 'matcher': {'simpleValue': '35'}}}},\n", - " {'messageValue': {'fields': {'locator': {'simpleValue': 'name'},\n", - " 'matcher': {'simpleValue': '35'}}}}]}},\n", - " 'text': {'simpleValue': '#space#'}}}},\n", - " {'messageValue': {'fields': {'ActionName': {'simpleValue': 'winSendText'},\n", - " 'isDirectText': {'simpleValue': 'true'},\n", - " 'locators': {'listValue': {'values': [{'messageValue': {'fields': {'locator': {'simpleValue': 'accessibilityId'},\n", - " 'matcher': {'simpleValue': '27'}}}},\n", - " {'messageValue': {'fields': {'locator': {'simpleValue': 'name'},\n", - " 'matcher': {'simpleValue': '35'}}}},\n", - " {'messageValue': {'fields': {'locator': {'simpleValue': 'name'},\n", - " 'matcher': {'simpleValue': '35'}}}}]}},\n", - " 'text': {'simpleValue': '#space#'}}}},\n", - " {'messageValue': {'fields': {'ActionName': {'simpleValue': 'winSendText'},\n", - " 'isDirectText': {'simpleValue': 'true'},\n", - " 'locators': {'listValue': {'values': [{'messageValue': {'fields': {'locator': {'simpleValue': 'accessibilityId'},\n", - " 'matcher': {'simpleValue': '27'}}}},\n", - " {'messageValue': {'fields': {'locator': {'simpleValue': 'name'},\n", - " 'matcher': {'simpleValue': '21'}}}},\n", - " {'messageValue': {'fields': {'locator': {'simpleValue': 'name'},\n", - " 'matcher': {'simpleValue': '21'}}}}]}},\n", - " 'text': {'simpleValue': '#space#'}}}},\n", - " {'messageValue': {'fields': {'ActionName': {'simpleValue': 'winSendText'},\n", - " 'isDirectText': {'simpleValue': 'true'},\n", - " 'locators': {'listValue': {'values': [{'messageValue': {'fields': {'locator': {'simpleValue': 'accessibilityId'},\n", - " 'matcher': {'simpleValue': '27'}}}},\n", - " {'messageValue': {'fields': {'locator': {'simpleValue': 'name'},\n", - " 'matcher': {'simpleValue': '21'}}}},\n", - " {'messageValue': {'fields': {'locator': {'simpleValue': 'name'},\n", - " 'matcher': {'simpleValue': '21'}}}}]}},\n", - " 'text': {'simpleValue': '#space#'}}}},\n", - " {'messageValue': {'fields': {'ActionName': {'simpleValue': 'winClick'},\n", - " 'locators': {'listValue': {'values': [{'messageValue': {'fields': {'locator': {'simpleValue': 'accessibilityId'},\n", - " 'matcher': {'simpleValue': '5007'}}}}]}}}}}]}}},\n", - " 'metadata': {'id': {'connectionId': {'sessionAlias': 'th2-hand-demo'},\n", - " 'direction': 'SECOND',\n", - " 'sequence': '1623751720263566005',\n", - " 'subsequence': [1]},\n", - " 'messageType': 'th2-hand',\n", - " 'timestamp': '2021-06-15T10:11:13.891674Z'}},\n", - " 'bodyBase64': 'eyJtZXNzYWdlcyI6W3siQWN0aW9uTmFtZSI6IndpbkNsaWNrIiwibG9jYXRvcnMiOlt7ImxvY2F0b3IiOiJjYWNoZWRJZCIsIm1hdGNoZXIiOiJtYWluV2luZG93RWxJZCJ9LHsibG9jYXRvciI6ImFjY2Vzc2liaWxpdHlJZCIsIm1hdGNoZXIiOiI1MDA0In0seyJsb2NhdG9yIjoibmFtZSIsIm1hdGNoZXIiOiJUcmFuc2FjdGlvbnMifV19LHsiQWN0aW9uTmFtZSI6IndpblNlbmRUZXh0IiwibG9jYXRvcnMiOlt7ImxvY2F0b3IiOiJhY2Nlc3NpYmlsaXR5SWQiLCJtYXRjaGVyIjoiMjUifV0sInRleHQiOiJOZXdPcmRlclNpbmdsZSIsImlzRGlyZWN0VGV4dCI6Ik5ld09yZGVyU2luZ2xlIn0seyJBY3Rpb25OYW1lIjoid2luU2VuZFRleHQiLCJsb2NhdG9ycyI6W3sibG9jYXRvciI6ImFjY2Vzc2liaWxpdHlJZCIsIm1hdGNoZXIiOiIyNyJ9LHsibG9jYXRvciI6Im5hbWUiLCJtYXRjaGVyIjoiMzUifSx7ImxvY2F0b3IiOiJuYW1lIiwibWF0Y2hlciI6IjM1In1dLCJ0ZXh0IjoiI3NwYWNlIyIsImlzRGlyZWN0VGV4dCI6InRydWUifSx7IkFjdGlvbk5hbWUiOiJ3aW5TZW5kVGV4dCIsImxvY2F0b3JzIjpbeyJsb2NhdG9yIjoiYWNjZXNzaWJpbGl0eUlkIiwibWF0Y2hlciI6IjI3In0seyJsb2NhdG9yIjoibmFtZSIsIm1hdGNoZXIiOiIzNSJ9LHsibG9jYXRvciI6Im5hbWUiLCJtYXRjaGVyIjoiMzUifV0sInRleHQiOiIjc3BhY2UjIiwiaXNEaXJlY3RUZXh0IjoidHJ1ZSJ9LHsiQWN0aW9uTmFtZSI6IndpblNlbmRUZXh0IiwibG9jYXRvcnMiOlt7ImxvY2F0b3IiOiJhY2Nlc3NpYmlsaXR5SWQiLCJtYXRjaGVyIjoiMjcifSx7ImxvY2F0b3IiOiJuYW1lIiwibWF0Y2hlciI6IjIxIn0seyJsb2NhdG9yIjoibmFtZSIsIm1hdGNoZXIiOiIyMSJ9XSwidGV4dCI6IiNzcGFjZSMiLCJpc0RpcmVjdFRleHQiOiJ0cnVlIn0seyJBY3Rpb25OYW1lIjoid2luU2VuZFRleHQiLCJsb2NhdG9ycyI6W3sibG9jYXRvciI6ImFjY2Vzc2liaWxpdHlJZCIsIm1hdGNoZXIiOiIyNyJ9LHsibG9jYXRvciI6Im5hbWUiLCJtYXRjaGVyIjoiMjEifSx7ImxvY2F0b3IiOiJuYW1lIiwibWF0Y2hlciI6IjIxIn1dLCJ0ZXh0IjoiI3NwYWNlIyIsImlzRGlyZWN0VGV4dCI6InRydWUifSx7IkFjdGlvbk5hbWUiOiJ3aW5DbGljayIsImxvY2F0b3JzIjpbeyJsb2NhdG9yIjoiYWNjZXNzaWJpbGl0eUlkIiwibWF0Y2hlciI6IjUwMDcifV19XX0=',\n", - " 'direction': 'OUT',\n", - " 'messageId': 'th2-hand-demo:second:1623751720263566005',\n", - " 'messageType': 'th2-hand',\n", - " 'sessionId': 'th2-hand-demo',\n", - " 'timestamp': {'epochSecond': 1623751873, 'nano': 891674000},\n", - " 'type': 'message'}\n" - ] - } - ], - "source": [ - "working_data = data_source.command(\n", - " http.GetMessages(\n", - " start_timestamp=datetime(year=2021, month=6, day=15, hour=9, minute=44, second=41, microsecond=692724),\n", - " end_timestamp=datetime(year=2021, month=6, day=15, hour=12, minute=45, second=49, microsecond=28579),\n", - " stream=[\"th2-hand-demo\"]\n", - " )\n", - ")\n", - "\n", - "for i in working_data.sift(limit=5):\n", - " pprint(i)" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "id": "ce3ce9bd", - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'messageType': 'th2-hand'}\n", - "{'messageType': 'th2-hand/th2-hand/th2-hand/th2-hand'}\n", - "{'messageType': 'th2-hand'}\n", - "{'messageType': 'th2-hand/th2-hand/th2-hand/th2-hand'}\n", - "{'messageType': 'th2-hand'}\n", - "{'messageType': 'th2-hand/th2-hand/th2-hand/th2-hand'}\n", - "{'messageType': 'th2-hand'}\n", - "{'messageType': 'th2-hand/th2-hand/th2-hand/th2-hand'}\n", - "{'messageType': 'th2-hand'}\n", - "{'messageType': 'th2-hand/th2-hand/th2-hand/th2-hand'}\n", - "{'messageType': 'th2-hand'}\n", - "{'messageType': 'th2-hand/th2-hand/th2-hand/th2-hand'}\n", - "{'messageType': 'th2-hand'}\n", - "{'messageType': 'th2-hand/th2-hand/th2-hand/th2-hand'}\n", - "{'messageType': 'th2-hand'}\n", - "{'messageType': 'th2-hand/th2-hand/th2-hand/th2-hand'}\n", - "{'messageType': 'th2-hand'}\n", - "{'messageType': 'th2-hand/th2-hand/th2-hand/th2-hand'}\n", - "{'messageType': 'th2-hand'}\n", - "{'messageType': 'th2-hand/th2-hand/th2-hand/th2-hand'}\n", - "{'messageType': 'th2-hand'}\n", - "{'messageType': 'th2-hand/th2-hand/th2-hand/th2-hand'}\n", - "{'messageType': 'th2-hand'}\n", - "{'messageType': 'th2-hand/th2-hand/th2-hand/th2-hand'}\n", - "{'messageType': 'th2-hand'}\n", - "{'messageType': 'th2-hand/th2-hand/th2-hand/th2-hand'}\n", - "{'messageType': 'th2-hand'}\n", - "{'messageType': 'th2-hand/th2-hand/th2-hand/th2-hand'}\n", - "{'messageType': 'th2-hand'}\n", - "{'messageType': 'th2-hand/th2-hand/th2-hand/th2-hand'}\n", - "{'messageType': 'th2-hand'}\n", - "{'messageType': 'th2-hand/th2-hand/th2-hand/th2-hand'}\n", - "{'messageType': 'th2-hand'}\n", - "{'messageType': 'th2-hand/th2-hand/th2-hand/th2-hand'}\n", - "{'messageType': 'th2-hand'}\n", - "{'messageType': 'th2-hand/th2-hand/th2-hand/th2-hand'}\n" - ] - } - ], - "source": [ - "def transform_output(record):\n", - " new_obj = {\n", - " \"messageType\": record.get(\"messageType\")\n", - " }\n", - " return new_obj\n", - "\n", - "data = working_data.map(transform_output)\n", - "\n", - "for i in data:\n", - " pprint(i)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "97bcb0e7", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.10" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/package_info.json b/package_info.json index f770c1c2..1ecc14e6 100644 --- a/package_info.json +++ b/package_info.json @@ -1,5 +1,4 @@ { "package_name": "th2-data-services", - "package_version": "1.2.1" + "package_version": "2.0.0" } - diff --git a/release_notes.md b/release_notes.md index 1c085281..9a112989 100644 --- a/release_notes.md +++ b/release_notes.md @@ -52,15 +52,15 @@ ## User impact and migration instructions -1. [I] You no longer need to enter UTC time corrected for local time. DataSource methods now expect UTC time. +1. [I] You no longer need to enter UTC time corrected for local time. DataSource methods now expect UTC time. [M] Change the time to UTC in all your scripts. -2. [I] The last "messageIds" message in the messages stream will be ignored. +2. [I] The last "messageIds" message in the messages stream will be ignored. [M] If you do checks for the last message, you can delete them. -3. [I] _DataSource.write_to_txt_ was moved to Data. The name has been changed to _write_to_file_. +3. [I] _DataSource.write_to_txt_ was moved to Data. The name has been changed to _write_to_file_. [M] If you use _write_to_file_ function, change the corresponding class and method. -4. [I] _len(Data)_ functionality was removed. The _Data.len_ property is now used. +4. [I] _len(Data)_ functionality was removed. The _Data.len_ property is now used. [M] Change _len(Data)_ to _Data.len_ for your functions. -5. [I] The codec-pipeline wrapper-messages are now split into sub-messages. +5. [I] The codec-pipeline wrapper-messages are now split into sub-messages. [M] If you use wrapper-messages for your statistics then adapt functions for sub-messages (now they look like a usual message) @@ -118,8 +118,8 @@ ## User impact and migration instructions -1. [I] The "metadataOnly" query parameter will now always be set to False in the get_X_from_data_provider methods. It’s - the option for Report Viewer front-end only. +1. [I] The "metadataOnly" query parameter will now always be set to False in the get_X_from_data_provider methods. It's + the option for Report Viewer front-end only. [M] (Optional) Remove "metadataOnly" parameter in your requests to get more logical and clean code. ## Improvements @@ -129,7 +129,7 @@ ## Features -1. You can import classes directly from th2_data_services now. +1. You can import classes directly from th2_data_services now. E.g. `from th2_data_services import Data, DataSource, Filter` 2. [TH2-2755] Added new parameters to DataSource methods. 1. get_X_from_data_provider: @@ -157,9 +157,17 @@ 1. [TH2-2922] Fixed infinite loop in events tree. +# v0.6.3 + +## BugFixes + +1. [TH2-3168] Fixed iterations in nested loops for Data object with limit. +2. [TH2-3336] Url now uses the utf-8 encoding. +3. [TH2-3700] Filter iterate values only once - fixed. + # v1.0.0 -The main goal of the release 1.0.0 is to implement new architecture that solves many of extension's problems. +The main goal of the release 1.0.0 is to implement new architecture that solves many of extension's problems. It also allows you to create your own Commands/DataSources/SourceAPIs. ## Attention @@ -173,26 +181,26 @@ use `CodecPipelinesAdapter` manually. ## User impact and migration instructions -1. [I] There is no more old-style DataSource class. +1. [I] There is no more old-style DataSource class. [M] Use a specific class for your purposes (HTTPDataSource or GRPCDataSource). 2. [I] There are no more `get_x` methods in the DataSource classes. Instead, it has the command method. This method - takes an object of the Command class. - [M] So if you used `data_source.get_events_from_data_provider` use `data_source.command(GetEvents(ARGS))` instead. + takes an object of the Command class. + [M] So if you used `data_source.get_events_from_data_provider` use `data_source.command(GetEvents(ARGS))` instead. from `data_source.get_messages_from_data_provider` to `data_source.command(GetMessages(ARGS).apply_adapter( - codec_pipeline_adapter))` - from `find_messages_by_id_from_data_provider` to `GetMessagesById` or `GetMessageById` - from `find_events_by_id_from_data_provider` to `GetEventsById` or `GetEventById` + codec_pipeline_adapter))` + from `find_messages_by_id_from_data_provider` to `GetMessagesById` or `GetMessageById` + from `find_events_by_id_from_data_provider` to `GetEventsById` or `GetEventById` if you used broken_events parameter initialize the command with use_stub=True parameter. -3. [I] Modules structure was changed. +3. [I] Modules structure was changed. [M] You need to change some import paths. -4. [I] All class constructors/methods have got explicit arguments. +4. [I] All class constructors/methods have got explicit arguments. [M] Change old args names to new if required. 5. [I] Set of classes to create `EventsTree` representation was significantly changed. - [M] Use `EventsTreesCollection` instead of `EventsTree`. `EventsTree` is a real tree structure now. + [M] Use `EventsTreesCollection` instead of `EventsTree`. `EventsTree` is a real tree structure now. Note, `EventsTreesCollection` has other methods, see the example to understand how to work with it. -6. [I] `EventsTree2` was removed. +6. [I] `EventsTree2` was removed. [M] Use `EventsTreesCollection` instead. -7. [I] Exceptions were updated. +7. [I] Exceptions were updated. [M] Update your try-except statements ## Improvements @@ -205,8 +213,8 @@ use `CodecPipelinesAdapter` manually. 1. [TH2-2465] Added the module `th2_gui_report` to create a link by event id or message id. 2. [TH2-2274] rpt-data-provider GRPC interface was implemented. -3. [TH2-3194] New `EventsTree` solution implemented. It includes the best parts from previous trees. - The tree also got a lot of useful methods to work with it ([see doc](documentation/api/events_tree.events_tree.md)). +3. [TH2-3194] New `EventsTree` solution implemented. It includes the best parts from previous trees. + The tree also got a lot of useful methods to work with it ([see doc](documentation/api/events_tree.events_tree.md)). 4. [TH2-2942] Pure Provider v5 APIs implemented: `GRPCProvider5API`, `HTTPProvider5API`. 5. [TH2-2944] Developed commands for http and grpc instead of `data_source` get/find methods. 6. [TH2-2994] Provider v5 data source classes implemented: `GRPCProvider5DataSource`, `HTTPProvider5DataSource`. @@ -234,22 +242,26 @@ use `CodecPipelinesAdapter` manually. # v1.0.2 ## BugFixes + 1. [TH2-3700] Filter iterate values only once - fixed. # v1.0.3 ## BugFixes + 1. [TH2-3739] GRPCProvider5API is based on grpc v0.1.6 now. # v1.1.0 ## User impact and migration instructions + This release is not required any additional steps to use. ## Features + 1. [TH2-3497] EventsTreeCollection got `get_leaves_iter` method. 2. [TH2-3497] EventsTreeCollection got `len_trees` and `len_detached_events` properties. -3. [TH2-3497] EventsTree and EventsTreeCollection got representation(`__repr__`) and `summary` methods. +3. [TH2-3497] EventsTree and EventsTreeCollection got representation(`__repr__`) and `summary` methods. 4. [TH2-3558] Added module-level functions `add_stderr_logger` and `add_file_logger` to easily enable logging. 5. [TH2-3546][TH2-3583] `INTERACTIVE_MODE` - global parameter was introduced. 6. `Data.use_cache()` <- True by default. @@ -259,22 +271,26 @@ This release is not required any additional steps to use. 10. [TH2-3475] Implement Data objects joining 11. [TH2-3467] Added utils classes to convert timestamps. 12. [TH2-3662][TH2-3492] Added `get_detached_events_iter` and `get_detached_events` methods in EventsTreeCollections. - * Warning: Property `detached_events` is deprecated and will be removed in the future. + * Warning: Property `detached_events` is deprecated and will be removed in the future. 13. [TH2-3496] Added get_parentless_tree_collection method in EventsTreeCollection. -14. [TH2-3905] Separate filer classes added instead of `th2_data_services.Filter` class. - * Warning: Class `th2_data_services.Filter` is deprecated and will be removed in the future. +14. [TH2-3905] Separate filer classes added instead of `th2_data_services.Filter` class. + * Warning: Class `th2_data_services.Filter` is deprecated and will be removed in the future. ## Improvements + 1. [TH2-3003] Added automatic attachment of example.py code in readme.md. 2. [TH2-3558] Added more debug info about Data cache using. 3. [TH2-3389] GetXById http-provider command handles 404 error status instead of JsonDecodeException. 4. [TH2-3663] Speed up len_detached_events property ## BugFixes + 1. [TH2-3557][TH2-3560] Parent Data cache file will be created if you iterate a child Data object now. -2. [TH2-3545][TH2-3580] The Data object now uses an absolute path, so it doesn't lose its cache file if you change the working directory. +2. [TH2-3545][TH2-3580] The Data object now uses an absolute path, so it doesn't lose its cache file if you change the + working directory. 3. [TH2-3546][TH2-3583] Data cache file will not be removed if you use `INTERACTIVE_MODE` and the file is being read. -4. [TH2-3487][TH2-3585] `data = Data(source_data, cache=True).map(func)` Data object didn't write the cache in such case before. Fixed. +4. [TH2-3487][TH2-3585] `data = Data(source_data, cache=True).map(func)` Data object didn't write the cache in such case + before. Fixed. 5. [TH2-3558] Used loggers name fixed. Changed to __name__. 6. [TH2-3733] Provider API class generate standard URL (without duplicate '/' and '/' before query) 7. [TH2-3598] Method get_subtree returns tree as EventsTree class. @@ -282,35 +298,318 @@ This release is not required any additional steps to use. 9. [TH2-3595] When ETC creates subtree or itself ETC doesn't copy incoming data-stream. 10. [TH2-3732] Log message in http.GetMessages contains name of the stream. 11. [TH2-3734] EventsTreeCollection append_event method doesn't add duplicate event. -12. [TH2-3596][TH2-3594][TH2-3473] EventsTreeCollections. Get or find methods includes parentless results, if parentless exists. +12. [TH2-3596][TH2-3594][TH2-3473] EventsTreeCollections. Get or find methods includes parentless results, if parentless + exists. # v1.1.1 ## BugFixes + 1. [TH2-4039] An empty filter is validated. # v1.2.0 ## User impact and migration instructions -This release implements rdp v6 support that requres new grpc version. It means you cannot connect to rdp5.grpc and rdp6.grpc via the same environment. This DS lib version will have grpc version for rdp v6 == th2-grpc-data-provider v1.1.0. -1. [I] The new version of grpc has been added. - [M] If you require the rdp v6 version of the interface, you do not need to do anything. - Otherwise, you need to reinstall th2-grpc-data-provider lib to the required one for your rdp. +This release implements rdp v6 support that requres new grpc version. It means you cannot connect to rdp5.grpc and +rdp6.grpc via the same environment. This DS lib version will have grpc version for rdp v6 == th2-grpc-data-provider +v1.1.0. + +1. [I] The new version of grpc has been added. + [M] If you require the rdp v6 version of the interface, you do not need to do anything. + Otherwise, you need to reinstall th2-grpc-data-provider lib to the required one for your rdp. More detail in [here](https://github.com/th2-net/th2-data-services/tree/dev_1.2.0#grpc-provider-warning) ## Features + 1. [TH2-3083] The problem with several versions of the grpc interface is solved. 2. [TH2-3512] Provider V6 module is developed. -3. [TH2-4141] Option to disable ssl certificate for rdp5 is added +3. [TH2-4141] Option to disable ssl certificate for rdp5 is added. 4. [TH2-4098] Added Streams class for the param 'stream'. # BugFixes + 1. [TH2-4072] Now ETC doesn't raise a warning for missing detached_events. 2. GRPC requests (start_timestamp, end_timestamp) are now made in UTC. # v1.2.1 # BugFixes -1. Added missing library importlib_metadata \ No newline at end of file + +1. Added missing library importlib_metadata. + +# v1.2.2 + +## BugFixes + +1. [TH2-4195] EventsTree without parent raises `EventIdNotInTree` exception when trying to use `get_parent()` method. + +# v1.2.3 + +## BugFixes + +1. [TH2-4234] The library can now be run on Windows. + +# v1.3.0 + +## User impact and migration instructions + +This release implements performance bug fixes and provides Data object cache file saving and loading. + +1. [I] Logging were removed from library. Only special builds will have logging. + User cannot use `add_stderr_logger` and `add_file_logger` logging functions. + [M] Remove DS lib logging usage anywhere. +2. [I] Since `v1.3.0`, the library doesn't provide data source dependencies. + [M] You should provide it manually during installation. + You just need to add square brackets after library name and put dependency name. + + ``` + pip install th2-data-services[dependency_name] + ``` + + **Dependencies list** + + | dependency name | provider version | + |:---------------:|:----------------:| + | RDP5 | 5 | + | RDP6 | 6 | + + **Example** + + ``` + pip install th2-data-services[rdp5] + ``` + +## Features + +1. [TH2-4289] Data.build_cache and Data.from_cache_file features were added. +2. Added `Data.cache_status` property + +## Improvements + +1. [TH2-4379] Speed improvements in json deserialization. + - StreamingSSEAdapter will now handle bytes from sse-stream into Dict objects. + - SSEAdapter is now deprecated class. +2. Data object will generate a warning if you put to it an object that has generator type. + +## BugFixes + +1. [TH2-4385] Logging in Data object slows down the ds library very much. + - Logging was removed. + - `add_stderr_logger` and `add_file_logger` are not available anymore. +2. [TH2-4380] Fixed apply_adpater feature for GetMessages / GetEvents / GetEventById / GetMessageById +3. [TH2-3767] Fixed bug with limit of Data object in Windows. +4. [TH2-4460] Fixed bug where GRPC omitted fields with None value in response. + +# v1.4.0 + +## Feature +1. [TH2-4601] Added `clear_cache` method to data object to remove cache file. + +## BugFixes +1. [TH2-4603] Fix += joining feature. Now it keeps cache status. +2. [TH2-4604] `Data.from_cache_file` method has return value now. +3. [TH2-4839] Changed FileExistsError to FileNotFoundError in Data.from_cache_file method + +# v2.0.0 + +## User impact and migration instructions + +By installing the package you will no longer get RDP package. +If you want to use RDP you have to specify dependency in square brackets `[ ]` + +1. [I] Adapter interface got required handle_stream method.\ + [M] Implement new method for your adapters. + +2. [I] It's no longer possible to import Data object directly from + th2_data_services package.\ + [M] All records should be changed from "from th2_data_services import Data" + to "from th2_data_services.data import Data". + +3. [I] Provider module is removed.\ + [M] You should use data source implementations, like th2-ds-source-lwdp. + +4. [I] INTERACTIVE_MODE cannot be accessed like + th2_data_services.INTERACTIVE_MODE anymore.\ + [M] It's now changed to th2_data_services.config.options.INTERACTIVE_MODE + +5. [I] EventsTree renamed to EventTree\ + [M] All records should be changed to EventTree + +6. [I] Message utils method `expand_message` moved into `MessageFieldResolver`.\ + [M] Implement new method in your resolver. + +7. [I] Data iteration logic is changed.\ + Why? Current behavior causes problems in some cases. E.g. when we don't want + to iterate objects inside the DataSet. + + [I.1] Lists and tuples used in building Data objects are treated as single + item and items inside them aren't iterated anymore.\ + [M.1] Update Data objects initialized with lists or tuples. + + [I.2] Change in iteration logic also changed how `map` function behaves. + If `map` function returns lists or tuples their content won't be iterated + anymore.\ + [M.2.1] If you are interest previous `map` function behavior, just update `map` + to `map_yield`. + + [M.2.2] Update `data.map(mfr.expand_message)` to `data.map_yield(mfr.expand_message)` + + [I.3] Data object will not iterate over contents of its stream if any of the + items are iterables (but not Data object).\ + It means that Data object will not iterate lists and tuples inside the + provided DataSet and will return they as is.\ + Only exception will be if all of the items are Data objects themselves.\ + [M.3] Update nested lists in Data object initializations to either Data + objects or switch to using addition operator.\ + [Examples]\ + `d1 = Data(['a', 'b'])`\ + a. `Data([1, 2, [3, 4], d1])` will yield 1,2,[3,4],d1. Prev. behavior: 1,2,3,4,'a','b'\ + b. `Data([d1, d2])` where d1 and d2 are Data objects. It will yield from d1, and after that yield from d2.\ + c. You can update the example from `a` to `Data([1,2,3,4])` or to `new_data = Data([1,2]) + Data([3,4]) + d1`.\ + d. You also can return prev behaviour doing the following: `new_data = Data([1, 2, [3, 4], d1]).map_yield(lambda r: r)` + +8. [I] A new version of `orjson` lib require python 3.8+. + [M] Change your python version if you use 3.7 to 3.8+. + +## Features + +1. [TH2-4128] pip no longer installs RDP by default +2. [TH2-4128][TH2-4738] extra dependencies can be installed using square brackets after + package name. + - Example: `pip install th2-data-services[lwdp]` + + Available data sources implementations: + + | dependency name | provider version | + |:-----------------:|---------------------------------------| + | lwdp | latest version of lwdp | + | lwdp2 | latest version of lwdp v2 | + | lwdp3 | latest version of lwdp v3 | + | utils-rpt-viewer | latest version of utils-rpt-viewer | + | utils-rpt-viewer5 | latest version of utils-rpt-viewer v5 | + | utils-advanced | latest version of ds-utils | + +3. [TH2-4493] Adapter interface got handle_stream method. +4. [TH2-4490] Added `map_stream` method to Data. + - Almost same as `map`, except it's designed to handle a stream of data + rather than a single record. + - Method accepts a generator function or a class which implements + IStreamAdapter with generator function. +5. [TH2-4582] IAdapter interface removed. + - IStreamAdapter interface added to handle streams. + - IRecordAdapter interface added to handle single record. + - Method accepts Generator function or IStreamAdapter interface class with + Generator function. +6. [TH2-4609] Data.filter implementation changed to use `yield`. +7. [TH2-4491] metadata attribute added to Data. It will contain request urls. +8. [TH2-4577] map method now can take either Callable function or Adapter which + implements IRecordAdapter. +9. [TH2-4611] DatetimeConverter, ProtobufTimestampConverter converters added. +10. [TH2-4646] + - metadata gets carried when using Data methods. + - update_metadata method added to update metadata. +11. [TH2-4684] Tree names changed from plural to singular. (e.g Event**s** + Tree -> EventTree) +12. [TH2-4693] Implemented namespace packages structure, allowing other th2 + libraries to be grouped together. +13. [TH2-4713] Added options module which enables user to tweak library + settings. +14. `DummyDataSource` added. +15. [TH2-4881] `Data.from_json` method was added. +16. [TH2-4919] `Data.from_any_file` method was added. +17. [TH2-4928] `Data.from_csv` method was added. +18. [TH2-4932] `Data.to_json` method was added. Puts your data to a valid json + object. +19. [TH2-4957] Added `gzip` option for `Data.to_json` method. +20. [TH2-4957] Added `decompress_gzip_file` function to utils.converters. +21. Added `to_csv` method to `PerfectTable` class. +22. `utils.converters.flatten_dict` converter added. +23. Added `Data.to_jsons` method that put your data object to jsons file + (file where every line is separate json-format line. That's not a valid json + format.) + Renamed `to_jsons` to `to_json_lines` later. + - to_jsons -- is deprecated now. +24. [TH2-5049] Added ExpandedMessageFieldResolver +25. [TH2-5053] Added `pickle_version` to Data.from_cache_file method. +26. `decode_base64` function added to converter utils. +27. [TH2-5156] `UniversalDatetimeStringConverter` and `UnixTimestampConverter` + added. +28. [TH2-5167] `Data.is_sorted`, `event_utils.is_sorted`, `message_utils.is_sorted` + and `stream_utils.is_sorted` methods were added. +29. [TH2-5176] `to_th2_timestamp` method was added for converters. +30. [TH2-5081] Added `map_yield` function, that should behave similar to + old `map` method. + That means that `map_yield` will iterate lists and tuples if the user map + function returns them. +31. [TH2-5197] Added the function `read_all_pickle_files_from_the_folder` + to get Data object from the folder with pickle files. +32. [TH2-5213] Added `Data.to_csv` method, that converts data to valid csv. +33. [TH2-4900] Added `Data.sort` method, that also works with large amount of Data. + +## BugFixes + +1. [TH2-4711] EventTreeCollection max_count parameter of findall functions + worked wrongly. +2. [TH2-4917] Readme duplicates removed. +3. [TH2-5083] Fixed comparison line formatting. Every event in block isn't + formatted as failed now if parent is failed. +4. [TH2-5081] Fixed iteration bug for case where Data object was made using + lists and tuple. +5. [TH2-5100] Fixed bug when we get Recursion Exception if we have too much + number of Data objects that iterate each other. +6. [TH2-5190] Fixed Data.to_json +7. [TH2-5193] orjson versions 3.7.0 through 3.9.14 library has vulnerability + https://devhub.checkmarx.com/cve-details/CVE-2024-27454/. +8. [TH2-5201] Fixed DatetimeStringConverter.to_th2_timestamp() bug which occurred for inputs not ending with 'Z'. +9. [TH2-5902] Fixed bug when cache file was removed after calling data.show(). +10. [TH2-5220] Fixed bug when Data.update_metadata() would change a string into a list. +11. [TH2-5101] Fixed bug when merging date objects via + or += overwrites the source file. + +## Improvements + +1. Added vulnerabilities scanning +2. [TH2-4828] EventNotFound and MessageNotFound now return error description as + argument instead of pre-written one. +3. [TH2-4775] Speed up `Data.build_cache` by disabling garbage collection at the + time of storing pickle file. +4. [TH2-4901] Added gap_mode and zero_anchor parameters for message and event + utils get_category_frequencies methods. + [See doc](documentation/frequencies.md) +5. [TH2-5048] Added typing hints for resolver methods. +6. [TH2-5172] Add faster implementations of the following + ProtobufTimestampConverter functions: to_microseconds, to_milliseconds, + to_nanoseconds. +7. [TH2-5081] `Data.__str__` was changed --> use `Data.show()` instead of `print(data)` +8. [TH2-5201] Performance improvements have been made to converters: +9. [TH2-5101] Data.update_metadata() now takes `change_type` argument (values: `update` default, `change` which denotes +whether to update or overwrite with new values. +10. [TH2-5099] Fixed slow iteration for Data objects created with many addition operators. + +Benchmark. +- 1mln iterations per test +- input: 2022-03-05T23:56:44.123456789Z + +| Converter | Method | Before (seconds) | After (seconds) | Improvement (rate) | +|----------------------------------|------------------|------------------|-----------------|--------------------| +| DatetimeStringConverter | parse_timestamp | 7.1721964 | 1.4974268 | x4.78 | +| | to_datetime | 8.9945099 | 0.1266325 | x71.02 | +| | to_seconds | 8.6180093 | 1.5360991 | x5.62 | +| | to_microseconds | 7.9066440 | 1.7628856 | x4.48 | +| | to_nanoseconds | 7.6787507 | 1.7114960 | x4.48 | +| | to_milliseconds | 7.6059985 | 1.7688387 | x4.29 | +| | to_datetime_str | 8.3861742 | 2.3781561 | x3.52 | +| | to_th2_timestamp | 7.7702033 | 1.5942235 | x4.87 | +| UniversalDatetimeStringConverter | parse_timestamp | 7.4161371 | 1.5752227 | x4.7 | +| | to_datetime | 8.2108218 | 0.1267797 | x64.76 | +| | to_seconds | 7.7745484 | 1.6453126 | x4.72 | +| | to_microseconds | 7.7569293 | 1.8240784 | x4.25 | +| | to_nanoseconds | 7.7879700 | 1.7930200 | x4.34 | +| | to_milliseconds | 7.8168710 | 1.8308856 | x4.26 | +| | to_datetime_str | 8.7388529 | 2.4592992 | x3.55 | +| | to_th2_timestamp | 7.8972679 | 1.6856898 | x4.68 | + +Other converters also have some not big speed improvements. + +9. [TH2-5213] Extend cache_files_reading_speed with csv support. diff --git a/requirements.txt b/requirements.txt index d933a569..d5f33b47 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,11 +1,14 @@ -sseclient-py==1.7.2 -requests==2.26.0 -setuptools==58.1.0 -urllib3==1.26.7 -simplejson>=3.17.6 -th2-grpc-data-provider==1.1.0 +ciso8601 +deprecated +flatdict~=4.0 +# orjson versions 3.7.0 through 3.9.14 library has +# vulnerability https://devhub.checkmarx.com/cve-details/CVE-2024-27454/. +orjson>=3.10,<4 +prettytable # Temporary required for summary +requests>=2.32.2 +sseclient-py~=1.7 +tabulate treelib==1.6.1 -grpcio==1.46.3 -grpcio-tools==1.38.1 -types-protobuf==3.19.22 -importlib_metadata \ No newline at end of file +# setuptools~=65.5 +urllib3>1.26.18, <2 +wheel>=0.38.1 # To get rid of wheel building errors diff --git a/requirements_dev.txt b/requirements_dev.txt index 63815c03..98c18b27 100644 --- a/requirements_dev.txt +++ b/requirements_dev.txt @@ -1,8 +1,10 @@ -pytest -pytest-xdist -pytest-mock -pre-commit +autoflake black +importlib_metadata lazydocs +pre-commit pydocstyle -autoflake \ No newline at end of file +pytest +pytest-mock +pytest-xdist +th2-data-services-lwdp==2.0.3.0 # To test utils. Utils imports resolvers diff --git a/run_unit_tests.sh b/run_unit_tests.sh new file mode 100755 index 00000000..289728d4 --- /dev/null +++ b/run_unit_tests.sh @@ -0,0 +1,4 @@ + +echo '----========unit tests========----' +pip list +python3 -m pytest tests/tests_unit -n auto --ignore tests/tests_unit/test_dependencies/ diff --git a/setup.py b/setup.py index 37b02333..4e5706b1 100644 --- a/setup.py +++ b/setup.py @@ -1,4 +1,4 @@ -# Copyright 2020-2020 Exactpro (Exactpro Systems Limited) +# Copyright 2022-2023 Exactpro (Exactpro Systems Limited) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -13,8 +13,9 @@ # limitations under the License. import json +from typing import Dict, List -from setuptools import setup, find_packages +from setuptools import setup, find_namespace_packages with open("package_info.json", "r") as file: package_info = json.load(file) @@ -26,7 +27,45 @@ long_description = file.read() with open("requirements.txt", "r") as file: - requirements = [line.strip() for line in file.readlines() if not line.startswith("#") and line != "\n"] + requirements = [ + line.strip() for line in file.readlines() if not line.startswith("#") and line != "\n" + ] + +CORE_EXTRAS_DEPENDENCIES: Dict[str, List[str]] = { + "rdp": [ + "th2-data-services-rdp", + ], + "rdp5": [ + "th2-data-services-rdp>=5,<6", + ], + "rdp6": [ + "th2-data-services-rdp>=6,<7", + ], + "lwdp": [ + "th2-data-services-lwdp", + ], + "lwdp1": [ + "th2-data-services-lwdp>=1,<2", + ], + "lwdp2": [ + "th2-data-services-lwdp>=2,<3", + ], + "lwdp3": [ + "th2-data-services-lwdp>=3,<4", + ], + "lwdp-dev": [ + "th2-data-services-lwdp~=2.0.2.0.dev", + ], + "utils-rpt-viewer": [ + "th2-data-services-utils-rpt-viewer", + ], + "utils-rpt-viewer5": [ + "th2-data-services-utils-rpt-viewer>=5,<6", + ], + "utils-advanced": [ + "th2-data-services-utils", + ], +} setup( name=package_name, @@ -38,8 +77,9 @@ author_email="th2-devs@exactprosystems.com", url="https://github.com/th2-net/th2-data-services", license="Apache License 2.0", - python_requires=">=3.7", + python_requires=">=3.8", install_requires=requirements, - packages=find_packages(include=["th2_data_services", "th2_data_services.*"]), + packages=find_namespace_packages(include=["th2_data_services", "th2_data_services.*"]), + extras_require=CORE_EXTRAS_DEPENDENCIES, include_package_data=True, ) diff --git a/tests/perf_test_bench/2024.07.01 -- csv test added.txt b/tests/perf_test_bench/2024.07.01 -- csv test added.txt new file mode 100644 index 00000000..9224456b --- /dev/null +++ b/tests/perf_test_bench/2024.07.01 -- csv test added.txt @@ -0,0 +1,16 @@ +\th2-data-services\th2_data_services\_internal\perf_tests.py +Store cache files for test: + -> cache_test.pickle -- 46.54133415222168 s + -> cache_test.jsons -- 40.48812770843506 s + -> cache_test.jsons.gz -- 105.24668741226196 s + -> cache_test.csv -- 51.27796673774719 s + -> cache_test_header.csv -- 49.28666377067566 s + +Data length: 10000001 +Iterate pickle: -- 25.856621742248535 s, with 3 filters -- 31.304664850234985 s +Iterate jsons: -- 27.18027377128601 s, with 3 filters -- 32.267205476760864 s +Iterate jsons.gz: -- 25.534587621688843 s, with 3 filters -- 29.695445775985718 s +Iterate csv: -- 24.453383922576904 s, with 3 filters -- 28.477383613586426 s +Iterate csv (header_first_line=True): -- 35.39145493507385 s, with 3 filters -- 36.51749086380005 s + +Total time taken in : cache_files_reading_speed 614.4873778820038 diff --git a/tests/test_files/file_to_read_by_data.csv b/tests/test_files/file_to_read_by_data.csv new file mode 100644 index 00000000..765de9d2 --- /dev/null +++ b/tests/test_files/file_to_read_by_data.csv @@ -0,0 +1,3 @@ +A,B,Two Words +1,"2",2.1 +,,"2.1 + 2" diff --git a/tests/test_files/file_to_test_to_csv.csv b/tests/test_files/file_to_test_to_csv.csv new file mode 100644 index 00000000..3adbc5f1 --- /dev/null +++ b/tests/test_files/file_to_test_to_csv.csv @@ -0,0 +1,3 @@ +a,b,c,d +1,2,, +,,3,4 diff --git a/tests/test_files/file_to_test_to_csv_expected.csv b/tests/test_files/file_to_test_to_csv_expected.csv new file mode 100644 index 00000000..3adbc5f1 --- /dev/null +++ b/tests/test_files/file_to_test_to_csv_expected.csv @@ -0,0 +1,3 @@ +a,b,c,d +1,2,, +,,3,4 diff --git a/tests/test_files/file_to_test_to_json.txt b/tests/test_files/file_to_test_to_json.txt new file mode 100644 index 00000000..cba75489 --- /dev/null +++ b/tests/test_files/file_to_test_to_json.txt @@ -0,0 +1,6 @@ +[ + 1, + 2, + {"3":5,"tt":4}, + 6 +] diff --git a/tests/test_files/file_to_test_to_json_expected.txt b/tests/test_files/file_to_test_to_json_expected.txt new file mode 100644 index 00000000..cba75489 --- /dev/null +++ b/tests/test_files/file_to_test_to_json_expected.txt @@ -0,0 +1,6 @@ +[ + 1, + 2, + {"3":5,"tt":4}, + 6 +] diff --git a/tests/tests_integration/tests_diff_version/__init__.py b/tests/tests_integration/tests_diff_version/__init__.py deleted file mode 100644 index 69c85b64..00000000 --- a/tests/tests_integration/tests_diff_version/__init__.py +++ /dev/null @@ -1,22 +0,0 @@ -from importlib.metadata import version, PackageNotFoundError - -v = version("th2_grpc_data_provider") -DEMO_PORT = "31789" # GRPC provider v6 - -if v == "1.1.0": # v6 - from th2_data_services.provider.v6.data_source.http import HTTPProvider6DataSource as HTTPProviderDataSource # noqa - from th2_data_services.provider.v6.commands import http # noqa - from th2_data_services.provider.v6.filters.filter import Provider6Filter as Filter # noqa - from th2_data_services.provider.v6.provider_api import HTTPProvider6API as HTTPProviderAPI # noqa - from th2_data_services.provider.v6.adapters.message_adapters import CodecPipelinesAdapter # noqa - - DEMO_PORT = "31788" # HTTP provider v6 - -elif v == "0.1.6": # v5 - from th2_data_services.provider.v5.data_source.http import HTTPProvider5DataSource as HTTPProviderDataSource # noqa - from th2_data_services.provider.v5.commands import http # noqa - from th2_data_services.provider.v5.provider_api import HTTPProvider5API as HTTPProviderAPI # noqa - from th2_data_services.provider.v5.adapters.message_adapters import CodecPipelinesAdapter # noqa - from th2_data_services.filter import Filter # noqa - - DEMO_PORT = "31787" # HTTP provider v5 diff --git a/tests/tests_integration/tests_diff_version/conftest.py b/tests/tests_integration/tests_diff_version/conftest.py deleted file mode 100644 index a77f8192..00000000 --- a/tests/tests_integration/tests_diff_version/conftest.py +++ /dev/null @@ -1,157 +0,0 @@ -from datetime import datetime - -import pytest - -from th2_data_services import Data -from . import HTTPProviderAPI, HTTPProviderDataSource, http, CodecPipelinesAdapter, Filter, DEMO_PORT # noqa # noqa - - -@pytest.fixture -def demo_data_source(): - DEMO_HOST = "10.100.66.114" # de-th2-qa - data_source = HTTPProviderDataSource(f"http://{DEMO_HOST}:{DEMO_PORT}") - return data_source - - -START_TIME = datetime(year=2022, month=6, day=30, hour=14, minute=0, second=0, microsecond=0) -END_TIME = datetime(year=2022, month=6, day=30, hour=15, minute=0, second=0, microsecond=0) - - -@pytest.fixture -def demo_get_events_with_one_filter(demo_data_source: HTTPProviderDataSource) -> Data: - case = demo_data_source.command( - http.GetEvents( - start_timestamp=START_TIME, - end_timestamp=END_TIME, - filters=[Filter("name", "TS_1")], - ) - ) - - return case - - -@pytest.fixture -def demo_get_events_with_filters(demo_data_source: HTTPProviderDataSource) -> Data: - case = demo_data_source.command( - http.GetEvents( - start_timestamp=START_TIME, - end_timestamp=END_TIME, - filters=[Filter("name", "ExecutionReport"), Filter("type", "message"), Filter("body", "589")], - ) - ) - - return case - - -@pytest.fixture -def demo_get_messages_with_one_filter(demo_data_source: HTTPProviderDataSource) -> Data: - case = demo_data_source.command( - http.GetMessages( - start_timestamp=datetime(year=2022, month=6, day=30, hour=14, minute=48, second=20, microsecond=0), - end_timestamp=datetime(year=2022, month=6, day=30, hour=14, minute=48, second=25, microsecond=0), - stream=["arfq01fix07"], - filters=Filter("type", "NewOrderSingle"), - ) - ) - - return case - - -@pytest.fixture -def demo_get_messages_with_filters(demo_data_source: HTTPProviderDataSource) -> Data: - case = demo_data_source.command( - http.GetMessages( - start_timestamp=datetime(year=2022, month=6, day=30, hour=14, minute=48, second=20, microsecond=0), - end_timestamp=datetime(year=2022, month=6, day=30, hour=14, minute=48, second=25, microsecond=0), - stream=["arfq01fix07"], - filters=[Filter("type", "NewOrderSingle"), Filter("body", "200")], - ) - ) - - return case - - -@pytest.fixture -def demo_events_from_data_source(demo_data_source: HTTPProviderDataSource) -> Data: - events = demo_data_source.command( - http.GetEvents( - start_timestamp=START_TIME, - end_timestamp=END_TIME, - ) - ) - # Returns 49 events #TODO - # Failed = 6 - return events - - -@pytest.fixture -def demo_messages_from_data_source(demo_data_source: HTTPProviderDataSource) -> Data: - messages = demo_data_source.command( - http.GetMessages( - start_timestamp=datetime(year=2022, month=6, day=30, hour=14, minute=58, second=0, microsecond=0), - end_timestamp=END_TIME, - stream=["arfq01fix07"], - ) - ) - # Returns 239 messages - return messages - - -@pytest.fixture -def demo_events_from_data_source_with_cache_status( - demo_data_source: HTTPProviderDataSource, -) -> Data: - events = demo_data_source.command(http.GetEvents(start_timestamp=START_TIME, end_timestamp=END_TIME, cache=True)) - # Returns 49 events #TODO - # Failed = 6 - return events - - -@pytest.fixture -def demo_messages_from_data_source_with_test_streams( - demo_data_source: HTTPProviderDataSource, -) -> Data: - messages = demo_data_source.command( - http.GetMessages( - start_timestamp=datetime(year=2022, month=6, day=30, hour=14, minute=58, second=0, microsecond=0), - end_timestamp=END_TIME, - stream=[ - "Test-123", - "Test-1234", - "Test-12345", - "Test-123456", - "Test-1234567", - "Test-12345678", - "Test-123456789", - "Test-1234567810", - "TestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTest", - "TestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTest1", - "TestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTest2", - "TestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTest3", - "TestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTest4", - "TestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTest5", - "TestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTest6", - "TestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTest7", - "TestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTest8", - "TestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTest9", - "TestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTest10", - "TestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTest11", - "TestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTest12", - "TestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTest13", - "TestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTest14", - "TestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTest15", - "TestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTest16", - "TestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTest17", - "TestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTest18", - "TestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTest19", - "TestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTest20", - "TestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTest21", - "TestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTest22", - "TestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTest23", - "arfq01fix07", - "arfq01dc03", - "arfq02dc10", - ], - ) - ) - return messages diff --git a/tests/tests_integration/tests_diff_version/tests_common/test_data_local.py b/tests/tests_integration/tests_diff_version/tests_common/test_data_local.py deleted file mode 100644 index 27f85547..00000000 --- a/tests/tests_integration/tests_diff_version/tests_common/test_data_local.py +++ /dev/null @@ -1,19 +0,0 @@ -from th2_data_services.data import Data - - -def test_iter_data(demo_events_from_data_source: Data): - """Test via data provider""" - events = demo_events_from_data_source - - # Check that list func works - assert list(events) - - # Check that we can use Data several times - assert list(events) - - -def test_filter_data(demo_events_from_data_source: Data): - events = demo_events_from_data_source - data = events.filter(lambda r: r["successful"] is False) - - assert len(list(data)) == 23 diff --git a/tests/tests_integration/tests_diff_version/tests_common/test_data_source_local.py b/tests/tests_integration/tests_diff_version/tests_common/test_data_source_local.py deleted file mode 100644 index bc6b0130..00000000 --- a/tests/tests_integration/tests_diff_version/tests_common/test_data_source_local.py +++ /dev/null @@ -1,79 +0,0 @@ -from datetime import datetime - -import pytest -import requests - -from th2_data_services.data import Data -from th2_data_services.provider.exceptions import CommandError -from tests.tests_unit.tests_diff_version.conftest import http, HTTPProviderDataSource - - -def test_find_message_by_id_from_data_provider_with_error(demo_data_source: HTTPProviderDataSource): - data_source = demo_data_source - - with pytest.raises(CommandError) as exc_info: - data_source.command(http.GetMessageById("demo-conn_not_exist:first:1624005448022245399")) - - -def test_get_events_from_data_provider_with_error(demo_data_source: HTTPProviderDataSource): - data_source = demo_data_source - - events = data_source.command(http.GetEvents(start_timestamp="test", end_timestamp="test")) - with pytest.raises(TypeError) as exc_info: - list(events) - assert "replace() takes no keyword arguments" in str(exc_info) - - -def test_get_messages_from_data_provider_with_error(demo_data_source: HTTPProviderDataSource): - data_source = demo_data_source - - events = data_source.command(http.GetMessages(start_timestamp="test", end_timestamp="test", stream="test")) - with pytest.raises(TypeError) as exc_info: - list(events) - assert "replace() takes no keyword arguments" in str(exc_info) - - -def test_check_url_for_data_source(): - with pytest.raises(requests.exceptions.ConnectionError) as exc_info: - data_source = HTTPProviderDataSource("http://test_test:8080/") - assert "Max retries exceeded with url" in str(exc_info) - - -def test_messageIds_not_in_last_msg(demo_messages_from_data_source: Data): - data = demo_messages_from_data_source - data_lst = list(data) - last_msg = data_lst[-1] - assert "messageIds" not in last_msg - - -def test_get_messages_with_multiple_url( - demo_messages_from_data_source_with_test_streams: Data, - demo_messages_from_data_source: Data, -): - messages = demo_messages_from_data_source_with_test_streams.use_cache(True) - - messages_hand_demo_expected = demo_messages_from_data_source - messages_hand_demo_actual = messages.filter(lambda record: record.get("sessionId") == "arfq01fix07") - - assert ( - len(list(messages)) == 272 - and len(list(messages_hand_demo_actual)) == len(list(messages_hand_demo_expected)) == 239 - ) - - -# def test_unprintable_character(demo_data_source: HTTPProviderDataSource): -# event = demo_data_source.command(http.GetEventById(("b85d9dca-6236-11ec-bc58-1b1c943c5c0d"))) -# -# assert "\x80" in event["body"][0]["value"] and event["body"][0]["value"] == "nobJjpBJkTuQMmscc4R\x80" - - -def test_attached_messages(demo_data_source: HTTPProviderDataSource): - events = demo_data_source.command( - http.GetEvents( - start_timestamp=datetime(year=2022, month=6, day=30, hour=14, minute=0, second=0, microsecond=0), - end_timestamp=datetime(year=2022, month=6, day=30, hour=15, minute=0, second=0, microsecond=0), - attached_messages=True, - ) - ) - - assert events.filter(lambda event: event.get("attachedMessageIds")).len diff --git a/tests/tests_integration/tests_diff_version/tests_common/test_filter.py b/tests/tests_integration/tests_diff_version/tests_common/test_filter.py deleted file mode 100644 index c409418a..00000000 --- a/tests/tests_integration/tests_diff_version/tests_common/test_filter.py +++ /dev/null @@ -1,26 +0,0 @@ -from tests.tests_unit.tests_diff_version.conftest import Filter - - -def test_filter_url(): - filter_ = Filter("type", ["one", 2, "three"], False, False) - assert ( - filter_.url() - == "&filters=type&type-values=one&type-values=2&type-values=three&type-negative=False&type-conjunct=False" - ) - - filter_ = Filter("name", "one", False, False) - assert filter_.url() == "&filters=name&name-values=one&name-negative=False&name-conjunct=False" - - filter_ = Filter("name", 1) - assert filter_.url() == "&filters=name&name-values=1&name-negative=False&name-conjunct=False" - - -def test_filter_grcp(): - assert isinstance(Filter("type", ["one", 2, "three"], False, False), Filter) - - -def test_iterate_filter_twice(): - f = Filter("type", ["one", 2, "three"]) - v1 = f.url() - v2 = f.url() - assert v1 == v2 diff --git a/tests/tests_integration/tests_diff_version/tests_common/tests_adapters/test_adapter_sse_local.py b/tests/tests_integration/tests_diff_version/tests_common/tests_adapters/test_adapter_sse_local.py deleted file mode 100644 index 76e8710b..00000000 --- a/tests/tests_integration/tests_diff_version/tests_common/tests_adapters/test_adapter_sse_local.py +++ /dev/null @@ -1,81 +0,0 @@ -from sseclient import Event -import pytest - -from th2_data_services import Data -from tests.tests_unit.tests_diff_version.conftest import HTTPProviderDataSource, http, START_TIME, END_TIME - - -def get_data_obj(rtype, ds, params_dict): - if rtype == "events": - return ds.command( - http.GetEvents(start_timestamp=params_dict["startTimestamp"], end_timestamp=params_dict["endTimestamp"]) - ) - elif rtype == "messages": - return ds.command( - http.GetMessages( - start_timestamp=params_dict["startTimestamp"], - end_timestamp=params_dict["endTimestamp"], - stream=params_dict["stream"], - ) - ) - else: - raise Exception("Not events or messages") - - -class TestSSEFlagTrue: - @pytest.mark.parametrize( - "params", - [ - ("events", dict(sse_adapter=True)), - ("events", dict()), - ( - "messages", - dict( - sse_adapter=True, - stream=["demo-conn2"], - provider_adapter=None, - ), - ), - ( - "messages", - dict( - stream=["demo-conn2"], - provider_adapter=None, - ), - ), - ], - ) - def test_x_flag_true_or_default(self, demo_data_source: HTTPProviderDataSource, params): - ds = demo_data_source - data: Data = get_data_obj(params[0], ds, dict(startTimestamp=START_TIME, endTimestamp=END_TIME, **params[1])) - - for e in data: - assert isinstance(e, dict) - - -class TestSSEFlagFalse: - # @pytest.mark.parametrize("rtype", ['events', 'messages']) - def test_events(self, demo_data_source: HTTPProviderDataSource): - ds = demo_data_source - data: Data = ds.command( - http.GetEventsSSEEvents( - start_timestamp=START_TIME, - end_timestamp=END_TIME, - ) - ) - - for e in data: - assert isinstance(e, Event) - - def test_messages_provider_none(self, demo_data_source: HTTPProviderDataSource): - ds = demo_data_source - data: Data = ds.command( - http.GetMessages( - start_timestamp=START_TIME, - end_timestamp=END_TIME, - stream=["demo-conn2"], - ) - ) - - for e in data: - assert isinstance(e, Event) diff --git a/tests/tests_integration/tests_diff_version/tests_v5/test_data_source_local.py b/tests/tests_integration/tests_diff_version/tests_v5/test_data_source_local.py deleted file mode 100644 index 301d3954..00000000 --- a/tests/tests_integration/tests_diff_version/tests_v5/test_data_source_local.py +++ /dev/null @@ -1,470 +0,0 @@ -import pytest - -from ..conftest import HTTPProviderDataSource, http, Data -from th2_data_services.provider.exceptions import CommandError - - -def test_find_events_by_id_from_data_provider(demo_data_source: HTTPProviderDataSource): - data_source = demo_data_source - - expected_event = { - "attachedMessageIds": [], - "batchId": None, - "body": {}, - "endTimestamp": {"epochSecond": 1656599851, "nano": 420806000}, - "eventId": "2c4b3a58-f882-11ec-b952-0a1e730db2c6", - "eventName": "Recon: Test", - "eventType": "", - "isBatched": False, - "parentEventId": None, - "startTimestamp": {"epochSecond": 1656599851, "nano": 420806000}, - "successful": False, - "type": "event", - } - - expected_events = [] - expected_events.append(expected_event) - expected_events.append( - { - "type": "event", - "eventId": "a5586d90-b83b-48a4-bd2b-b2059fb79374:b84cff2c-f883-11ec-b070-0a1e730db2c6", - "batchId": "a5586d90-b83b-48a4-bd2b-b2059fb79374", - "isBatched": True, - "eventName": "Match by ClOrdID: '7706360'", - "eventType": "", - "endTimestamp": {"nano": 809998000, "epochSecond": 1656600515}, - "startTimestamp": {"nano": 809998000, "epochSecond": 1656600515}, - "parentEventId": "b21a03c0-f883-11ec-b070-0a1e730db2c6", - "successful": True, - "attachedMessageIds": ["arfq01fix08:first:1656599887515453583", "arfq01fix08:second:1656599887515499581"], - "body": { - "type": "table", - "rows": [ - {"Name": "ClOrdId", "Value": "7706360"}, - {"Name": "Message Response", "Value": "ExecutionReport"}, - {"Name": "Message Request", "Value": "NewOrderSingle"}, - {"Name": "Latency type", "Value": "Trade"}, - {"Name": "Latency", "Value": 29000.0}, - ], - "_TableComponent__column_names": ["Name", "Value"], - }, - } - ) - - event = data_source.command(http.GetEventById("2c4b3a58-f882-11ec-b952-0a1e730db2c6")) - events = data_source.command( - http.GetEventsById( - [ - "2c4b3a58-f882-11ec-b952-0a1e730db2c6", - "a5586d90-b83b-48a4-bd2b-b2059fb79374:b84cff2c-f883-11ec-b070-0a1e730db2c6", - ] - ) - ) - events_with_one_element = data_source.command( - http.GetEventsById( - [ - "2c4b3a58-f882-11ec-b952-0a1e730db2c6", - ] - ) - ) - for event_ in events: - event_["attachedMessageIds"].sort() - - broken_event: dict = data_source.command(http.GetEventById("id", use_stub=True)) - broken_events: list = data_source.command(http.GetEventsById(["id", "ids"], use_stub=True)) - - plug_for_broken_event: dict = { - "attachedMessageIds": [], - "batchId": "Broken_Event", - "endTimestamp": {"nano": 0, "epochSecond": 0}, - "startTimestamp": {"nano": 0, "epochSecond": 0}, - "type": "event", - "eventId": "id", - "eventName": "Broken_Event", - "eventType": "Broken_Event", - "parentEventId": "Broken_Event", - "successful": None, - "isBatched": None, - } - - plug_for_broken_events: list = [ - plug_for_broken_event.copy(), - plug_for_broken_event.copy(), - ] - plug_for_broken_events[1]["eventId"] = "ids" - - # Check types - assert isinstance(event, dict) - assert isinstance(events, list) - assert isinstance(events_with_one_element, list) - assert isinstance(broken_event, dict) - assert isinstance(broken_events, list) - # Check content. - assert event == expected_event - assert events == expected_events - assert len(events) == 2 - assert len(events_with_one_element) == 1 - # Check Broken_Events - assert broken_event == plug_for_broken_event - assert broken_events == plug_for_broken_events - assert [event, broken_event] == data_source.command( - http.GetEventsById(["2c4b3a58-f882-11ec-b952-0a1e730db2c6", "id"], use_stub=True) - ) - with pytest.raises(CommandError): - data_source.command(http.GetEventsById(["2c4b3a58-f882-11ec-b952-0a1e730db2c6", "id"])) - with pytest.raises(CommandError): - data_source.command(http.GetEventById("id")) - - -def test_find_messages_by_id_from_data_provider(demo_data_source: HTTPProviderDataSource): - data_source = demo_data_source - - expected_message = { - "attachedEventIds": [], - "body": { - "fields": { - "header": { - "messageValue": { - "fields": { - "BeginString": {"simpleValue": "FIXT.1.1"}, - "BodyLength": {"simpleValue": "61"}, - "MsgSeqNum": {"simpleValue": "33"}, - "MsgType": {"simpleValue": "0"}, - "SenderCompID": {"simpleValue": "ARFQ01FIX08"}, - "SendingTime": {"simpleValue": "2022-06-30T14:39:27.111"}, - "TargetCompID": {"simpleValue": "FGW"}, - } - } - }, - "trailer": {"messageValue": {"fields": {"CheckSum": {"simpleValue": "160"}}}}, - }, - "metadata": { - "id": { - "connectionId": {"sessionAlias": "arfq01fix08"}, - "direction": "SECOND", - "sequence": "1656599887515499033", - "subsequence": [1], - }, - "messageType": "Heartbeat", - "protocol": "FIX", - "timestamp": "2022-06-30T14:39:27.112Z", - }, - }, - "bodyBase64": "OD1GSVhULjEuMQE5PTYxATM1PTABMzQ9MzMBNDk9QVJGUTAxRklYMDgBNTI9MjAyMjA2MzAtMTQ6Mzk6MjcuMTExMDAwATU2PUZHVwExMD0xNjAB", - "direction": "OUT", - "messageId": "arfq01fix08:second:1656599887515499033", - "messageType": "Heartbeat", - "sessionId": "arfq01fix08", - "timestamp": {"epochSecond": 1656599967, "nano": 112000000}, - "type": "message", - } - - expected_messages = [] - expected_messages.append(expected_message) - expected_messages.append( - { - "attachedEventIds": [], - "body": { - "fields": { - "DefaultApplVerID": {"simpleValue": "9"}, - "EncryptMethod": {"simpleValue": "0"}, - "HeartBtInt": {"simpleValue": "5"}, - "Password": {"simpleValue": "mit123"}, - "ResetSeqNumFlag": {"simpleValue": "true"}, - "header": { - "messageValue": { - "fields": { - "BeginString": {"simpleValue": "FIXT.1.1"}, - "BodyLength": {"simpleValue": "91"}, - "MsgSeqNum": {"simpleValue": "1"}, - "MsgType": {"simpleValue": "A"}, - "SenderCompID": {"simpleValue": "ARFQ01DC03"}, - "SendingTime": {"simpleValue": "2022-06-30T14:46:03.911"}, - "TargetCompID": {"simpleValue": "FGW"}, - } - } - }, - "trailer": {"messageValue": {"fields": {"CheckSum": {"simpleValue": "161"}}}}, - }, - "metadata": { - "id": { - "connectionId": {"sessionAlias": "arfq01dc03"}, - "direction": "SECOND", - "sequence": "1656599850628059096", - "subsequence": [1], - }, - "messageType": "Logon", - "protocol": "FIX", - "timestamp": "2022-06-30T14:46:03.915Z", - }, - }, - "bodyBase64": "OD1GSVhULjEuMQE5PTkxATM1PUEBMzQ9MQE0OT1BUkZRMDFEQzAzATUyPTIwMjIwNjMwLTE0OjQ2OjAzLjkxMQE1Nj1GR1cBOTg9MAExMDg9NQExNDE9WQE1NTQ9bWl0MTIzATExMzc9OQExMD0xNjEB", - "direction": "OUT", - "messageId": "arfq01dc03:second:1656599850628059096", - "messageType": "Logon", - "sessionId": "arfq01dc03", - "timestamp": {"epochSecond": 1656600363, "nano": 915000000}, - "type": "message", - } - ) - - message = data_source.command(http.GetMessageById("arfq01fix08:second:1656599887515499033")) - messages = data_source.command( - http.GetMessagesById(["arfq01fix08:second:1656599887515499033", "arfq01dc03:second:1656599850628059096"]) - ) - messages_with_one_element = data_source.command(http.GetMessagesById(["arfq01fix08:second:1656599887515499033"])) - # Check types - assert isinstance(message, dict) - assert isinstance(messages, list) - assert isinstance(messages_with_one_element, list) - # Check content. - assert message == expected_message - assert messages == expected_messages - assert len(messages) == 2 - assert len(messages_with_one_element) == 1 - - -def test_get_x_with_filters( - demo_get_events_with_one_filter: Data, - demo_get_messages_with_one_filter: Data, - demo_get_events_with_filters: Data, - demo_get_messages_with_filters: Data, -): - case = [ - { - "type": "event", - "eventId": "a2321a5b-f883-11ec-8225-52540095fac0", - "batchId": None, - "isBatched": False, - "eventName": "[TS_1]5 partfill trades and cancel.", - "eventType": "", - "endTimestamp": {"nano": 735114000, "epochSecond": 1656600478}, - "startTimestamp": {"nano": 735039000, "epochSecond": 1656600478}, - "parentEventId": None, - "successful": False, - "attachedMessageIds": [], - "body": {}, - } - ] - case1 = [ - { - "type": "event", - "eventId": "bb0da3a9-f883-11ec-aeb3-adf8526f5eec", - "batchId": None, - "isBatched": False, - "eventName": "Received 'ExecutionReport' response message", - "eventType": "message", - "endTimestamp": {"nano": 428471000, "epochSecond": 1656600520}, - "startTimestamp": {"nano": 428350000, "epochSecond": 1656600520}, - "parentEventId": "ba4e7257-f883-11ec-aeb3-adf8526f5eec", - "successful": True, - "attachedMessageIds": [], - "body": [ - { - "type": "treeTable", - "rows": { - "ExecID": {"type": "row", "columns": {"fieldValue": "E0AmqxctTQGw"}}, - "OrderQty": {"type": "row", "columns": {"fieldValue": "20"}}, - "LastQty": {"type": "row", "columns": {"fieldValue": "20"}}, - "OrderID": {"type": "row", "columns": {"fieldValue": "00Amr2Sw36j1"}}, - "TransactTime": {"type": "row", "columns": {"fieldValue": "2022-06-30T14:48:39.526758"}}, - "GroupID": {"type": "row", "columns": {"fieldValue": "0"}}, - "trailer": { - "type": "collection", - "rows": {"CheckSum": {"type": "row", "columns": {"fieldValue": "136"}}}, - }, - "Side": {"type": "row", "columns": {"fieldValue": "2"}}, - "OrdStatus": {"type": "row", "columns": {"fieldValue": "2"}}, - "TimeInForce": {"type": "row", "columns": {"fieldValue": "0"}}, - "SecurityID": {"type": "row", "columns": {"fieldValue": "5221001"}}, - "ExecType": {"type": "row", "columns": {"fieldValue": "F"}}, - "TradeLiquidityIndicator": {"type": "row", "columns": {"fieldValue": "R"}}, - "LastLiquidityInd": {"type": "row", "columns": {"fieldValue": "2"}}, - "LeavesQty": {"type": "row", "columns": {"fieldValue": "0"}}, - "CumQty": {"type": "row", "columns": {"fieldValue": "20"}}, - "LastPx": {"type": "row", "columns": {"fieldValue": "55"}}, - "TypeOfTrade": {"type": "row", "columns": {"fieldValue": "2"}}, - "TrdMatchID": {"type": "row", "columns": {"fieldValue": "L2N1AYTNPW"}}, - "OrdType": {"type": "row", "columns": {"fieldValue": "2"}}, - "ClOrdID": {"type": "row", "columns": {"fieldValue": "1985282"}}, - "SecurityIDSource": {"type": "row", "columns": {"fieldValue": "8"}}, - "LastMkt": {"type": "row", "columns": {"fieldValue": "XLOM"}}, - "OrderCapacity": {"type": "row", "columns": {"fieldValue": "A"}}, - "SecondaryClOrdID": {"type": "row", "columns": {"fieldValue": "33333"}}, - "AccountType": {"type": "row", "columns": {"fieldValue": "1"}}, - "Price": {"type": "row", "columns": {"fieldValue": "55"}}, - "MDEntryID": {"type": "row", "columns": {"fieldValue": "00Amr2Sw36j1"}}, - "TradingParty": { - "type": "collection", - "rows": { - "NoPartyIDs": { - "type": "collection", - "rows": { - "0": { - "type": "collection", - "rows": { - "PartyRole": {"type": "row", "columns": {"fieldValue": "76"}}, - "PartyID": {"type": "row", "columns": {"fieldValue": "ARFQ01FIX08"}}, - "PartyIDSource": {"type": "row", "columns": {"fieldValue": "D"}}, - }, - }, - "1": { - "type": "collection", - "rows": { - "PartyRole": {"type": "row", "columns": {"fieldValue": "17"}}, - "PartyID": {"type": "row", "columns": {"fieldValue": "ARFQ01"}}, - "PartyIDSource": {"type": "row", "columns": {"fieldValue": "D"}}, - }, - }, - "2": { - "type": "collection", - "rows": { - "PartyRole": {"type": "row", "columns": {"fieldValue": "3"}}, - "PartyID": {"type": "row", "columns": {"fieldValue": "0"}}, - "PartyIDSource": {"type": "row", "columns": {"fieldValue": "P"}}, - }, - }, - "3": { - "type": "collection", - "rows": { - "PartyRole": {"type": "row", "columns": {"fieldValue": "122"}}, - "PartyID": {"type": "row", "columns": {"fieldValue": "0"}}, - "PartyIDSource": {"type": "row", "columns": {"fieldValue": "P"}}, - }, - }, - "4": { - "type": "collection", - "rows": { - "PartyRole": {"type": "row", "columns": {"fieldValue": "12"}}, - "PartyID": {"type": "row", "columns": {"fieldValue": "3"}}, - "PartyIDSource": {"type": "row", "columns": {"fieldValue": "P"}}, - }, - }, - }, - } - }, - }, - "header": { - "type": "collection", - "rows": { - "BeginString": {"type": "row", "columns": {"fieldValue": "FIXT.1.1"}}, - "SenderCompID": {"type": "row", "columns": {"fieldValue": "FGW"}}, - "SendingTime": {"type": "row", "columns": {"fieldValue": "2022-06-30T14:48:39.530311"}}, - "TargetCompID": {"type": "row", "columns": {"fieldValue": "ARFQ01FIX08"}}, - "ApplVerID": {"type": "row", "columns": {"fieldValue": "9"}}, - "MsgType": {"type": "row", "columns": {"fieldValue": "8"}}, - "MsgSeqNum": {"type": "row", "columns": {"fieldValue": "589"}}, - "BodyLength": {"type": "row", "columns": {"fieldValue": "432"}}, - }, - }, - "DisplayQty": {"type": "row", "columns": {"fieldValue": "0"}}, - }, - } - ], - } - ] - case3 = [ - { - "type": "message", - "timestamp": {"nano": 422000000, "epochSecond": 1656600504}, - "messageType": "NewOrderSingle", - "direction": "OUT", - "sessionId": "arfq01fix07", - "attachedEventIds": [], - "messageId": "arfq01fix07:second:1656599837520228626", - "body": { - "metadata": { - "id": { - "connectionId": {"sessionAlias": "arfq01fix07"}, - "direction": "SECOND", - "sequence": "1656599837520228626", - "subsequence": [1], - }, - "timestamp": "2022-06-30T14:48:24.422Z", - "messageType": "NewOrderSingle", - "protocol": "FIX", - }, - "fields": { - "OrderQty": {"simpleValue": "200"}, - "OrdType": {"simpleValue": "2"}, - "ClOrdID": {"simpleValue": "1830410"}, - "SecurityIDSource": {"simpleValue": "8"}, - "OrderCapacity": {"simpleValue": "A"}, - "TransactTime": {"simpleValue": "2022-06-30T14:47:59.032276"}, - "SecondaryClOrdID": {"simpleValue": "11111"}, - "AccountType": {"simpleValue": "1"}, - "trailer": {"messageValue": {"fields": {"CheckSum": {"simpleValue": "152"}}}}, - "Side": {"simpleValue": "1"}, - "Price": {"simpleValue": "55"}, - "TradingParty": { - "messageValue": { - "fields": { - "NoPartyIDs": { - "listValue": { - "values": [ - { - "messageValue": { - "fields": { - "PartyRole": {"simpleValue": "76"}, - "PartyID": {"simpleValue": "ARFQ01FIX07"}, - "PartyIDSource": {"simpleValue": "D"}, - } - } - }, - { - "messageValue": { - "fields": { - "PartyRole": {"simpleValue": "3"}, - "PartyID": {"simpleValue": "0"}, - "PartyIDSource": {"simpleValue": "P"}, - } - } - }, - { - "messageValue": { - "fields": { - "PartyRole": {"simpleValue": "122"}, - "PartyID": {"simpleValue": "0"}, - "PartyIDSource": {"simpleValue": "P"}, - } - } - }, - { - "messageValue": { - "fields": { - "PartyRole": {"simpleValue": "12"}, - "PartyID": {"simpleValue": "3"}, - "PartyIDSource": {"simpleValue": "P"}, - } - } - }, - ] - } - } - } - } - }, - "SecurityID": {"simpleValue": "5221001"}, - "header": { - "messageValue": { - "fields": { - "BeginString": {"simpleValue": "FIXT.1.1"}, - "SenderCompID": {"simpleValue": "ARFQ01FIX07"}, - "SendingTime": {"simpleValue": "2022-06-30T14:48:24.330"}, - "TargetCompID": {"simpleValue": "FGW"}, - "MsgType": {"simpleValue": "D"}, - "MsgSeqNum": {"simpleValue": "626"}, - "BodyLength": {"simpleValue": "263"}, - } - } - }, - "DisplayQty": {"simpleValue": "200"}, - }, - }, - "bodyBase64": "OD1GSVhULjEuMQE5PTI2MwEzNT1EATM0PTYyNgE0OT1BUkZRMDFGSVgwNwE1Mj0yMDIyMDYzMC0xNDo0ODoyNC4zMzAwMDABNTY9RkdXATExPTE4MzA0MTABMjI9OAEzOD0yMDABNDA9MgE0ND01NQE0OD01MjIxMDAxATU0PTEBNjA9MjAyMjA2MzAtMTQ6NDc6NTkuMDMyMjc2ATUyNj0xMTExMQE1Mjg9QQE1ODE9MQExMTM4PTIwMAE0NTM9NAE0NDg9QVJGUTAxRklYMDcBNDQ3PUQBNDUyPTc2ATQ0OD0wATQ0Nz1QATQ1Mj0zATQ0OD0wATQ0Nz1QATQ1Mj0xMjIBNDQ4PTMBNDQ3PVABNDUyPTEyATEwPTE1MgE=", - } - ] - assert list(demo_get_messages_with_one_filter) == case3 - assert list(demo_get_messages_with_filters) == case3 - assert list(demo_get_events_with_one_filter) == case and len(case) is 1 - assert list(demo_get_events_with_filters) == case1 and len(case1) is 1 diff --git a/tests/tests_integration/tests_diff_version/tests_v5/tests_events_tree/test_events_tree_local.py b/tests/tests_integration/tests_diff_version/tests_v5/tests_events_tree/test_events_tree_local.py deleted file mode 100644 index 5908c2f0..00000000 --- a/tests/tests_integration/tests_diff_version/tests_v5/tests_events_tree/test_events_tree_local.py +++ /dev/null @@ -1,106 +0,0 @@ -from datetime import datetime -from th2_data_services import Data -from th2_data_services.provider.v5.commands.http import GetEvents -from th2_data_services.provider.v5.data_source import HTTPProvider5DataSource -from th2_data_services.provider.v5.events_tree.events_tree_collection import EventsTreeCollectionProvider5 - - -def test_recover_unknown_events(): - data_source = HTTPProvider5DataSource("http://10.100.66.114:31787/") - events: Data = data_source.command( - GetEvents( - start_timestamp=datetime(year=2022, month=6, day=30, hour=14, minute=50, second=0, microsecond=0), - end_timestamp=datetime(year=2022, month=6, day=30, hour=15, minute=0, second=0, microsecond=0), - ) - ) - - before_tree = events.len - collection = EventsTreeCollectionProvider5(events, data_source=data_source) - after_tree = len(collection) - - assert not collection.detached_events and before_tree != after_tree - - -def test_recover_unknown_events_ds_passed_into_method(): - data_source = HTTPProvider5DataSource("http://10.100.66.114:31787/") - events: Data = data_source.command( - GetEvents( - start_timestamp=datetime(year=2022, month=6, day=30, hour=14, minute=50, second=0, microsecond=0), - end_timestamp=datetime(year=2022, month=6, day=30, hour=15, minute=0, second=0, microsecond=0), - ) - ) - - before_tree = events.len - collection = EventsTreeCollectionProvider5(events) - collection.recover_unknown_events(data_source=data_source) - after_tree = len(collection) - - assert not collection.detached_events and before_tree != after_tree - - -def test_recover_unknown_events_with_stub_events(): - data_source = HTTPProvider5DataSource("http://10.100.66.114:31787/") - events: Data = data_source.command( - GetEvents( - start_timestamp=datetime(year=2022, month=6, day=30, hour=14, minute=50, second=0, microsecond=0), - end_timestamp=datetime(year=2022, month=6, day=30, hour=15, minute=0, second=0, microsecond=0), - ) - ) - - broken_event = { - "attachedMessageIds": [], - "batchId": "Broken_Event", - "endTimestamp": {"nano": 0, "epochSecond": 0}, - "startTimestamp": {"nano": 0, "epochSecond": 0}, - "type": "event", - "eventId": f"33499-333-111-test-03221", - "eventName": "Broken_Event", - "eventType": "Broken_Event", - "parentEventId": "Broken_Event", - "successful": None, - "isBatched": None, - } - events: list = [event for event in events] + [broken_event] - - before_tree = len(events) - collection = EventsTreeCollectionProvider5(events, data_source=data_source, stub=True) - after_tree = len(collection) - - assert collection.detached_events == {"Broken_Event": [broken_event]} and before_tree != after_tree - - -def test_preserve_body(): - data_source = HTTPProvider5DataSource("http://10.100.66.114:31787/") - events: Data = data_source.command( - GetEvents( - start_timestamp=datetime(year=2022, month=6, day=30, hour=14, minute=0, second=0, microsecond=0), - end_timestamp=datetime(year=2022, month=6, day=30, hour=15, minute=0, second=0, microsecond=0), - ) - ) - - collection = EventsTreeCollectionProvider5(events, data_source=data_source, preserve_body=True) - - assert all( - [True if event.get("body") is not None else False for event in collection.get_trees()[0].get_all_events()] - ) - - -def test_create_subtree_incoming_data_stream(): - data_source = HTTPProvider5DataSource("http://10.100.66.114:31787/") - events: Data = data_source.command( - GetEvents( - start_timestamp=datetime(year=2022, month=6, day=30, hour=14, minute=0, second=0, microsecond=0), - end_timestamp=datetime(year=2022, month=6, day=30, hour=15, minute=0, second=0, microsecond=0), - ) - ) - tree = EventsTreeCollectionProvider5(events, preserve_body=True).get_trees()[0] - etc_1 = EventsTreeCollectionProvider5(tree.findall(lambda e: e["eventName"]), preserve_body=True) - sub_tree_0 = etc_1.get_trees()[0] - root_sub_tree_0 = sub_tree_0.get_root().copy() - etc_2 = EventsTreeCollectionProvider5(tree.findall(lambda e: e["eventName"])) - assert root_sub_tree_0 != etc_2.get_trees()[0] - assert root_sub_tree_0 == sub_tree_0.get_root() - assert ( - root_sub_tree_0.get("body") == [{"data": "Root event", "type": "message"}] - and etc_2.get_trees()[0].get_root().get("body") is None - ) diff --git a/tests/tests_integration/tests_diff_version/tests_v5/tests_events_tree/test_parent_events_tree_local.py b/tests/tests_integration/tests_diff_version/tests_v5/tests_events_tree/test_parent_events_tree_local.py deleted file mode 100644 index ee074950..00000000 --- a/tests/tests_integration/tests_diff_version/tests_v5/tests_events_tree/test_parent_events_tree_local.py +++ /dev/null @@ -1,71 +0,0 @@ -from datetime import datetime - -from th2_data_services import Data -from th2_data_services.provider.v5.commands.http import GetEvents -from th2_data_services.provider.v5.data_source import HTTPProvider5DataSource -from th2_data_services.provider.v5.events_tree.parent_events_tree_collection import ( - ParentEventsTreeCollectionProvider5, -) - - -def test_recover_unknown_events(): - data_source = HTTPProvider5DataSource("http://10.100.66.114:31787/") - events: Data = data_source.command( - GetEvents( - start_timestamp=datetime(year=2022, month=6, day=30, hour=14, minute=0, second=0, microsecond=0), - end_timestamp=datetime(year=2022, month=6, day=30, hour=15, minute=0, second=0, microsecond=0), - ) - ) - - before_tree = events.len - collection = ParentEventsTreeCollectionProvider5(events, data_source=data_source) - after_tree = len(collection) - - assert not collection.detached_events and before_tree != after_tree - - -def test_recover_unknown_events_with_stub_events(): - data_source = HTTPProvider5DataSource("http://10.100.66.114:31787/") - events: Data = data_source.command( - GetEvents( - start_timestamp=datetime(year=2022, month=6, day=30, hour=14, minute=0, second=0, microsecond=0), - end_timestamp=datetime(year=2022, month=6, day=30, hour=15, minute=0, second=0, microsecond=0), - ) - ) - - broken_event = { - "attachedMessageIds": [], - "batchId": "Broken_Event", - "endTimestamp": {"nano": 0, "epochSecond": 0}, - "startTimestamp": {"nano": 0, "epochSecond": 0}, - "type": "event", - "eventId": f"33499-333-111-test-03221", - "eventName": "Broken_Event", - "eventType": "Broken_Event", - "parentEventId": "Broken_Event", - "successful": None, - "isBatched": None, - } - events: list = [event for event in events] + [broken_event] - - before_tree = len(events) - collection = ParentEventsTreeCollectionProvider5(events, data_source=data_source, stub=True) - after_tree = len(collection) - - assert collection.detached_events == {"Broken_Event": [broken_event]} and before_tree != after_tree - - -def test_preserve_body(): - data_source = HTTPProvider5DataSource("http://10.100.66.114:31787/") - events: Data = data_source.command( - GetEvents( - start_timestamp=datetime(year=2022, month=6, day=30, hour=14, minute=0, second=0, microsecond=0), - end_timestamp=datetime(year=2022, month=6, day=30, hour=15, minute=0, second=0, microsecond=0), - ) - ) - - collection = ParentEventsTreeCollectionProvider5(events, data_source=data_source, preserve_body=True) - - assert all( - [True if event.get("body") is not None else False for event in collection.get_trees()[0].get_all_events()] - ) diff --git a/tests/tests_integration/tests_diff_version/tests_v6/test_data_source_local.py b/tests/tests_integration/tests_diff_version/tests_v6/test_data_source_local.py deleted file mode 100644 index e62a3df2..00000000 --- a/tests/tests_integration/tests_diff_version/tests_v6/test_data_source_local.py +++ /dev/null @@ -1,489 +0,0 @@ -import pytest - -from ..conftest import HTTPProviderDataSource, http, Data -from th2_data_services.provider.exceptions import CommandError - - -def test_find_events_by_id_from_data_provider(demo_data_source: HTTPProviderDataSource): - data_source = demo_data_source - - expected_event = { - "attachedMessageIds": [], - "batchId": None, - "body": {}, - "endTimestamp": "2022-06-30T14:37:31.420806000Z", - "eventId": "2c4b3a58-f882-11ec-b952-0a1e730db2c6", - "eventName": "Recon: Test", - "eventType": "", - "isBatched": False, - "parentEventId": None, - "startTimestamp": "2022-06-30T14:37:31.420806000Z", - "successful": False, - "type": "event", - } - - expected_events = [] - expected_events.append(expected_event) - expected_events.append( - { - "type": "event", - "eventId": "a5586d90-b83b-48a4-bd2b-b2059fb79374:b84cff2c-f883-11ec-b070-0a1e730db2c6", - "batchId": "a5586d90-b83b-48a4-bd2b-b2059fb79374", - "isBatched": True, - "eventName": "Match by ClOrdID: '7706360'", - "eventType": "", - "endTimestamp": "2022-06-30T14:48:35.809998000Z", - "startTimestamp": "2022-06-30T14:48:35.809998000Z", - "parentEventId": "b21a03c0-f883-11ec-b070-0a1e730db2c6", - "successful": True, - "attachedMessageIds": ["arfq01fix08:first:1656599887515453583", "arfq01fix08:second:1656599887515499581"], - "body": { - "type": "table", - "rows": [ - {"Name": "ClOrdId", "Value": "7706360"}, - {"Name": "Message Response", "Value": "ExecutionReport"}, - {"Name": "Message Request", "Value": "NewOrderSingle"}, - {"Name": "Latency type", "Value": "Trade"}, - {"Name": "Latency", "Value": 29000.0}, - ], - "_TableComponent__column_names": ["Name", "Value"], - }, - } - ) - - event = data_source.command(http.GetEventById("2c4b3a58-f882-11ec-b952-0a1e730db2c6")) - events = data_source.command( - http.GetEventsById( - [ - "2c4b3a58-f882-11ec-b952-0a1e730db2c6", - "a5586d90-b83b-48a4-bd2b-b2059fb79374:b84cff2c-f883-11ec-b070-0a1e730db2c6", - ] - ) - ) - events_with_one_element = data_source.command( - http.GetEventsById( - [ - "2c4b3a58-f882-11ec-b952-0a1e730db2c6", - ] - ) - ) - for event_ in events: - event_["attachedMessageIds"].sort() - - broken_event: dict = data_source.command(http.GetEventById("id", use_stub=True)) - broken_events: list = data_source.command(http.GetEventsById(["id", "ids"], use_stub=True)) - - plug_for_broken_event: dict = { - "attachedMessageIds": [], - "batchId": "Broken_Event", - "endTimestamp": {"nano": 0, "epochSecond": 0}, - "startTimestamp": {"nano": 0, "epochSecond": 0}, - "type": "event", - "eventId": "id", - "eventName": "Broken_Event", - "eventType": "Broken_Event", - "parentEventId": "Broken_Event", - "successful": None, - "isBatched": None, - } - - plug_for_broken_events: list = [ - plug_for_broken_event.copy(), - plug_for_broken_event.copy(), - ] - plug_for_broken_events[1]["eventId"] = "ids" - - # Check types - assert isinstance(event, dict) - assert isinstance(events, list) - assert isinstance(events_with_one_element, list) - assert isinstance(broken_event, dict) - assert isinstance(broken_events, list) - # Check content. - assert event == expected_event - assert events == expected_events - assert len(events) == 2 - assert len(events_with_one_element) == 1 - # Check Broken_Events - assert broken_event == plug_for_broken_event - assert broken_events == plug_for_broken_events - assert [event, broken_event] == data_source.command( - http.GetEventsById(["2c4b3a58-f882-11ec-b952-0a1e730db2c6", "id"], use_stub=True) - ) - with pytest.raises(CommandError): - data_source.command(http.GetEventsById(["2c4b3a58-f882-11ec-b952-0a1e730db2c6", "id"])) - with pytest.raises(CommandError): - data_source.command(http.GetEventById("id")) - - -def test_find_messages_by_id_from_data_provider(demo_data_source: HTTPProviderDataSource): - data_source = demo_data_source - - expected_message = { - "attachedEventIds": [], - "direction": "SECOND", - "id": "arfq01fix08:second:1656599887515499033", - "parsedMessages": [ - { - "id": "arfq01fix08:second:1656599887515499033.1", - "match": True, - "message": { - "fields": { - "header": { - "messageValue": { - "fields": { - "BeginString": {"simpleValue": "FIXT.1.1"}, - "BodyLength": {"simpleValue": "61"}, - "MsgSeqNum": {"simpleValue": "33"}, - "MsgType": {"simpleValue": "0"}, - "SenderCompID": {"simpleValue": "ARFQ01FIX08"}, - "SendingTime": {"simpleValue": "2022-06-30T14:39:27.111"}, - "TargetCompID": {"simpleValue": "FGW"}, - } - } - }, - "trailer": {"messageValue": {"fields": {"CheckSum": {"simpleValue": "160"}}}}, - }, - "metadata": { - "id": { - "connectionId": {"sessionAlias": "arfq01fix08"}, - "direction": "SECOND", - "sequence": "1656599887515499033", - "subsequence": [1], - }, - "messageType": "Heartbeat", - "protocol": "FIX", - "timestamp": "2022-06-30T14:39:27.112Z", - }, - }, - } - ], - "rawMessageBase64": "OD1GSVhULjEuMQE5PTYxATM1PTABMzQ9MzMBNDk9QVJGUTAxRklYMDgBNTI9MjAyMjA2MzAtMTQ6Mzk6MjcuMTExMDAwATU2PUZHVwExMD0xNjAB", - "sequence": "1656599887515499033", - "sessionId": "arfq01fix08", - "timestamp": "2022-06-30T14:39:27.112000000Z", - "type": "message", - } - - expected_messages = [] - expected_messages.append(expected_message) - expected_messages.append( - { - "attachedEventIds": [], - "direction": "SECOND", - "id": "arfq01dc03:second:1656599850628059096", - "parsedMessages": [ - { - "id": "arfq01dc03:second:1656599850628059096.1", - "match": True, - "message": { - "fields": { - "DefaultApplVerID": {"simpleValue": "9"}, - "EncryptMethod": {"simpleValue": "0"}, - "HeartBtInt": {"simpleValue": "5"}, - "Password": {"simpleValue": "mit123"}, - "ResetSeqNumFlag": {"simpleValue": "true"}, - "header": { - "messageValue": { - "fields": { - "BeginString": {"simpleValue": "FIXT.1.1"}, - "BodyLength": {"simpleValue": "91"}, - "MsgSeqNum": {"simpleValue": "1"}, - "MsgType": {"simpleValue": "A"}, - "SenderCompID": {"simpleValue": "ARFQ01DC03"}, - "SendingTime": {"simpleValue": "2022-06-30T14:46:03.911"}, - "TargetCompID": {"simpleValue": "FGW"}, - } - } - }, - "trailer": {"messageValue": {"fields": {"CheckSum": {"simpleValue": "161"}}}}, - }, - "metadata": { - "id": { - "connectionId": {"sessionAlias": "arfq01dc03"}, - "direction": "SECOND", - "sequence": "1656599850628059096", - "subsequence": [1], - }, - "messageType": "Logon", - "protocol": "FIX", - "timestamp": "2022-06-30T14:46:03.915Z", - }, - }, - } - ], - "rawMessageBase64": "OD1GSVhULjEuMQE5PTkxATM1PUEBMzQ9MQE0OT1BUkZRMDFEQzAzATUyPTIwMjIwNjMwLTE0OjQ2OjAzLjkxMQE1Nj1GR1cBOTg9MAExMDg9NQExNDE9WQE1NTQ9bWl0MTIzATExMzc9OQExMD0xNjEB", - "sequence": "1656599850628059096", - "sessionId": "arfq01dc03", - "timestamp": "2022-06-30T14:46:03.915000000Z", - "type": "message", - } - ) - - message = data_source.command(http.GetMessageById("arfq01fix08:second:1656599887515499033")) - messages = data_source.command( - http.GetMessagesById(["arfq01fix08:second:1656599887515499033", "arfq01dc03:second:1656599850628059096"]) - ) - messages_with_one_element = data_source.command(http.GetMessagesById(["arfq01fix08:second:1656599887515499033"])) - # Check types - assert isinstance(message, dict) - assert isinstance(messages, list) - assert isinstance(messages_with_one_element, list) - # Check content. - assert message == expected_message - assert messages == expected_messages - assert len(messages) == 2 - assert len(messages_with_one_element) == 1 - - -def test_get_x_with_filters( - demo_get_events_with_one_filter: Data, - demo_get_messages_with_one_filter: Data, - demo_get_events_with_filters: Data, - demo_get_messages_with_filters: Data, -): - case = [ - { - "type": "event", - "eventId": "a2321a5b-f883-11ec-8225-52540095fac0", - "batchId": None, - "isBatched": False, - "eventName": "[TS_1]5 partfill trades and cancel.", - "eventType": "", - "endTimestamp": "2022-06-30T14:47:58.735114000Z", - "startTimestamp": "2022-06-30T14:47:58.735039000Z", - "parentEventId": None, - "successful": False, - "attachedMessageIds": [], - "body": {}, - } - ] - case1 = [ - { - "type": "event", - "eventId": "bb0da3a9-f883-11ec-aeb3-adf8526f5eec", - "batchId": None, - "isBatched": False, - "eventName": "Received 'ExecutionReport' response message", - "eventType": "message", - "endTimestamp": "2022-06-30T14:48:40.428471000Z", - "startTimestamp": "2022-06-30T14:48:40.428350000Z", - "parentEventId": "ba4e7257-f883-11ec-aeb3-adf8526f5eec", - "successful": True, - "attachedMessageIds": [], - "body": [ - { - "type": "treeTable", - "rows": { - "ExecID": {"type": "row", "columns": {"fieldValue": "E0AmqxctTQGw"}}, - "OrderQty": {"type": "row", "columns": {"fieldValue": "20"}}, - "LastQty": {"type": "row", "columns": {"fieldValue": "20"}}, - "OrderID": {"type": "row", "columns": {"fieldValue": "00Amr2Sw36j1"}}, - "TransactTime": {"type": "row", "columns": {"fieldValue": "2022-06-30T14:48:39.526758"}}, - "GroupID": {"type": "row", "columns": {"fieldValue": "0"}}, - "trailer": { - "type": "collection", - "rows": {"CheckSum": {"type": "row", "columns": {"fieldValue": "136"}}}, - }, - "Side": {"type": "row", "columns": {"fieldValue": "2"}}, - "OrdStatus": {"type": "row", "columns": {"fieldValue": "2"}}, - "TimeInForce": {"type": "row", "columns": {"fieldValue": "0"}}, - "SecurityID": {"type": "row", "columns": {"fieldValue": "5221001"}}, - "ExecType": {"type": "row", "columns": {"fieldValue": "F"}}, - "TradeLiquidityIndicator": {"type": "row", "columns": {"fieldValue": "R"}}, - "LastLiquidityInd": {"type": "row", "columns": {"fieldValue": "2"}}, - "LeavesQty": {"type": "row", "columns": {"fieldValue": "0"}}, - "CumQty": {"type": "row", "columns": {"fieldValue": "20"}}, - "LastPx": {"type": "row", "columns": {"fieldValue": "55"}}, - "TypeOfTrade": {"type": "row", "columns": {"fieldValue": "2"}}, - "TrdMatchID": {"type": "row", "columns": {"fieldValue": "L2N1AYTNPW"}}, - "OrdType": {"type": "row", "columns": {"fieldValue": "2"}}, - "ClOrdID": {"type": "row", "columns": {"fieldValue": "1985282"}}, - "SecurityIDSource": {"type": "row", "columns": {"fieldValue": "8"}}, - "LastMkt": {"type": "row", "columns": {"fieldValue": "XLOM"}}, - "OrderCapacity": {"type": "row", "columns": {"fieldValue": "A"}}, - "SecondaryClOrdID": {"type": "row", "columns": {"fieldValue": "33333"}}, - "AccountType": {"type": "row", "columns": {"fieldValue": "1"}}, - "Price": {"type": "row", "columns": {"fieldValue": "55"}}, - "MDEntryID": {"type": "row", "columns": {"fieldValue": "00Amr2Sw36j1"}}, - "TradingParty": { - "type": "collection", - "rows": { - "NoPartyIDs": { - "type": "collection", - "rows": { - "0": { - "type": "collection", - "rows": { - "PartyRole": {"type": "row", "columns": {"fieldValue": "76"}}, - "PartyID": {"type": "row", "columns": {"fieldValue": "ARFQ01FIX08"}}, - "PartyIDSource": {"type": "row", "columns": {"fieldValue": "D"}}, - }, - }, - "1": { - "type": "collection", - "rows": { - "PartyRole": {"type": "row", "columns": {"fieldValue": "17"}}, - "PartyID": {"type": "row", "columns": {"fieldValue": "ARFQ01"}}, - "PartyIDSource": {"type": "row", "columns": {"fieldValue": "D"}}, - }, - }, - "2": { - "type": "collection", - "rows": { - "PartyRole": {"type": "row", "columns": {"fieldValue": "3"}}, - "PartyID": {"type": "row", "columns": {"fieldValue": "0"}}, - "PartyIDSource": {"type": "row", "columns": {"fieldValue": "P"}}, - }, - }, - "3": { - "type": "collection", - "rows": { - "PartyRole": {"type": "row", "columns": {"fieldValue": "122"}}, - "PartyID": {"type": "row", "columns": {"fieldValue": "0"}}, - "PartyIDSource": {"type": "row", "columns": {"fieldValue": "P"}}, - }, - }, - "4": { - "type": "collection", - "rows": { - "PartyRole": {"type": "row", "columns": {"fieldValue": "12"}}, - "PartyID": {"type": "row", "columns": {"fieldValue": "3"}}, - "PartyIDSource": {"type": "row", "columns": {"fieldValue": "P"}}, - }, - }, - }, - } - }, - }, - "header": { - "type": "collection", - "rows": { - "BeginString": {"type": "row", "columns": {"fieldValue": "FIXT.1.1"}}, - "SenderCompID": {"type": "row", "columns": {"fieldValue": "FGW"}}, - "SendingTime": {"type": "row", "columns": {"fieldValue": "2022-06-30T14:48:39.530311"}}, - "TargetCompID": {"type": "row", "columns": {"fieldValue": "ARFQ01FIX08"}}, - "ApplVerID": {"type": "row", "columns": {"fieldValue": "9"}}, - "MsgType": {"type": "row", "columns": {"fieldValue": "8"}}, - "MsgSeqNum": {"type": "row", "columns": {"fieldValue": "589"}}, - "BodyLength": {"type": "row", "columns": {"fieldValue": "432"}}, - }, - }, - "DisplayQty": {"type": "row", "columns": {"fieldValue": "0"}}, - }, - } - ], - } - ] - case3 = [ - { - "attachedEventIds": [], - "direction": "SECOND", - "id": "arfq01fix07:second:1656599837520228626", - "parsedMessages": [ - { - "id": "arfq01fix07:second:1656599837520228626.1", - "match": True, - "message": { - "fields": { - "AccountType": {"simpleValue": "1"}, - "ClOrdID": {"simpleValue": "1830410"}, - "DisplayQty": {"simpleValue": "200"}, - "OrdType": {"simpleValue": "2"}, - "OrderCapacity": {"simpleValue": "A"}, - "OrderQty": {"simpleValue": "200"}, - "Price": {"simpleValue": "55"}, - "SecondaryClOrdID": {"simpleValue": "11111"}, - "SecurityID": {"simpleValue": "5221001"}, - "SecurityIDSource": {"simpleValue": "8"}, - "Side": {"simpleValue": "1"}, - "TradingParty": { - "messageValue": { - "fields": { - "NoPartyIDs": { - "listValue": { - "values": [ - { - "messageValue": { - "fields": { - "PartyID": {"simpleValue": "ARFQ01FIX07"}, - "PartyIDSource": {"simpleValue": "D"}, - "PartyRole": {"simpleValue": "76"}, - } - } - }, - { - "messageValue": { - "fields": { - "PartyID": {"simpleValue": "0"}, - "PartyIDSource": {"simpleValue": "P"}, - "PartyRole": {"simpleValue": "3"}, - } - } - }, - { - "messageValue": { - "fields": { - "PartyID": {"simpleValue": "0"}, - "PartyIDSource": {"simpleValue": "P"}, - "PartyRole": {"simpleValue": "122"}, - } - } - }, - { - "messageValue": { - "fields": { - "PartyID": {"simpleValue": "3"}, - "PartyIDSource": {"simpleValue": "P"}, - "PartyRole": {"simpleValue": "12"}, - } - } - }, - ] - } - } - } - } - }, - "TransactTime": {"simpleValue": "2022-06-30T14:47:59.032276"}, - "header": { - "messageValue": { - "fields": { - "BeginString": {"simpleValue": "FIXT.1.1"}, - "BodyLength": {"simpleValue": "263"}, - "MsgSeqNum": {"simpleValue": "626"}, - "MsgType": {"simpleValue": "D"}, - "SenderCompID": {"simpleValue": "ARFQ01FIX07"}, - "SendingTime": {"simpleValue": "2022-06-30T14:48:24.330"}, - "TargetCompID": {"simpleValue": "FGW"}, - } - } - }, - "trailer": {"messageValue": {"fields": {"CheckSum": {"simpleValue": "152"}}}}, - }, - "metadata": { - "id": { - "connectionId": {"sessionAlias": "arfq01fix07"}, - "direction": "SECOND", - "sequence": "1656599837520228626", - "subsequence": [1], - }, - "messageType": "NewOrderSingle", - "protocol": "FIX", - "timestamp": "2022-06-30T14:48:24.422Z", - }, - "parentEventId": {"id": "a4bee27b-f883-11ec-aeb3-adf8526f5eec"}, - }, - } - ], - "rawMessageBase64": "OD1GSVhULjEuMQE5PTI2MwEzNT1EATM0PTYyNgE0OT1BUkZRMDFGSVgwNwE1Mj0yMDIyMDYzMC0xNDo0ODoyNC4zMzAwMDABNTY9RkdXATExPTE4MzA0MTABMjI9OAEzOD0yMDABNDA9MgE0ND01NQE0OD01MjIxMDAxATU0PTEBNjA9MjAyMjA2MzAtMTQ6NDc6NTkuMDMyMjc2ATUyNj0xMTExMQE1Mjg9QQE1ODE9MQExMTM4PTIwMAE0NTM9NAE0NDg9QVJGUTAxRklYMDcBNDQ3PUQBNDUyPTc2ATQ0OD0wATQ0Nz1QATQ1Mj0zATQ0OD0wATQ0Nz1QATQ1Mj0xMjIBNDQ4PTMBNDQ3PVABNDUyPTEyATEwPTE1MgE=", - "sequence": "1656599837520228626", - "sessionId": "arfq01fix07", - "timestamp": "2022-06-30T14:48:24.422000000Z", - "type": "message", - } - ] - assert list(demo_get_messages_with_one_filter) == case3 - assert list(demo_get_messages_with_filters) == case3 - assert list(demo_get_events_with_one_filter) == case and len(case) is 1 - assert list(demo_get_events_with_filters) == case1 and len(case1) is 1 diff --git a/tests/tests_unit/conftest.py b/tests/tests_unit/conftest.py index 82a8f62a..e3f5a8f2 100644 --- a/tests/tests_unit/conftest.py +++ b/tests/tests_unit/conftest.py @@ -1,11 +1,27 @@ import logging +import os from collections import namedtuple from datetime import datetime -from typing import List, NamedTuple - +from pathlib import Path +from typing import List, NamedTuple, Sequence, Optional import pytest - +from tests.tests_unit.test_event_trees.demo_etc_data import demo_etc_data_big, demo_etc_data_small from tests.tests_unit.utils import LogsChecker +from th2_data_services.data import Data +from th2_data_services.event_tree import ( + EventTree, + EventTreeCollection, + ParentEventTreeCollection, + IETCDriver, +) +from th2_data_services.event_tree.etc_driver import Th2EventType +from th2_data_services.event_tree.exceptions import FieldIsNotExist +from th2_data_services.interfaces import IEventStruct, IEventStub +from dataclasses import dataclass + +EXTERNAL_CACHE_FILE = ( + Path().cwd() / "tests/tests_unit/test_data/test_cache/dir_for_test/external_cache_file" +) @pytest.fixture @@ -15,7 +31,8 @@ def general_data() -> List[dict]: { "batchId": None, "eventId": "84db48fc-d1b4-11eb-b0fb-199708acc7bc", - "eventName": "[TS_1]Aggressive IOC vs two orders: second order's price is " "lower than first", + "eventName": "[TS_1]Aggressive IOC vs two orders: second order's price is " + "lower than first", "eventType": "", "isBatched": False, "parentEventId": None, @@ -23,7 +40,8 @@ def general_data() -> List[dict]: { "batchId": None, "eventId": "88a3ee80-d1b4-11eb-b0fb-199708acc7bc", - "eventName": "Case[TC_1.1]: Trader DEMO-CONN1 vs trader DEMO-CONN2 for " "instrument INSTR1", + "eventName": "Case[TC_1.1]: Trader DEMO-CONN1 vs trader DEMO-CONN2 for " + "instrument INSTR1", "eventType": "", "isBatched": False, "parentEventId": "84db48fc-d1b4-11eb-b0fb-199708acc7bc", @@ -65,7 +83,8 @@ def general_data() -> List[dict]: { "batchId": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4", "eventId": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c1114a6-d1b4-11eb-9278-591e568ad66e", - "eventName": "Checkpoint for session alias 'demo-dc1' direction 'SECOND' " "sequence '1624005475721015014'", + "eventName": "Checkpoint for session alias 'demo-dc1' direction 'SECOND' " + "sequence '1624005475721015014'", "eventType": "Checkpoint for session", "isBatched": True, "parentEventId": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c035903-d1b4-11eb-9278-591e568ad66e", @@ -73,7 +92,8 @@ def general_data() -> List[dict]: { "batchId": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4", "eventId": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c1114a7-d1b4-11eb-9278-591e568ad66e", - "eventName": "Checkpoint for session alias 'demo-dc1' direction 'FIRST' " "sequence '1624005475720919499'", + "eventName": "Checkpoint for session alias 'demo-dc1' direction 'FIRST' " + "sequence '1624005475720919499'", "eventType": "Checkpoint for session", "isBatched": True, "parentEventId": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c035903-d1b4-11eb-9278-591e568ad66e", @@ -99,7 +119,8 @@ def general_data() -> List[dict]: { "batchId": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4", "eventId": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c1114aa-d1b4-11eb-9278-591e568ad66e", - "eventName": "Checkpoint for session alias 'demo-dc2' direction 'SECOND' " "sequence '1624005466840347015'", + "eventName": "Checkpoint for session alias 'demo-dc2' direction 'SECOND' " + "sequence '1624005466840347015'", "eventType": "Checkpoint for session", "isBatched": True, "parentEventId": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c035903-d1b4-11eb-9278-591e568ad66e", @@ -107,7 +128,8 @@ def general_data() -> List[dict]: { "batchId": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4", "eventId": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c1114ab-d1b4-11eb-9278-591e568ad66e", - "eventName": "Checkpoint for session alias 'demo-dc2' direction 'FIRST' " "sequence '1624005466840263372'", + "eventName": "Checkpoint for session alias 'demo-dc2' direction 'FIRST' " + "sequence '1624005466840263372'", "eventType": "Checkpoint for session", "isBatched": True, "parentEventId": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c035903-d1b4-11eb-9278-591e568ad66e", @@ -124,7 +146,8 @@ def general_data() -> List[dict]: { "batchId": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4", "eventId": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c1114ad-d1b4-11eb-9278-591e568ad66e", - "eventName": "Checkpoint for session alias 'demo-log' direction 'FIRST' " "sequence '1624029363623063053'", + "eventName": "Checkpoint for session alias 'demo-log' direction 'FIRST' " + "sequence '1624029363623063053'", "eventType": "Checkpoint for session", "isBatched": True, "parentEventId": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c035903-d1b4-11eb-9278-591e568ad66e", @@ -200,7 +223,8 @@ def detached_data() -> List[dict]: { "batchId": None, "eventId": "84db48fc-d1b4-11eb-b0fb-199708acc7bc", - "eventName": "[TS_1]Aggressive IOC vs two orders: second order's price is " "lower than first", + "eventName": "[TS_1]Aggressive IOC vs two orders: second order's price is " + "lower than first", "eventType": "", "isBatched": False, "parentEventId": None, @@ -208,7 +232,8 @@ def detached_data() -> List[dict]: { "batchId": None, "eventId": "88a3ee80-d1b4-11eb-b0fb-199708acc7bc", - "eventName": "Case[TC_1.1]: Trader DEMO-CONN1 vs trader DEMO-CONN2 for " "instrument INSTR1", + "eventName": "Case[TC_1.1]: Trader DEMO-CONN1 vs trader DEMO-CONN2 for " + "instrument INSTR1", "eventType": "", "isBatched": False, "parentEventId": "84db48fc-d1b4-11eb-b0fb-199708acc7bc", @@ -250,7 +275,8 @@ def detached_data() -> List[dict]: { "batchId": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4", "eventId": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c1114a6-d1b4-11eb-9278-591e568ad66e", - "eventName": "Checkpoint for session alias 'demo-dc1' direction 'SECOND' " "sequence '1624005475721015014'", + "eventName": "Checkpoint for session alias 'demo-dc1' direction 'SECOND' " + "sequence '1624005475721015014'", "eventType": "Checkpoint for session", "isBatched": True, "parentEventId": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c035903-d1b4-11eb-9278-591e568ad66e", @@ -258,7 +284,8 @@ def detached_data() -> List[dict]: { "batchId": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4", "eventId": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c1114a7-d1b4-11eb-9278-591e568ad66e", - "eventName": "Checkpoint for session alias 'demo-dc1' direction 'FIRST' " "sequence '1624005475720919499'", + "eventName": "Checkpoint for session alias 'demo-dc1' direction 'FIRST' " + "sequence '1624005475720919499'", "eventType": "Checkpoint for session", "isBatched": True, "parentEventId": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c035903-d1b4-11eb-9278-591e568ad66e", @@ -284,7 +311,8 @@ def detached_data() -> List[dict]: { "batchId": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4", "eventId": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c1114aa-d1b4-11eb-9278-591e568ad66e", - "eventName": "Checkpoint for session alias 'demo-dc2' direction 'SECOND' " "sequence '1624005466840347015'", + "eventName": "Checkpoint for session alias 'demo-dc2' direction 'SECOND' " + "sequence '1624005466840347015'", "eventType": "Checkpoint for session", "isBatched": True, "parentEventId": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c035903-d1b4-11eb-9278-591e568ad66e", @@ -292,7 +320,8 @@ def detached_data() -> List[dict]: { "batchId": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4", "eventId": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c1114ab-d1b4-11eb-9278-591e568ad66e", - "eventName": "Checkpoint for session alias 'demo-dc2' direction 'FIRST' " "sequence '1624005466840263372'", + "eventName": "Checkpoint for session alias 'demo-dc2' direction 'FIRST' " + "sequence '1624005466840263372'", "eventType": "Checkpoint for session", "isBatched": True, "parentEventId": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c035903-d1b4-11eb-9278-591e568ad66e", @@ -309,7 +338,8 @@ def detached_data() -> List[dict]: { "batchId": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4", "eventId": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c1114ad-d1b4-11eb-9278-591e568ad66e", - "eventName": "Checkpoint for session alias 'demo-log' direction 'FIRST' " "sequence '1624029363623063053'", + "eventName": "Checkpoint for session alias 'demo-log' direction 'FIRST' " + "sequence '1624029363623063053'", "eventType": "Checkpoint for session", "isBatched": True, "parentEventId": None, @@ -1109,7 +1139,9 @@ def messages_before_pipeline_adapter(): ], "body": { "fields": { - "TestMessageHeader": {"messageValue": {"fields": {"Length": {"simpleValue": "4"}}}}, + "TestMessageHeader": { + "messageValue": {"fields": {"Length": {"simpleValue": "4"}}} + }, "PacketHeader": { "messageValue": { "fields": { @@ -1177,8 +1209,12 @@ def messages_before_pipeline_adapter(): } } }, - "TestMessageHeader-2": {"messageValue": {"fields": {"Length": {"simpleValue": "5"}}}}, - "TestMessageHeader-4": {"messageValue": {"fields": {"Length": {"simpleValue": "37"}}}}, + "TestMessageHeader-2": { + "messageValue": {"fields": {"Length": {"simpleValue": "5"}}} + }, + "TestMessageHeader-4": { + "messageValue": {"fields": {"Length": {"simpleValue": "37"}}} + }, "PacketHeader-1": { "messageValue": { "fields": { @@ -1654,8 +1690,12 @@ def message_from_pipeline(): } } }, - "TestMessageHeader-2": {"messageValue": {"fields": {"Length": {"simpleValue": "5"}}}}, - "TestMessageHeader-4": {"messageValue": {"fields": {"Length": {"simpleValue": "37"}}}}, + "TestMessageHeader-2": { + "messageValue": {"fields": {"Length": {"simpleValue": "5"}}} + }, + "TestMessageHeader-4": { + "messageValue": {"fields": {"Length": {"simpleValue": "37"}}} + }, "PacketHeader-1": { "messageValue": { "fields": { @@ -1815,3 +1855,386 @@ def parentless_data() -> List[dict]: {"type": "event", "eventId": "t", "eventName": "t", "parentEventId": "d"}, ] return data + + +@pytest.fixture(params=[True, False]) +def interactive_mod(request): + """INTERACTIVE_MODE or script mod""" + INTERACTIVE_MODE = request.param + return INTERACTIVE_MODE + + +@dataclass +class DataCase: + data: Data + create_type: str + expected_data_values: list + + +# DataCase = namedtuple("DataCase", +# ["data", "create_type", "expected_data_values"]) + +case1_values = ["a", "b", "c", "d", "e", "f", "g"] + + +# TODO - make data_case with the same set of data maybe? +@pytest.fixture( + params=[ + DataCase(Data(case1_values, cache=True), "list", case1_values), + DataCase(Data.from_cache_file(EXTERNAL_CACHE_FILE), "external_cache_file", general_data), + DataCase( + Data([1, 2, 3]) + Data([4, 5, 6, "end", {"a": 123}]), + "join", + [1, 2, 3, 4, 5, 6, "end", {"a": 123}], + ), + ] +) +def data_case(request) -> DataCase: + """ + Possible Data objects + + STR_PRINT_LEN = 5 + + 1. Init with list + 1.1. With <= STR_PRINT_LEN args + 1.2. With > STR_PRINT_LEN args + + 2. Init with joining + 2.1. With <= STR_PRINT_LEN args + 2.2. With > STR_PRINT_LEN args + + 3. Init with external cache file + + + """ + return request.param + + +@pytest.fixture +def tmp_test_folder() -> Path: + """.""" + cwd = Path.cwd().resolve() + new_dir = cwd / "test_dir" + new_dir.mkdir(exist_ok=True) + yield new_dir + os.chdir(cwd) + + +@pytest.fixture +def events_tree_for_test() -> EventTree: + tree = EventTree(event_name="root event", event_id="root_id", data={"data": [1, 2, 3, 4, 5]}) + tree.append_event(event_name="A", event_id="A_id", data=None, parent_id="root_id") + tree.append_event(event_name="B", event_id="B_id", data=None, parent_id="root_id") + tree.append_event(event_name="C", event_id="C_id", data={"data": "test data"}, parent_id="B_id") + tree.append_event(event_name="D", event_id="D_id", data=None, parent_id="B_id") + tree.append_event( + event_name="D1", + event_id="D1_id", + data={"key1": "value1", "key2": "value2"}, + parent_id="D_id", + ) + return tree + + +class DemoEventStruct(IEventStruct): + EVENT_ID = "eventId" + PARENT_EVENT_ID = "parentEventId" + STATUS = "successful" + NAME = "eventName" + BATCH_ID = "batchId" + IS_BATCHED = "isBatched" + EVENT_TYPE = "eventType" + END_TIMESTAMP = "endTimestamp" + START_TIMESTAMP = "startTimestamp" + ATTACHED_MESSAGES_IDS = "attachedMessageIds" + BODY = "body" + + +class DemoEventStubBuilder(IEventStub): + def __init__(self, event_struct): + self.event_fields = event_struct + super().__init__() # Requirement to define fields for the template earlier. + + @property + def template(self) -> dict: + return { + self.event_fields.ATTACHED_MESSAGES_IDS: [], + self.event_fields.BATCH_ID: "Broken_Event", + self.event_fields.END_TIMESTAMP: {"nano": 0, "epochSecond": 0}, + self.event_fields.START_TIMESTAMP: {"nano": 0, "epochSecond": 0}, + self.event_fields.EVENT_ID: self.REQUIRED_FIELD, + self.event_fields.NAME: "Broken_Event", + self.event_fields.EVENT_TYPE: "Broken_Event", + self.event_fields.PARENT_EVENT_ID: "Broken_Event", + self.event_fields.STATUS: None, + self.event_fields.IS_BATCHED: None, + } + + +class DemoDriver(IETCDriver): + def __init__( + self, + data_source=None, + event_struct=DemoEventStruct(), + use_stub: bool = False, + ): + super().__init__(data_source=data_source, event_struct=event_struct, use_stub=use_stub) + self.stub_builder = DemoEventStubBuilder(event_struct) + + def get_event_id(self, event: Th2EventType) -> str: + try: + if event: + return event[self.event_struct.EVENT_ID] + except KeyError: + raise FieldIsNotExist(self.event_struct.EVENT_ID) + + def get_event_name(self, event: Th2EventType) -> str: + try: + if event: + return event[self.event_struct.NAME] + except KeyError: + raise FieldIsNotExist(self.event_struct.NAME) + + def get_parent_event_id(self, event) -> Optional[str]: + return event.get(self.event_struct.PARENT_EVENT_ID) + + def get_events_by_id_from_source(self, ids: Sequence) -> list: + ... + + def build_stub_event(self, id_): + return self.stub_builder.build({self.event_struct.EVENT_ID: id_}) + + def stub_event_name(self): + return self.stub_builder.template[self.event_struct.NAME] + + +@pytest.fixture +def demo_etc_driver(): + return DemoDriver() + + +@pytest.fixture +def demo_etc(demo_etc_driver): + data = Data(demo_etc_data_small) + etc = EventTreeCollection(demo_etc_driver) + etc.build(data) + return etc + + +@pytest.fixture +def demo_etc_with_general_data(demo_etc_driver, general_data): + data = Data(general_data) + etc = EventTreeCollection(demo_etc_driver) + etc.build(data) + return etc + + +@pytest.fixture +def demo_petc(demo_etc_driver): + data = Data(demo_etc_data_small) + etc = ParentEventTreeCollection(demo_etc_driver) + etc.build(data) + return etc + + +@pytest.fixture +def demo_petc_with_general_data(demo_etc_driver, general_data): + data = Data(general_data) + petc = ParentEventTreeCollection(demo_etc_driver) + petc.build(data) + return petc + + +@pytest.fixture +def demo_etc_big(demo_etc_driver) -> EventTreeCollection: + data = Data(demo_etc_data_big) + etc = EventTreeCollection(demo_etc_driver) + etc.build(data) + return etc + + +@pytest.fixture +def frequency_table_data() -> List[dict]: + data = [ + { + "timestamp": "2023-08-14T08:53:05.688049Z", + "MessageType": "OrderCancel", + "Direction": "OUT", + "Stream": "stream2", + }, + { + "timestamp": "2023-08-21T07:51:27.942076Z", + "MessageType": "NewOrder", + "Direction": "IN", + "Stream": "stream4", + }, + { + "timestamp": "2023-08-24T11:51:12.616085Z", + "MessageType": "NewOrder", + "Direction": "IN", + "Stream": "stream1", + }, + { + "timestamp": "2023-08-16T05:41:54.963540Z", + "MessageType": "OrderCancel", + "Direction": "OUT", + "Stream": "stream2", + }, + { + "timestamp": "2023-08-16T15:29:01.422646Z", + "MessageType": "NewOrder", + "Direction": "IN", + "Stream": "stream4", + }, + { + "timestamp": "2023-08-19T02:49:16.551326Z", + "MessageType": "NewOrder", + "Direction": "OUT", + "Stream": "stream1", + }, + { + "timestamp": "2023-08-22T23:06:20.612952Z", + "MessageType": "ExecutionReport", + "Direction": "OUT", + "Stream": "stream3", + }, + { + "timestamp": "2023-08-23T20:12:40.152099Z", + "MessageType": "NewOrder", + "Direction": "OUT", + "Stream": "stream1", + }, + { + "timestamp": "2023-08-16T02:15:49.844689Z", + "MessageType": "OrderCancel", + "Direction": "OUT", + "Stream": "stream2", + }, + { + "timestamp": "2023-08-23T11:16:11.021005Z", + "MessageType": "NewOrder", + "Direction": "OUT", + "Stream": "stream1", + }, + { + "timestamp": "2023-08-21T09:15:39.315806Z", + "MessageType": "ExecutionReport", + "Direction": "OUT", + "Stream": "stream3", + }, + { + "timestamp": "2023-08-21T23:27:37.341876Z", + "MessageType": "NewOrder", + "Direction": "OUT", + "Stream": "stream1", + }, + { + "timestamp": "2023-08-14T13:49:10.534961Z", + "MessageType": "OrderCancel", + "Direction": "IN", + "Stream": "stream2", + }, + { + "timestamp": "2023-08-16T23:07:22.431359Z", + "MessageType": "OrderCancel", + "Direction": "IN", + "Stream": "stream3", + }, + { + "timestamp": "2023-08-24T04:35:55.852704Z", + "MessageType": "NewOrder", + "Direction": "OUT", + "Stream": "stream4", + }, + { + "timestamp": "2023-08-20T10:31:42.493202Z", + "MessageType": "OrderCancel", + "Direction": "OUT", + "Stream": "stream2", + }, + { + "timestamp": "2023-08-13T18:45:42.299591Z", + "MessageType": "OrderCancel", + "Direction": "OUT", + "Stream": "stream2", + }, + { + "timestamp": "2023-08-20T07:51:16.455842Z", + "MessageType": "OrderCancel", + "Direction": "OUT", + "Stream": "stream4", + }, + { + "timestamp": "2023-08-14T22:23:47.334876Z", + "MessageType": "NewOrder", + "Direction": "IN", + "Stream": "stream4", + }, + { + "timestamp": "2023-08-23T11:13:21.811535Z", + "MessageType": "NewOrder", + "Direction": "IN", + "Stream": "stream2", + }, + { + "timestamp": "2023-08-13T21:34:04.089095Z", + "MessageType": "NewOrder", + "Direction": "OUT", + "Stream": "stream4", + }, + { + "timestamp": "2023-08-14T19:53:49.159667Z", + "MessageType": "ExecutionReport", + "Direction": "IN", + "Stream": "stream1", + }, + { + "timestamp": "2023-08-13T17:23:15.927140Z", + "MessageType": "ExecutionReport", + "Direction": "OUT", + "Stream": "stream1", + }, + { + "timestamp": "2023-08-19T21:06:32.548659Z", + "MessageType": "ExecutionReport", + "Direction": "IN", + "Stream": "stream3", + }, + { + "timestamp": "2023-08-16T06:26:01.182164Z", + "MessageType": "NewOrder", + "Direction": "OUT", + "Stream": "stream2", + }, + { + "timestamp": "2023-08-21T23:19:27.914964Z", + "MessageType": "NewOrder", + "Direction": "IN", + "Stream": "stream3", + }, + { + "timestamp": "2023-08-17T12:13:45.597220Z", + "MessageType": "ExecutionReport", + "Direction": "OUT", + "Stream": "stream2", + }, + { + "timestamp": "2023-08-24T04:10:05.793870Z", + "MessageType": "OrderCancel", + "Direction": "IN", + "Stream": "stream1", + }, + { + "timestamp": "2023-08-17T10:25:05.916986Z", + "MessageType": "OrderCancel", + "Direction": "IN", + "Stream": "stream2", + }, + { + "timestamp": "2023-08-13T19:38:00.721701Z", + "MessageType": "OrderCancel", + "Direction": "IN", + "Stream": "stream3", + }, + ] + return data diff --git a/tests/tests_unit/test_data.py b/tests/tests_unit/test_data.py deleted file mode 100644 index bdc60706..00000000 --- a/tests/tests_unit/test_data.py +++ /dev/null @@ -1,762 +0,0 @@ -import os -from typing import List - -from tests.tests_unit.utils import ( - is_cache_file_exists, - iterate_data_and_do_checks, - iterate_data, - is_pending_cache_file_exists, -) -from th2_data_services.th2_gui_report import Th2GUIReport -from th2_data_services.data import Data -import pytest - - -def test_iter_data(general_data: List[dict]): - data = Data(general_data) - - output = [record for record in data] - assert len(output) == 21 - - -def test_filter_data(general_data: List[dict]): - data = Data(general_data).filter(lambda record: record.get("batchId") is None) - - assert len(list(data)) == 9 - - -def test_map_data_transform(general_data: List[dict]): - data = Data(general_data).map(lambda record: record.get("eventType")) - event_types = set([record for record in data]) - - assert event_types == { - "", - "placeOrderFIX", - "Send message", - "Checkpoint", - "Checkpoint for session", - "message", - "Outgoing message", - } - - -def test_map_data_increase(general_data: List[dict]): - data = ( - Data(general_data) - .filter(lambda record: record.get("batchId") is None) - .map(lambda record: (record.get("eventType"), record.get("eventType"))) - ) - - assert len(list(data)) == 18 - - -def test_map_for_list_record(general_data: List[dict]): - data = Data(general_data).map(lambda record: [record, record]).map(lambda record: record.get("eventType")) - - event_types = [ - "", - "", - "", - "", - "placeOrderFIX", - "placeOrderFIX", - "Checkpoint", - "Checkpoint", - "Checkpoint for session", - "Checkpoint for session", - "Checkpoint for session", - "Checkpoint for session", - "Checkpoint for session", - "Checkpoint for session", - "Checkpoint for session", - "Checkpoint for session", - "Checkpoint for session", - "Checkpoint for session", - "Checkpoint for session", - "Checkpoint for session", - "Checkpoint for session", - "Checkpoint for session", - "Checkpoint for session", - "Checkpoint for session", - "Checkpoint for session", - "Checkpoint for session", - "Checkpoint for session", - "Checkpoint for session", - "Outgoing message", - "Outgoing message", - "Outgoing message", - "Outgoing message", - "", - "", - "Send message", - "Send message", - "Send message", - "Send message", - "message", - "message", - "Checkpoint for session", - "Checkpoint for session", - ] - assert event_types == list(data) - - -def test_filter_for_list_record(general_data: List[dict]): - data = ( - Data(general_data) - .map(lambda record: [record, record]) - .map(lambda record: record.get("eventType")) - .filter(lambda record: record in ["placeOrderFIX", "Checkpoint"]) - ) - - event_types = [ - "placeOrderFIX", - "placeOrderFIX", - "Checkpoint", - "Checkpoint", - ] - - assert event_types == list(data) - - -def test_increase_records_after_similar_map(cache): - source = [1, 2, 3] - data = Data(source, cache=cache).map(lambda record: [record, record]).map(lambda record: [record, record, record]) - - assert list(data) == [ - 1, - 1, - 1, - 1, - 1, - 1, - 2, - 2, - 2, - 2, - 2, - 2, - 3, - 3, - 3, - 3, - 3, - 3, - ] - - -def test_shuffle_data(general_data: List[dict]): - data = ( - Data(general_data) - .filter(lambda record: record.get("batchId") is not None) - .map(lambda record: record.get("eventId")) - .filter(lambda record: "b" in record) - ) - - assert len(list(data)) == 12 - - -def test_limit(general_data: List[dict], cache): - data = Data(general_data, cache=cache) - data10 = data.limit(10) - data5 = data10.limit(5) - - assert list(data10) == general_data[:10] - if cache: - assert not is_cache_file_exists(data), "data shouldn't have cache because was iterated via child data object." - assert not is_pending_cache_file_exists( - data - ), "data shouldn't have cache because was iterated via child data object." - assert list(data5) == general_data[:5] - assert data.len == len(general_data) - assert data10.len == 10 - assert data5.len == 5 - - -def test_limit_for_list_record(cache): - data_stream = [1, 2, 3, 4, 5] - data = Data(data_stream, cache=cache).map(lambda record: [record, record]) - - data10 = data.limit(10) - data5 = data10.limit(5) - - assert list(data10) == [1, 1, 2, 2, 3, 3, 4, 4, 5, 5] - if cache: - assert not is_cache_file_exists(data), "data shouldn't have cache because was iterated via child data object." - assert not is_pending_cache_file_exists( - data - ), "data shouldn't have cache because was iterated via child data object." - assert list(data5) == [1, 1, 2, 2, 3] - - -def test_limit_in_loops(cache): - data_stream = [1, 2, 3, 4, 5] - data = Data(data_stream, cache=cache) - res5 = [0 for _ in range(4)] - for _ in data.limit(4): - res5[0] += 1 - for __ in data.limit(3): - res5[1] += 1 - for ___ in data.limit(2): - res5[2] += 1 - for ____ in data.limit(1): - res5[3] += 1 - - assert res5 == [4, 4 * 3, 4 * 3 * 2, 4 * 3 * 2 * 1] - assert not is_cache_file_exists(data) - assert not is_pending_cache_file_exists(data) - assert data.len == len(data_stream) # It'll create cache. - - -def test_limit_before_loops(cache): - data_stream = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] - data = Data(data_stream, cache) - limit = 5 - data5 = data.limit(limit) - - res5 = [0 for _ in range(4)] - - for _ in data5: - res5[0] += 1 - for __ in data5: - res5[1] += 1 - for ___ in data5: - res5[2] += 1 - for ____ in data5: - res5[3] += 1 - - assert res5 == [limit, limit ** 2, limit ** 3, limit ** 4] - assert not is_cache_file_exists(data) - assert not is_pending_cache_file_exists(data) - assert data.len == len(data_stream) # It'll creates cache. - - -def test_new_limit_is_less(general_data: List[dict], cache): - data5 = Data(general_data, cache).limit(5) - data3 = data5.limit(3) - res = [0 for _ in range(4)] - - for _ in data3: - res[0] += 1 - for __ in data3: - res[1] += 1 - for ___ in data3: - res[2] += 1 - for ____ in data3: - res[3] += 1 - - assert res == [3, 9, 27, 81] - assert data5.len == 5 - assert not is_cache_file_exists(data5) - assert not is_pending_cache_file_exists(data5) - - -def test_new_limit_is_bigger(general_data: List[dict], cache): - data5 = Data(general_data, cache=cache).limit(3).limit(5) - res = [0 for _ in range(4)] - - for _ in data5: - res[0] += 1 - for __ in data5: - res[1] += 1 - for ___ in data5: - res[2] += 1 - for ____ in data5: - res[3] += 1 - - assert res == [3, 9, 27, 81] - assert data5.len == 3 - - -def test_limit_for_limit_in_iterations(general_data: List[dict], cache): - data = Data(general_data, cache=cache) - data5 = data.limit(5) - - res5 = [0 for _ in range(4)] - for _ in data5.limit(4): - res5[0] += 1 - for __ in data5.limit(3): - res5[1] += 1 - for ___ in data5.limit(7): - res5[2] += 1 - for ____ in data5.limit(2): - res5[3] += 1 - - assert res5 == [4, 3 * 4, 3 * 4 * 5, 3 * 4 * 5 * 2] - - -def test_sift_limit_data(general_data: List[dict]): - data = Data(general_data) - output = [record for record in data.sift(limit=2)] - - assert len(output) == 2 - - -def test_sift_skip_data(general_data: List[dict]): - data = Data(general_data) - output1 = data.sift(limit=2) - output2 = [record for record in data.sift(limit=2, skip=2)] - - assert len(list(output1)) == 2 - assert output1 != output2 - - -def map_read_failure(e): - if e != 1: - return e["a"] - - -def map_keyboard_interrupt(e): - if e != 1: - raise KeyboardInterrupt - - -@pytest.fixture(params=[True, False]) -def interactive_mod(request): - """INTERACTIVE_MODE or script mod""" - INTERACTIVE_MODE = request.param - return INTERACTIVE_MODE - - -def new_data_with_limit2(data: Data) -> Data: - return data.limit(2) - - -def new_data_with_map_keyboard_interrupt(data: Data) -> Data: - return data.map(map_keyboard_interrupt) - - -class TestDataCache: - def test_data_iterates_own_cache_file(self, log_checker, general_data: List[dict]): - data = Data(general_data, cache=True) - output1 = iterate_data_and_do_checks(data, log_checker) # It'll create a cache file. - - # Deactivate cache and set empty data source. - data.use_cache(False) - data._data_stream = [] - output2 = list(data) - assert output2 == [] - - # Activate cache to check that data iterate cache file. - data.use_cache(True) - output3 = list(data) - assert output1 == output3 - log_checker.used_own_cache_file(data) - - @pytest.mark.parametrize("magic_func", [bool, str]) - def test_cache_file_isnt_created_after_using_magic_function(self, general_data: List[dict], magic_func): - """Checks that Data object successfully iterates after using of magic functions. - - Data object shouldn't create cache file after using these functions. - Otherwise it will consume data from incomplete cache. - """ - data = Data(general_data, cache=True) - magic_func(data) # It shouldn't create cache file. - output = list(data) - assert output == general_data - - def test_data_doesnt_left_their_cache_file_if_you_change_dir(self, log_checker): - """Issue related test: https://exactpro.atlassian.net/browse/TH2-3545""" - data = Data([1, 2, 3], cache=True) - dl = iterate_data_and_do_checks(data, log_checker) - - cwd = os.getcwd() - os.chdir("/") - data._data_stream = [] - assert list(data) == dl - log_checker.used_own_cache_file(data) - os.chdir(cwd) - - @pytest.mark.parametrize( - ["expected_exception", "map_func"], - [ - (TypeError, map_read_failure), - (KeyboardInterrupt, map_keyboard_interrupt), - ], - ) - def test_cache_file_will_be_removed_only_if_data_write_it(self, interactive_mod, expected_exception, map_func): - """Issue related test: https://exactpro.atlassian.net/browse/TH2-3546""" - import th2_data_services - - th2_data_services.INTERACTIVE_MODE = interactive_mod - - # Write test - data = Data([1, 2, 3, 4, 5], cache=True).map(map_func) - with pytest.raises(expected_exception): - list(data) - assert not is_cache_file_exists(data), "Cache file exists despite data object wrote it." - assert not is_pending_cache_file_exists(data), "Cache file exists despite data object wrote it." - - # Read test - data = Data([1, 2, 3, 4, 5], cache=True) - list(data) # It'll create a cache file. - with pytest.raises(expected_exception): - list(data.map(map_func)) - if expected_exception is TypeError: - if interactive_mod: - assert is_cache_file_exists( - data - ), "Cache file should be exist if Data object just read it in interactive_mod." - # else: - # It's expected that cache should be deleted if it's SCRIPT MODE but `del data` doesn't work for testing - # cache_filepath = data.get_cache_filepath() - # del data - # time.sleep(2) - # assert not cache_filepath.is_file() - elif expected_exception is KeyboardInterrupt: - if interactive_mod: - assert is_cache_file_exists( - data - ), "Cache file should be exist if Data object just read it in interactive_mod." - # else: - # It's expected that cache should be deleted if it's SCRIPT MODE but `del data` doesn't work for testing - # cache_filepath = data.get_cache_filepath() - # del data - # assert not cache_filepath.is_file() - - @pytest.mark.parametrize( - ["change_type"], - [ - (new_data_with_limit2,), - ], - ) - def test_tmp_cache_will_be_deleted_if_not_fully_recorded(self, change_type): - # Cache has parent - data = Data([1, 2, 3], cache=True) - data2 = change_type(data) - iterate_data(data2, to_return=False) - assert not is_pending_cache_file_exists(data) - - # Cache has data itself - data = Data([1, 2, 3]) - data2 = change_type(data).use_cache() - iterate_data(data2, to_return=False) - assert not is_pending_cache_file_exists(data2) - - class TestCacheInheritance: - def test_parent_cache_was_created(self, log_checker, general_data: List[dict]): - """ - Issue related test: https://exactpro.atlassian.net/browse/TH2-3557 - - Cases: - [1] D(cache) -> D1(filter) -> D2(map) - creates D cache when you iterate D2. - [2] D(cache) -> D1(filter) -> D2(map + cache) - creates D and D2 cache files - """ - # [1] - data = Data(general_data, cache=True) - data1 = data.filter(lambda record: record.get("isBatched")) - data2 = data1.map(lambda record: {**record, "batch_status": record.get("isBatched")}) - list(data2) # Just to iterate and create D cache file. - assert is_cache_file_exists(data) - log_checker.cache_file_created(data) - - # [2] - data = Data(general_data, cache=True) - data1 = data.filter(lambda record: record.get("isBatched")) - data2 = data1.map(lambda record: {**record, "batch_status": record.get("isBatched")}) - data2.use_cache(True) - list(data2) # Just to iterate and create cache files. - assert is_cache_file_exists(data) - assert is_cache_file_exists(data2) - log_checker.cache_file_created(data) - log_checker.cache_file_created(data2) - - def test_data_iterates_parent_cache_file(self, log_checker, general_data: List[dict]): - """D(cache) -> D1(filter) -> D2(map + cache) -> D3(filter) -> D4(map) - creates D and D2 cache files. - There are 2 cache files, it should iterate D2 cache file. - """ - data = Data(general_data, cache=True) - data1 = data.filter(lambda record: record.get("isBatched")) - data2 = data1.map(lambda record: {**record, "batch_status": record.get("isBatched")}) - data2.use_cache(True) - iterate_data_and_do_checks(data2, log_checker) # Just to iterate and create cache files. - log_checker.cache_file_created(data) - - data3 = data2.filter(lambda record: record.get("eventType")) - data4 = data3.map(lambda record: (record, record)) - - # Change D and D2 sources to [] to be aware data iterates cache file. - data._data_stream = ["D"] - data2._data_stream = ["D2"] - assert len(list(data4)) == len(list(data3)) * 2 - log_checker.used_own_cache_file(data2) - - def test_cache_linear_inheritance(self, general_data: List[dict]): - """Cache file should be created for the first data object. - - Issue related test: https://exactpro.atlassian.net/browse/TH2-3487 - """ - data = ( - Data(general_data, cache=True) - .filter(lambda record: record.get("isBatched")) - .map(lambda record: {**record, "batch_status": record.get("isBatched")}) - ) - list(data) # Just to iterate and create cache files. - assert is_cache_file_exists(data._data_stream._data_stream) - - -def test_big_modification_chain(log_checker): - d1 = Data([1, 2, 3, 4, 5]).use_cache(True) - d2 = d1.filter(lambda x: x == 1 or x == 2) - d3 = d2.map(lambda x: [x, x]).use_cache(True) - d4 = d3.limit(3) - d5 = d4.map(lambda x: [x, x]) - - # It should have all "Data[d3] Iterating working data" log records (for each data object) - assert list(d5) == [1, 1, 1, 1, 2, 2] - # Cache files should not be written because they not iterated to the end. - assert not is_cache_file_exists(d3) - assert not is_cache_file_exists(d1) - assert not is_pending_cache_file_exists(d3) - assert not is_pending_cache_file_exists(d1) - - assert list(d4) == [1, 1, 2] - assert list(d3) == [1, 1, 2, 2] # It also should iterate cache file. - - -def test_write_to_file(general_data): - events = Data(general_data) - file_to_test = "demo_file.txt" - expected = """{'batchId': None, - 'eventId': '84db48fc-d1b4-11eb-b0fb-199708acc7bc', - 'eventName': "[TS_1]Aggressive IOC vs two orders: second order's price is " - 'lower than first', - 'eventType': '', - 'isBatched': False, - 'parentEventId': None} --------------------------------------------------- -""" - events.limit(1).write_to_file(file_to_test) - with open(file_to_test) as f: - assert f.read() == expected - - os.remove(file_to_test) - - -################### -# TEST LEN -################### - - -def test_len_with_stream_cache(general_data: List[dict], cache): - # From empty list - data = Data(general_data, cache=cache) - elements_num = len(list(data)) - assert data.len == elements_num - assert data.limit(10).len == 10 - - # After print - data = Data(general_data, cache=cache) - str(data) # The same as print. - assert data.len == elements_num, f"After print, cache: {cache}" - - # After is_empty - data = Data(general_data, cache=cache) - r = data.is_empty - assert data.len == elements_num, f"After is_empty, cache: {cache}" - - # After sift - data = Data(general_data, cache=cache) - r = list(data.sift(limit=5)) - assert data.len == elements_num, f"After sift, cache: {cache}" - - # The cache was dumped after using len - data = Data(general_data, cache=cache) - r = data.len - if cache: - assert is_cache_file_exists(data), f"The cache was dumped after using len: {cache}" - else: - assert not is_cache_file_exists(data), f"The cache was dumped after using len: {cache}" - assert not is_pending_cache_file_exists(data), f"The cache was dumped after using len: {cache}" - - # Check that we do not calc len, after already calculated len or after iter - # TODO - append when we add logging - - -def test_len_has_correct_value_after_multiple_loop_iteration(cache): - stream = [1, 2, 3] - data = Data(stream, cache=cache) - - for a in data: - for b in data: - for c in data: - pass - - assert data.len == len(stream) - - -@pytest.mark.parametrize( - ["limit2", "limit3", "exp_data2", "exp_data3", "exp_data"], - # Data.limit(A).limit(B) - [ - # A == B - pytest.param(1, 1, 1, 1, None, marks=pytest.mark.xfail(reason="Low priority issue")), - (1, 1, None, 1, None), # Issue, but it checks that data3 has correct value - (2, 2, None, 2, None), # Issue - pytest.param(5, 5, 5, 5, 5, marks=pytest.mark.xfail(reason="Low priority issue")), - (5, 5, None, 5, None), # Issue, but it checks that data3 has correct value - (10, 8, 5, 5, 5), # Higher than data_stream len == 5 - # A > B - (3, 2, None, 2, None), # data2 should be None because it's not fully iterated. - (5, 2, None, 2, None), - (10, 2, None, 2, None), - (10, 6, 5, 5, 5), # data3 == 5 because data_stream len == 5 - # A < B - (1, 2, 1, 1, None), - (1, 10, 1, 1, None), - ], -) -def test_len_will_be_saved_if_limit_used(cache, limit2, limit3, exp_data3, exp_data2, exp_data): - data_stream = [1, 2, 3, 4, 5] - data = Data(data_stream, cache) - data2 = data.limit(limit2) - data3 = data2.limit(limit3) - list(data3) # Just to iterate. - assert data3._len == exp_data3 - assert data2._len == exp_data2 - assert data._len == exp_data - - -def test_is_empty(general_data: List[dict]): - empty_data = Data([]) - data = Data(general_data) - - assert empty_data.is_empty is True - assert data.is_empty is False - - -def test_inner_cycle_with_cache(general_data: List[dict]): - data = Data(general_data).use_cache(True) # 21 objects - external_counter = 0 - internal_counter = 0 - - for _ in data: - external_counter += 1 - for _ in data: - internal_counter += 1 - - assert external_counter == 21 and internal_counter == 441 - - -def test_inner_cycle_with_cache_and_workflow(general_data: List[dict]): - data = Data(general_data).use_cache(True) # 21 objects - data_filter = data.filter(lambda record: "Checkpoint" in record.get("eventType")) # 12 objects - external_counter = 0 - internal_counter = 0 - - for _ in data: - external_counter += 1 - for _ in data_filter: - internal_counter += 1 - - assert external_counter == len(general_data) and internal_counter == len(general_data) * data_filter.len - - -def test_break_cycle(general_data: List[dict]): - data = Data(general_data).use_cache(True) # 21 objects - first_cycle = 0 - second_cycle = 0 - - for _ in data: - first_cycle += 1 - if first_cycle == 10: - break - for _ in data: - second_cycle += 1 - - assert second_cycle == 21 - - -def test_link_provider(): - link_gui1 = Th2GUIReport("host:port/th2-common/") - link_gui2 = Th2GUIReport("host:port/th2-common") - link_gui3 = Th2GUIReport("http://host:port/th2-common/") - link_gui4 = Th2GUIReport("http://host:port/th2-common") - link_gui5 = Th2GUIReport("host:port/th2-commonhttp") - - result = "http://host:port/th2-common/" - - assert ( - link_gui1._provider_link == result - and link_gui2._provider_link == result - and link_gui3._provider_link == result - and link_gui4._provider_link == result - and link_gui5._provider_link == "http://host:port/th2-commonhttp/" - ) - - -def test_link_gui_with_event_id(): - gui = Th2GUIReport("host:port/th2-common/") - link_event_id1 = gui.get_event_link("fcace9a4-8fd8-11ec-98fc-038f439375a0") - - result = "http://host:port/th2-common/?eventId=fcace9a4-8fd8-11ec-98fc-038f439375a0" - - assert link_event_id1 == result - - -def test_link_gui_with_message_id(): - gui = Th2GUIReport("host:port/th2-common/") - link_message_id1 = gui.get_message_link("fix01:first:1600854429908302153") - - result = "http://host:port/th2-common/?messageId=fix01:first:1600854429908302153" - - assert link_message_id1 == result - - -def test_cache_filename(): - data = Data([1, 2, 3, 4, 5], cache=True) - for d in data: - d - assert data._cache_filename.find(":") == -1 - - -class TestDataObjectJoining: - @classmethod - def setup_class(cls): - cls.d1 = Data([1, 2, 3]) - cls.d2 = Data(["a", {"id": 123}, "c"]) - cls.d3 = Data([7, 8, 9]) - cls.data_via_init = Data([cls.d1, cls.d2, cls.d3]) - cls.data_via_add = cls.d1 + cls.d2 + cls.d3 - cls.data_with_non_data_obj_via_init = Data([cls.d1, ["a", {"id": 123}, "c"], cls.d3]) - cls.data_with_non_data_obj_via_add = cls.d1 + ["a", {"id": 123}, "c"] + cls.d3 - cls.expected_dx_lst = [1, 2, 3, "a", {"id": 123}, "c", 7, 8, 9] - - # It contains Data objects with exactly the same values inside == cls.expected_dx_lst. - cls.complex_datas_lst = [ - cls.data_via_init, - cls.data_via_add, - cls.data_with_non_data_obj_via_init, - cls.data_with_non_data_obj_via_add, - ] - - def test_iters_all_data_objects_inside(self): - """Checks data consistency.""" - for dx in self.complex_datas_lst: - assert list(dx) == self.expected_dx_lst - - def test_iterates_many_times(self): - """Iterates the same data object 3 times.""" - for dx in self.complex_datas_lst: - l1 = list(dx) - l2 = list(dx) - l3 = list(dx) - assert l1 == l2 == l3 - - def test_len_joined_data(self): - for dx in self.complex_datas_lst: - assert dx.len == len(self.expected_dx_lst) - - def test_cache(self): - """ - dx = d1 + d2(with_cache) + d3 <- d2 cache should work - dx.use_cache(True) <- dx will get own cache - """ - # dx = self.d1 + Data(['a', {'id': 123}, 'c'], cache=True) + self.d3 - d2 = Data(["a", {"id": 123}, "c"], cache=True) - dx = self.d1 + d2 + self.d3 - iterate_data(dx, to_return=False) # It should create d2 cache file. - assert is_cache_file_exists(d2), f"The cache was not dumped after using len" - - dx.use_cache(True) - iterate_data(dx, to_return=False) # It should create dx cache file. - assert is_cache_file_exists(dx), f"The cache was not dumped after using len" diff --git a/tests/tests_integration/__init__.py b/tests/tests_unit/test_data/__init__.py similarity index 100% rename from tests/tests_integration/__init__.py rename to tests/tests_unit/test_data/__init__.py diff --git a/tests/tests_integration/tests_diff_version/tests_common/__init__.py b/tests/tests_unit/test_data/test_cache/__init__.py similarity index 100% rename from tests/tests_integration/tests_diff_version/tests_common/__init__.py rename to tests/tests_unit/test_data/test_cache/__init__.py diff --git a/tests/tests_integration/tests_diff_version/tests_common/tests_adapters/__init__.py b/tests/tests_unit/test_data/test_cache/dir_for_test/__init__.py similarity index 100% rename from tests/tests_integration/tests_diff_version/tests_common/tests_adapters/__init__.py rename to tests/tests_unit/test_data/test_cache/dir_for_test/__init__.py diff --git a/tests/tests_unit/test_data/test_cache/dir_for_test/external_cache_file b/tests/tests_unit/test_data/test_cache/dir_for_test/external_cache_file new file mode 100644 index 00000000..12328937 Binary files /dev/null and b/tests/tests_unit/test_data/test_cache/dir_for_test/external_cache_file differ diff --git a/tests/tests_unit/test_data/test_cache/dir_for_test/external_non_pickle_file b/tests/tests_unit/test_data/test_cache/dir_for_test/external_non_pickle_file new file mode 100644 index 00000000..6841d18b --- /dev/null +++ b/tests/tests_unit/test_data/test_cache/dir_for_test/external_non_pickle_file @@ -0,0 +1,2 @@ +123 +321 diff --git a/tests/tests_unit/test_data/test_cache/external_cache_file b/tests/tests_unit/test_data/test_cache/external_cache_file new file mode 100644 index 00000000..12328937 Binary files /dev/null and b/tests/tests_unit/test_data/test_cache/external_cache_file differ diff --git a/tests/tests_unit/test_data/test_cache/test_build_cache.py b/tests/tests_unit/test_data/test_cache/test_build_cache.py new file mode 100644 index 00000000..d881f07c --- /dev/null +++ b/tests/tests_unit/test_data/test_cache/test_build_cache.py @@ -0,0 +1,28 @@ +from pathlib import Path +from typing import List +from th2_data_services.data import Data +import pytest + + +@pytest.mark.parametrize( + ["cache_file"], + [ + ("my_cache_file",), + (Path().cwd() / "tests/tests_unit/test_data/test_cache/dir_for_test/file_path",), + ], +) +def test_build_cache_file_created(general_data: List[dict], cache_file): + """Check that file have been created. + + Check for + - filename + - filepath + """ + data = Data(general_data, cache=True) + + path_obj_filename = Path(cache_file).resolve() + data.build_cache(cache_file) + + # Requested cache file have been created. + assert path_obj_filename.is_file(), "Cache file haven't been created" + path_obj_filename.unlink() diff --git a/tests/tests_unit/test_data/test_cache/test_clear_cache.py b/tests/tests_unit/test_data/test_cache/test_clear_cache.py new file mode 100644 index 00000000..5d4841cd --- /dev/null +++ b/tests/tests_unit/test_data/test_cache/test_clear_cache.py @@ -0,0 +1,33 @@ +from typing import List + +from tests.tests_unit.utils import ( + iterate_data_and_do_cache_checks, + is_cache_file_exists, + iterate_data, +) +from th2_data_services.data import Data + + +def test_cache_file_removed(general_data: List[dict]): + """ + Check that Tmp cache file is removed. + """ + data = Data(general_data, cache=True) + iterate_data_and_do_cache_checks(data) + data.clear_cache() + + assert not is_cache_file_exists(data) + + +def test_cache_file_removed_but_data_object_iterates(general_data: List[dict]): + """ + Check that second iteration the same data object works after cache clearing. + """ + data = Data(general_data, cache=True) + r = iterate_data(data) + data.clear_cache() + data += Data([1, 2, 3]) + res = r + [1, 2, 3] + + assert list(data) == res + assert is_cache_file_exists(data) diff --git a/tests/tests_unit/test_data/test_cache/test_common.py b/tests/tests_unit/test_data/test_cache/test_common.py new file mode 100644 index 00000000..ee784e16 --- /dev/null +++ b/tests/tests_unit/test_data/test_cache/test_common.py @@ -0,0 +1,229 @@ +import os +from pathlib import Path +from typing import List + +from tests.tests_unit.conftest import EXTERNAL_CACHE_FILE, DataCase +from tests.tests_unit.utils import ( + is_cache_file_exists, + iterate_data_and_do_cache_checks, + iterate_data, + is_pending_cache_file_exists, +) + +from th2_data_services.data import Data +import pytest + + +def map_read_failure(e): + if e != 1: + return e["a"] + + +def map_keyboard_interrupt(e): + if e != 1: + raise KeyboardInterrupt + + +def new_data_with_limit2(data: Data) -> Data: + return data.limit(2) + + +def new_data_with_map_keyboard_interrupt(data: Data) -> Data: + return data.map(map_keyboard_interrupt) + + +########## +# TESTS +########## + + +# Expected that you run pytest from the lib root. + + +def test_data_iterates_own_cache_file(log_checker, general_data: List[dict]): + data = Data(general_data, cache=True) + output1: List = iterate_data_and_do_cache_checks( + data, log_checker + ) # It'll create a cache file. + + # Deactivate cache and set empty data source. + data.use_cache(False) + data._data_source = [] + output2 = list(data) + assert output2 == [] + + # Activate cache to check that data iterate cache file. + data.use_cache(True) + output3 = list(data) + assert output1 == output3 + # log_checker.used_own_cache_file(data) + + +def test_data_iterates_own_external_cache_file(log_checker, general_data: List[dict]): + data = Data.from_cache_file(EXTERNAL_CACHE_FILE) + output1: List = list(data) + + # Activate cache to check that data iterate cache file. + data.use_cache(True) + output3 = list(data) + assert output1 == output3 + # log_checker.used_own_cache_file(data) + + +@pytest.mark.parametrize("magic_func", [bool, str]) +def test_cache_file_isnt_created_after_using_magic_function(general_data: List[dict], magic_func): + """Checks that Data object successfully iterates after using of magic functions. + + Data object shouldn't create cache file after using these functions. + Otherwise, it will consume data from incomplete cache. + """ + data = Data(general_data, cache=True) + magic_func(data) # It shouldn't create cache file. + assert not is_pending_cache_file_exists(data) + assert not is_cache_file_exists(data) + + # It should create cache file after full iteration + output = list(data) + assert output == general_data + + +def test_data_doesnt_left_their_cache_file_if_you_change_dir( + log_checker, data_case: DataCase, tmp_test_folder: Path +): + """Issue related test: https://exactpro.atlassian.net/browse/TH2-3545""" + data = data_case.data + create_type = data_case.create_type + if create_type in ["list", "join"]: + if create_type == "join": + data.use_cache() + dl = iterate_data_and_do_cache_checks(data, log_checker) + elif create_type == "external_cache_file": + dl = iterate_data(data, to_return=True) # Just to iterate and create cache files. + # assert is_cache_file_exists(data) + + old_cwd = Path.cwd() + os.chdir(tmp_test_folder) + # data._data_stream = ["You lost your cache file it's a bug"] + assert list(data) == dl, ( + f"old dir: {old_cwd}, " + f"new dir: {tmp_test_folder}, " + f"cache file: {data.get_cache_filepath()}" + ) # Data obj should read from cache + # log_checker.used_own_cache_file(data) + + +def test_data_doesnt_left_their_cache_file_if_you_change_dir_external_cache( + log_checker, tmp_test_folder: Path +): + """Issue related test: https://exactpro.atlassian.net/browse/TH2-3545""" + data = Data.from_cache_file(EXTERNAL_CACHE_FILE) + dl: List = list(data) + + cwd = Path.cwd() + os.chdir(tmp_test_folder) + # data._data_stream = [] + assert list(data) == dl + # log_checker.used_own_cache_file(data) + + +@pytest.mark.parametrize( + ["expected_exception", "map_func"], + [ + (TypeError, map_read_failure), + (KeyboardInterrupt, map_keyboard_interrupt), + ], +) +def test_cache_file_will_be_removed_only_if_data_write_it( + interactive_mod, expected_exception, map_func +): + """If Data obj reads the cache file and something went wrong + 1. We have to delete it in the script mode + 2. We DO NOT have to delete it in the interactive mode + 3. We DO NOT have to delete file if we read the file using special method. + + Issue related test: https://exactpro.atlassian.net/browse/TH2-3546""" + from th2_data_services.config import options + + options.INTERACTIVE_MODE = interactive_mod + + # Write test + data = Data([1, 2, 3, 4, 5], cache=True).map(map_func) + with pytest.raises(expected_exception): + list(data) + assert not is_cache_file_exists(data), "Cache file exists despite data object wrote it." + assert not is_pending_cache_file_exists(data), "Cache file exists despite data object wrote it." + + # Read test + data = Data([1, 2, 3, 4, 5], cache=True) + list(data) # It'll create a cache file. + with pytest.raises(expected_exception): + list(data.map(map_func)) + if expected_exception is TypeError: + if interactive_mod: + assert is_cache_file_exists( + data + ), "Cache file should be exist if Data object just read it in interactive_mod." + # else: + # It's expected that cache should be deleted if it's SCRIPT MODE but `del data` doesn't work for testing + # cache_filepath = data.get_cache_filepath() + # del data + # time.sleep(2) + # assert not cache_filepath.is_file() + elif expected_exception is KeyboardInterrupt: + if interactive_mod: + assert is_cache_file_exists( + data + ), "Cache file should be exist if Data object just read it in interactive_mod." + # else: + # It's expected that cache should be deleted if it's SCRIPT MODE but `del data` doesn't work for testing + # cache_filepath = data.get_cache_filepath() + # del data + # assert not cache_filepath.is_file() + + +@pytest.mark.parametrize( + ["expected_exception", "map_func"], + [ + (KeyError, map_read_failure), + (KeyboardInterrupt, map_keyboard_interrupt), + ], +) +def test_cache_file_wont_remove_external_cache(interactive_mod, expected_exception, map_func): + # Read test for external cache + data = Data.from_cache_file(EXTERNAL_CACHE_FILE) + list(data) # It'll create a cache file. + with pytest.raises(expected_exception): + list(data.map(map_func)) + + # The logic changed -- now, when we read from cache, this file is not cache source. + # It just data source of Data object + # assert is_cache_file_exists( + # data + # ), "Cache file should be exist if Data object just read it from external cache file." + + +@pytest.mark.parametrize( + ["change_type"], + [ + (new_data_with_limit2,), + ], +) +def test_tmp_cache_will_be_deleted_if_not_fully_recorded(change_type): + # Cache has parent + data = Data([1, 2, 3], cache=True) + data2 = change_type(data) + iterate_data(data2, to_return=False) + assert not is_pending_cache_file_exists(data) + + # Cache has data itself + data = Data([1, 2, 3]) + data2 = change_type(data).use_cache() + iterate_data(data2, to_return=False) + assert not is_pending_cache_file_exists(data2) + + +def test_cache_filename(): + data = Data([1, 2, 3, 4, 5], cache=True) + for d in data: + d + assert data._cache_filename.find(":") == -1 diff --git a/tests/tests_unit/test_data/test_cache/test_from_cache_file.py b/tests/tests_unit/test_data/test_cache/test_from_cache_file.py new file mode 100644 index 00000000..a75d110f --- /dev/null +++ b/tests/tests_unit/test_data/test_cache/test_from_cache_file.py @@ -0,0 +1,45 @@ +from pathlib import Path +from pickle import UnpicklingError +from typing import List + +from tests.tests_unit.utils import iterate_data +from th2_data_services.data import Data +import pytest + + +@pytest.mark.parametrize( + ["cache_file"], + [ + (Path().cwd() / "tests/tests_unit/test_data/test_cache/dir_for_test/external_cache_file",), + ], +) +def test_from_cache_file(general_data: List[dict], cache_file): + """Check that file have been created.""" + data = Data.from_cache_file(cache_file) + print() + assert list(data) == general_data + + +# def test_from_cache_file_windows_path(): +# # https://exactpro.atlassian.net/browse/TH2-5085 +# data = Data.from_cache_file("abc:20:20.pickle") + + +def test_from_cache_file_non_exist_file(general_data: List[dict]): + """Check that the lib will raise exception.""" + cache_file = Path().cwd() / "tests/non_exist_file" + with pytest.raises(FileNotFoundError) as ex: + Data.from_cache_file(cache_file) + + +def test_from_cache_file_non_pickle_file(general_data: List[dict]): + """Check that the lib will raise exception if unpickle file. + + Actually it will raise the Exception only during iteration. + """ + cache_file = ( + Path().cwd() / "tests/tests_unit/test_data/test_cache/dir_for_test/external_non_pickle_file" + ) + with pytest.raises(UnpicklingError) as ex: + d = Data.from_cache_file(cache_file) + iterate_data(d) # to iterate diff --git a/tests/tests_unit/test_data/test_cache/test_inheritance.py b/tests/tests_unit/test_data/test_cache/test_inheritance.py new file mode 100644 index 00000000..93506ec3 --- /dev/null +++ b/tests/tests_unit/test_data/test_cache/test_inheritance.py @@ -0,0 +1,244 @@ +from typing import List + + +from tests.tests_unit.utils import ( + iterate_data_and_do_cache_checks, + double_generator, +) + +from th2_data_services.data import Data + + +# [2024.04.15] NOTE -- this test won't work more. +# Reason: +# It works when the Data source of the new Data obj is an old Data obj. +# But now we added DataWorkflow class. It allows us to decrease overheads +# on Data objects iterations. +# This is especially noticeable when the Date object has a long forkflow +# chain. +# So it means that now, when we iterate a child Data object, which parent has +# cache=True -> parent cache won't be created. +# +# def test_parent_cache_was_created(log_checker, general_data: List[dict]): +# """ +# Issue related test: https://exactpro.atlassian.net/browse/TH2-3557 +# +# Cases: +# [1] D(cache) -> D1(filter) -> D2(map) - creates D cache when you iterate D2. +# [2] D(cache) -> D1(filter) -> D2(map + cache) - creates D and D2 cache files +# """ +# # [1] +# data = Data(general_data, cache=True) +# data1 = data.filter(lambda record: record.get("isBatched")) +# data2 = data1.map(lambda record: {**record, "batch_status": record.get("isBatched")}) +# iterate_data(data2) # Just to iterate and create D cache file. +# assert is_cache_file_exists(data) +# # log_checker.cache_file_created(data) +# +# # [2] +# data = Data(general_data, cache=True) +# data1 = data.filter(lambda record: record.get("isBatched")) +# data2 = data1.map(lambda record: {**record, "batch_status": record.get("isBatched")}) +# data2.use_cache(True) +# iterate_data(data2) # Just to iterate and create cache files. +# assert is_cache_file_exists(data) +# assert is_cache_file_exists(data2) +# # log_checker.cache_file_created(data) +# # log_checker.cache_file_created(data2) + + +def test_data_iterates_parent_cache_file(log_checker, general_data: List[dict]): + """D(cache) -> D1(filter) -> D2(map + cache) -> D3(filter) -> D4(map) - creates D and D2 cache files. + There are 2 cache files, it should iterate D2 cache file. + """ + + def add_batch_status_to_dict_generator(stream): + for record in stream: + yield {**record, "batch-status": record.get("isBatched")} + + data = Data(general_data, cache=True) + data1 = data.filter(lambda record: record.get("isBatched")) + data2 = data1.map(lambda record: {**record, "batch_status": record.get("isBatched")}) + data2.use_cache(True) + iterate_data_and_do_cache_checks(data2, log_checker) # Just to iterate and create cache files. + # log_checker.cache_file_created(data) + + data3 = data2.filter(lambda record: record.get("eventType")) + data4 = data3.map_stream(double_generator) + + # Change D and D2 sources to [] to be aware data iterates cache file. + data._data_source = ["D"] + data2._data_source = ["D2"] + assert len(list(data4)) == len(list(data3)) * 2 + # log_checker.used_own_cache_file(data2) + + +# [2024.04.15] NOTE -- this test won't work more. +# Reason: +# It works when the Data source of the new Data obj is an old Data obj. +# But now we added DataWorkflow class. It allows us to decrease overheads +# on Data objects iterations. +# This is especially noticeable when the Date object has a long forkflow +# chain. +# So it means that now, when we iterate a child Data object, which parent has +# cache=True -> parent cache won't be created. +# +# # @pytest.mark.xfail(reason="New methods return partial object which blocks knowing parent.") +# def test_cache_linear_inheritance(general_data: List[dict]): +# """Cache file should be created for the first data object. +# +# Issue related test: https://exactpro.atlassian.net/browse/TH2-3487 +# """ +# data = ( +# Data(general_data, cache=True) +# .filter(lambda record: record.get("isBatched")) +# .map(lambda record: {**record, "batch_status": record.get("isBatched")}) +# ) +# list(data) # Just to iterate and create cache files. +# assert is_cache_file_exists(data) + + +def test_cache_new_data_read_prev_data_cache(general_data: List[dict]): + """ + Case: We create a Data obj. + If the prev Data obj has cache file, the new Data object should read from + this cache file. + """ + expected_res_for_data_after_workflow = [ + { + "batchId": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4", + "batch_status": True, + "eventId": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c035903-d1b4-11eb-9278-591e568ad66e", + "eventName": "Checkpoint", + "eventType": "Checkpoint", + "isBatched": True, + "parentEventId": "8bc787fe-d1b4-11eb-bae5-57b0c4472880", + }, + { + "batchId": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4", + "batch_status": True, + "eventId": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c1114a4-d1b4-11eb-9278-591e568ad66e", + "eventName": "Checkpoint for session alias 'th2-hand-demo' direction 'FIRST' " + "sequence '1623852603564709030'", + "eventType": "Checkpoint for session", + "isBatched": True, + "parentEventId": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c035903-d1b4-11eb-9278-591e568ad66e", + }, + { + "batchId": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4", + "batch_status": True, + "eventId": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c1114a6-d1b4-11eb-9278-591e568ad66e", + "eventName": "Checkpoint for session alias 'demo-dc1' direction 'SECOND' " + "sequence '1624005475721015014'", + "eventType": "Checkpoint for session", + "isBatched": True, + "parentEventId": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c035903-d1b4-11eb-9278-591e568ad66e", + }, + { + "batchId": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4", + "batch_status": True, + "eventId": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c1114a7-d1b4-11eb-9278-591e568ad66e", + "eventName": "Checkpoint for session alias 'demo-dc1' direction 'FIRST' " + "sequence '1624005475720919499'", + "eventType": "Checkpoint for session", + "isBatched": True, + "parentEventId": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c035903-d1b4-11eb-9278-591e568ad66e", + }, + { + "batchId": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4", + "batch_status": True, + "eventId": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c1114a8-d1b4-11eb-9278-591e568ad66e", + "eventName": "Checkpoint for session alias 'demo-conn2' direction 'FIRST' " + "sequence '1624005448022245399'", + "eventType": "Checkpoint for session", + "isBatched": True, + "parentEventId": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c035903-d1b4-11eb-9278-591e568ad66e", + }, + { + "batchId": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4", + "batch_status": True, + "eventId": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c1114a9-d1b4-11eb-9278-591e568ad66e", + "eventName": "Checkpoint for session alias 'demo-conn2' direction 'SECOND' " + "sequence '1624005448022426113'", + "eventType": "Checkpoint for session", + "isBatched": True, + "parentEventId": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c035903-d1b4-11eb-9278-591e568ad66e", + }, + { + "batchId": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4", + "batch_status": True, + "eventId": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c1114aa-d1b4-11eb-9278-591e568ad66e", + "eventName": "Checkpoint for session alias 'demo-dc2' direction 'SECOND' " + "sequence '1624005466840347015'", + "eventType": "Checkpoint for session", + "isBatched": True, + "parentEventId": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c035903-d1b4-11eb-9278-591e568ad66e", + }, + { + "batchId": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4", + "batch_status": True, + "eventId": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c1114ab-d1b4-11eb-9278-591e568ad66e", + "eventName": "Checkpoint for session alias 'demo-dc2' direction 'FIRST' " + "sequence '1624005466840263372'", + "eventType": "Checkpoint for session", + "isBatched": True, + "parentEventId": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c035903-d1b4-11eb-9278-591e568ad66e", + }, + { + "batchId": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4", + "batch_status": True, + "eventId": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c1114ac-d1b4-11eb-9278-591e568ad66e", + "eventName": "Checkpoint for session alias 'demo-conn1' direction 'FIRST' " + "sequence '1624005455622011522'", + "eventType": "Checkpoint for session", + "isBatched": True, + "parentEventId": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c035903-d1b4-11eb-9278-591e568ad66e", + }, + { + "batchId": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4", + "batch_status": True, + "eventId": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c1114ad-d1b4-11eb-9278-591e568ad66e", + "eventName": "Checkpoint for session alias 'demo-log' direction 'FIRST' " + "sequence '1624029363623063053'", + "eventType": "Checkpoint for session", + "isBatched": True, + "parentEventId": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c035903-d1b4-11eb-9278-591e568ad66e", + }, + { + "batchId": "654c2724-5202-460b-8e6c-a7ee9fb02ddf", + "batch_status": True, + "eventId": "654c2724-5202-460b-8e6c-a7ee9fb02ddf:8ca20288-d1b4-11eb-986f-1e8d42132387", + "eventName": "Remove 'NewOrderSingle' " + "id='demo-conn1:SECOND:1624005455622135205' " + "Hash='7009491514226292581' Group='NOS_CONN' " + "Hash['SecondaryClOrdID': 11111, 'SecurityID': INSTR1]", + "eventType": "", + "isBatched": True, + "parentEventId": "a3779b94-d051-11eb-986f-1e8d42132387", + }, + ] + + d1 = Data(general_data, cache=True) + + list(d1) # Just to iterate and create cache files. + d1._data_source = [] + + # d1 should read cache + assert list(d1) == general_data + + data = d1.filter(lambda record: record.get("isBatched")).map( + lambda record: {**record, "batch_status": record.get("isBatched")} + ) + + # check that data reads cache file + assert list(data) == expected_res_for_data_after_workflow + + d1.clear_cache() + assert not d1.is_cache_file_exists() + + # If the source cache was removed, it should read the original source + # List in our case. + d1._data_source = general_data + assert list(data) == expected_res_for_data_after_workflow + + # assert is_cache_file_exists(data) diff --git a/tests/tests_unit/test_data/test_data.py b/tests/tests_unit/test_data/test_data.py new file mode 100644 index 00000000..158c7cae --- /dev/null +++ b/tests/tests_unit/test_data/test_data.py @@ -0,0 +1,373 @@ +import os +from typing import List + +from tests.tests_unit.utils import ( + is_cache_file_exists, + iterate_data, + is_pending_cache_file_exists, +) +from th2_data_services.data import Data +import pytest + + +def test_iter_data(general_data: List[dict]): + data = Data(general_data) + + output = [record for record in data] + assert len(output) == 21 + + +def test_filter_data(general_data: List[dict]): + data = Data(general_data).filter(lambda record: record.get("batchId") is None) + + assert len(list(data)) == 9 + + +def test_map_data_transform(general_data: List[dict]): + data = Data(general_data).map(lambda record: record.get("eventType")) + event_types = set([record for record in data]) + + assert event_types == { + "", + "placeOrderFIX", + "Send message", + "Checkpoint", + "Checkpoint for session", + "message", + "Outgoing message", + } + + +def test_shuffle_data(general_data: List[dict]): + data = ( + Data(general_data) + .filter(lambda record: record.get("batchId") is not None) + .map(lambda record: record.get("eventId")) + .filter(lambda record: "b" in record) + ) + + assert len(list(data)) == 12 + + +def test_limit(general_data: List[dict], cache): + data = Data(general_data, cache=cache) + data10 = data.limit(10) + data5 = data10.limit(5) + + assert list(data10) == general_data[:10] + if cache: + assert not is_cache_file_exists( + data + ), "data shouldn't have cache because was iterated via child data object." + assert not is_pending_cache_file_exists( + data + ), "data shouldn't have cache because was iterated via child data object." + assert list(data5) == general_data[:5] + assert data.len == len(general_data) + assert data10.len == 10 + assert data5.len == 5 + + +def test_limit_for_list_record(cache): + data_stream = [1, 2, 3, 4, 5] + data = Data(data_stream, cache=cache).map(lambda record: [record, record]) + + data10 = data.limit(4) + data5 = data10.limit(2) + + assert list(data10) == [[1, 1], [2, 2], [3, 3], [4, 4]] + if cache: + assert not is_cache_file_exists( + data + ), "data shouldn't have cache because was iterated via child data object." + assert not is_pending_cache_file_exists( + data + ), "data shouldn't have cache because was iterated via child data object." + assert list(data5) == [[1, 1], [2, 2]] + + +def test_limit_in_loops(cache): + data_stream = [1, 2, 3, 4, 5] + data = Data(data_stream, cache=cache) + res5 = [0 for _ in range(4)] + for _ in data.limit(4): + res5[0] += 1 + for __ in data.limit(3): + res5[1] += 1 + for ___ in data.limit(2): + res5[2] += 1 + for ____ in data.limit(1): + res5[3] += 1 + + assert res5 == [4, 4 * 3, 4 * 3 * 2, 4 * 3 * 2 * 1] + assert not is_cache_file_exists(data) + assert not is_pending_cache_file_exists(data) + assert data.len == len(data_stream) # It'll create cache. + + +def test_limit_before_loops(cache=True): + """Related Windows bug: https://exactpro.atlassian.net/browse/TH2-3767""" + data_stream = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + data = Data(data_stream, cache) + limit = 5 + data5 = data.limit(limit) + + res5 = [0 for _ in range(4)] + + for _ in data5: + res5[0] += 1 + for __ in data5: + res5[1] += 1 + for ___ in data5: + res5[2] += 1 + for ____ in data5: + res5[3] += 1 + + assert res5 == [limit, limit**2, limit**3, limit**4] + assert not is_cache_file_exists(data) + assert not is_pending_cache_file_exists(data) + assert data.len == len(data_stream) # It'll create cache. + assert is_cache_file_exists(data) + + +def test_new_limit_is_less(general_data: List[dict], cache): + data5 = Data(general_data, cache).limit(5) + data3 = data5.limit(3) + res = [0 for _ in range(4)] + + for _ in data3: + res[0] += 1 + for __ in data3: + res[1] += 1 + for ___ in data3: + res[2] += 1 + for ____ in data3: + res[3] += 1 + + assert res == [3, 9, 27, 81] + assert data5.len == 5 + assert not is_cache_file_exists(data5) + assert not is_pending_cache_file_exists(data5) + + +def test_new_limit_is_bigger(general_data: List[dict], cache): + data5 = Data(general_data, cache=cache).limit(3).limit(5) + res = [0 for _ in range(4)] + + for _ in data5: + res[0] += 1 + for __ in data5: + res[1] += 1 + for ___ in data5: + res[2] += 1 + for ____ in data5: + res[3] += 1 + + assert res == [3, 9, 27, 81] + assert data5.len == 3 + + +def test_limit_for_limit_in_iterations(general_data: List[dict], cache): + data = Data(general_data, cache=cache) + data5 = data.limit(5) + + res5 = [0 for _ in range(4)] + for _ in data5.limit(4): + res5[0] += 1 + for __ in data5.limit(3): + res5[1] += 1 + for ___ in data5.limit(7): + res5[2] += 1 + for ____ in data5.limit(2): + res5[3] += 1 + + assert res5 == [4, 3 * 4, 3 * 4 * 5, 3 * 4 * 5 * 2] + + +def test_sift_limit_data(general_data: List[dict]): + data = Data(general_data) + output = [record for record in data.sift(limit=2)] + + assert len(output) == 2 + + +def test_sift_skip_data(general_data: List[dict]): + data = Data(general_data) + output1 = data.sift(limit=2) + output2 = [record for record in data.sift(limit=2, skip=2)] + + assert len(list(output1)) == 2 + assert output1 != output2 + + +def test_data_loss_with_fixed_generator(general_data: List[dict]): + def general_data_gen(): + return (item for item in general_data) + + with pytest.warns(RuntimeWarning): + data = Data(general_data_gen()) + + for _ in range(3): + for _ in data: + pass + + assert len(list(data)) == 0 + + +def test_data_loss_with_new_generator(general_data: List[dict]): + def general_data_gen(): + return (item for item in general_data) + + data = Data(general_data_gen) + for _ in range(3): + for _ in data: + pass + + assert len(list(data)) == len(general_data) + + +def test_write_to_file(general_data): + events = Data(general_data) + file_to_test = "demo_file.txt" + expected = """{'batchId': None, + 'eventId': '84db48fc-d1b4-11eb-b0fb-199708acc7bc', + 'eventName': "[TS_1]Aggressive IOC vs two orders: second order's price is " + 'lower than first', + 'eventType': '', + 'isBatched': False, + 'parentEventId': None} +-------------------------------------------------- +""" + events.limit(1).write_to_file(file_to_test) + with open(file_to_test) as f: + assert f.read() == expected + + os.remove(file_to_test) + + +def test_is_empty(general_data: List[dict]): + empty_data = Data([]) + data = Data(general_data) + + assert empty_data.is_empty is True + assert data.is_empty is False + + +def test_inner_cycle_with_cache(general_data: List[dict]): + data = Data(general_data).use_cache(True) # 21 objects + external_counter = 0 + internal_counter = 0 + + for _ in data: + external_counter += 1 + for _ in data: + internal_counter += 1 + + assert external_counter == 21 and internal_counter == 441 + + +def test_inner_cycle_with_cache_and_workflow(general_data: List[dict]): + data = Data(general_data).use_cache(True) # 21 objects + data_filter = data.filter(lambda record: "Checkpoint" in record.get("eventType")) # 12 objects + external_counter = 0 + internal_counter = 0 + + for _ in data: + external_counter += 1 + for _ in data_filter: + internal_counter += 1 + + assert ( + external_counter == len(general_data) + and internal_counter == len(general_data) * data_filter.len + ) + + +def test_break_cycle(general_data: List[dict]): + data = Data(general_data).use_cache(True) # 21 objects + first_cycle = 0 + second_cycle = 0 + + for _ in data: + first_cycle += 1 + if first_cycle == 10: + break + for _ in data: + second_cycle += 1 + + assert second_cycle == 21 + + +def test_to_json(): + data = Data([1, 2, {"3": 5, "tt": 4}, 6]) + path_result = "tests/test_files/file_to_test_to_json.txt" + path_expected = "tests/test_files/file_to_test_to_json_expected.txt" + + data.to_json(path_result, indent=4, overwrite=True) + + with open(path_result, encoding="utf-8") as f1, open(path_expected, encoding="utf-8") as f2: + for l1, l2 in zip(f1, f2): + assert l1 == l2 + + +def test_to_csv(): + data = Data([{"a": 1, "b": 2}, {"c": 3, "d": 4}]) + path_result = "tests/test_files/file_to_test_to_csv.csv" + path_expected = "tests/test_files/file_to_test_to_csv_expected.csv" + + data.to_csv(path_result, overwrite=True) + + with open(path_result, encoding="utf-8") as f1, open(path_expected, encoding="utf-8") as f2: + for l1, l2 in zip(f1, f2): + assert l1 == l2 + + +class TestDataObjectJoining: + @classmethod + def setup_class(cls): + cls.d1 = Data([1, 2, 3]) + cls.d2 = Data(["a", {"id": 123}, "c"]) + cls.d3 = Data([7, 8, 9]) + cls.data_via_init = Data([cls.d1, cls.d2, cls.d3]) + cls.data_via_add = cls.d1 + cls.d2 + cls.d3 + cls.data_with_non_data_obj_via_add = cls.d1 + Data(["a", {"id": 123}, "c"]) + cls.d3 + cls.expected_dx_lst = [1, 2, 3, "a", {"id": 123}, "c", 7, 8, 9] + + # It contains Data objects with exactly the same values inside == cls.expected_dx_lst. + cls.complex_datas_lst = [ + cls.data_via_init, + cls.data_via_add, + cls.data_with_non_data_obj_via_add, + ] + + def test_iters_all_data_objects_inside(self): + """Checks data consistency.""" + for dx in self.complex_datas_lst: + assert list(dx) == self.expected_dx_lst + + def test_iterates_many_times(self): + """Iterates the same data object 3 times.""" + for dx in self.complex_datas_lst: + l1 = list(dx) + l2 = list(dx) + l3 = list(dx) + assert l1 == l2 == l3 + + def test_len_joined_data(self): + for dx in self.complex_datas_lst: + assert dx.len == len(self.expected_dx_lst) + + def test_cache(self): + """ + dx = d1 + d2(with_cache) + d3 <- d2 cache should work + dx.use_cache(True) <- dx will get own cache + """ + # dx = self.d1 + Data(['a', {'id': 123}, 'c'], cache=True) + self.d3 + d2 = Data(["a", {"id": 123}, "c"], cache=True) + dx = self.d1 + d2 + self.d3 + iterate_data(dx, to_return=False) # It should create d2 cache file. + assert is_cache_file_exists(d2), "The cache was not dumped after using len" + + dx.use_cache(True) + iterate_data(dx, to_return=False) # It should create dx cache file. + assert is_cache_file_exists(dx), "The cache was not dumped after using len" diff --git a/tests/tests_integration/tests_diff_version/tests_v5/__init__.py b/tests/tests_unit/test_data/test_from_json/__init__.py similarity index 100% rename from tests/tests_integration/tests_diff_version/tests_v5/__init__.py rename to tests/tests_unit/test_data/test_from_json/__init__.py diff --git a/tests/tests_unit/test_data/test_from_json/file_with_unicode_symbols.jsonl b/tests/tests_unit/test_data/test_from_json/file_with_unicode_symbols.jsonl new file mode 100644 index 00000000..f34c5d93 --- /dev/null +++ b/tests/tests_unit/test_data/test_from_json/file_with_unicode_symbols.jsonl @@ -0,0 +1 @@ +{"Device Control Three val": "h\nÁ`Å{abc "} \ No newline at end of file diff --git a/tests/tests_unit/test_data/test_from_json/file_with_unicode_symbols.jsonl.gz b/tests/tests_unit/test_data/test_from_json/file_with_unicode_symbols.jsonl.gz new file mode 100644 index 00000000..92314084 Binary files /dev/null and b/tests/tests_unit/test_data/test_from_json/file_with_unicode_symbols.jsonl.gz differ diff --git a/tests/tests_unit/test_data/test_from_json/test_from_json.py b/tests/tests_unit/test_data/test_from_json/test_from_json.py new file mode 100644 index 00000000..4ccde1ff --- /dev/null +++ b/tests/tests_unit/test_data/test_from_json/test_from_json.py @@ -0,0 +1,24 @@ +from th2_data_services.data import Data + +file = "tests/tests_unit/test_data/test_from_json/file_with_unicode_symbols.jsonl" +data = Data.from_json(file) +file = "tests/tests_unit/test_data/test_from_json/file_with_unicode_symbols.jsonl.gz" +data = Data.from_json(file, gzip=True) + +# ['{"Device Control Three val": "h\\nÁ␓`Å␒abc"}\r\n', '{"Device Control Three val": "h\\\\nÁ\\x13`Åx18abc"}\r\n' + +# {"Device Control Three val": "h\\nÁ\x13`Åx18abc"} +# {"no_escape character in val": "\_abc"} +# {"\no_escape character in key": "_abc"} +# {"in_the_key_î": "abc"} +# {"in_the_val": "î_abc"} +# {"\tval": "\t_abc"} +# {"\nval": "\n_abc"} +def test_can_iterate_jsonl_file(): + pass + # for x in data: + # print(x) + + # s = '{"Device Control Three val": "h\nÁ␓`Å␒abc"}' + # import json + # print(json.loads(s)) diff --git a/tests/tests_integration/tests_diff_version/tests_v5/tests_events_tree/__init__.py b/tests/tests_unit/test_data/test_from_json/test_from_json_gz.py similarity index 100% rename from tests/tests_integration/tests_diff_version/tests_v5/tests_events_tree/__init__.py rename to tests/tests_unit/test_data/test_from_json/test_from_json_gz.py diff --git a/tests/tests_unit/test_data/test_len.py b/tests/tests_unit/test_data/test_len.py new file mode 100644 index 00000000..1990e30c --- /dev/null +++ b/tests/tests_unit/test_data/test_len.py @@ -0,0 +1,100 @@ +import pathlib +from typing import List + +from tests.tests_unit.utils import ( + is_cache_file_exists, + is_pending_cache_file_exists, +) + +from th2_data_services.data import Data + + +def test_len_with_stream_cache(general_data: List[dict], cache=True): + # From empty list + data = Data(general_data, cache=cache) + elements_num = len(general_data) + assert data.len == elements_num + assert data.limit(10).len == 10 + + # After print + data = Data(general_data, cache=cache) + str(data) # The same as print. + assert data.len == elements_num, f"After print, cache: {cache}" + + # After is_empty + data = Data(general_data, cache=cache) + r = data.is_empty + assert data.len == elements_num, f"After is_empty, cache: {cache}" + + # After sift + data = Data(general_data, cache=cache) + r = list(data.sift(limit=5)) + assert data.len == elements_num, f"After sift, cache: {cache}" + + # The cache was dumped after using len + data = Data(general_data, cache=cache) + r = data.len + if cache: + assert is_cache_file_exists(data), f"The cache was dumped after using len: {cache}" + else: + assert not is_cache_file_exists(data), f"The cache was dumped after using len: {cache}" + assert not is_pending_cache_file_exists( + data + ), f"The cache was dumped after using len: {cache}" + + # TODO - Check that we do not calc len, after already calculated len or after iter + + +def test_len_has_correct_value_after_multiple_loop_iteration(cache): + stream = [1, 2, 3] + data = Data(stream, cache=cache) + + for a in data: + for b in data: + for c in data: + pass + + assert data.len == len(stream) + + +# FIXME +# Temporarily commented -- was broken after Workflow changes +# @pytest.mark.parametrize( +# ["limit2", "limit3", "exp_data2", "exp_data3", "exp_data"], +# # Data.limit(A).limit(B) +# [ +# # A == B +# pytest.param(1, 1, 1, 1, None, marks=pytest.mark.xfail(reason="Low priority issue")), +# (1, 1, None, 1, None), # Issue, but it checks that data3 has correct value +# (2, 2, None, 2, None), # Issue +# pytest.param(5, 5, 5, 5, 5, marks=pytest.mark.xfail(reason="Low priority issue")), +# (5, 5, None, 5, None), # Issue, but it checks that data3 has correct value +# (10, 8, 5, 5, 5), # Higher than data_stream len == 5 +# # A > B +# (3, 2, None, 2, None), # data2 should be None because it's not fully iterated. +# (5, 2, None, 2, None), +# (10, 2, None, 2, None), +# (10, 6, 5, 5, 5), # data3 == 5 because data_stream len == 5 +# # A < B +# (1, 2, 1, 1, None), +# (1, 10, 1, 1, None), +# ], +# ) +# def test_len_will_be_saved_if_limit_used(cache, limit2, limit3, exp_data3, exp_data2, exp_data): +# data_stream = [1, 2, 3, 4, 5] +# data = Data(data_stream, cache) +# data2 = data.limit(limit2) +# data3 = data2.limit(limit3) +# list(data3) # Just to iterate. +# assert data3._len == exp_data3 +# assert data2._len == exp_data2 +# assert data._len == exp_data + + +def test_len_after_reading_file(): + # Related issue - TH2-4930 + # Any file: cache, json, csv + path = pathlib.Path("tests/test_files/file_to_read_by_data.csv") + data = Data.from_csv(path) + + assert list(data.limit(2)) == [["A", "B", "Two Words"], ["1", "2", "2.1"]] diff --git a/tests/tests_unit/test_data/test_map_stream.py b/tests/tests_unit/test_data/test_map_stream.py new file mode 100644 index 00000000..aa32e8d5 --- /dev/null +++ b/tests/tests_unit/test_data/test_map_stream.py @@ -0,0 +1,240 @@ +from typing import List, Iterable + +from th2_data_services.data import Data +from th2_data_services.interfaces import IStreamAdapter +from tests.tests_unit.utils import ( + is_cache_file_exists, + is_pending_cache_file_exists, + double_generator, + triple_generator, + event_type_generator, + iterate_data, +) + + +class SimpleAdapter(IStreamAdapter): + def handle(self, stream: Iterable): + for record in stream: + if record["eventType"] == "Checkpoint": + yield {"id": record["eventId"], "name": record["eventName"]} + + +class AdapterWithInit(IStreamAdapter): + def __init__(self): + self.len_iter = 0 + + def handle(self, stream: Iterable): + for record in stream: + self.len_iter += 1 + yield {"id": record["eventId"], "name": record["eventName"]} + + def __copy__(self): + return self + + def __deepcopy__(self, memo): + # NOTE, the reason why we need this workaround -- look at Data._build_workflow + return self + + +def test_map_stream_with_adapter_with_variables_inside_adapter(general_data: List[dict]): + a = AdapterWithInit() + data = Data(general_data).map_stream(a) + iterate_data(data) + assert a.len_iter == 21 + iterate_data(data) + assert a.len_iter == 42 + + +def test_map_stream_with_adapter(general_data: List[dict]): + data = Data(general_data).map_stream(SimpleAdapter()) + assert list(data) == [ + { + "id": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c035903-d1b4-11eb-9278-591e568ad66e", + "name": "Checkpoint", + } + ] + + +def test_map_stream_with_generator_function(general_data: List[dict]): + def simple_gen(stream): + for event in stream: + if event["eventType"] == "Checkpoint": + yield {"id": event["eventId"], "name": event["eventName"]} + + data = Data(general_data).map_stream(simple_gen) + assert list(data) == [ + { + "id": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c035903-d1b4-11eb-9278-591e568ad66e", + "name": "Checkpoint", + } + ] + + +def test_map_stream_chaining(general_data: List[dict]): + def simple_gen(stream): + for event in stream: + if "Checkpoint" in event["name"]: + yield {"id": event["id"]} + + data = Data(general_data).map_stream(SimpleAdapter()).map_stream(simple_gen) + assert list(data) == [ + {"id": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c035903-d1b4-11eb-9278-591e568ad66e"} + ] + + +def test_map_stream_chaining_with_other_methods(general_data: List[dict]): + def simple_gen(stream): + for event in stream: + if event["eventName"] == "Checkpoint": + yield {"id": event["eventId"]} + + data = ( + Data(general_data) + .filter(lambda event: "Checkpoint" in event["eventName"]) + .map_stream(simple_gen) + ) + assert list(data) == [ + {"id": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c035903-d1b4-11eb-9278-591e568ad66e"} + ] + + +def test_increase_records_after_similar_map_stream(): + source = [1, 2, 3] + + data = Data(source).map_stream(double_generator).map_stream(triple_generator) + + assert list(data) == [ + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + ] + + +def test_big_modification_chain(log_checker): + d1 = Data([1, 2, 3, 4, 5]).use_cache(True) + d2 = d1.filter(lambda x: x == 1 or x == 2) + d3 = d2.map_stream(double_generator).use_cache(True) + d4 = d3.limit(3) + d5 = d4.map_stream(double_generator) + + # It should have all "Data[d3] Iterating working data" log records (for each data object) + assert list(d5) == [1, 1, 1, 1, 2, 2] + # Cache files should not be written because they not iterated to the end. + assert not is_cache_file_exists(d3) + assert not is_cache_file_exists(d1) + assert not is_pending_cache_file_exists(d3) + assert not is_pending_cache_file_exists(d1) + + assert list(d4) == [1, 1, 2] + assert list(d3) == [1, 1, 2, 2] # It also should iterate cache file. + assert list(d2) == [1, 2] + assert list(d1) == [1, 2, 3, 4, 5] + assert list(d5) == [1, 1, 1, 1, 2, 2] + + +def test_filter_for_list_record(general_data: List[dict]): + data = ( + Data(general_data) + .map_stream(double_generator) + .map_stream(event_type_generator) + .filter(lambda record: record in ["placeOrderFIX", "Checkpoint"]) + ) + + event_types = [ + "placeOrderFIX", + "placeOrderFIX", + "Checkpoint", + "Checkpoint", + ] + + assert event_types == list(data) + + +def test_map_stream_for_list_record(general_data: List[dict]): + data = ( + Data(general_data).map_stream(double_generator).map(lambda record: record.get("eventType")) + ) + + event_types = [ + "", + "", + "", + "", + "placeOrderFIX", + "placeOrderFIX", + "Checkpoint", + "Checkpoint", + "Checkpoint for session", + "Checkpoint for session", + "Checkpoint for session", + "Checkpoint for session", + "Checkpoint for session", + "Checkpoint for session", + "Checkpoint for session", + "Checkpoint for session", + "Checkpoint for session", + "Checkpoint for session", + "Checkpoint for session", + "Checkpoint for session", + "Checkpoint for session", + "Checkpoint for session", + "Checkpoint for session", + "Checkpoint for session", + "Checkpoint for session", + "Checkpoint for session", + "Checkpoint for session", + "Checkpoint for session", + "Outgoing message", + "Outgoing message", + "Outgoing message", + "Outgoing message", + "", + "", + "Send message", + "Send message", + "Send message", + "Send message", + "message", + "message", + "Checkpoint for session", + "Checkpoint for session", + ] + assert event_types == list(data) + + +def test_map_stream_data_increase(general_data: List[dict]): + data = ( + Data(general_data) + .filter(lambda record: record.get("batchId") is None) # returns 9 + .map_stream(double_generator) + .map_stream(event_type_generator) + ) + + for m in data: + print(m) + + assert len(list(data)) == 18 + + +def test_map_stream_data_can_yield_None(): + def x(s): + for m in s: + yield None + + d = Data(["a", "b"]).map_stream(x) + assert list(d) == [None, None] diff --git a/tests/tests_unit/test_data/test_map_yield.py b/tests/tests_unit/test_data/test_map_yield.py new file mode 100644 index 00000000..d02d838c --- /dev/null +++ b/tests/tests_unit/test_data/test_map_yield.py @@ -0,0 +1,138 @@ +from typing import List + +from th2_data_services.data import Data +from tests.tests_unit.utils import ( + is_cache_file_exists, + is_pending_cache_file_exists, + return_two_items_if_value_greater_than_10, +) + + +def test_map_yield_with_simple_function(): + data = Data([1, 2, 3, 4]).map_yield(lambda a: a * 2) + assert list(data) == [2, 4, 6, 8] + + +def test_map_yield_list_return_value_increases_size(): + data = Data([1, 5, 10, 15, 20]).map_yield(return_two_items_if_value_greater_than_10) + assert list(data) == [1, 5, 10, 15, 15, 20, 20] + + +def test_map_yield_chaining(): + data = ( + Data([2, 4, 6, 8]) + .map_yield(lambda a: a * 2) + .map_yield(return_two_items_if_value_greater_than_10) + ) + assert list(data) == [4, 8, 12, 12, 16, 16] + + +def test_map_yield_chaining_with_other_methods(general_data: List[dict]): + data = ( + Data([5, 10, 15, 20]) + .filter(lambda item: item**2 > 100) + .map_yield(lambda item: [item, item]) + ) + assert list(data) == [15, 15, 20, 20] + + +def test_increase_records_after_similar_map_yield(): + source = [1, 2, 3] + + data = ( + Data(source).map_yield(lambda item: [item, item]).map_yield(lambda item: [item, item, item]) + ) + + assert list(data) == [ + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + ] + + +def test_map_yield_big_modification_chain(): + d1 = Data([1, 2, 3, 4, 5]).use_cache(True) + d2 = d1.filter(lambda x: x == 1 or x == 2) + d3 = d2.map_yield(lambda item: [item, item]).use_cache(True) + d4 = d3.limit(3) + d5 = d4.map_yield(lambda item: [item, item]) + + # It should have all "Data[d3] Iterating working data" log records (for each data object) + assert list(d5) == [1, 1, 1, 1, 2, 2] + # Cache files should not be written because they not iterated to the end. + assert not is_cache_file_exists(d3) + assert not is_cache_file_exists(d1) + assert not is_pending_cache_file_exists(d3) + assert not is_pending_cache_file_exists(d1) + + assert list(d4) == [1, 1, 2] + assert list(d3) == [1, 1, 2, 2] # It also should iterate cache file. + + +def test_map_yield_for_list_record(general_data: List[dict]): + data = ( + Data(general_data) + .map_yield(lambda record: [record, record]) + .map_yield(lambda record: record.get("eventType")) + ) + + event_types = [ + "", + "", + "", + "", + "placeOrderFIX", + "placeOrderFIX", + "Checkpoint", + "Checkpoint", + "Checkpoint for session", + "Checkpoint for session", + "Checkpoint for session", + "Checkpoint for session", + "Checkpoint for session", + "Checkpoint for session", + "Checkpoint for session", + "Checkpoint for session", + "Checkpoint for session", + "Checkpoint for session", + "Checkpoint for session", + "Checkpoint for session", + "Checkpoint for session", + "Checkpoint for session", + "Checkpoint for session", + "Checkpoint for session", + "Checkpoint for session", + "Checkpoint for session", + "Checkpoint for session", + "Checkpoint for session", + "Outgoing message", + "Outgoing message", + "Outgoing message", + "Outgoing message", + "", + "", + "Send message", + "Send message", + "Send message", + "Send message", + "message", + "message", + "Checkpoint for session", + "Checkpoint for session", + ] + assert event_types == list(data) diff --git a/tests/tests_unit/test_data/test_metadata.py b/tests/tests_unit/test_data/test_metadata.py new file mode 100644 index 00000000..badbf6b3 --- /dev/null +++ b/tests/tests_unit/test_data/test_metadata.py @@ -0,0 +1,106 @@ +from typing import List + +from th2_data_services.data import Data + + +def test_metadata_is_carried(general_data: List[dict]): + data = Data(general_data) + metadata = {"some": "default value", "test": "case"} + data.update_metadata(metadata) + data2 = data.filter(lambda event: event["isBatched"]).map( + lambda event: {"id": event["eventId"]} + ) + assert data2.metadata == metadata + + +def test_updating_one_data_object_metadata_dont_affect_parent_data(general_data: List[dict]): + data = Data(general_data) + metadata = {"some": "default value", "test": "case"} + data.update_metadata(metadata) + data2 = data.filter(lambda event: event["isBatched"]).map( + lambda event: {"id": event["eventId"]} + ) + data2.update_metadata({"a": 123}) + assert data.metadata != data2.metadata + + +def test_metadata_joining_iadd(general_data: List[dict]): + data = Data(general_data) + metadata = {"some": "default value", "test": "case"} + data.update_metadata(metadata) + + data += Data([1, 2, 3]) + assert data.metadata == metadata + + data_m_metadata = {"a": "nums"} + data_m = Data([4, 5, 6]).update_metadata(data_m_metadata) + + data += data_m + exp_metadata = metadata.copy() + exp_metadata.update(data_m_metadata) + assert data.metadata == exp_metadata + + +def test_metadata_joining_add(general_data: List[dict]): + data = Data(general_data) + metadata = {"some": "default value", "test": "case"} + data.update_metadata(metadata) + + data1 = data + Data([1, 2, 3]) + assert data1.metadata == metadata + + data_m_metadata = {"a": "nums"} + data_m = Data([4, 5, 6]).update_metadata(data_m_metadata) + + data2 = data + data_m + exp_metadata = metadata.copy() + exp_metadata.update(data_m_metadata) + assert data2.metadata == exp_metadata + + +def test_source_file_in_metadata_removed_when_adding(): + data1 = Data([1, 2, 3]) + data2 = Data([4, 5, 6]) + data1.update_metadata({"source_file": "file1"}) + data2.update_metadata({"source_file": "file2"}) + data3 = data1 + data2 + + assert data3.metadata["source_files"] == ["file1", "file2"] + + +def test_strings_update_in_metadata(): + """ + If both values of same key are strings update replaces the value. + If at least one value is a list, second value is pushed into the list. + """ + data1 = Data([1, 2, 3]) + data1.update_metadata( + {"test_str": "str1", "test_list_and_str": ["str1"], "test_list_and_list": ["str1"]} + ) + data1.update_metadata( + {"test_str": "str2", "test_list_and_str": "str2", "test_list_and_list": ["str2"]} + ) + + assert data1.metadata == { + "test_str": "str2", + "test_list_and_str": ["str1", "str2"], + "test_list_and_list": ["str1", "str2"], + } + + +def test_metadata_update_with_string_as_value_in_dict(): + data = Data([]) + data.update_metadata({1: "ab"}) + data.update_metadata({1: "cd"}) + + exp_metadata = {1: "cd"} + assert data.metadata == exp_metadata + + +def test_metadata_update_with_change_type_change(): + data = Data([]) + data.update_metadata({1: ["ab"]}) + data.update_metadata({1: "cd"}, change_type="change") + + exp_metadata = {1: "cd"} + assert data.metadata == exp_metadata diff --git a/tests/tests_unit/test_data/test_performance/iteration_on_data_files.py b/tests/tests_unit/test_data/test_performance/iteration_on_data_files.py new file mode 100644 index 00000000..f0d1b3f5 --- /dev/null +++ b/tests/tests_unit/test_data/test_performance/iteration_on_data_files.py @@ -0,0 +1,57 @@ +import os +import time +import random + +from th2_data_services.data import Data + + +def get_iteration_speed_plus(): + data = Data.from_json(f"benchmark/json0.gz", gzip=True) + for i in range(1, 122): + data = data + Data.from_json(f"benchmark/json{i}.gz", gzip=True) + + _iterate_and_print_stats(data) + + +def get_iteration_speed_plus_equals(): + data = Data.from_json(f"benchmark/json0.gz", gzip=True) + for i in range(1, 122): + data += Data.from_json(f"benchmark/json{i}.gz", gzip=True) + + _iterate_and_print_stats(data) + + +def get_iteration_speed_list_comprehension(): + data = Data([Data.from_json(f"benchmark/json{i}.gz", gzip=True) for i in range(122)]) + + _iterate_and_print_stats(data) + + +def _generate_data(): + n = 10_000 + data = Data([random.randint(1, 100_000) for _ in range(n)]) + os.makedirs("benchmark", exist_ok=True) + data.to_json_lines(f"benchmark/json0.gz", gzip=True, overwrite=True) + for i in range(1, 122): + data = Data([random.randint(1, 100_000) for _ in range(n)]) + data.to_json_lines(f"benchmark/json{i}.gz", gzip=True, overwrite=True) + + +def _iterate_and_print_stats(data): + start_time = time.time() + j = 0 + for _ in data: + j += 1 + + print(f"Number of records iterated: {j}") + print(f"Time took: {time.time() - start_time} seconds") + + +if __name__ == "__main__": + _generate_data() + print("get_iteration_speed_plus()") + get_iteration_speed_plus() + print("get_iteration_speed_plus_equals()") + get_iteration_speed_plus_equals() + print("get_iteration_speed_list_comprehension()") + get_iteration_speed_list_comprehension() diff --git a/tests/tests_unit/test_data/test_performance/test_many_files.py b/tests/tests_unit/test_data/test_performance/test_many_files.py new file mode 100644 index 00000000..06fb2dff --- /dev/null +++ b/tests/tests_unit/test_data/test_performance/test_many_files.py @@ -0,0 +1,168 @@ +import timeit +from pathlib import Path + +from tests.tests_unit.test_data.test_performance.util import ( + Multiply, + reads_all_json_files_from_the_folder, + data_template, +) + +# from profilehooks import profile + +from th2_data_services.data import Data + +TEST_FILES_PATH = "perf_files" + + +def create_files(): + """Creates 100 json-lines files""" + files_path = Path(TEST_FILES_PATH).resolve().absolute() + files_path.mkdir(exist_ok=True) + files_num = 100 + file_lines_num = 5000 + + for i in range(files_num): + Data([data_template]).map_stream(Multiply(file_lines_num)).to_json_lines( + filename=files_path / f"file_{i}.jsons", gzip=True, overwrite=True + ) + + +def create_1_file(): + """Creates 1 json-lines files""" + files_path = Path(TEST_FILES_PATH).resolve().absolute() + files_path.mkdir(exist_ok=True) + files_num = 100 + file_lines_num = 5000 * files_num + + Data([data_template]).map_stream(Multiply(file_lines_num)).to_json_lines( + filename="file_all.jsons", gzip=True, overwrite=True + ) + + +# @profile +def many_files(): + + # create_files() + # create_1_file() + pass + + data_many_files = reads_all_json_files_from_the_folder(TEST_FILES_PATH) + data_many_files_datas_list = reads_all_json_files_from_the_folder( + TEST_FILES_PATH, return_list=True + ) + print("test") + files = [str(Path(TEST_FILES_PATH) / f"file_{i}.jsons") for i in range(100)] + # print(locals()) + # print(timeit.repeat("[x for x in data_many_files]", globals=locals())) + all_msgs_in_1_filepath = "file_all.jsons" + data_all_in_one_file = Data.from_json(all_msgs_in_1_filepath, gzip=True) + # print(timeit.repeat("[x for x in data_all_in_one_file]", globals=locals())) + + print("just iter") + + # x = data_many_files.map(lambda x: x['eventName']).limit(1) + x = data_many_files.limit(2) + y = x.limit(3) + # x.show() + # y.show() + + # print(x) + # print(y) + # # + # for m in x: + # print("X: " + str(x.workflow._data[0].callback.pushed)) + # # print(m) + # for n in y: + # print("\tY limit2: " +str(y.workflow._data[0].callback.pushed)) + # # print(n) + # # print("Y limit3: " +str(y.workflow._data[1].callback.pushed)) + # + # return + + d1 = Data([1, 2, 3]) + # d2 = d1.filter(lambda x: x == 1 or x == 2) + # from tests.tests_unit.utils import double_generator + # d3 = d2.map_stream(double_generator) + # + def map_read_failure(e): + if e != 1: + return e["a"] + + # print(list(d1.map(map_read_failure))) + + def fun_map(s): + for m in s: + raise KeyError + yield x + "12" + + # print(list(d1.map_stream(fun_map))) + # + # for m in d1.map(map_read_failure): + # print(m) + # for m in d2: + # print(m) + # for m in d3: + # print(m) + + # return + + # cnt1 = 0 + # + # for f in files: + # iterator = iter_json_gzip_file(f, buffer_limit=0) + # for m in iterator(): + # cnt1 += 1 + + # print(cnt1) + # return + # cnt2 = 0 + # print(len(data_many_files_datas_list)) + # return + # for f in data_many_files_datas_list: + # for x in f: + # cnt2 += 1 + # print(cnt2) + # print(data_many_files.len) + # return + + s1 = """ +for x in data_many_files: + pass + """ + s1_filters = """ +for x in data_many_files.filter(lambda x: True).filter(lambda x: True).filter(lambda x: True): + pass + """ + + s2 = """ +for x in data_all_in_one_file.filter(lambda x: True): + pass + """ + + print(files) + s3 = """ +for f in files: + iterator = iter_json_gzip_file(f, buffer_limit=0) + for m in iterator(): + pass + """ + s4 = """ +iterator = iter_json_gzip_file(all_msgs_in_1_filepath) +for m in iterator(): + pass + """ + s5_iterate_every_data_file_separatelly = """ +for f in data_many_files_datas_list: + for x in f.filter(lambda x: True): + pass + """ + + print(timeit.repeat(s2, globals=locals(), repeat=2, number=1)) + print(timeit.repeat(s1, globals=locals(), repeat=5, number=1)) + print(timeit.repeat(s1_filters, globals=locals(), repeat=5, number=1)) + # print(timeit.repeat(s5_iterate_every_data_file_separatelly, globals=locals(), repeat=2, number=1)) + # print(timeit.repeat(s3, globals=locals(), repeat=2, number=1)) + # print(timeit.repeat(s4, globals=locals(), repeat=2, number=1)) + + +# many_files() diff --git a/tests/tests_unit/test_data/test_performance/util.py b/tests/tests_unit/test_data/test_performance/util.py new file mode 100644 index 00000000..0e7a8774 --- /dev/null +++ b/tests/tests_unit/test_data/test_performance/util.py @@ -0,0 +1,52 @@ +import os +from typing import Iterable, Any + +from th2_data_services.data import Data +from th2_data_services.interfaces import IStreamAdapter + + +class Multiply(IStreamAdapter): + def __init__(self, multiplier): + self.multiplier = multiplier + + def handle(self, stream: Iterable) -> Any: + m: dict + for m in stream: + for x in range(self.multiplier): + new = m.copy() + new["eventId"] += str(x) + new["eventName"] += str(x) + new["eventName"] += str(x) + yield new + + +def reads_all_json_files_from_the_folder(path, return_list=False) -> Data: + # TODO -- add files templates e.g. only *.py files + datas = [] + for (dirpath, dirnames, filenames) in os.walk(path): + for filename in filenames: + file_path = os.path.join(dirpath, filename) + datas.append(Data.from_json(file_path, gzip=True, buffer_limit=250)) + + if return_list: + return datas + if len(datas) == 1: + return datas[0] + else: + return Data(datas) + + +data_template = { + "batchId": None, + "eventId": "84db48fc-d1b4-11eb-b0fb-199708acc7bc", + "eventName": "some event name that will have +1 every new one", + "eventType": "Test event", + "isBatched": False, + "parentEventId": None, + "body": { + "a": 1, + "b": [1, 2, 3], + "c": {"x": 1, "y": 2}, + "d": 4, + }, +} diff --git a/tests/tests_unit/test_data/test_show.py b/tests/tests_unit/test_data/test_show.py new file mode 100644 index 00000000..6e185baf --- /dev/null +++ b/tests/tests_unit/test_data/test_show.py @@ -0,0 +1,69 @@ +from th2_data_services.data import Data + +data = Data([1, 2, 3, 4, 5, 6, 7, 8]) + + +def test_show_shows_more_than_default(capsys): + n = 6 + data.show(n, idx_print=False) + captured = capsys.readouterr() + assert ( + captured.out + == f"""------------- Printed first {n} records ------------- +1 +2 +3 +4 +5 +6 +""" + ) + + +def test_show_shows_less_than_default(capsys): + n = 2 + data.show(n, idx_print=False) + captured = capsys.readouterr() + assert ( + captured.out + == f"""------------- Printed first {n} records ------------- +1 +2 +""" + ) + + +# FIXME -- some issues with tests via pre-commit +# def test_show_extra_prints(capsys, general_data: List[dict]): +# # First element is +# x = { +# "batchId": None, +# "eventId": "84db48fc-d1b4-11eb-b0fb-199708acc7bc", +# "eventName": "[TS_1]Aggressive IOC", +# "eventType": "", +# "isBatched": False, +# "parentEventId": None, +# } +# n = 1 +# d1 = Data([x] + general_data) +# d1.show(n, extra_prints={"isBatched": lambda e: "Yes" if e["isBatched"] else "No"}) +# captured = capsys.readouterr() +# assert ( +# captured.out +# == "------------- Printed first 1 records -------------\n[1] ------\nisBatched: No\n{'batchId': None,\n 'eventId': '84db48fc-d1b4-11eb-b0fb-199708acc7bc',\n 'eventName': '[TS_1]Aggressive IOC',\n 'eventType': '',\n 'isBatched': False,\n 'parentEventId': None}\n" +# ) + + +# assert ( +# captured.out +# == f"""------------- Printed first {n} records ------------- +# [1] ------ +# isBatched: No +# {{'batchId': None, +# 'eventId': '84db48fc-d1b4-11eb-b0fb-199708acc7bc', +# 'eventName': '[TS_1]Aggressive IOC', +# 'eventType': '', +# 'isBatched': False, +# 'parentEventId': None}} +# """ +# ) diff --git a/tests/tests_integration/tests_diff_version/tests_v6/__init__.py b/tests/tests_unit/test_dependencies/__init__.py similarity index 100% rename from tests/tests_integration/tests_diff_version/tests_v6/__init__.py rename to tests/tests_unit/test_dependencies/__init__.py diff --git a/tests/tests_unit/test_dependencies/conftest.py b/tests/tests_unit/test_dependencies/conftest.py new file mode 100644 index 00000000..c2fb2c79 --- /dev/null +++ b/tests/tests_unit/test_dependencies/conftest.py @@ -0,0 +1,2 @@ +def pytest_addoption(parser): + parser.addoption("--provider", action="store", default="rdp") diff --git a/tests/tests_unit/test_dependencies/test_dependency_install.py b/tests/tests_unit/test_dependencies/test_dependency_install.py new file mode 100644 index 00000000..4531a451 --- /dev/null +++ b/tests/tests_unit/test_dependencies/test_dependency_install.py @@ -0,0 +1,26 @@ +import pytest +from importlib_metadata import metadata + + +@pytest.fixture(scope="session") +def provider(pytestconfig): + return pytestconfig.getoption("provider").lower() + + +rdp = "th2-data-services-rdp" +lwdp = "th2-data-services-lwdp" + + +def test_major_version_of_provider(provider): + if provider == "rdp": + assert metadata(rdp) + elif provider == "rdp5": + assert metadata(rdp)["version"].startswith("5") + elif provider == "rdp6": + assert metadata(rdp)["version"].startswith("6") + elif provider == "lwdp": + assert metadata(lwdp) + elif provider == "lwdp1": + assert metadata(lwdp)["version"].startswith("1") + else: + raise AssertionError("Unexpected Provider") diff --git a/tests/tests_unit/tests_diff_version/tests_common/__init__.py b/tests/tests_unit/test_event_trees/__init__.py similarity index 100% rename from tests/tests_unit/tests_diff_version/tests_common/__init__.py rename to tests/tests_unit/test_event_trees/__init__.py diff --git a/tests/tests_unit/test_event_trees/demo_etc_data.py b/tests/tests_unit/test_event_trees/demo_etc_data.py new file mode 100644 index 00000000..86ff1438 --- /dev/null +++ b/tests/tests_unit/test_event_trees/demo_etc_data.py @@ -0,0 +1,2395 @@ +demo_etc_data_small = [ + {"eventName": "Root Event", "eventId": "root_id", "data": {"data": [1, 2, 3, 4, 5]}}, + { + "eventName": "Event A1", + "eventId": "a1_id", + "data": {"data": "A1"}, + "parentEventId": "root_id", + }, + { + "eventName": "Event A1_child1", + "eventId": "a1_child1_id", + "data": {"data": "A1_child1"}, + "parentEventId": "a1_id", + }, + { + "eventName": "Event A1_child2", + "eventId": "a1_child2_id", + "data": {"data": "A1_child2"}, + "parentEventId": "a1_id", + }, + { + "eventName": "Event B1", + "eventId": "b1_id", + "data": {"data": "B1"}, + "parentEventId": "root_id", + }, + { + "eventName": "Event B1_child1", + "eventId": "b1_child1_id", + "data": {"data": "B1_child1"}, + "parentEventId": "b1_id", + }, + { + "eventName": "Event B1_child2", + "eventId": "b1_child2_id", + "data": {"data": "B1_child2"}, + "parentEventId": "b1_id", + }, + { + "eventName": "Event B1_child3", + "eventId": "b1_child3_id", + "data": {"data": "B1_child3"}, + "parentEventId": "b1_id", + }, + { + "eventName": "Event C1", + "eventId": "c1_id", + "data": {"data": "C1"}, + "parentEventId": "root_id", + }, + {"eventName": "Event D1", "eventId": "d1_id", "data": {"data": "D1"}, "parentEventId": "c1_id"}, + {"eventName": "Event E1", "eventId": "e1_id", "data": {"data": "E1"}, "parentEventId": "d1_id"}, + { + "eventName": "Event E1_child1", + "eventId": "e1_child1_id", + "data": {"data": "E1_child1"}, + "parentEventId": "d1_id", + }, + { + "eventName": "Event E1_child2", + "eventId": "e1_child2_id", + "data": {"data": "E1_child2"}, + "parentEventId": "d1_id", + }, + { + "eventName": "Event E1_child3", + "eventId": "e1_child3_id", + "data": {"data": "E1_child3"}, + "parentEventId": "d1_id", + }, + # + {"eventName": "Root Event 2", "eventId": "root_id2", "data": {"data": [6, 7, 8, 9, 10]}}, + { + "eventName": "Event A2", + "eventId": "a2_id", + "data": {"data": "A2"}, + "parentEventId": "root_id2", + }, + { + "eventName": "Event A2_child1", + "eventId": "a2_child1_id", + "data": {"data": "A2_child1"}, + "parentEventId": "a2_id", + }, + { + "eventName": "Event A2_child2", + "eventId": "a2_child2_id", + "data": {"data": "A2_child2"}, + "parentEventId": "a2_id", + }, + { + "eventName": "Event B2", + "eventId": "b2_id", + "data": {"data": "B2"}, + "parentEventId": "root_id2", + }, + { + "eventName": "Event B2_child1", + "eventId": "b2_child1_id", + "data": {"data": "B2_child1"}, + "parentEventId": "b2_id", + }, + { + "eventName": "Event B2_child2", + "eventId": "b2_child2_id", + "data": {"data": "B2_child2"}, + "parentEventId": "b2_id", + }, + { + "eventName": "Event B2_child3", + "eventId": "b2_child3_id", + "data": {"data": "B2_child3"}, + "parentEventId": "b2_id", + }, + { + "eventName": "Event C2", + "eventId": "c2_id", + "data": {"data": "C2"}, + "parentEventId": "root_id2", + }, + {"eventName": "Event D2", "eventId": "d2_id", "data": {"data": "D2"}, "parentEventId": "c2_id"}, + {"eventName": "Event E2", "eventId": "e2_id", "data": {"data": "E2"}, "parentEventId": "d2_id"}, + { + "eventName": "Event E2_child1", + "eventId": "e2_child1_id", + "data": {"data": "E2_child1"}, + "parentEventId": "e2_id", + }, + { + "eventName": "Event E2_child2", + "eventId": "e2_child2_id", + "data": {"data": "E2_child2"}, + "parentEventId": "e2_id", + }, + { + "eventName": "Event E2_child3", + "eventId": "e2_child3_id", + "data": {"data": "E2_child3"}, + "parentEventId": "e2_id", + }, + # + {"eventName": "Root Event 3", "eventId": "root_id3", "data": {"data": [11, 12]}}, + { + "eventName": "Event A3", + "eventId": "a3_id", + "data": {"data": "A3"}, + "parentEventId": "root_id3", + }, + { + "eventName": "Event A3_child1", + "eventId": "a3_child1_id", + "data": {"data": "A3_child1"}, + "parentEventId": "a3_id", + }, + # + { + "eventName": "Root Event 4", + "eventId": "root_id4", + "data": {"data": [13, 14]}, + "parentEventId": "Unknown", + }, +] + +demo_etc_data_big = [ + {"eventName": "Root Event 0", "eventId": "root_id0", "data": {"data": [13, 11, 53]}}, + { + "eventName": "Event A0", + "eventId": "A0_id", + "data": {"data": [89, 98, 58]}, + "parentEventId": "root_id0", + }, + { + "eventName": "Event A1", + "eventId": "A1_id", + "data": {"data": [40, 40, 61]}, + "parentEventId": "root_id0", + }, + { + "eventName": "Event A1_child0", + "eventId": "A1_child0_id", + "data": {"data": [9, 90, 81]}, + "parentEventId": "A1_id", + }, + { + "eventName": "Event A1_child1", + "eventId": "A1_child1_id", + "data": {"data": [100, 67, 21]}, + "parentEventId": "A1_id", + }, + { + "eventName": "Event A1_child2", + "eventId": "A1_child2_id", + "data": {"data": [77, 83, 55]}, + "parentEventId": "A1_id", + }, + { + "eventName": "Event A2", + "eventId": "A2_id", + "data": {"data": [33, 60, 15]}, + "parentEventId": "root_id0", + }, + { + "eventName": "Event A2_child0", + "eventId": "A2_child0_id", + "data": {"data": [14, 13, 66]}, + "parentEventId": "A2_id", + }, + { + "eventName": "Event A3", + "eventId": "A3_id", + "data": {"data": [19, 1, 17]}, + "parentEventId": "root_id0", + }, + { + "eventName": "Event A3_child0", + "eventId": "A3_child0_id", + "data": {"data": [59, 37, 57]}, + "parentEventId": "A3_id", + }, + { + "eventName": "Event A3_child1", + "eventId": "A3_child1_id", + "data": {"data": [96, 94, 99]}, + "parentEventId": "A3_id", + }, + { + "eventName": "Event A3_child2", + "eventId": "A3_child2_id", + "data": {"data": [88, 1, 96]}, + "parentEventId": "A3_id", + }, + {"eventName": "Root Event 1", "eventId": "root_id1", "data": {"data": [49, 2, 85]}}, + { + "eventName": "Event R0", + "eventId": "R0_id", + "data": {"data": [48, 84, 39]}, + "parentEventId": "root_id1", + }, + {"eventName": "Root Event 2", "eventId": "root_id2", "data": {"data": [99, 82, 93]}}, + { + "eventName": "Event P0", + "eventId": "P0_id", + "data": {"data": [76, 22, 17]}, + "parentEventId": "root_id2", + }, + { + "eventName": "Event P1", + "eventId": "P1_id", + "data": {"data": [90, 7, 3]}, + "parentEventId": "root_id2", + }, + { + "eventName": "Event P1_child0", + "eventId": "P1_child0_id", + "data": {"data": [37, 18, 39]}, + "parentEventId": "P1_id", + }, + { + "eventName": "Event P1_child1", + "eventId": "P1_child1_id", + "data": {"data": [3, 91, 85]}, + "parentEventId": "P1_id", + }, + { + "eventName": "Event P2", + "eventId": "P2_id", + "data": {"data": [44, 42, 56]}, + "parentEventId": "root_id2", + }, + { + "eventName": "Event P3", + "eventId": "P3_id", + "data": {"data": [3, 94, 66]}, + "parentEventId": "root_id2", + }, + {"eventName": "Root Event 3", "eventId": "root_id3", "data": {"data": [44, 89, 9]}}, + { + "eventName": "Event A0", + "eventId": "A0_id", + "data": {"data": [96, 71, 78]}, + "parentEventId": "root_id3", + }, + { + "eventName": "Event A1", + "eventId": "A1_id", + "data": {"data": [20, 24, 9]}, + "parentEventId": "root_id3", + }, + {"eventName": "Root Event 4", "eventId": "root_id4", "data": {"data": [91, 50, 78]}}, + { + "eventName": "Event G0", + "eventId": "G0_id", + "data": {"data": [59, 35, 78]}, + "parentEventId": "root_id4", + }, + { + "eventName": "Event G1", + "eventId": "G1_id", + "data": {"data": [50, 60, 62]}, + "parentEventId": "root_id4", + }, + {"eventName": "Root Event 5", "eventId": "root_id5", "data": {"data": [99, 54, 39]}}, + { + "eventName": "Event U0", + "eventId": "U0_id", + "data": {"data": [73, 42, 95]}, + "parentEventId": "root_id5", + }, + { + "eventName": "Event U0_child0", + "eventId": "U0_child0_id", + "data": {"data": [57, 9, 67]}, + "parentEventId": "U0_id", + }, + { + "eventName": "Event U0_child1", + "eventId": "U0_child1_id", + "data": {"data": [10, 94, 5]}, + "parentEventId": "U0_id", + }, + { + "eventName": "Event U0_child2", + "eventId": "U0_child2_id", + "data": {"data": [86, 13, 36]}, + "parentEventId": "U0_id", + }, + { + "eventName": "Event U1", + "eventId": "U1_id", + "data": {"data": [4, 41, 86]}, + "parentEventId": "root_id5", + }, + { + "eventName": "Event U1_child0", + "eventId": "U1_child0_id", + "data": {"data": [90, 32, 32]}, + "parentEventId": "U1_id", + }, + { + "eventName": "Event U1_child1", + "eventId": "U1_child1_id", + "data": {"data": [21, 42, 97]}, + "parentEventId": "U1_id", + }, + { + "eventName": "Event U1_child2", + "eventId": "U1_child2_id", + "data": {"data": [99, 70, 64]}, + "parentEventId": "U1_id", + }, + {"eventName": "Root Event 6", "eventId": "root_id6", "data": {"data": [87, 53, 32]}}, + { + "eventName": "Event Z0", + "eventId": "Z0_id", + "data": {"data": [76, 97, 68]}, + "parentEventId": "root_id6", + }, + { + "eventName": "Event Z0_child0", + "eventId": "Z0_child0_id", + "data": {"data": [66, 68, 30]}, + "parentEventId": "Z0_id", + }, + {"eventName": "Root Event 7", "eventId": "root_id7", "data": {"data": [65, 4, 4]}}, + { + "eventName": "Event E0", + "eventId": "E0_id", + "data": {"data": [94, 43, 10]}, + "parentEventId": "root_id7", + }, + { + "eventName": "Event E1", + "eventId": "E1_id", + "data": {"data": [58, 22, 50]}, + "parentEventId": "root_id7", + }, + { + "eventName": "Event E2", + "eventId": "E2_id", + "data": {"data": [7, 46, 63]}, + "parentEventId": "root_id7", + }, + { + "eventName": "Event E3", + "eventId": "E3_id", + "data": {"data": [95, 94, 28]}, + "parentEventId": "root_id7", + }, + { + "eventName": "Event E4", + "eventId": "E4_id", + "data": {"data": [53, 66, 27]}, + "parentEventId": "root_id7", + }, + {"eventName": "Root Event 8", "eventId": "root_id8", "data": {"data": [62, 17, 78]}}, + { + "eventName": "Event U0", + "eventId": "U0_id", + "data": {"data": [99, 13, 16]}, + "parentEventId": "root_id8", + }, + { + "eventName": "Event U1", + "eventId": "U1_id", + "data": {"data": [78, 72, 13]}, + "parentEventId": "root_id8", + }, + { + "eventName": "Event U2", + "eventId": "U2_id", + "data": {"data": [45, 88, 43]}, + "parentEventId": "root_id8", + }, + { + "eventName": "Event U2_child0", + "eventId": "U2_child0_id", + "data": {"data": [45, 97, 42]}, + "parentEventId": "U2_id", + }, + { + "eventName": "Event U2_child1", + "eventId": "U2_child1_id", + "data": {"data": [58, 57, 62]}, + "parentEventId": "U2_id", + }, + { + "eventName": "Event U2_child2", + "eventId": "U2_child2_id", + "data": {"data": [60, 30, 6]}, + "parentEventId": "U2_id", + }, + { + "eventName": "Event U3", + "eventId": "U3_id", + "data": {"data": [50, 22, 81]}, + "parentEventId": "root_id8", + }, + { + "eventName": "Event U4", + "eventId": "U4_id", + "data": {"data": [48, 40, 59]}, + "parentEventId": "root_id8", + }, + {"eventName": "Root Event 9", "eventId": "root_id9", "data": {"data": [6, 1, 26]}}, + { + "eventName": "Event U0", + "eventId": "U0_id", + "data": {"data": [47, 21, 84]}, + "parentEventId": "root_id9", + }, + { + "eventName": "Event U1", + "eventId": "U1_id", + "data": {"data": [87, 82, 24]}, + "parentEventId": "root_id9", + }, + { + "eventName": "Event U2", + "eventId": "U2_id", + "data": {"data": [29, 46, 60]}, + "parentEventId": "root_id9", + }, + { + "eventName": "Event U3", + "eventId": "U3_id", + "data": {"data": [66, 98, 34]}, + "parentEventId": "root_id9", + }, + {"eventName": "Root Event 10", "eventId": "root_id10", "data": {"data": [71, 60, 18]}}, + { + "eventName": "Event K0", + "eventId": "K0_id", + "data": {"data": [11, 75, 81]}, + "parentEventId": "root_id10", + }, + {"eventName": "Root Event 11", "eventId": "root_id11", "data": {"data": [82, 16, 9]}}, + { + "eventName": "Event I0", + "eventId": "I0_id", + "data": {"data": [26, 88, 92]}, + "parentEventId": "root_id11", + }, + { + "eventName": "Event I0_child0", + "eventId": "I0_child0_id", + "data": {"data": [32, 42, 18]}, + "parentEventId": "I0_id", + }, + {"eventName": "Root Event 12", "eventId": "root_id12", "data": {"data": [24, 3, 6]}}, + { + "eventName": "Event P0", + "eventId": "P0_id", + "data": {"data": [97, 64, 6]}, + "parentEventId": "root_id12", + }, + { + "eventName": "Event P1", + "eventId": "P1_id", + "data": {"data": [87, 29, 70]}, + "parentEventId": "root_id12", + }, + { + "eventName": "Event P2", + "eventId": "P2_id", + "data": {"data": [89, 95, 66]}, + "parentEventId": "root_id12", + }, + {"eventName": "Root Event 13", "eventId": "root_id13", "data": {"data": [58, 34, 77]}}, + { + "eventName": "Event W0", + "eventId": "W0_id", + "data": {"data": [51, 7, 84]}, + "parentEventId": "root_id13", + }, + { + "eventName": "Event W0_child0", + "eventId": "W0_child0_id", + "data": {"data": [35, 61, 11]}, + "parentEventId": "W0_id", + }, + { + "eventName": "Event W0_child1", + "eventId": "W0_child1_id", + "data": {"data": [24, 94, 11]}, + "parentEventId": "W0_id", + }, + { + "eventName": "Event W0_child2", + "eventId": "W0_child2_id", + "data": {"data": [9, 50, 94]}, + "parentEventId": "W0_id", + }, + { + "eventName": "Event W1", + "eventId": "W1_id", + "data": {"data": [98, 62, 81]}, + "parentEventId": "root_id13", + }, + {"eventName": "Root Event 14", "eventId": "root_id14", "data": {"data": [65, 87, 49]}}, + { + "eventName": "Event L0", + "eventId": "L0_id", + "data": {"data": [98, 41, 36]}, + "parentEventId": "root_id14", + }, + { + "eventName": "Event L1", + "eventId": "L1_id", + "data": {"data": [51, 23, 91]}, + "parentEventId": "root_id14", + }, + { + "eventName": "Event L2", + "eventId": "L2_id", + "data": {"data": [41, 57, 79]}, + "parentEventId": "root_id14", + }, + { + "eventName": "Event L2_child0", + "eventId": "L2_child0_id", + "data": {"data": [18, 93, 59]}, + "parentEventId": "L2_id", + }, + { + "eventName": "Event L3", + "eventId": "L3_id", + "data": {"data": [73, 11, 79]}, + "parentEventId": "root_id14", + }, + { + "eventName": "Event L3_child0", + "eventId": "L3_child0_id", + "data": {"data": [37, 18, 5]}, + "parentEventId": "L3_id", + }, + { + "eventName": "Event L3_child1", + "eventId": "L3_child1_id", + "data": {"data": [5, 100, 66]}, + "parentEventId": "L3_id", + }, + { + "eventName": "Event L3_child2", + "eventId": "L3_child2_id", + "data": {"data": [58, 4, 72]}, + "parentEventId": "L3_id", + }, + {"eventName": "Root Event 15", "eventId": "root_id15", "data": {"data": [50, 59, 14]}}, + { + "eventName": "Event M0", + "eventId": "M0_id", + "data": {"data": [63, 82, 41]}, + "parentEventId": "root_id15", + }, + { + "eventName": "Event M0_child0", + "eventId": "M0_child0_id", + "data": {"data": [3, 29, 80]}, + "parentEventId": "M0_id", + }, + { + "eventName": "Event M1", + "eventId": "M1_id", + "data": {"data": [69, 70, 99]}, + "parentEventId": "root_id15", + }, + { + "eventName": "Event M2", + "eventId": "M2_id", + "data": {"data": [37, 88, 11]}, + "parentEventId": "root_id15", + }, + {"eventName": "Root Event 16", "eventId": "root_id16", "data": {"data": [25, 2, 52]}}, + { + "eventName": "Event C0", + "eventId": "C0_id", + "data": {"data": [44, 66, 81]}, + "parentEventId": "root_id16", + }, + { + "eventName": "Event C1", + "eventId": "C1_id", + "data": {"data": [24, 66, 57]}, + "parentEventId": "root_id16", + }, + { + "eventName": "Event C1_child0", + "eventId": "C1_child0_id", + "data": {"data": [36, 65, 30]}, + "parentEventId": "C1_id", + }, + { + "eventName": "Event C1_child1", + "eventId": "C1_child1_id", + "data": {"data": [16, 60, 76]}, + "parentEventId": "C1_id", + }, + { + "eventName": "Event C1_child2", + "eventId": "C1_child2_id", + "data": {"data": [27, 84, 30]}, + "parentEventId": "C1_id", + }, + { + "eventName": "Event C2", + "eventId": "C2_id", + "data": {"data": [71, 8, 98]}, + "parentEventId": "root_id16", + }, + { + "eventName": "Event C3", + "eventId": "C3_id", + "data": {"data": [59, 90, 22]}, + "parentEventId": "root_id16", + }, + {"eventName": "Root Event 17", "eventId": "root_id17", "data": {"data": [49, 97, 47]}}, + { + "eventName": "Event Q0", + "eventId": "Q0_id", + "data": {"data": [95, 77, 51]}, + "parentEventId": "root_id17", + }, + { + "eventName": "Event Q0_child0", + "eventId": "Q0_child0_id", + "data": {"data": [19, 12, 95]}, + "parentEventId": "Q0_id", + }, + { + "eventName": "Event Q0_child1", + "eventId": "Q0_child1_id", + "data": {"data": [30, 59, 62]}, + "parentEventId": "Q0_id", + }, + { + "eventName": "Event Q0_child2", + "eventId": "Q0_child2_id", + "data": {"data": [64, 75, 60]}, + "parentEventId": "Q0_id", + }, + {"eventName": "Root Event 18", "eventId": "root_id18", "data": {"data": [53, 27, 25]}}, + { + "eventName": "Event B0", + "eventId": "B0_id", + "data": {"data": [22, 73, 6]}, + "parentEventId": "root_id18", + }, + { + "eventName": "Event B1", + "eventId": "B1_id", + "data": {"data": [47, 36, 48]}, + "parentEventId": "root_id18", + }, + { + "eventName": "Event B2", + "eventId": "B2_id", + "data": {"data": [41, 12, 34]}, + "parentEventId": "root_id18", + }, + { + "eventName": "Event B3", + "eventId": "B3_id", + "data": {"data": [80, 65, 60]}, + "parentEventId": "root_id18", + }, + {"eventName": "Root Event 19", "eventId": "root_id19", "data": {"data": [3, 24, 26]}}, + { + "eventName": "Event Q0", + "eventId": "Q0_id", + "data": {"data": [68, 76, 71]}, + "parentEventId": "root_id19", + }, + { + "eventName": "Event Q1", + "eventId": "Q1_id", + "data": {"data": [76, 46, 82]}, + "parentEventId": "root_id19", + }, + {"eventName": "Root Event 20", "eventId": "root_id20", "data": {"data": [42, 80, 58]}}, + { + "eventName": "Event O0", + "eventId": "O0_id", + "data": {"data": [43, 7, 53]}, + "parentEventId": "root_id20", + }, + {"eventName": "Root Event 21", "eventId": "root_id21", "data": {"data": [15, 8, 94]}}, + { + "eventName": "Event K0", + "eventId": "K0_id", + "data": {"data": [99, 21, 39]}, + "parentEventId": "root_id21", + }, + { + "eventName": "Event K1", + "eventId": "K1_id", + "data": {"data": [29, 54, 23]}, + "parentEventId": "root_id21", + }, + { + "eventName": "Event K2", + "eventId": "K2_id", + "data": {"data": [71, 35, 68]}, + "parentEventId": "root_id21", + }, + { + "eventName": "Event K3", + "eventId": "K3_id", + "data": {"data": [57, 82, 76]}, + "parentEventId": "root_id21", + }, + { + "eventName": "Event K3_child0", + "eventId": "K3_child0_id", + "data": {"data": [56, 57, 89]}, + "parentEventId": "K3_id", + }, + { + "eventName": "Event K3_child1", + "eventId": "K3_child1_id", + "data": {"data": [73, 78, 2]}, + "parentEventId": "K3_id", + }, + {"eventName": "Root Event 22", "eventId": "root_id22", "data": {"data": [21, 46, 15]}}, + { + "eventName": "Event S0", + "eventId": "S0_id", + "data": {"data": [97, 12, 89]}, + "parentEventId": "root_id22", + }, + { + "eventName": "Event S1", + "eventId": "S1_id", + "data": {"data": [37, 3, 57]}, + "parentEventId": "root_id22", + }, + { + "eventName": "Event S2", + "eventId": "S2_id", + "data": {"data": [46, 98, 70]}, + "parentEventId": "root_id22", + }, + { + "eventName": "Event S3", + "eventId": "S3_id", + "data": {"data": [15, 75, 29]}, + "parentEventId": "root_id22", + }, + { + "eventName": "Event S4", + "eventId": "S4_id", + "data": {"data": [45, 34, 70]}, + "parentEventId": "root_id22", + }, + {"eventName": "Root Event 23", "eventId": "root_id23", "data": {"data": [55, 68, 78]}}, + { + "eventName": "Event J0", + "eventId": "J0_id", + "data": {"data": [33, 22, 19]}, + "parentEventId": "root_id23", + }, + { + "eventName": "Event J1", + "eventId": "J1_id", + "data": {"data": [3, 20, 94]}, + "parentEventId": "root_id23", + }, + { + "eventName": "Event J2", + "eventId": "J2_id", + "data": {"data": [20, 50, 70]}, + "parentEventId": "root_id23", + }, + {"eventName": "Root Event 24", "eventId": "root_id24", "data": {"data": [70, 60, 18]}}, + { + "eventName": "Event Y0", + "eventId": "Y0_id", + "data": {"data": [41, 22, 73]}, + "parentEventId": "root_id24", + }, + {"eventName": "Root Event 25", "eventId": "root_id25", "data": {"data": [48, 4, 70]}}, + { + "eventName": "Event G0", + "eventId": "G0_id", + "data": {"data": [45, 95, 21]}, + "parentEventId": "root_id25", + }, + { + "eventName": "Event G1", + "eventId": "G1_id", + "data": {"data": [1, 65, 6]}, + "parentEventId": "root_id25", + }, + { + "eventName": "Event G2", + "eventId": "G2_id", + "data": {"data": [98, 95, 98]}, + "parentEventId": "root_id25", + }, + {"eventName": "Root Event 26", "eventId": "root_id26", "data": {"data": [19, 26, 10]}}, + { + "eventName": "Event V0", + "eventId": "V0_id", + "data": {"data": [57, 97, 45]}, + "parentEventId": "root_id26", + }, + { + "eventName": "Event V1", + "eventId": "V1_id", + "data": {"data": [47, 28, 11]}, + "parentEventId": "root_id26", + }, + { + "eventName": "Event V1_child0", + "eventId": "V1_child0_id", + "data": {"data": [7, 8, 74]}, + "parentEventId": "V1_id", + }, + { + "eventName": "Event V2", + "eventId": "V2_id", + "data": {"data": [4, 95, 10]}, + "parentEventId": "root_id26", + }, + { + "eventName": "Event V3", + "eventId": "V3_id", + "data": {"data": [91, 19, 69]}, + "parentEventId": "root_id26", + }, + { + "eventName": "Event V3_child0", + "eventId": "V3_child0_id", + "data": {"data": [44, 7, 41]}, + "parentEventId": "V3_id", + }, + { + "eventName": "Event V3_child1", + "eventId": "V3_child1_id", + "data": {"data": [72, 64, 12]}, + "parentEventId": "V3_id", + }, + { + "eventName": "Event V3_child2", + "eventId": "V3_child2_id", + "data": {"data": [88, 73, 13]}, + "parentEventId": "V3_id", + }, + { + "eventName": "Event V4", + "eventId": "V4_id", + "data": {"data": [71, 29, 85]}, + "parentEventId": "root_id26", + }, + {"eventName": "Root Event 27", "eventId": "root_id27", "data": {"data": [37, 13, 80]}}, + { + "eventName": "Event X0", + "eventId": "X0_id", + "data": {"data": [20, 39, 65]}, + "parentEventId": "root_id27", + }, + { + "eventName": "Event X1", + "eventId": "X1_id", + "data": {"data": [49, 40, 5]}, + "parentEventId": "root_id27", + }, + { + "eventName": "Event X2", + "eventId": "X2_id", + "data": {"data": [94, 90, 68]}, + "parentEventId": "root_id27", + }, + {"eventName": "Root Event 28", "eventId": "root_id28", "data": {"data": [90, 15, 14]}}, + { + "eventName": "Event Z0", + "eventId": "Z0_id", + "data": {"data": [69, 56, 5]}, + "parentEventId": "root_id28", + }, + { + "eventName": "Event Z1", + "eventId": "Z1_id", + "data": {"data": [29, 16, 24]}, + "parentEventId": "root_id28", + }, + { + "eventName": "Event Z1_child0", + "eventId": "Z1_child0_id", + "data": {"data": [3, 76, 91]}, + "parentEventId": "Z1_id", + }, + { + "eventName": "Event Z1_child1", + "eventId": "Z1_child1_id", + "data": {"data": [52, 95, 52]}, + "parentEventId": "Z1_id", + }, + { + "eventName": "Event Z2", + "eventId": "Z2_id", + "data": {"data": [77, 56, 1]}, + "parentEventId": "root_id28", + }, + { + "eventName": "Event Z3", + "eventId": "Z3_id", + "data": {"data": [41, 98, 90]}, + "parentEventId": "root_id28", + }, + {"eventName": "Root Event 29", "eventId": "root_id29", "data": {"data": [86, 27, 42]}}, + { + "eventName": "Event N0", + "eventId": "N0_id", + "data": {"data": [48, 83, 81]}, + "parentEventId": "root_id29", + }, + { + "eventName": "Event N0_child0", + "eventId": "N0_child0_id", + "data": {"data": [29, 94, 32]}, + "parentEventId": "N0_id", + }, + { + "eventName": "Event N1", + "eventId": "N1_id", + "data": {"data": [2, 55, 22]}, + "parentEventId": "root_id29", + }, + {"eventName": "Root Event 30", "eventId": "root_id30", "data": {"data": [38, 20, 65]}}, + { + "eventName": "Event W0", + "eventId": "W0_id", + "data": {"data": [62, 56, 34]}, + "parentEventId": "root_id30", + }, + { + "eventName": "Event W1", + "eventId": "W1_id", + "data": {"data": [83, 1, 68]}, + "parentEventId": "root_id30", + }, + { + "eventName": "Event W2", + "eventId": "W2_id", + "data": {"data": [61, 7, 19]}, + "parentEventId": "root_id30", + }, + { + "eventName": "Event W3", + "eventId": "W3_id", + "data": {"data": [77, 30, 87]}, + "parentEventId": "root_id30", + }, + { + "eventName": "Event W4", + "eventId": "W4_id", + "data": {"data": [92, 41, 1]}, + "parentEventId": "root_id30", + }, + {"eventName": "Root Event 31", "eventId": "root_id31", "data": {"data": [59, 88, 13]}}, + { + "eventName": "Event S0", + "eventId": "S0_id", + "data": {"data": [21, 80, 4]}, + "parentEventId": "root_id31", + }, + { + "eventName": "Event S1", + "eventId": "S1_id", + "data": {"data": [46, 95, 67]}, + "parentEventId": "root_id31", + }, + { + "eventName": "Event S2", + "eventId": "S2_id", + "data": {"data": [67, 79, 86]}, + "parentEventId": "root_id31", + }, + { + "eventName": "Event S3", + "eventId": "S3_id", + "data": {"data": [23, 34, 23]}, + "parentEventId": "root_id31", + }, + {"eventName": "Root Event 32", "eventId": "root_id32", "data": {"data": [10, 66, 7]}}, + { + "eventName": "Event Q0", + "eventId": "Q0_id", + "data": {"data": [51, 36, 100]}, + "parentEventId": "root_id32", + }, + { + "eventName": "Event Q1", + "eventId": "Q1_id", + "data": {"data": [67, 25, 22]}, + "parentEventId": "root_id32", + }, + {"eventName": "Root Event 33", "eventId": "root_id33", "data": {"data": [87, 53, 58]}}, + { + "eventName": "Event T0", + "eventId": "T0_id", + "data": {"data": [31, 51, 86]}, + "parentEventId": "root_id33", + }, + { + "eventName": "Event T0_child0", + "eventId": "T0_child0_id", + "data": {"data": [65, 47, 13]}, + "parentEventId": "T0_id", + }, + { + "eventName": "Event T0_child1", + "eventId": "T0_child1_id", + "data": {"data": [90, 75, 35]}, + "parentEventId": "T0_id", + }, + {"eventName": "Root Event 34", "eventId": "root_id34", "data": {"data": [81, 25, 83]}}, + { + "eventName": "Event N0", + "eventId": "N0_id", + "data": {"data": [25, 66, 64]}, + "parentEventId": "root_id34", + }, + { + "eventName": "Event N1", + "eventId": "N1_id", + "data": {"data": [91, 34, 99]}, + "parentEventId": "root_id34", + }, + { + "eventName": "Event N2", + "eventId": "N2_id", + "data": {"data": [5, 18, 35]}, + "parentEventId": "root_id34", + }, + { + "eventName": "Event N2_child0", + "eventId": "N2_child0_id", + "data": {"data": [80, 97, 3]}, + "parentEventId": "N2_id", + }, + { + "eventName": "Event N2_child1", + "eventId": "N2_child1_id", + "data": {"data": [77, 88, 83]}, + "parentEventId": "N2_id", + }, + { + "eventName": "Event N2_child2", + "eventId": "N2_child2_id", + "data": {"data": [3, 69, 7]}, + "parentEventId": "N2_id", + }, + {"eventName": "Root Event 35", "eventId": "root_id35", "data": {"data": [57, 48, 93]}}, + { + "eventName": "Event D0", + "eventId": "D0_id", + "data": {"data": [76, 55, 49]}, + "parentEventId": "root_id35", + }, + { + "eventName": "Event D0_child0", + "eventId": "D0_child0_id", + "data": {"data": [69, 22, 55]}, + "parentEventId": "D0_id", + }, + { + "eventName": "Event D0_child1", + "eventId": "D0_child1_id", + "data": {"data": [63, 51, 69]}, + "parentEventId": "D0_id", + }, + { + "eventName": "Event D1", + "eventId": "D1_id", + "data": {"data": [21, 33, 90]}, + "parentEventId": "root_id35", + }, + { + "eventName": "Event D2", + "eventId": "D2_id", + "data": {"data": [41, 22, 65]}, + "parentEventId": "root_id35", + }, + { + "eventName": "Event D3", + "eventId": "D3_id", + "data": {"data": [11, 78, 68]}, + "parentEventId": "root_id35", + }, + { + "eventName": "Event D4", + "eventId": "D4_id", + "data": {"data": [87, 42, 15]}, + "parentEventId": "root_id35", + }, + { + "eventName": "Event D4_child0", + "eventId": "D4_child0_id", + "data": {"data": [94, 65, 18]}, + "parentEventId": "D4_id", + }, + { + "eventName": "Event D4_child1", + "eventId": "D4_child1_id", + "data": {"data": [15, 91, 80]}, + "parentEventId": "D4_id", + }, + { + "eventName": "Event D4_child2", + "eventId": "D4_child2_id", + "data": {"data": [19, 54, 62]}, + "parentEventId": "D4_id", + }, + {"eventName": "Root Event 36", "eventId": "root_id36", "data": {"data": [53, 7, 94]}}, + { + "eventName": "Event E0", + "eventId": "E0_id", + "data": {"data": [14, 44, 49]}, + "parentEventId": "root_id36", + }, + { + "eventName": "Event E1", + "eventId": "E1_id", + "data": {"data": [20, 27, 54]}, + "parentEventId": "root_id36", + }, + { + "eventName": "Event E2", + "eventId": "E2_id", + "data": {"data": [93, 9, 21]}, + "parentEventId": "root_id36", + }, + {"eventName": "Root Event 37", "eventId": "root_id37", "data": {"data": [69, 7, 55]}}, + { + "eventName": "Event L0", + "eventId": "L0_id", + "data": {"data": [12, 79, 37]}, + "parentEventId": "root_id37", + }, + { + "eventName": "Event L1", + "eventId": "L1_id", + "data": {"data": [98, 19, 71]}, + "parentEventId": "root_id37", + }, + { + "eventName": "Event L2", + "eventId": "L2_id", + "data": {"data": [68, 43, 70]}, + "parentEventId": "root_id37", + }, + {"eventName": "Root Event 38", "eventId": "root_id38", "data": {"data": [88, 3, 31]}}, + { + "eventName": "Event Y0", + "eventId": "Y0_id", + "data": {"data": [86, 33, 63]}, + "parentEventId": "root_id38", + }, + { + "eventName": "Event Y1", + "eventId": "Y1_id", + "data": {"data": [8, 8, 87]}, + "parentEventId": "root_id38", + }, + {"eventName": "Root Event 39", "eventId": "root_id39", "data": {"data": [78, 79, 17]}}, + { + "eventName": "Event U0", + "eventId": "U0_id", + "data": {"data": [98, 40, 64]}, + "parentEventId": "root_id39", + }, + { + "eventName": "Event U1", + "eventId": "U1_id", + "data": {"data": [28, 43, 100]}, + "parentEventId": "root_id39", + }, + {"eventName": "Root Event 40", "eventId": "root_id40", "data": {"data": [73, 21, 8]}}, + { + "eventName": "Event A0", + "eventId": "A0_id", + "data": {"data": [59, 94, 74]}, + "parentEventId": "root_id40", + }, + { + "eventName": "Event A1", + "eventId": "A1_id", + "data": {"data": [14, 36, 76]}, + "parentEventId": "root_id40", + }, + { + "eventName": "Event A2", + "eventId": "A2_id", + "data": {"data": [81, 2, 92]}, + "parentEventId": "root_id40", + }, + { + "eventName": "Event A3", + "eventId": "A3_id", + "data": {"data": [42, 5, 68]}, + "parentEventId": "root_id40", + }, + { + "eventName": "Event A4", + "eventId": "A4_id", + "data": {"data": [28, 33, 27]}, + "parentEventId": "root_id40", + }, + {"eventName": "Root Event 41", "eventId": "root_id41", "data": {"data": [75, 37, 33]}}, + { + "eventName": "Event V0", + "eventId": "V0_id", + "data": {"data": [97, 78, 70]}, + "parentEventId": "root_id41", + }, + { + "eventName": "Event V1", + "eventId": "V1_id", + "data": {"data": [53, 60, 27]}, + "parentEventId": "root_id41", + }, + { + "eventName": "Event V2", + "eventId": "V2_id", + "data": {"data": [48, 19, 19]}, + "parentEventId": "root_id41", + }, + {"eventName": "Root Event 42", "eventId": "root_id42", "data": {"data": [19, 89, 25]}}, + { + "eventName": "Event O0", + "eventId": "O0_id", + "data": {"data": [53, 99, 11]}, + "parentEventId": "root_id42", + }, + { + "eventName": "Event O1", + "eventId": "O1_id", + "data": {"data": [44, 25, 54]}, + "parentEventId": "root_id42", + }, + { + "eventName": "Event O2", + "eventId": "O2_id", + "data": {"data": [7, 30, 3]}, + "parentEventId": "root_id42", + }, + { + "eventName": "Event O2_child0", + "eventId": "O2_child0_id", + "data": {"data": [96, 75, 79]}, + "parentEventId": "O2_id", + }, + { + "eventName": "Event O2_child1", + "eventId": "O2_child1_id", + "data": {"data": [90, 48, 97]}, + "parentEventId": "O2_id", + }, + { + "eventName": "Event O2_child2", + "eventId": "O2_child2_id", + "data": {"data": [77, 15, 23]}, + "parentEventId": "O2_id", + }, + { + "eventName": "Event O3", + "eventId": "O3_id", + "data": {"data": [2, 98, 100]}, + "parentEventId": "root_id42", + }, + { + "eventName": "Event O4", + "eventId": "O4_id", + "data": {"data": [80, 9, 79]}, + "parentEventId": "root_id42", + }, + {"eventName": "Root Event 43", "eventId": "root_id43", "data": {"data": [42, 70, 29]}}, + { + "eventName": "Event C0", + "eventId": "C0_id", + "data": {"data": [44, 10, 44]}, + "parentEventId": "root_id43", + }, + {"eventName": "Root Event 44", "eventId": "root_id44", "data": {"data": [44, 13, 74]}}, + { + "eventName": "Event M0", + "eventId": "M0_id", + "data": {"data": [81, 16, 73]}, + "parentEventId": "root_id44", + }, + {"eventName": "Root Event 45", "eventId": "root_id45", "data": {"data": [98, 2, 63]}}, + { + "eventName": "Event K0", + "eventId": "K0_id", + "data": {"data": [94, 54, 96]}, + "parentEventId": "root_id45", + }, + { + "eventName": "Event K1", + "eventId": "K1_id", + "data": {"data": [91, 76, 28]}, + "parentEventId": "root_id45", + }, + { + "eventName": "Event K2", + "eventId": "K2_id", + "data": {"data": [97, 20, 55]}, + "parentEventId": "root_id45", + }, + { + "eventName": "Event K3", + "eventId": "K3_id", + "data": {"data": [87, 33, 29]}, + "parentEventId": "root_id45", + }, + {"eventName": "Root Event 46", "eventId": "root_id46", "data": {"data": [50, 8, 15]}}, + { + "eventName": "Event V0", + "eventId": "V0_id", + "data": {"data": [53, 25, 26]}, + "parentEventId": "root_id46", + }, + { + "eventName": "Event V1", + "eventId": "V1_id", + "data": {"data": [38, 5, 54]}, + "parentEventId": "root_id46", + }, + { + "eventName": "Event V2", + "eventId": "V2_id", + "data": {"data": [30, 56, 24]}, + "parentEventId": "root_id46", + }, + { + "eventName": "Event V3", + "eventId": "V3_id", + "data": {"data": [64, 40, 78]}, + "parentEventId": "root_id46", + }, + {"eventName": "Root Event 47", "eventId": "root_id47", "data": {"data": [39, 84, 92]}}, + { + "eventName": "Event V0", + "eventId": "V0_id", + "data": {"data": [29, 69, 47]}, + "parentEventId": "root_id47", + }, + { + "eventName": "Event V1", + "eventId": "V1_id", + "data": {"data": [77, 100, 82]}, + "parentEventId": "root_id47", + }, + { + "eventName": "Event V2", + "eventId": "V2_id", + "data": {"data": [1, 83, 69]}, + "parentEventId": "root_id47", + }, + { + "eventName": "Event V3", + "eventId": "V3_id", + "data": {"data": [26, 49, 17]}, + "parentEventId": "root_id47", + }, + {"eventName": "Root Event 48", "eventId": "root_id48", "data": {"data": [100, 53, 75]}}, + { + "eventName": "Event H0", + "eventId": "H0_id", + "data": {"data": [75, 36, 52]}, + "parentEventId": "root_id48", + }, + { + "eventName": "Event H1", + "eventId": "H1_id", + "data": {"data": [34, 3, 64]}, + "parentEventId": "root_id48", + }, + { + "eventName": "Event H2", + "eventId": "H2_id", + "data": {"data": [92, 51, 16]}, + "parentEventId": "root_id48", + }, + {"eventName": "Root Event 49", "eventId": "root_id49", "data": {"data": [13, 9, 79]}}, + { + "eventName": "Event D0", + "eventId": "D0_id", + "data": {"data": [69, 79, 20]}, + "parentEventId": "root_id49", + }, + { + "eventName": "Event D1", + "eventId": "D1_id", + "data": {"data": [17, 36, 74]}, + "parentEventId": "root_id49", + }, + { + "eventName": "Event D2", + "eventId": "D2_id", + "data": {"data": [91, 36, 52]}, + "parentEventId": "root_id49", + }, + { + "eventName": "Event D3", + "eventId": "D3_id", + "data": {"data": [78, 74, 58]}, + "parentEventId": "root_id49", + }, + { + "eventName": "Event D4", + "eventId": "D4_id", + "data": {"data": [47, 73, 10]}, + "parentEventId": "root_id49", + }, + {"eventName": "Root Event 50", "eventId": "root_id50", "data": {"data": [26, 2, 22]}}, + { + "eventName": "Event Q0", + "eventId": "Q0_id", + "data": {"data": [14, 100, 76]}, + "parentEventId": "root_id50", + }, + { + "eventName": "Event Q1", + "eventId": "Q1_id", + "data": {"data": [75, 23, 65]}, + "parentEventId": "root_id50", + }, + { + "eventName": "Event Q2", + "eventId": "Q2_id", + "data": {"data": [78, 35, 86]}, + "parentEventId": "root_id50", + }, + { + "eventName": "Event Q2_child0", + "eventId": "Q2_child0_id", + "data": {"data": [15, 52, 24]}, + "parentEventId": "Q2_id", + }, + {"eventName": "Root Event 51", "eventId": "root_id51", "data": {"data": [10, 83, 99]}}, + { + "eventName": "Event A0", + "eventId": "A0_id", + "data": {"data": [20, 60, 90]}, + "parentEventId": "root_id51", + }, + { + "eventName": "Event A1", + "eventId": "A1_id", + "data": {"data": [10, 60, 80]}, + "parentEventId": "root_id51", + }, + { + "eventName": "Event A2", + "eventId": "A2_id", + "data": {"data": [28, 80, 25]}, + "parentEventId": "root_id51", + }, + {"eventName": "Root Event 52", "eventId": "root_id52", "data": {"data": [4, 2, 82]}}, + { + "eventName": "Event O0", + "eventId": "O0_id", + "data": {"data": [86, 88, 9]}, + "parentEventId": "root_id52", + }, + { + "eventName": "Event O1", + "eventId": "O1_id", + "data": {"data": [83, 97, 4]}, + "parentEventId": "root_id52", + }, + { + "eventName": "Event O2", + "eventId": "O2_id", + "data": {"data": [60, 55, 75]}, + "parentEventId": "root_id52", + }, + {"eventName": "Root Event 53", "eventId": "root_id53", "data": {"data": [15, 51, 21]}}, + { + "eventName": "Event C0", + "eventId": "C0_id", + "data": {"data": [99, 17, 26]}, + "parentEventId": "root_id53", + }, + { + "eventName": "Event C1", + "eventId": "C1_id", + "data": {"data": [12, 13, 16]}, + "parentEventId": "root_id53", + }, + {"eventName": "Root Event 54", "eventId": "root_id54", "data": {"data": [1, 56, 65]}}, + { + "eventName": "Event K0", + "eventId": "K0_id", + "data": {"data": [59, 59, 54]}, + "parentEventId": "root_id54", + }, + { + "eventName": "Event K1", + "eventId": "K1_id", + "data": {"data": [78, 38, 76]}, + "parentEventId": "root_id54", + }, + { + "eventName": "Event K2", + "eventId": "K2_id", + "data": {"data": [100, 69, 38]}, + "parentEventId": "root_id54", + }, + { + "eventName": "Event K3", + "eventId": "K3_id", + "data": {"data": [83, 44, 19]}, + "parentEventId": "root_id54", + }, + {"eventName": "Root Event 55", "eventId": "root_id55", "data": {"data": [55, 80, 5]}}, + { + "eventName": "Event I0", + "eventId": "I0_id", + "data": {"data": [69, 50, 94]}, + "parentEventId": "root_id55", + }, + {"eventName": "Root Event 56", "eventId": "root_id56", "data": {"data": [4, 32, 74]}}, + { + "eventName": "Event F0", + "eventId": "F0_id", + "data": {"data": [49, 21, 23]}, + "parentEventId": "root_id56", + }, + { + "eventName": "Event F1", + "eventId": "F1_id", + "data": {"data": [79, 1, 40]}, + "parentEventId": "root_id56", + }, + { + "eventName": "Event F2", + "eventId": "F2_id", + "data": {"data": [93, 71, 40]}, + "parentEventId": "root_id56", + }, + {"eventName": "Root Event 57", "eventId": "root_id57", "data": {"data": [57, 43, 25]}}, + { + "eventName": "Event L0", + "eventId": "L0_id", + "data": {"data": [67, 47, 62]}, + "parentEventId": "root_id57", + }, + { + "eventName": "Event L1", + "eventId": "L1_id", + "data": {"data": [33, 70, 43]}, + "parentEventId": "root_id57", + }, + { + "eventName": "Event L2", + "eventId": "L2_id", + "data": {"data": [3, 93, 5]}, + "parentEventId": "root_id57", + }, + { + "eventName": "Event L3", + "eventId": "L3_id", + "data": {"data": [1, 55, 6]}, + "parentEventId": "root_id57", + }, + {"eventName": "Root Event 58", "eventId": "root_id58", "data": {"data": [83, 28, 45]}}, + { + "eventName": "Event A0", + "eventId": "A0_id", + "data": {"data": [21, 58, 34]}, + "parentEventId": "root_id58", + }, + { + "eventName": "Event A1", + "eventId": "A1_id", + "data": {"data": [40, 88, 12]}, + "parentEventId": "root_id58", + }, + { + "eventName": "Event A2", + "eventId": "A2_id", + "data": {"data": [85, 1, 63]}, + "parentEventId": "root_id58", + }, + { + "eventName": "Event A3", + "eventId": "A3_id", + "data": {"data": [25, 35, 92]}, + "parentEventId": "root_id58", + }, + {"eventName": "Root Event 59", "eventId": "root_id59", "data": {"data": [36, 80, 6]}}, + { + "eventName": "Event U0", + "eventId": "U0_id", + "data": {"data": [58, 40, 6]}, + "parentEventId": "root_id59", + }, + {"eventName": "Root Event 60", "eventId": "root_id60", "data": {"data": [50, 51, 75]}}, + { + "eventName": "Event J0", + "eventId": "J0_id", + "data": {"data": [51, 30, 58]}, + "parentEventId": "root_id60", + }, + {"eventName": "Root Event 61", "eventId": "root_id61", "data": {"data": [2, 40, 21]}}, + { + "eventName": "Event X0", + "eventId": "X0_id", + "data": {"data": [36, 15, 28]}, + "parentEventId": "root_id61", + }, + { + "eventName": "Event X1", + "eventId": "X1_id", + "data": {"data": [78, 72, 57]}, + "parentEventId": "root_id61", + }, + {"eventName": "Root Event 62", "eventId": "root_id62", "data": {"data": [22, 72, 80]}}, + { + "eventName": "Event K0", + "eventId": "K0_id", + "data": {"data": [10, 93, 74]}, + "parentEventId": "root_id62", + }, + { + "eventName": "Event K1", + "eventId": "K1_id", + "data": {"data": [50, 81, 21]}, + "parentEventId": "root_id62", + }, + { + "eventName": "Event K2", + "eventId": "K2_id", + "data": {"data": [18, 62, 38]}, + "parentEventId": "root_id62", + }, + {"eventName": "Root Event 63", "eventId": "root_id63", "data": {"data": [53, 96, 46]}}, + { + "eventName": "Event M0", + "eventId": "M0_id", + "data": {"data": [70, 95, 41]}, + "parentEventId": "root_id63", + }, + { + "eventName": "Event M1", + "eventId": "M1_id", + "data": {"data": [13, 26, 97]}, + "parentEventId": "root_id63", + }, + { + "eventName": "Event M2", + "eventId": "M2_id", + "data": {"data": [92, 10, 8]}, + "parentEventId": "root_id63", + }, + { + "eventName": "Event M3", + "eventId": "M3_id", + "data": {"data": [40, 37, 31]}, + "parentEventId": "root_id63", + }, + { + "eventName": "Event M4", + "eventId": "M4_id", + "data": {"data": [7, 13, 37]}, + "parentEventId": "root_id63", + }, + {"eventName": "Root Event 64", "eventId": "root_id64", "data": {"data": [79, 94, 67]}}, + { + "eventName": "Event A0", + "eventId": "A0_id", + "data": {"data": [89, 2, 41]}, + "parentEventId": "root_id64", + }, + { + "eventName": "Event A1", + "eventId": "A1_id", + "data": {"data": [61, 16, 82]}, + "parentEventId": "root_id64", + }, + { + "eventName": "Event A2", + "eventId": "A2_id", + "data": {"data": [87, 19, 85]}, + "parentEventId": "root_id64", + }, + { + "eventName": "Event A3", + "eventId": "A3_id", + "data": {"data": [99, 76, 86]}, + "parentEventId": "root_id64", + }, + {"eventName": "Root Event 65", "eventId": "root_id65", "data": {"data": [29, 17, 45]}}, + { + "eventName": "Event W0", + "eventId": "W0_id", + "data": {"data": [7, 86, 5]}, + "parentEventId": "root_id65", + }, + { + "eventName": "Event W1", + "eventId": "W1_id", + "data": {"data": [66, 74, 53]}, + "parentEventId": "root_id65", + }, + { + "eventName": "Event W2", + "eventId": "W2_id", + "data": {"data": [41, 45, 57]}, + "parentEventId": "root_id65", + }, + { + "eventName": "Event W3", + "eventId": "W3_id", + "data": {"data": [22, 37, 10]}, + "parentEventId": "root_id65", + }, + { + "eventName": "Event W4", + "eventId": "W4_id", + "data": {"data": [96, 4, 30]}, + "parentEventId": "root_id65", + }, + {"eventName": "Root Event 66", "eventId": "root_id66", "data": {"data": [63, 66, 1]}}, + { + "eventName": "Event U0", + "eventId": "U0_id", + "data": {"data": [92, 3, 39]}, + "parentEventId": "root_id66", + }, + { + "eventName": "Event U1", + "eventId": "U1_id", + "data": {"data": [37, 97, 64]}, + "parentEventId": "root_id66", + }, + { + "eventName": "Event U2", + "eventId": "U2_id", + "data": {"data": [20, 86, 49]}, + "parentEventId": "root_id66", + }, + { + "eventName": "Event U3", + "eventId": "U3_id", + "data": {"data": [44, 24, 14]}, + "parentEventId": "root_id66", + }, + { + "eventName": "Event U4", + "eventId": "U4_id", + "data": {"data": [93, 1, 29]}, + "parentEventId": "root_id66", + }, + {"eventName": "Root Event 67", "eventId": "root_id67", "data": {"data": [95, 28, 40]}}, + { + "eventName": "Event R0", + "eventId": "R0_id", + "data": {"data": [53, 12, 73]}, + "parentEventId": "root_id67", + }, + { + "eventName": "Event R1", + "eventId": "R1_id", + "data": {"data": [95, 24, 65]}, + "parentEventId": "root_id67", + }, + { + "eventName": "Event R2", + "eventId": "R2_id", + "data": {"data": [18, 13, 1]}, + "parentEventId": "root_id67", + }, + {"eventName": "Root Event 68", "eventId": "root_id68", "data": {"data": [33, 21, 79]}}, + { + "eventName": "Event C0", + "eventId": "C0_id", + "data": {"data": [67, 60, 61]}, + "parentEventId": "root_id68", + }, + {"eventName": "Root Event 69", "eventId": "root_id69", "data": {"data": [31, 5, 15]}}, + { + "eventName": "Event T0", + "eventId": "T0_id", + "data": {"data": [80, 79, 26]}, + "parentEventId": "root_id69", + }, + { + "eventName": "Event T1", + "eventId": "T1_id", + "data": {"data": [56, 4, 19]}, + "parentEventId": "root_id69", + }, + { + "eventName": "Event T2", + "eventId": "T2_id", + "data": {"data": [27, 79, 31]}, + "parentEventId": "root_id69", + }, + { + "eventName": "Event T3", + "eventId": "T3_id", + "data": {"data": [20, 100, 51]}, + "parentEventId": "root_id69", + }, + {"eventName": "Root Event 70", "eventId": "root_id70", "data": {"data": [74, 10, 70]}}, + { + "eventName": "Event D0", + "eventId": "D0_id", + "data": {"data": [32, 21, 92]}, + "parentEventId": "root_id70", + }, + {"eventName": "Root Event 71", "eventId": "root_id71", "data": {"data": [57, 62, 59]}}, + { + "eventName": "Event T0", + "eventId": "T0_id", + "data": {"data": [36, 93, 53]}, + "parentEventId": "root_id71", + }, + { + "eventName": "Event T1", + "eventId": "T1_id", + "data": {"data": [51, 6, 28]}, + "parentEventId": "root_id71", + }, + { + "eventName": "Event T2", + "eventId": "T2_id", + "data": {"data": [28, 92, 8]}, + "parentEventId": "root_id71", + }, + {"eventName": "Root Event 72", "eventId": "root_id72", "data": {"data": [42, 11, 23]}}, + { + "eventName": "Event C0", + "eventId": "C0_id", + "data": {"data": [88, 65, 27]}, + "parentEventId": "root_id72", + }, + { + "eventName": "Event C1", + "eventId": "C1_id", + "data": {"data": [79, 100, 72]}, + "parentEventId": "root_id72", + }, + { + "eventName": "Event C2", + "eventId": "C2_id", + "data": {"data": [39, 64, 18]}, + "parentEventId": "root_id72", + }, + {"eventName": "Root Event 73", "eventId": "root_id73", "data": {"data": [36, 34, 83]}}, + { + "eventName": "Event Z0", + "eventId": "Z0_id", + "data": {"data": [1, 7, 71]}, + "parentEventId": "root_id73", + }, + { + "eventName": "Event Z1", + "eventId": "Z1_id", + "data": {"data": [61, 51, 34]}, + "parentEventId": "root_id73", + }, + {"eventName": "Root Event 74", "eventId": "root_id74", "data": {"data": [54, 61, 53]}}, + { + "eventName": "Event W0", + "eventId": "W0_id", + "data": {"data": [31, 2, 58]}, + "parentEventId": "root_id74", + }, + { + "eventName": "Event W1", + "eventId": "W1_id", + "data": {"data": [83, 16, 95]}, + "parentEventId": "root_id74", + }, + { + "eventName": "Event W2", + "eventId": "W2_id", + "data": {"data": [96, 75, 59]}, + "parentEventId": "root_id74", + }, + { + "eventName": "Event W3", + "eventId": "W3_id", + "data": {"data": [19, 30, 67]}, + "parentEventId": "root_id74", + }, + {"eventName": "Root Event 75", "eventId": "root_id75", "data": {"data": [75, 23, 77]}}, + { + "eventName": "Event K0", + "eventId": "K0_id", + "data": {"data": [91, 86, 97]}, + "parentEventId": "root_id75", + }, + {"eventName": "Root Event 76", "eventId": "root_id76", "data": {"data": [84, 37, 52]}}, + { + "eventName": "Event B0", + "eventId": "B0_id", + "data": {"data": [78, 42, 58]}, + "parentEventId": "root_id76", + }, + {"eventName": "Root Event 77", "eventId": "root_id77", "data": {"data": [80, 25, 17]}}, + { + "eventName": "Event E0", + "eventId": "E0_id", + "data": {"data": [4, 36, 90]}, + "parentEventId": "root_id77", + }, + { + "eventName": "Event E1", + "eventId": "E1_id", + "data": {"data": [97, 25, 77]}, + "parentEventId": "root_id77", + }, + { + "eventName": "Event E2", + "eventId": "E2_id", + "data": {"data": [42, 54, 73]}, + "parentEventId": "root_id77", + }, + {"eventName": "Root Event 78", "eventId": "root_id78", "data": {"data": [73, 40, 24]}}, + { + "eventName": "Event Z0", + "eventId": "Z0_id", + "data": {"data": [32, 77, 83]}, + "parentEventId": "root_id78", + }, + { + "eventName": "Event Z1", + "eventId": "Z1_id", + "data": {"data": [91, 92, 4]}, + "parentEventId": "root_id78", + }, + { + "eventName": "Event Z2", + "eventId": "Z2_id", + "data": {"data": [21, 17, 49]}, + "parentEventId": "root_id78", + }, + { + "eventName": "Event Z3", + "eventId": "Z3_id", + "data": {"data": [16, 90, 42]}, + "parentEventId": "root_id78", + }, + { + "eventName": "Event Z4", + "eventId": "Z4_id", + "data": {"data": [43, 74, 23]}, + "parentEventId": "root_id78", + }, + {"eventName": "Root Event 79", "eventId": "root_id79", "data": {"data": [42, 51, 22]}}, + { + "eventName": "Event S0", + "eventId": "S0_id", + "data": {"data": [11, 45, 74]}, + "parentEventId": "root_id79", + }, + { + "eventName": "Event S1", + "eventId": "S1_id", + "data": {"data": [5, 67, 21]}, + "parentEventId": "root_id79", + }, + { + "eventName": "Event S2", + "eventId": "S2_id", + "data": {"data": [39, 96, 43]}, + "parentEventId": "root_id79", + }, + { + "eventName": "Event S3", + "eventId": "S3_id", + "data": {"data": [8, 53, 67]}, + "parentEventId": "root_id79", + }, + { + "eventName": "Event S4", + "eventId": "S4_id", + "data": {"data": [63, 25, 19]}, + "parentEventId": "root_id79", + }, + {"eventName": "Root Event 80", "eventId": "root_id80", "data": {"data": [8, 8, 99]}}, + { + "eventName": "Event Q0", + "eventId": "Q0_id", + "data": {"data": [75, 9, 81]}, + "parentEventId": "root_id80", + }, + { + "eventName": "Event Q1", + "eventId": "Q1_id", + "data": {"data": [93, 53, 83]}, + "parentEventId": "root_id80", + }, + { + "eventName": "Event Q2", + "eventId": "Q2_id", + "data": {"data": [71, 63, 36]}, + "parentEventId": "root_id80", + }, + { + "eventName": "Event Q3", + "eventId": "Q3_id", + "data": {"data": [78, 38, 11]}, + "parentEventId": "root_id80", + }, + { + "eventName": "Event Q4", + "eventId": "Q4_id", + "data": {"data": [74, 87, 35]}, + "parentEventId": "root_id80", + }, + {"eventName": "Root Event 81", "eventId": "root_id81", "data": {"data": [84, 43, 99]}}, + { + "eventName": "Event U0", + "eventId": "U0_id", + "data": {"data": [41, 82, 45]}, + "parentEventId": "root_id81", + }, + { + "eventName": "Event U1", + "eventId": "U1_id", + "data": {"data": [26, 40, 21]}, + "parentEventId": "root_id81", + }, + {"eventName": "Root Event 82", "eventId": "root_id82", "data": {"data": [44, 35, 2]}}, + { + "eventName": "Event J0", + "eventId": "J0_id", + "data": {"data": [91, 13, 37]}, + "parentEventId": "root_id82", + }, + { + "eventName": "Event J1", + "eventId": "J1_id", + "data": {"data": [53, 83, 98]}, + "parentEventId": "root_id82", + }, + { + "eventName": "Event J2", + "eventId": "J2_id", + "data": {"data": [61, 18, 3]}, + "parentEventId": "root_id82", + }, + {"eventName": "Root Event 83", "eventId": "root_id83", "data": {"data": [78, 8, 33]}}, + { + "eventName": "Event I0", + "eventId": "I0_id", + "data": {"data": [77, 58, 43]}, + "parentEventId": "root_id83", + }, + { + "eventName": "Event I1", + "eventId": "I1_id", + "data": {"data": [39, 86, 51]}, + "parentEventId": "root_id83", + }, + { + "eventName": "Event I2", + "eventId": "I2_id", + "data": {"data": [38, 75, 92]}, + "parentEventId": "root_id83", + }, + { + "eventName": "Event I3", + "eventId": "I3_id", + "data": {"data": [36, 98, 69]}, + "parentEventId": "root_id83", + }, + { + "eventName": "Event I4", + "eventId": "I4_id", + "data": {"data": [26, 34, 69]}, + "parentEventId": "root_id83", + }, + {"eventName": "Root Event 84", "eventId": "root_id84", "data": {"data": [19, 41, 39]}}, + { + "eventName": "Event H0", + "eventId": "H0_id", + "data": {"data": [60, 52, 65]}, + "parentEventId": "root_id84", + }, + { + "eventName": "Event H1", + "eventId": "H1_id", + "data": {"data": [29, 85, 91]}, + "parentEventId": "root_id84", + }, + {"eventName": "Root Event 85", "eventId": "root_id85", "data": {"data": [89, 41, 56]}}, + { + "eventName": "Event R0", + "eventId": "R0_id", + "data": {"data": [29, 72, 58]}, + "parentEventId": "root_id85", + }, + { + "eventName": "Event R1", + "eventId": "R1_id", + "data": {"data": [72, 33, 11]}, + "parentEventId": "root_id85", + }, + { + "eventName": "Event R2", + "eventId": "R2_id", + "data": {"data": [56, 19, 94]}, + "parentEventId": "root_id85", + }, + { + "eventName": "Event R3", + "eventId": "R3_id", + "data": {"data": [91, 11, 20]}, + "parentEventId": "root_id85", + }, + {"eventName": "Root Event 86", "eventId": "root_id86", "data": {"data": [26, 64, 98]}}, + { + "eventName": "Event G0", + "eventId": "G0_id", + "data": {"data": [20, 30, 43]}, + "parentEventId": "root_id86", + }, + {"eventName": "Root Event 87", "eventId": "root_id87", "data": {"data": [37, 5, 53]}}, + { + "eventName": "Event C0", + "eventId": "C0_id", + "data": {"data": [100, 22, 88]}, + "parentEventId": "root_id87", + }, + { + "eventName": "Event C1", + "eventId": "C1_id", + "data": {"data": [64, 9, 51]}, + "parentEventId": "root_id87", + }, + { + "eventName": "Event C2", + "eventId": "C2_id", + "data": {"data": [89, 22, 81]}, + "parentEventId": "root_id87", + }, + {"eventName": "Root Event 88", "eventId": "root_id88", "data": {"data": [33, 26, 72]}}, + { + "eventName": "Event A0", + "eventId": "A0_id", + "data": {"data": [77, 14, 17]}, + "parentEventId": "root_id88", + }, + { + "eventName": "Event A1", + "eventId": "A1_id", + "data": {"data": [10, 28, 59]}, + "parentEventId": "root_id88", + }, + { + "eventName": "Event A2", + "eventId": "A2_id", + "data": {"data": [89, 97, 96]}, + "parentEventId": "root_id88", + }, + { + "eventName": "Event A3", + "eventId": "A3_id", + "data": {"data": [57, 42, 7]}, + "parentEventId": "root_id88", + }, + {"eventName": "Root Event 89", "eventId": "root_id89", "data": {"data": [33, 60, 51]}}, + { + "eventName": "Event T0", + "eventId": "T0_id", + "data": {"data": [86, 1, 48]}, + "parentEventId": "root_id89", + }, + { + "eventName": "Event T1", + "eventId": "T1_id", + "data": {"data": [45, 94, 97]}, + "parentEventId": "root_id89", + }, + { + "eventName": "Event T2", + "eventId": "T2_id", + "data": {"data": [10, 94, 87]}, + "parentEventId": "root_id89", + }, + { + "eventName": "Event T3", + "eventId": "T3_id", + "data": {"data": [41, 56, 3]}, + "parentEventId": "root_id89", + }, + { + "eventName": "Event T4", + "eventId": "T4_id", + "data": {"data": [55, 80, 33]}, + "parentEventId": "root_id89", + }, + {"eventName": "Root Event 90", "eventId": "root_id90", "data": {"data": [40, 19, 44]}}, + { + "eventName": "Event C0", + "eventId": "C0_id", + "data": {"data": [65, 5, 87]}, + "parentEventId": "root_id90", + }, + { + "eventName": "Event C1", + "eventId": "C1_id", + "data": {"data": [47, 17, 42]}, + "parentEventId": "root_id90", + }, + { + "eventName": "Event C2", + "eventId": "C2_id", + "data": {"data": [46, 37, 3]}, + "parentEventId": "root_id90", + }, + { + "eventName": "Event C3", + "eventId": "C3_id", + "data": {"data": [9, 36, 58]}, + "parentEventId": "root_id90", + }, + {"eventName": "Root Event 91", "eventId": "root_id91", "data": {"data": [92, 84, 8]}}, + { + "eventName": "Event Z0", + "eventId": "Z0_id", + "data": {"data": [42, 87, 5]}, + "parentEventId": "root_id91", + }, + {"eventName": "Root Event 92", "eventId": "root_id92", "data": {"data": [3, 91, 99]}}, + { + "eventName": "Event P0", + "eventId": "P0_id", + "data": {"data": [25, 81, 37]}, + "parentEventId": "root_id92", + }, + { + "eventName": "Event P1", + "eventId": "P1_id", + "data": {"data": [8, 23, 31]}, + "parentEventId": "root_id92", + }, + { + "eventName": "Event P2", + "eventId": "P2_id", + "data": {"data": [67, 67, 64]}, + "parentEventId": "root_id92", + }, + { + "eventName": "Event P3", + "eventId": "P3_id", + "data": {"data": [71, 99, 85]}, + "parentEventId": "root_id92", + }, + { + "eventName": "Event P4", + "eventId": "P4_id", + "data": {"data": [36, 85, 64]}, + "parentEventId": "root_id92", + }, + {"eventName": "Root Event 93", "eventId": "root_id93", "data": {"data": [65, 49, 96]}}, + { + "eventName": "Event K0", + "eventId": "K0_id", + "data": {"data": [89, 71, 29]}, + "parentEventId": "root_id93", + }, + { + "eventName": "Event K1", + "eventId": "K1_id", + "data": {"data": [35, 5, 11]}, + "parentEventId": "root_id93", + }, + { + "eventName": "Event K2", + "eventId": "K2_id", + "data": {"data": [1, 78, 7]}, + "parentEventId": "root_id93", + }, + { + "eventName": "Event K3", + "eventId": "K3_id", + "data": {"data": [2, 76, 11]}, + "parentEventId": "root_id93", + }, + {"eventName": "Root Event 94", "eventId": "root_id94", "data": {"data": [8, 97, 36]}}, + { + "eventName": "Event D0", + "eventId": "D0_id", + "data": {"data": [87, 77, 77]}, + "parentEventId": "root_id94", + }, + { + "eventName": "Event D1", + "eventId": "D1_id", + "data": {"data": [35, 25, 72]}, + "parentEventId": "root_id94", + }, + { + "eventName": "Event D2", + "eventId": "D2_id", + "data": {"data": [77, 89, 54]}, + "parentEventId": "root_id94", + }, + {"eventName": "Root Event 95", "eventId": "root_id95", "data": {"data": [47, 93, 41]}}, + { + "eventName": "Event P0", + "eventId": "P0_id", + "data": {"data": [27, 44, 88]}, + "parentEventId": "root_id95", + }, + { + "eventName": "Event P1", + "eventId": "P1_id", + "data": {"data": [98, 3, 95]}, + "parentEventId": "root_id95", + }, + {"eventName": "Root Event 96", "eventId": "root_id96", "data": {"data": [15, 29, 63]}}, + { + "eventName": "Event D0", + "eventId": "D0_id", + "data": {"data": [65, 83, 34]}, + "parentEventId": "root_id96", + }, + {"eventName": "Root Event 97", "eventId": "root_id97", "data": {"data": [3, 69, 78]}}, + { + "eventName": "Event Z0", + "eventId": "Z0_id", + "data": {"data": [64, 99, 30]}, + "parentEventId": "root_id97", + }, + {"eventName": "Root Event 98", "eventId": "root_id98", "data": {"data": [68, 63, 64]}}, + { + "eventName": "Event Z0", + "eventId": "Z0_id", + "data": {"data": [46, 33, 74]}, + "parentEventId": "root_id98", + }, + { + "eventName": "Event Z1", + "eventId": "Z1_id", + "data": {"data": [49, 30, 52]}, + "parentEventId": "root_id98", + }, + {"eventName": "Root Event 99", "eventId": "root_id99", "data": {"data": [89, 19, 62]}}, + { + "eventName": "Event B0", + "eventId": "B0_id", + "data": {"data": [14, 64, 95]}, + "parentEventId": "root_id99", + }, +] diff --git a/tests/tests_unit/test_event_trees/test_event_tree.py b/tests/tests_unit/test_event_trees/test_event_tree.py new file mode 100644 index 00000000..7f3fa195 --- /dev/null +++ b/tests/tests_unit/test_event_trees/test_event_tree.py @@ -0,0 +1,121 @@ +from copy import deepcopy + +import pytest + +from th2_data_services.event_tree import EventTree +from th2_data_services.event_tree.exceptions import EventIdNotInTree, TreeLoop + + +def test_getitem(events_tree_for_test: EventTree): + tree = events_tree_for_test + assert tree["D1_id"] == {"key1": "value1", "key2": "value2"} and tree["C_id"] == { + "data": "test data" + } + + +def test_getitem_id_error(events_tree_for_test: EventTree): + with pytest.raises(EventIdNotInTree) as exc: + _ = events_tree_for_test["test"] + assert exc + + +def test_setitem(events_tree_for_test: EventTree): + tree = events_tree_for_test + tree["A_id"] = {"new data": 123} + assert tree["A_id"] == {"new data": 123} + + +def test_setitem_id_error(events_tree_for_test: EventTree): + with pytest.raises(EventIdNotInTree) as exc: + events_tree_for_test["test"] = "test" + assert exc + + +def test_update_parent_link(events_tree_for_test: EventTree): + tree = events_tree_for_test + tree.update_parent_link("D1_id", "root_id") + assert tree.get_parent("D1_id") == {"data": [1, 2, 3, 4, 5]} + + +def test_update_parent_link_id_error(events_tree_for_test: EventTree): + with pytest.raises(EventIdNotInTree) as exc: + events_tree_for_test.update_parent_link("test", "to_test") + assert exc + + +def test_update_parent_link_loop_error(events_tree_for_test: EventTree): + with pytest.raises(TreeLoop) as exc: + tree = events_tree_for_test + tree.update_parent_link("B_id", "C_id") + assert exc + + +def test_update_event_name(events_tree_for_test: EventTree): + tree = events_tree_for_test + tree.update_event_name("C_id", "NewEvent") + assert tree._tree["C_id"].tag == "NewEvent" + + +def test_update_event_name_id_error(events_tree_for_test: EventTree): + with pytest.raises(EventIdNotInTree) as exc: + events_tree_for_test.update_event_name("test", "test_name") + assert exc + + +def test_merge_events_tree(events_tree_for_test: EventTree): + tree = deepcopy(events_tree_for_test) + + other_tree_root = dict(event_name="RootEvent", event_id="root_id") + other_tree_nodes = [ + dict(event_name="12A", event_id="12A_id", data={"A": 65}, parent_id="root_id"), + dict(event_name="12B", event_id="12B_id", data={"B": 66}, parent_id="root_id"), + ] + other_tree = EventTree(**other_tree_root) + other_tree.append_event(**other_tree_nodes[0]) + other_tree.append_event(**other_tree_nodes[1]) + + tree.merge_tree("A_id", other_tree=other_tree) + + merged_tree_events = tree.get_all_events() + expected_events = events_tree_for_test.get_all_events() + [ + event["data"] for event in other_tree_nodes + ] + assert merged_tree_events == expected_events + + +def test_merge_events_tree_id_error(events_tree_for_test: EventTree): + tree = events_tree_for_test + other_tree = EventTree(event_name="RootEvent", event_id="root_id") + tree.append_event(event_name="12A", event_id="12A_id", data=None, parent_id="root_id") + + with pytest.raises(EventIdNotInTree) as exc: + tree.merge_tree("Test_id", other_tree=other_tree) + assert exc + + +def test_append_event(events_tree_for_test): + tree = events_tree_for_test + node = { + "event_name": "0xA", + "event_id": "0xA_id", + "data": {"msg": "Event Has Been Created"}, + "parent_id": "root_id", + } + tree.append_event(**node) + assert tree.get_event("0xA_id") == node["data"] + + +@pytest.mark.xfail(reason="Raises exception now in Windows") +def test_show(events_tree_for_test: EventTree): + """Raises exception now in Windows + https://stackoverflow.com/questions/27092833/unicodeencodeerror-charmap-codec-cant-encode-characters + """ + expected = """root event +├── A +└── B + ├── C + └── D + └── D1 +""" + + assert events_tree_for_test.show() diff --git a/tests/tests_unit/test_event_trees/test_event_tree_collection.py b/tests/tests_unit/test_event_trees/test_event_tree_collection.py new file mode 100644 index 00000000..da30fbdd --- /dev/null +++ b/tests/tests_unit/test_event_trees/test_event_tree_collection.py @@ -0,0 +1,409 @@ +from tests.tests_unit.test_event_trees.demo_etc_data import demo_etc_data_small +from th2_data_services.data import Data + +EXPECTED_STUB = { + "attachedMessageIds": [], + "batchId": "Broken_Event", + "endTimestamp": {"nano": 0, "epochSecond": 0}, + "startTimestamp": {"nano": 0, "epochSecond": 0}, + "eventId": "Unknown", + "eventName": "Broken_Event", + "eventType": "Broken_Event", + "parentEventId": "Broken_Event", + "successful": None, + "isBatched": None, +} + + +def test_etc_for_detached_events_with_data(demo_etc, all_test=False): + """Checks that ETC returns its detached events.""" + detached_events = demo_etc.get_detached_events() + if all_test: + assert ( + detached_events == [] + ) # After get_parentless_trees Detached Events Become Root Events + else: + assert detached_events == [ + { + "eventName": "Root Event 4", + "eventId": "root_id4", + "data": {"data": [13, 14]}, + "parentEventId": "Unknown", + } + ] + + +def test_etc_to_get_roots_ids(demo_etc_with_general_data, general_data): + """Check that ETC returns correct root ids.""" + etc = demo_etc_with_general_data + root_ids = etc.get_roots_ids() + root_events_in_data = Data(general_data).filter(lambda event: event["parentEventId"] is None) + assert root_ids == [event["eventId"] for event in root_events_in_data] + + +def test_etc_to_get_roots_ids_with_multiple_trees(demo_etc): + """Check that ETC returns correct root ids.""" + etc = demo_etc + root_ids = etc.get_roots_ids() + assert all(["root_id" in root_id or "Unknown" in root_id for root_id in root_ids]) + + +def test_etc_find_event(demo_etc, all_test=False): + etc = demo_etc + if all_test: + event_by_find = etc.find(lambda event: event["eventName"] == "Root Event 4") + expected_event = { + "eventName": "Root Event 4", + "eventId": "root_id4", + "data": {"data": [13, 14]}, + "parentEventId": "Unknown", + } + assert event_by_find == expected_event + else: + event_by_find = etc.find(lambda event: event["eventName"] == "Event E2_child3") + expected_event = { + "eventName": "Event E2_child3", + "eventId": "e2_child3_id", + "data": {"data": "E2_child3"}, + "parentEventId": "e2_id", + } + assert event_by_find == expected_event + + +def test_etc_find_events(demo_etc, all_test=False): + etc = demo_etc + if all_test: + event_by_find = etc.findall(lambda event: "Root Event" in event["eventName"]) + expected_events = [ + {"eventName": "Root Event", "eventId": "root_id", "data": {"data": [1, 2, 3, 4, 5]}}, + { + "eventName": "Root Event 2", + "eventId": "root_id2", + "data": {"data": [6, 7, 8, 9, 10]}, + }, + {"eventName": "Root Event 3", "eventId": "root_id3", "data": {"data": [11, 12]}}, + { + "eventName": "Root Event 4", + "eventId": "root_id4", + "data": {"data": [13, 14]}, + "parentEventId": "Unknown", + }, + ] + assert event_by_find == expected_events + else: + event_by_find = etc.findall(lambda event: "E2_child" in event["eventName"]) + expected_events = [ + { + "eventName": "Event E2_child1", + "eventId": "e2_child1_id", + "data": {"data": "E2_child1"}, + "parentEventId": "e2_id", + }, + { + "eventName": "Event E2_child2", + "eventId": "e2_child2_id", + "data": {"data": "E2_child2"}, + "parentEventId": "e2_id", + }, + { + "eventName": "Event E2_child3", + "eventId": "e2_child3_id", + "data": {"data": "E2_child3"}, + "parentEventId": "e2_id", + }, + ] + assert event_by_find == expected_events + + +def test_etc_find_ancestor(demo_etc, all_test=False): + etc = demo_etc + if all_test: + ancestor = etc.find_ancestor( + "root_id4", filter=lambda event: event.get("parentEventId") == "Broken_Event" + ) + expected_event = EXPECTED_STUB + assert ancestor == expected_event + else: + ancestor = etc.find_ancestor( + "e2_child1_id", filter=lambda event: not event.get("parentEventId") + ) + expected_event = { + "eventName": "Root Event 2", + "eventId": "root_id2", + "data": {"data": [6, 7, 8, 9, 10]}, + } + assert ancestor == expected_event + + +def test_etc_get_ancestors(demo_etc, all_test=False): + etc = demo_etc + if all_test: + ancestors = etc.get_ancestors("root_id4") + assert [ancestor["eventId"] for ancestor in ancestors] == ["Unknown"] + else: + ancestors = etc.get_ancestors("b2_child1_id") + assert [ancestor["eventId"] for ancestor in ancestors] == ["root_id2", "b2_id"] + + +def test_etc_get_children(demo_etc, all_test=False): + etc = demo_etc + if all_test: + id_ = "Unknown" + children = etc.get_children(id_) + expected_children = ( + { + "eventName": "Root Event 4", + "eventId": "root_id4", + "data": {"data": [13, 14]}, + "parentEventId": "Unknown", + }, + ) + assert children == expected_children + else: + id_ = "a1_id" + children = etc.get_children(id_) + expected_children = ( + { + "eventName": "Event A1_child1", + "eventId": "a1_child1_id", + "data": {"data": "A1_child1"}, + "parentEventId": "a1_id", + }, + { + "eventName": "Event A1_child2", + "eventId": "a1_child2_id", + "data": {"data": "A1_child2"}, + "parentEventId": "a1_id", + }, + ) + assert children == expected_children + + +def test_etc_get_full_path(demo_etc, all_test=False): + etc = demo_etc + if all_test: + child, ancestor = "root_id4", "Unknown" + event_path = etc.get_full_path(child) + assert [event["eventId"] for event in event_path] == [ancestor, child] + else: + expected_path = ["root_id", "c1_id", "d1_id", "e1_child1_id"] + event_path = etc.get_full_path("e1_child1_id") + assert [event["eventId"] for event in event_path] == expected_path + + +def test_etc_get_parent(demo_etc, all_test=False): + etc = demo_etc + if all_test: + parent = etc.get_parent("root_id4") + assert parent == EXPECTED_STUB + else: + parent = etc.get_parent("a1_child1_id") + assert parent["eventId"] == "a1_id" + + +def test_etc_append_stub_event(demo_etc_with_general_data): + etc = demo_etc_with_general_data + stub_event = { + "eventId": "a20f5ef4-c3fe-bb10-a29c-dd3d784909eb", + "parentEventId": "8e2524fa-cf59-11eb-a3f7-094f904c3a62", + "eventName": "CustomStubEvent", + } + etc.append_event(event=stub_event) + filter_for_stub_event = [ + event for event in etc.get_all_events_iter() if event["eventName"] == "CustomStubEvent" + ] + assert len(filter_for_stub_event) == 1 + assert filter_for_stub_event[0] == stub_event + + +def test_etc_append_non_stub_event(demo_etc_with_general_data): + etc = demo_etc_with_general_data + demo_event = { + "eventId": "a20f5ef4-c3fe-bb10-a29c-dd3d784909eb", + "parentEventId": "84db48fc-d1b4-11eb-b0fb-199708acc7bc", # NonStub Parent Event + "eventName": "DemoEvent", + } + + etc.append_event(event=demo_event) + event = etc.find(lambda event_: event_["eventName"] == "DemoEvent") + assert event == demo_event + + +def test_etc_get_all_events(demo_etc, all_test=False): + etc = demo_etc + data = sorted(demo_etc_data_small, key=lambda event: event["eventId"]) + events = sorted(etc.get_all_events(), key=lambda event: event["eventId"]) + if not all_test: + events.extend(etc.get_detached_events()) + data.extend( + [ + { + "eventName": "Root Event 4", + "eventId": "root_id4", + "data": {"data": [13, 14]}, + "parentEventId": "Unknown", + } + ] + ) + assert events == data + else: + data.insert(0, EXPECTED_STUB) + assert events == data + + +def test_get_parentless_trees(demo_etc): + etc = demo_etc + parentless_trees = etc.get_parentless_trees() + expected_parentless_tree = [ + EXPECTED_STUB, + { + "eventName": "Root Event 4", + "eventId": "root_id4", + "data": {"data": [13, 14]}, + "parentEventId": "Unknown", + }, + ] + assert len(parentless_trees) == 1 + assert parentless_trees[0].get_all_events() == expected_parentless_tree + + +def test_etc_get_trees(demo_etc): + etc = demo_etc + trees = etc.get_trees() + root_ids = [tree.get_root_id() for tree in trees] + assert all(["root_id" in root_id or "Unknown" in root_id for root_id in root_ids]) + + +def test_etc_get_root_by_id(demo_etc, all_test=False): + etc = demo_etc + if all_test: + root = etc.get_root_by_id("Unknown") + expected_root = EXPECTED_STUB + assert root == expected_root + else: + root = etc.get_root_by_id("root_id") + expected_root = { + "eventName": "Root Event", + "eventId": "root_id", + "data": {"data": [1, 2, 3, 4, 5]}, + } + assert root == expected_root + + +def test_etc_get_tree_by_id(demo_etc, all_test=False): + etc = demo_etc + if all_test: + tree = etc.get_tree_by_id("Unknown") + expected_tree = etc.get_trees()[-1] + assert tree == expected_tree + else: + tree = etc.get_tree_by_id("b1_child2_id") + expected_tree = etc.get_trees()[0] + assert tree == expected_tree + + +def test_all_after_get_parentless_trees(demo_etc): + test_get_parentless_trees(demo_etc) + + test_etc_get_all_events(demo_etc, True) + test_etc_get_trees(demo_etc) + test_etc_get_ancestors(demo_etc, True) + test_etc_get_children(demo_etc, True) + test_etc_get_full_path(demo_etc, True) + test_etc_get_parent(demo_etc, True) + test_etc_get_root_by_id(demo_etc, True) + test_etc_get_tree_by_id(demo_etc, True) + test_etc_to_get_roots_ids_with_multiple_trees(demo_etc) + test_etc_for_detached_events_with_data(demo_etc, True) + test_etc_find_event(demo_etc, True) + test_etc_find_events(demo_etc, True) + test_etc_find_ancestor(demo_etc, True) + + +def test_findall_max_count(demo_etc_big): + """https://exactpro.atlassian.net/browse/TH2-4711 - issue related test. + these tests will fail when ETC will have More than 1 tree + and max_count > than number of events that were found in the first tree. + """ + etc = demo_etc_big + max_nodes_to_get = 10 + expected_nodes = [ + { + "eventName": "Event A0", + "eventId": "A0_id", + "data": {"data": [89, 98, 58]}, + "parentEventId": "root_id0", + }, + { + "eventName": "Event A1", + "eventId": "A1_id", + "data": {"data": [40, 40, 61]}, + "parentEventId": "root_id0", + }, + { + "eventName": "Event A1_child0", + "eventId": "A1_child0_id", + "data": {"data": [9, 90, 81]}, + "parentEventId": "A1_id", + }, + { + "eventName": "Event A1_child1", + "eventId": "A1_child1_id", + "data": {"data": [100, 67, 21]}, + "parentEventId": "A1_id", + }, + { + "eventName": "Event A1_child2", + "eventId": "A1_child2_id", + "data": {"data": [77, 83, 55]}, + "parentEventId": "A1_id", + }, + { + "eventName": "Event A2", + "eventId": "A2_id", + "data": {"data": [33, 60, 15]}, + "parentEventId": "root_id0", + }, + { + "eventName": "Event A2_child0", + "eventId": "A2_child0_id", + "data": {"data": [14, 13, 66]}, + "parentEventId": "A2_id", + }, + { + "eventName": "Event A3", + "eventId": "A3_id", + "data": {"data": [19, 1, 17]}, + "parentEventId": "root_id0", + }, + { + "eventName": "Event A3_child0", + "eventId": "A3_child0_id", + "data": {"data": [59, 37, 57]}, + "parentEventId": "A3_id", + }, + { + "eventName": "Event A3_child1", + "eventId": "A3_child1_id", + "data": {"data": [96, 94, 99]}, + "parentEventId": "A3_id", + }, + ] + findall_nodes = etc.findall(filter=lambda e: e.get("parentEventId"), max_count=max_nodes_to_get) + assert len(findall_nodes) == max_nodes_to_get + assert expected_nodes == findall_nodes + + +def test_findall_iter_max_count(demo_etc_big): + etc = demo_etc_big + one_value_from_findall = list( + etc.findall_iter(filter=lambda e: e.get("parentEventId") is not None, max_count=1) + ) + assert [ + { + "eventName": "Event A0", + "eventId": "A0_id", + "data": {"data": [89, 98, 58]}, + "parentEventId": "root_id0", + } + ] == one_value_from_findall diff --git a/tests/tests_unit/test_event_trees/test_event_tree_parent_collection.py b/tests/tests_unit/test_event_trees/test_event_tree_parent_collection.py new file mode 100644 index 00000000..5dfc675a --- /dev/null +++ b/tests/tests_unit/test_event_trees/test_event_tree_parent_collection.py @@ -0,0 +1,166 @@ +from th2_data_services.data import Data + +DEMO_CHILD_ID = "88a3ee80-d1b4-11eb-b0fb-199708acc7bc" +DEMO_PARENT_ID = "84db48fc-d1b4-11eb-b0fb-199708acc7bc" + + +def test_petc_for_detached_events_with_data(demo_petc_with_general_data): + expected_detached = [ + { + "batchId": "654c2724-5202-460b-8e6c-a7ee9fb02ddf", + "eventId": "654c2724-5202-460b-8e6c-a7ee9fb02ddf:8ca20288-d1b4-11eb-986f-1e8d42132387", + "eventName": "Remove 'NewOrderSingle' id='demo-conn1:SECOND:1624005455622135205' Hash='7009491514226292581' Group='NOS_CONN' Hash['SecondaryClOrdID': 11111, 'SecurityID': INSTR1]", + "isBatched": True, + "eventType": "", + "parentEventId": "a3779b94-d051-11eb-986f-1e8d42132387", + }, + { + "batchId": None, + "eventId": "8ceb47f6-d1b4-11eb-a9ed-ffb57363e013", + "eventName": "Send 'ExecutionReport' message", + "isBatched": False, + "eventType": "Send message", + "parentEventId": "845d70d2-9c68-11eb-8598-691ebd7f413d", + }, + { + "batchId": None, + "eventId": "8ced1c93-d1b4-11eb-a9f4-b12655548efc", + "eventName": "Send 'ExecutionReport' message", + "isBatched": False, + "eventType": "Send message", + "parentEventId": "845d70d2-9c68-11eb-8598-691ebd7f413d", + }, + ] + assert demo_petc_with_general_data.get_detached_events() == expected_detached + + +def test_petc_to_get_roots_ids(demo_petc_with_general_data, general_data): + petc = demo_petc_with_general_data + root_ids = petc.get_roots_ids() + events_filtered = Data(general_data).filter(lambda event: not event.get("parentEventId")) + assert root_ids == [event["eventId"] for event in events_filtered] + + +def test_petc_to_get_roots_ids_with_multiple_trees(demo_petc): + petc = demo_petc + root_ids = petc.get_roots_ids() + assert all(["root_id" in root_id for root_id in root_ids]) + + +def test_petc_find_event(demo_petc_with_general_data, general_data): + petc = demo_petc_with_general_data + event_by_find = petc.find(lambda event: "Aggressive" in event["eventName"]) + event_filtered = Data(general_data).filter(lambda event: "Aggressive" in event["eventName"]) + assert list(event_filtered) == list(event_filtered) + + +def test_petc_find_events(demo_petc_with_general_data, general_data): + petc = demo_petc_with_general_data + event_by_find = petc.findall(lambda event: event["batchId"]) + event_filtered = Data(general_data).filter(lambda event: event["batchId"]) + assert list(event_filtered) == list(event_filtered) + + +def test_petc_find_ancestor(demo_petc_with_general_data): + petc = demo_petc_with_general_data + ancestor = petc.find_ancestor( + DEMO_CHILD_ID, filter=lambda event: not event.get("parentEventId") + ) + assert ancestor["eventId"] == DEMO_PARENT_ID + + +def test_petc_get_children(demo_petc_with_general_data, general_data): + petc = demo_petc_with_general_data + id_ = DEMO_CHILD_ID + children = petc.get_children(id_) + data = Data(general_data).filter(lambda event: event["parentEventId"] == id_) + data = [ + event for event in data if petc.find(lambda ev: ev["parentEventId"] == event["eventId"]) + ] + assert list(children) == data + + +def test_petc_get_full_path(demo_petc_with_general_data): + petc = demo_petc_with_general_data + child, ancestor = DEMO_CHILD_ID, DEMO_PARENT_ID + event_path = petc.get_full_path(child) # [ancestor_root, ancestor_level1, ..., event] + assert [event["eventId"] for event in event_path] == [ancestor, child] + + +# +def test_petc_get_parent(demo_petc_with_general_data): + petc = demo_petc_with_general_data + parent = petc.get_parent(DEMO_CHILD_ID) + assert parent["eventId"] == "84db48fc-d1b4-11eb-b0fb-199708acc7bc" + + +def test_petc_append_stub_event(demo_petc_with_general_data): + petc = demo_petc_with_general_data + stub_event = { + "eventId": "a20f5ef4-c3fe-bb10-a29c-dd3d784909eb", + "parentEventId": "8e2524fa-cf59-11eb-a3f7-094f904c3a62", + "eventName": "CustomStubEvent", + } + petc.append_event(event=stub_event) + filter_for_stub_event = [ + event for event in petc.get_all_events_iter() if event["eventName"] == "CustomStubEvent" + ] + assert len(filter_for_stub_event) == 1 + assert filter_for_stub_event[0] == stub_event + + +def test_petc_append_non_stub_event(demo_petc_with_general_data): + petc = demo_petc_with_general_data + demo_event = { + "eventId": "a20f5ef4-c3fe-bb10-a29c-dd3d784909eb", + "parentEventId": DEMO_PARENT_ID, # + "eventName": "DemoEvent", + } + petc.append_event(event=demo_event) + event = petc.find(lambda event_: event_["eventName"] == "DemoEvent") + assert event == demo_event + + +def test_petc_get_trees(demo_petc): + petc = demo_petc + trees = petc.get_trees() + assert all(["root_id" in tree.get_root_id() for tree in trees]) + + +def test_petc_get_root_by_id(demo_petc): + petc = demo_petc + root = petc.get_root_by_id("root_id2") + expected_root = { + "eventName": "Root Event 2", + "eventId": "root_id2", + "data": {"data": [6, 7, 8, 9, 10]}, + } + assert root == expected_root + + +def test_petc_get_tree_by_id(demo_petc): + petc = demo_petc + tree = petc.get_tree_by_id("b2_id") + expected_tree = petc.get_trees()[1] + assert tree == expected_tree + + +def test_get_parentless_trees(demo_petc): + petc = demo_petc + parentless_trees = petc.get_parentless_trees() + expected_parentless_tree = [ + { + "attachedMessageIds": [], + "batchId": "Broken_Event", + "endTimestamp": {"nano": 0, "epochSecond": 0}, + "startTimestamp": {"nano": 0, "epochSecond": 0}, + "eventId": "Unknown", + "eventName": "Broken_Event", + "eventType": "Broken_Event", + "parentEventId": "Broken_Event", + "successful": None, + "isBatched": None, + } + ] + assert len(parentless_trees) == 1 + assert parentless_trees[0].get_all_events() == expected_parentless_tree diff --git a/tests/tests_unit/tests_diff_version/__init__.py b/tests/tests_unit/tests_diff_version/__init__.py deleted file mode 100644 index 8f0243d8..00000000 --- a/tests/tests_unit/tests_diff_version/__init__.py +++ /dev/null @@ -1,22 +0,0 @@ -from importlib_metadata import version, PackageNotFoundError - -v = version("th2_grpc_data_provider") -DEMO_PORT = "31789" # GRPC provider v6 - -if v == "1.1.0": # v6 - from th2_data_services.provider.v6.data_source.http import HTTPProvider6DataSource as HTTPProviderDataSource # noqa - from th2_data_services.provider.v6.commands import http # noqa - from th2_data_services.provider.v6.filters.filter import Provider6Filter as Filter # noqa - from th2_data_services.provider.v6.provider_api import HTTPProvider6API as HTTPProviderAPI # noqa - from th2_data_services.provider.v6.adapters.message_adapters import CodecPipelinesAdapter # noqa - - DEMO_PORT = "31788" # HTTP provider v6 - -elif v == "0.1.6": # v5 - from th2_data_services.provider.v5.data_source.http import HTTPProvider5DataSource as HTTPProviderDataSource # noqa - from th2_data_services.provider.v5.commands import http # noqa - from th2_data_services.provider.v5.provider_api import HTTPProvider5API as HTTPProviderAPI # noqa - from th2_data_services.provider.v5.adapters.message_adapters import CodecPipelinesAdapter # noqa - from th2_data_services.filter import Filter # noqa - - DEMO_PORT = "31787" # HTTP provider v5 diff --git a/tests/tests_unit/tests_diff_version/conftest.py b/tests/tests_unit/tests_diff_version/conftest.py deleted file mode 100644 index a77f8192..00000000 --- a/tests/tests_unit/tests_diff_version/conftest.py +++ /dev/null @@ -1,157 +0,0 @@ -from datetime import datetime - -import pytest - -from th2_data_services import Data -from . import HTTPProviderAPI, HTTPProviderDataSource, http, CodecPipelinesAdapter, Filter, DEMO_PORT # noqa # noqa - - -@pytest.fixture -def demo_data_source(): - DEMO_HOST = "10.100.66.114" # de-th2-qa - data_source = HTTPProviderDataSource(f"http://{DEMO_HOST}:{DEMO_PORT}") - return data_source - - -START_TIME = datetime(year=2022, month=6, day=30, hour=14, minute=0, second=0, microsecond=0) -END_TIME = datetime(year=2022, month=6, day=30, hour=15, minute=0, second=0, microsecond=0) - - -@pytest.fixture -def demo_get_events_with_one_filter(demo_data_source: HTTPProviderDataSource) -> Data: - case = demo_data_source.command( - http.GetEvents( - start_timestamp=START_TIME, - end_timestamp=END_TIME, - filters=[Filter("name", "TS_1")], - ) - ) - - return case - - -@pytest.fixture -def demo_get_events_with_filters(demo_data_source: HTTPProviderDataSource) -> Data: - case = demo_data_source.command( - http.GetEvents( - start_timestamp=START_TIME, - end_timestamp=END_TIME, - filters=[Filter("name", "ExecutionReport"), Filter("type", "message"), Filter("body", "589")], - ) - ) - - return case - - -@pytest.fixture -def demo_get_messages_with_one_filter(demo_data_source: HTTPProviderDataSource) -> Data: - case = demo_data_source.command( - http.GetMessages( - start_timestamp=datetime(year=2022, month=6, day=30, hour=14, minute=48, second=20, microsecond=0), - end_timestamp=datetime(year=2022, month=6, day=30, hour=14, minute=48, second=25, microsecond=0), - stream=["arfq01fix07"], - filters=Filter("type", "NewOrderSingle"), - ) - ) - - return case - - -@pytest.fixture -def demo_get_messages_with_filters(demo_data_source: HTTPProviderDataSource) -> Data: - case = demo_data_source.command( - http.GetMessages( - start_timestamp=datetime(year=2022, month=6, day=30, hour=14, minute=48, second=20, microsecond=0), - end_timestamp=datetime(year=2022, month=6, day=30, hour=14, minute=48, second=25, microsecond=0), - stream=["arfq01fix07"], - filters=[Filter("type", "NewOrderSingle"), Filter("body", "200")], - ) - ) - - return case - - -@pytest.fixture -def demo_events_from_data_source(demo_data_source: HTTPProviderDataSource) -> Data: - events = demo_data_source.command( - http.GetEvents( - start_timestamp=START_TIME, - end_timestamp=END_TIME, - ) - ) - # Returns 49 events #TODO - # Failed = 6 - return events - - -@pytest.fixture -def demo_messages_from_data_source(demo_data_source: HTTPProviderDataSource) -> Data: - messages = demo_data_source.command( - http.GetMessages( - start_timestamp=datetime(year=2022, month=6, day=30, hour=14, minute=58, second=0, microsecond=0), - end_timestamp=END_TIME, - stream=["arfq01fix07"], - ) - ) - # Returns 239 messages - return messages - - -@pytest.fixture -def demo_events_from_data_source_with_cache_status( - demo_data_source: HTTPProviderDataSource, -) -> Data: - events = demo_data_source.command(http.GetEvents(start_timestamp=START_TIME, end_timestamp=END_TIME, cache=True)) - # Returns 49 events #TODO - # Failed = 6 - return events - - -@pytest.fixture -def demo_messages_from_data_source_with_test_streams( - demo_data_source: HTTPProviderDataSource, -) -> Data: - messages = demo_data_source.command( - http.GetMessages( - start_timestamp=datetime(year=2022, month=6, day=30, hour=14, minute=58, second=0, microsecond=0), - end_timestamp=END_TIME, - stream=[ - "Test-123", - "Test-1234", - "Test-12345", - "Test-123456", - "Test-1234567", - "Test-12345678", - "Test-123456789", - "Test-1234567810", - "TestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTest", - "TestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTest1", - "TestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTest2", - "TestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTest3", - "TestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTest4", - "TestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTest5", - "TestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTest6", - "TestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTest7", - "TestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTest8", - "TestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTest9", - "TestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTest10", - "TestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTest11", - "TestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTest12", - "TestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTest13", - "TestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTest14", - "TestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTest15", - "TestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTest16", - "TestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTest17", - "TestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTest18", - "TestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTest19", - "TestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTest20", - "TestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTest21", - "TestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTest22", - "TestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTest23", - "arfq01fix07", - "arfq01dc03", - "arfq02dc10", - ], - ) - ) - return messages diff --git a/tests/tests_unit/tests_diff_version/tests_common/test_data_local.py b/tests/tests_unit/tests_diff_version/tests_common/test_data_local.py deleted file mode 100644 index 340dcdc8..00000000 --- a/tests/tests_unit/tests_diff_version/tests_common/test_data_local.py +++ /dev/null @@ -1,31 +0,0 @@ -import pytest - -from th2_data_services.data import Data - - -@pytest.mark.skip -def test_iter_data(demo_events_from_data_source: Data): - """Test via data provider""" - # output = [ - # {"eventName": "test1", "eventId": "id1"}, - # {"eventName": "test2", "eventId": "id2"}, - # {"eventName": "test3", "eventId": "id3"}, - # ] - # mocker.patch("", ) - # TODO: Change on mock - events = demo_events_from_data_source - - # Check that list func works - assert list(events) - - # Check that we can use Data several times - assert list(events) - - -@pytest.mark.skip -def test_filter_data(demo_events_from_data_source: Data): - # TODO: Change on mock - events = demo_events_from_data_source - data = events.filter(lambda r: r["successful"] is False) - - assert len(list(data)) == 23 diff --git a/tests/tests_unit/tests_diff_version/tests_common/test_data_source.py b/tests/tests_unit/tests_diff_version/tests_common/test_data_source.py deleted file mode 100644 index ac6001c0..00000000 --- a/tests/tests_unit/tests_diff_version/tests_common/test_data_source.py +++ /dev/null @@ -1,167 +0,0 @@ -from datetime import datetime - -from tests.tests_unit.tests_diff_version.conftest import Filter, HTTPProviderAPI - - -def test_generate_url_search_sse_events(): - api = HTTPProviderAPI(url="http://host:port") - - start_time = int(datetime.now().timestamp() * 1000) - end_time = int(datetime.now().timestamp() * 1000) - parent_event_id = "event_test" - - url = api.get_url_search_sse_events( - start_timestamp=start_time, - end_timestamp=end_time, - attached_messages=True, - parent_event=parent_event_id, - keep_open=True, - ) - - assert ( - url == f"http://host:port/search/sse/events?startTimestamp={start_time}&endTimestamp={end_time}" - f"&parentEvent={parent_event_id}&searchDirection=next&keepOpen={True}&metadataOnly=True" - f"&attachedMessages={True}" - ) - - -def test_generate_url_search_sse_events_with_filters(): - api = HTTPProviderAPI(url="http://host:port") - - start_time = int(datetime.now().timestamp() * 1000) - end_time = int(datetime.now().timestamp() * 1000) - filter_name, filter_value = "body", "test" - - url = api.get_url_search_sse_events( - start_timestamp=start_time, end_timestamp=end_time, filters=Filter(filter_name, filter_value).url() - ) - - assert ( - url == f"http://host:port/search/sse/events?startTimestamp={start_time}&endTimestamp={end_time}" - f"&searchDirection=next&keepOpen=False&metadataOnly=True&attachedMessages=False&filters={filter_name}" - f"&{filter_name}-values={filter_value}&{filter_name}-negative=False&{filter_name}-conjunct=False" - ) - - -def test_generate_url_search_sse_messages(): - api = HTTPProviderAPI(url="http://host:port") - - start_time = int(datetime.now().timestamp() * 1000) - end_time = int(datetime.now().timestamp() * 1000) - stream = ["test-stream", "test-stream2"] - - url = api.get_url_search_sse_messages( - start_timestamp=start_time, end_timestamp=end_time, keep_open=True, stream=stream - ) - - assert ( - url == f"http://host:port/search/sse/messages?startTimestamp={start_time}&endTimestamp={end_time}" - f"&stream={stream[0]}&stream={stream[1]}&searchDirection=next&keepOpen={True}&attachedEvents=False" - ) - - -def test_generate_url_search_sse_messages_with_filters(): - api = HTTPProviderAPI(url="http://host:port") - - start_time = int(datetime.now().timestamp() * 1000) - end_time = int(datetime.now().timestamp() * 1000) - stream = ["test-stream", "test-stream2"] - filter_name, filter_value = "body", "test" - - url = api.get_url_search_sse_messages( - start_timestamp=start_time, - end_timestamp=end_time, - keep_open=True, - stream=stream, - filters=Filter(filter_name, filter_value).url(), - ) - - assert ( - url == f"http://host:port/search/sse/messages?startTimestamp={start_time}&endTimestamp={end_time}" - f"&stream={stream[0]}&stream={stream[1]}&searchDirection=next&keepOpen={True}&attachedEvents=False" - f"&filters={filter_name}&{filter_name}-values={filter_value}&{filter_name}-negative=False&{filter_name}-conjunct=False" - ) - - -def test_encoding_url(): - api = HTTPProviderAPI(url="http://host:port") - - start_time = int(datetime.now().timestamp() * 1000) - end_time = int(datetime.now().timestamp() * 1000) - filter_name, filter_value = "test0 test1", "test2 test3" - - url = api.get_url_search_sse_events( - start_timestamp=start_time, end_timestamp=end_time, filters=Filter(filter_name, filter_value).url() - ) - - filter_name = filter_name.split() - filter_value = filter_value.split() - - encoded_filter_name = filter_name[0] + "%20" + filter_name[1] - - assert ( - url == f"http://host:port/search/sse/events?startTimestamp={start_time}&endTimestamp={end_time}" - f"&searchDirection=next&keepOpen=False&metadataOnly=True&attachedMessages=False&filters=" - f"{encoded_filter_name}" - f"&{encoded_filter_name}-values={filter_value[0] + '%20' + filter_value[1]}&" - f"{encoded_filter_name}-negative=False&{encoded_filter_name}-conjunct=False" - ) - - -def test_generate_non_standart_url_search_sse_events(): - api = HTTPProviderAPI(url="http://host:port////") - - start_time = int(datetime.now().timestamp() * 1000) - end_time = int(datetime.now().timestamp() * 1000) - parent_event_id = "event_test" - - url = api.get_url_search_sse_events( - start_timestamp=start_time, - end_timestamp=end_time, - attached_messages=True, - parent_event=parent_event_id, - keep_open=True, - ) - - assert ( - url == f"http://host:port/search/sse/events?startTimestamp={start_time}&endTimestamp={end_time}" - f"&parentEvent={parent_event_id}&searchDirection=next&keepOpen={True}&metadataOnly=True" - f"&attachedMessages={True}" - ) - - -def test_generate_non_standart_url_search_sse_messages_with_filters(): - api = HTTPProviderAPI(url="http://host:port/") - - start_time = int(datetime.now().timestamp() * 1000) - end_time = int(datetime.now().timestamp() * 1000) - stream = ["test-stream", "test-stream2"] - filter_name, filter_value = "body", "test" - - url = api.get_url_search_sse_messages( - start_timestamp=start_time, - end_timestamp=end_time, - keep_open=True, - stream=stream, - filters=Filter(filter_name, filter_value).url(), - ) - - assert ( - url == f"http://host:port/search/sse/messages?startTimestamp={start_time}&endTimestamp={end_time}" - f"&stream={stream[0]}&stream={stream[1]}&searchDirection=next&keepOpen={True}&attachedEvents=False" - f"&filters={filter_name}&{filter_name}-values={filter_value}&{filter_name}-negative=False&{filter_name}-conjunct=False" - ) - - -def test_count_slash_in_non_standart_url(): - api0 = HTTPProviderAPI(url="http://host:port") - api1 = HTTPProviderAPI(url="http://host:port/") - api4 = HTTPProviderAPI(url="http://host:port/////") - api10 = HTTPProviderAPI(url="//////////") - - assert ( - api0._url == "http://host:port" - and api1._url == "http://host:port" - and api4._url == "http://host:port" - and api10._url == "" - ) diff --git a/tests/tests_unit/tests_diff_version/tests_common/test_data_source_local.py b/tests/tests_unit/tests_diff_version/tests_common/test_data_source_local.py deleted file mode 100644 index 11fc9a21..00000000 --- a/tests/tests_unit/tests_diff_version/tests_common/test_data_source_local.py +++ /dev/null @@ -1,89 +0,0 @@ -from datetime import datetime - -import pytest -import requests - -from th2_data_services.data import Data -from th2_data_services.provider.exceptions import CommandError -from tests.tests_unit.tests_diff_version.conftest import http, HTTPProviderDataSource - - -# TODO: Change on mock - - -@pytest.mark.skip -def test_find_message_by_id_from_data_provider_with_error(demo_data_source: HTTPProviderDataSource): - data_source = demo_data_source - - with pytest.raises(CommandError) as exc_info: - data_source.command(http.GetMessageById("demo-conn_not_exist:first:1624005448022245399")) - - -@pytest.mark.skip -def test_get_events_from_data_provider_with_error(demo_data_source: HTTPProviderDataSource): - data_source = demo_data_source - - events = data_source.command(http.GetEvents(start_timestamp="test", end_timestamp="test")) - with pytest.raises(TypeError) as exc_info: - list(events) - assert "replace() takes no keyword arguments" in str(exc_info) - - -@pytest.mark.skip -def test_get_messages_from_data_provider_with_error(demo_data_source: HTTPProviderDataSource): - data_source = demo_data_source - - events = data_source.command(http.GetMessages(start_timestamp="test", end_timestamp="test", stream="test")) - with pytest.raises(TypeError) as exc_info: - list(events) - assert "replace() takes no keyword arguments" in str(exc_info) - - -@pytest.mark.skip -def test_check_url_for_data_source(): - with pytest.raises(requests.exceptions.ConnectionError) as exc_info: - data_source = HTTPProviderDataSource("http://test_test:8080/") - assert "Max retries exceeded with url" in str(exc_info) - - -@pytest.mark.skip -def test_messageIds_not_in_last_msg(demo_messages_from_data_source: Data): - data = demo_messages_from_data_source - data_lst = list(data) - last_msg = data_lst[-1] - assert "messageIds" not in last_msg - - -@pytest.mark.skip -def test_get_messages_with_multiple_url( - demo_messages_from_data_source_with_test_streams: Data, - demo_messages_from_data_source: Data, -): - messages = demo_messages_from_data_source_with_test_streams.use_cache(True) - - messages_hand_demo_expected = demo_messages_from_data_source - messages_hand_demo_actual = messages.filter(lambda record: record.get("sessionId") == "arfq01fix07") - - assert ( - len(list(messages)) == 272 - and len(list(messages_hand_demo_actual)) == len(list(messages_hand_demo_expected)) == 239 - ) - - -# def test_unprintable_character(demo_data_source: HTTPProviderDataSource): -# event = demo_data_source.command(http.GetEventById(("b85d9dca-6236-11ec-bc58-1b1c943c5c0d"))) -# -# assert "\x80" in event["body"][0]["value"] and event["body"][0]["value"] == "nobJjpBJkTuQMmscc4R\x80" - - -@pytest.mark.skip -def test_attached_messages(demo_data_source: HTTPProviderDataSource): - events = demo_data_source.command( - http.GetEvents( - start_timestamp=datetime(year=2022, month=6, day=30, hour=14, minute=0, second=0, microsecond=0), - end_timestamp=datetime(year=2022, month=6, day=30, hour=15, minute=0, second=0, microsecond=0), - attached_messages=True, - ) - ) - - assert events.filter(lambda event: event.get("attachedMessageIds")).len diff --git a/tests/tests_unit/tests_diff_version/tests_common/test_filter.py b/tests/tests_unit/tests_diff_version/tests_common/test_filter.py deleted file mode 100644 index c409418a..00000000 --- a/tests/tests_unit/tests_diff_version/tests_common/test_filter.py +++ /dev/null @@ -1,26 +0,0 @@ -from tests.tests_unit.tests_diff_version.conftest import Filter - - -def test_filter_url(): - filter_ = Filter("type", ["one", 2, "three"], False, False) - assert ( - filter_.url() - == "&filters=type&type-values=one&type-values=2&type-values=three&type-negative=False&type-conjunct=False" - ) - - filter_ = Filter("name", "one", False, False) - assert filter_.url() == "&filters=name&name-values=one&name-negative=False&name-conjunct=False" - - filter_ = Filter("name", 1) - assert filter_.url() == "&filters=name&name-values=1&name-negative=False&name-conjunct=False" - - -def test_filter_grcp(): - assert isinstance(Filter("type", ["one", 2, "three"], False, False), Filter) - - -def test_iterate_filter_twice(): - f = Filter("type", ["one", 2, "three"]) - v1 = f.url() - v2 = f.url() - assert v1 == v2 diff --git a/tests/tests_unit/tests_diff_version/tests_common/tests_adapters/test_adapter_codec_pipelines.py b/tests/tests_unit/tests_diff_version/tests_common/tests_adapters/test_adapter_codec_pipelines.py deleted file mode 100644 index 2398b2e4..00000000 --- a/tests/tests_unit/tests_diff_version/tests_common/tests_adapters/test_adapter_codec_pipelines.py +++ /dev/null @@ -1,116 +0,0 @@ -from typing import List - -from tests.tests_unit.tests_diff_version.conftest import CodecPipelinesAdapter - - -def create_adapter_with_ignore_errors(): - return CodecPipelinesAdapter(ignore_errors=True) - - -def create_adapter_wo_ignore_errors(): - return CodecPipelinesAdapter(ignore_errors=False) - - -def test_adapter_with_id(messages_before_pipeline_adapter: List[dict], messages_after_pipeline_adapter: List[dict]): - adapter = create_adapter_with_ignore_errors() - output = [] - for message in messages_before_pipeline_adapter: - messages = adapter.handle(message) - if isinstance(messages, dict): - messages = [messages] - output.extend(messages) - - assert len(output) == 11 and output == messages_after_pipeline_adapter - - -def test_find_sub_message_with_adapter(message_from_pipeline: dict): - adapter = create_adapter_with_ignore_errors() - msg_id = message_from_pipeline.get("messageId") + ".5" - message_from_pipeline = adapter.handle(message_from_pipeline) - - index = None - if msg_id.find(".") != -1: - msg_id, index = msg_id.split(".")[:-1], int(msg_id[-1]) - - result = [] - if isinstance(message_from_pipeline, list): - if index: - for message in message_from_pipeline: - if message["body"]["metadata"]["id"]["subsequence"][0] == index: - result.append(message) - break - else: - result += message_from_pipeline - else: - result.append(message_from_pipeline) - - assert result == [ - { - "attachedEventIds": ["09960e51-1c6b-11ec-9d85-cd5454918fce", "09963563-1c6b-11ec-9d85-cd5454918fce"], - "body": { - "fields": { - "ExchangeOrderType": {"simpleValue": "0"}, - "LotType": {"simpleValue": "2"}, - "MessageSequenceNumber": {"simpleValue": "15500"}, - "MessageType": {"simpleValue": "A"}, - "OrderBookID": {"simpleValue": "119549"}, - "OrderBookPosition": {"simpleValue": "1"}, - "OrderID": {"simpleValue": "7478143635544868134"}, - "PHCount": {"simpleValue": "2"}, - "PHSequence": {"simpleValue": "15499"}, - "PHSession": {"simpleValue": "M127205328"}, - "Price": {"simpleValue": "1000"}, - "Quantity": {"simpleValue": "2000"}, - "Side": {"simpleValue": "B"}, - "TimestampNanoseconds": {"simpleValue": "2724576"}, - }, - "metadata": { - "id": { - "connectionId": {"sessionAlias": "test-42"}, - "sequence": "1632216515838617066", - "subsequence": [5], - }, - "messageType": "AddOrder", - "protocol": "SOUP", - "timestamp": "2021-09-23T12:37:38.004Z", - }, - }, - "direction": "IN", - "messageId": "test-42:first:1632216515838617066.5", - "messageType": "AddOrder", - "sessionId": "test-42", - "timestamp": {"epochSecond": 1632400658, "nano": 4000000}, - "type": "message", - } - ] - - -def test_find_messages_with_adapter(message_from_pipeline: dict): - adapter = create_adapter_with_ignore_errors() - msg_id = message_from_pipeline.get("messageId") - message_from_pipeline = adapter.handle(message_from_pipeline) - - index = None - if msg_id.find(".") != -1: - msg_id, index = msg_id.split(".")[:-1], int(msg_id[-1]) - - result = [] - if isinstance(message_from_pipeline, list): - if index: - for message in message_from_pipeline: - if message["body"]["metadata"]["id"]["subsequence"][0] == index: - result.append(message) - break - else: - result += message_from_pipeline - else: - result.append(message_from_pipeline) - - assert len(result) == 5 - - -def test_message_with_empty_body(message_from_pipeline_empty_body, messages_from_after_pipeline_empty_body): - adapter = create_adapter_with_ignore_errors() - messages = adapter.handle(message_from_pipeline_empty_body) - - assert messages_from_after_pipeline_empty_body == messages diff --git a/tests/tests_unit/tests_diff_version/tests_common/tests_adapters/test_adapter_sse_local.py b/tests/tests_unit/tests_diff_version/tests_common/tests_adapters/test_adapter_sse_local.py deleted file mode 100644 index ee6616ac..00000000 --- a/tests/tests_unit/tests_diff_version/tests_common/tests_adapters/test_adapter_sse_local.py +++ /dev/null @@ -1,84 +0,0 @@ -from sseclient import Event -import pytest - -from th2_data_services import Data -from tests.tests_unit.tests_diff_version.conftest import HTTPProviderDataSource, http, START_TIME, END_TIME - - -@pytest.mark.skip -def get_data_obj(rtype, ds, params_dict): - if rtype == "events": - return ds.command( - http.GetEvents(start_timestamp=params_dict["startTimestamp"], end_timestamp=params_dict["endTimestamp"]) - ) - elif rtype == "messages": - return ds.command( - http.GetMessages( - start_timestamp=params_dict["startTimestamp"], - end_timestamp=params_dict["endTimestamp"], - stream=params_dict["stream"], - ) - ) - else: - raise Exception("Not events or messages") - - -@pytest.mark.skip -class TestSSEFlagTrue: - @pytest.mark.parametrize( - "params", - [ - ("events", dict(sse_adapter=True)), - ("events", dict()), - ( - "messages", - dict( - sse_adapter=True, - stream=["demo-conn2"], - provider_adapter=None, - ), - ), - ( - "messages", - dict( - stream=["demo-conn2"], - provider_adapter=None, - ), - ), - ], - ) - def test_x_flag_true_or_default(self, demo_data_source: HTTPProviderDataSource, params): - ds = demo_data_source - data: Data = get_data_obj(params[0], ds, dict(startTimestamp=START_TIME, endTimestamp=END_TIME, **params[1])) - - for e in data: - assert isinstance(e, dict) - - -@pytest.mark.skip -class TestSSEFlagFalse: - # @pytest.mark.parametrize("rtype", ['events', 'messages']) - def test_events(self, demo_data_source: HTTPProviderDataSource): - ds = demo_data_source - data: Data = ds.command( - http.GetEventsSSEEvents( - start_timestamp=START_TIME, - end_timestamp=END_TIME, - ) - ) - - for e in data: - assert isinstance(e, Event) - - def test_messages_provider_none(self, demo_data_source: HTTPProviderDataSource): - ds = demo_data_source - data: Data = ds.command( - http.GetMessages( - start_timestamp=START_TIME, - end_timestamp=END_TIME, - stream=["demo-conn2"], - ) - ) - - for e in data: - assert isinstance(e, Event) diff --git a/tests/tests_unit/tests_diff_version/tests_v5/test_data_source_local.py b/tests/tests_unit/tests_diff_version/tests_v5/test_data_source_local.py deleted file mode 100644 index 159136f6..00000000 --- a/tests/tests_unit/tests_diff_version/tests_v5/test_data_source_local.py +++ /dev/null @@ -1,474 +0,0 @@ -import pytest - -from ..conftest import HTTPProviderDataSource, http, Data -from th2_data_services.provider.exceptions import CommandError - - -@pytest.mark.skip -def test_find_events_by_id_from_data_provider(demo_data_source: HTTPProviderDataSource): - data_source = demo_data_source # TODO: Change on mock - - expected_event = { - "attachedMessageIds": [], - "batchId": None, - "body": {}, - "endTimestamp": {"epochSecond": 1656599851, "nano": 420806000}, - "eventId": "2c4b3a58-f882-11ec-b952-0a1e730db2c6", - "eventName": "Recon: Test", - "eventType": "", - "isBatched": False, - "parentEventId": None, - "startTimestamp": {"epochSecond": 1656599851, "nano": 420806000}, - "successful": False, - "type": "event", - } - - expected_events = [] - expected_events.append(expected_event) - expected_events.append( - { - "type": "event", - "eventId": "a5586d90-b83b-48a4-bd2b-b2059fb79374:b84cff2c-f883-11ec-b070-0a1e730db2c6", - "batchId": "a5586d90-b83b-48a4-bd2b-b2059fb79374", - "isBatched": True, - "eventName": "Match by ClOrdID: '7706360'", - "eventType": "", - "endTimestamp": {"nano": 809998000, "epochSecond": 1656600515}, - "startTimestamp": {"nano": 809998000, "epochSecond": 1656600515}, - "parentEventId": "b21a03c0-f883-11ec-b070-0a1e730db2c6", - "successful": True, - "attachedMessageIds": ["arfq01fix08:first:1656599887515453583", "arfq01fix08:second:1656599887515499581"], - "body": { - "type": "table", - "rows": [ - {"Name": "ClOrdId", "Value": "7706360"}, - {"Name": "Message Response", "Value": "ExecutionReport"}, - {"Name": "Message Request", "Value": "NewOrderSingle"}, - {"Name": "Latency type", "Value": "Trade"}, - {"Name": "Latency", "Value": 29000.0}, - ], - "_TableComponent__column_names": ["Name", "Value"], - }, - } - ) - - event = data_source.command(http.GetEventById("2c4b3a58-f882-11ec-b952-0a1e730db2c6")) - events = data_source.command( - http.GetEventsById( - [ - "2c4b3a58-f882-11ec-b952-0a1e730db2c6", - "a5586d90-b83b-48a4-bd2b-b2059fb79374:b84cff2c-f883-11ec-b070-0a1e730db2c6", - ] - ) - ) - events_with_one_element = data_source.command( - http.GetEventsById( - [ - "2c4b3a58-f882-11ec-b952-0a1e730db2c6", - ] - ) - ) - for event_ in events: - event_["attachedMessageIds"].sort() - - broken_event: dict = data_source.command(http.GetEventById("id", use_stub=True)) - broken_events: list = data_source.command(http.GetEventsById(["id", "ids"], use_stub=True)) - - plug_for_broken_event: dict = { - "attachedMessageIds": [], - "batchId": "Broken_Event", - "endTimestamp": {"nano": 0, "epochSecond": 0}, - "startTimestamp": {"nano": 0, "epochSecond": 0}, - "type": "event", - "eventId": "id", - "eventName": "Broken_Event", - "eventType": "Broken_Event", - "parentEventId": "Broken_Event", - "successful": None, - "isBatched": None, - } - - plug_for_broken_events: list = [ - plug_for_broken_event.copy(), - plug_for_broken_event.copy(), - ] - plug_for_broken_events[1]["eventId"] = "ids" - - # Check types - assert isinstance(event, dict) - assert isinstance(events, list) - assert isinstance(events_with_one_element, list) - assert isinstance(broken_event, dict) - assert isinstance(broken_events, list) - # Check content. - assert event == expected_event - assert events == expected_events - assert len(events) == 2 - assert len(events_with_one_element) == 1 - # Check Broken_Events - assert broken_event == plug_for_broken_event - assert broken_events == plug_for_broken_events - assert [event, broken_event] == data_source.command( - http.GetEventsById(["2c4b3a58-f882-11ec-b952-0a1e730db2c6", "id"], use_stub=True) - ) - with pytest.raises(CommandError): - data_source.command(http.GetEventsById(["2c4b3a58-f882-11ec-b952-0a1e730db2c6", "id"])) - with pytest.raises(CommandError): - data_source.command(http.GetEventById("id")) - - -@pytest.mark.skip -def test_find_messages_by_id_from_data_provider(demo_data_source: HTTPProviderDataSource): - data_source = demo_data_source # TODO: Change on mock - - expected_message = { - "attachedEventIds": [], - "body": { - "fields": { - "header": { - "messageValue": { - "fields": { - "BeginString": {"simpleValue": "FIXT.1.1"}, - "BodyLength": {"simpleValue": "61"}, - "MsgSeqNum": {"simpleValue": "33"}, - "MsgType": {"simpleValue": "0"}, - "SenderCompID": {"simpleValue": "ARFQ01FIX08"}, - "SendingTime": {"simpleValue": "2022-06-30T14:39:27.111"}, - "TargetCompID": {"simpleValue": "FGW"}, - } - } - }, - "trailer": {"messageValue": {"fields": {"CheckSum": {"simpleValue": "160"}}}}, - }, - "metadata": { - "id": { - "connectionId": {"sessionAlias": "arfq01fix08"}, - "direction": "SECOND", - "sequence": "1656599887515499033", - "subsequence": [1], - }, - "messageType": "Heartbeat", - "protocol": "FIX", - "timestamp": "2022-06-30T14:39:27.112Z", - }, - }, - "bodyBase64": "OD1GSVhULjEuMQE5PTYxATM1PTABMzQ9MzMBNDk9QVJGUTAxRklYMDgBNTI9MjAyMjA2MzAtMTQ6Mzk6MjcuMTExMDAwATU2PUZHVwExMD0xNjAB", - "direction": "OUT", - "messageId": "arfq01fix08:second:1656599887515499033", - "messageType": "Heartbeat", - "sessionId": "arfq01fix08", - "timestamp": {"epochSecond": 1656599967, "nano": 112000000}, - "type": "message", - } - - expected_messages = [] - expected_messages.append(expected_message) - expected_messages.append( - { - "attachedEventIds": [], - "body": { - "fields": { - "DefaultApplVerID": {"simpleValue": "9"}, - "EncryptMethod": {"simpleValue": "0"}, - "HeartBtInt": {"simpleValue": "5"}, - "Password": {"simpleValue": "mit123"}, - "ResetSeqNumFlag": {"simpleValue": "true"}, - "header": { - "messageValue": { - "fields": { - "BeginString": {"simpleValue": "FIXT.1.1"}, - "BodyLength": {"simpleValue": "91"}, - "MsgSeqNum": {"simpleValue": "1"}, - "MsgType": {"simpleValue": "A"}, - "SenderCompID": {"simpleValue": "ARFQ01DC03"}, - "SendingTime": {"simpleValue": "2022-06-30T14:46:03.911"}, - "TargetCompID": {"simpleValue": "FGW"}, - } - } - }, - "trailer": {"messageValue": {"fields": {"CheckSum": {"simpleValue": "161"}}}}, - }, - "metadata": { - "id": { - "connectionId": {"sessionAlias": "arfq01dc03"}, - "direction": "SECOND", - "sequence": "1656599850628059096", - "subsequence": [1], - }, - "messageType": "Logon", - "protocol": "FIX", - "timestamp": "2022-06-30T14:46:03.915Z", - }, - }, - "bodyBase64": "OD1GSVhULjEuMQE5PTkxATM1PUEBMzQ9MQE0OT1BUkZRMDFEQzAzATUyPTIwMjIwNjMwLTE0OjQ2OjAzLjkxMQE1Nj1GR1cBOTg9MAExMDg9NQExNDE9WQE1NTQ9bWl0MTIzATExMzc9OQExMD0xNjEB", - "direction": "OUT", - "messageId": "arfq01dc03:second:1656599850628059096", - "messageType": "Logon", - "sessionId": "arfq01dc03", - "timestamp": {"epochSecond": 1656600363, "nano": 915000000}, - "type": "message", - } - ) - - message = data_source.command(http.GetMessageById("arfq01fix08:second:1656599887515499033")) - messages = data_source.command( - http.GetMessagesById(["arfq01fix08:second:1656599887515499033", "arfq01dc03:second:1656599850628059096"]) - ) - messages_with_one_element = data_source.command(http.GetMessagesById(["arfq01fix08:second:1656599887515499033"])) - # Check types - assert isinstance(message, dict) - assert isinstance(messages, list) - assert isinstance(messages_with_one_element, list) - # Check content. - assert message == expected_message - assert messages == expected_messages - assert len(messages) == 2 - assert len(messages_with_one_element) == 1 - - -@pytest.mark.skip -def test_get_x_with_filters( - demo_get_events_with_one_filter: Data, - demo_get_messages_with_one_filter: Data, - demo_get_events_with_filters: Data, - demo_get_messages_with_filters: Data, -): - # TODO: Change on mock - case = [ - { - "type": "event", - "eventId": "a2321a5b-f883-11ec-8225-52540095fac0", - "batchId": None, - "isBatched": False, - "eventName": "[TS_1]5 partfill trades and cancel.", - "eventType": "", - "endTimestamp": {"nano": 735114000, "epochSecond": 1656600478}, - "startTimestamp": {"nano": 735039000, "epochSecond": 1656600478}, - "parentEventId": None, - "successful": False, - "attachedMessageIds": [], - "body": {}, - } - ] - case1 = [ - { - "type": "event", - "eventId": "bb0da3a9-f883-11ec-aeb3-adf8526f5eec", - "batchId": None, - "isBatched": False, - "eventName": "Received 'ExecutionReport' response message", - "eventType": "message", - "endTimestamp": {"nano": 428471000, "epochSecond": 1656600520}, - "startTimestamp": {"nano": 428350000, "epochSecond": 1656600520}, - "parentEventId": "ba4e7257-f883-11ec-aeb3-adf8526f5eec", - "successful": True, - "attachedMessageIds": [], - "body": [ - { - "type": "treeTable", - "rows": { - "ExecID": {"type": "row", "columns": {"fieldValue": "E0AmqxctTQGw"}}, - "OrderQty": {"type": "row", "columns": {"fieldValue": "20"}}, - "LastQty": {"type": "row", "columns": {"fieldValue": "20"}}, - "OrderID": {"type": "row", "columns": {"fieldValue": "00Amr2Sw36j1"}}, - "TransactTime": {"type": "row", "columns": {"fieldValue": "2022-06-30T14:48:39.526758"}}, - "GroupID": {"type": "row", "columns": {"fieldValue": "0"}}, - "trailer": { - "type": "collection", - "rows": {"CheckSum": {"type": "row", "columns": {"fieldValue": "136"}}}, - }, - "Side": {"type": "row", "columns": {"fieldValue": "2"}}, - "OrdStatus": {"type": "row", "columns": {"fieldValue": "2"}}, - "TimeInForce": {"type": "row", "columns": {"fieldValue": "0"}}, - "SecurityID": {"type": "row", "columns": {"fieldValue": "5221001"}}, - "ExecType": {"type": "row", "columns": {"fieldValue": "F"}}, - "TradeLiquidityIndicator": {"type": "row", "columns": {"fieldValue": "R"}}, - "LastLiquidityInd": {"type": "row", "columns": {"fieldValue": "2"}}, - "LeavesQty": {"type": "row", "columns": {"fieldValue": "0"}}, - "CumQty": {"type": "row", "columns": {"fieldValue": "20"}}, - "LastPx": {"type": "row", "columns": {"fieldValue": "55"}}, - "TypeOfTrade": {"type": "row", "columns": {"fieldValue": "2"}}, - "TrdMatchID": {"type": "row", "columns": {"fieldValue": "L2N1AYTNPW"}}, - "OrdType": {"type": "row", "columns": {"fieldValue": "2"}}, - "ClOrdID": {"type": "row", "columns": {"fieldValue": "1985282"}}, - "SecurityIDSource": {"type": "row", "columns": {"fieldValue": "8"}}, - "LastMkt": {"type": "row", "columns": {"fieldValue": "XLOM"}}, - "OrderCapacity": {"type": "row", "columns": {"fieldValue": "A"}}, - "SecondaryClOrdID": {"type": "row", "columns": {"fieldValue": "33333"}}, - "AccountType": {"type": "row", "columns": {"fieldValue": "1"}}, - "Price": {"type": "row", "columns": {"fieldValue": "55"}}, - "MDEntryID": {"type": "row", "columns": {"fieldValue": "00Amr2Sw36j1"}}, - "TradingParty": { - "type": "collection", - "rows": { - "NoPartyIDs": { - "type": "collection", - "rows": { - "0": { - "type": "collection", - "rows": { - "PartyRole": {"type": "row", "columns": {"fieldValue": "76"}}, - "PartyID": {"type": "row", "columns": {"fieldValue": "ARFQ01FIX08"}}, - "PartyIDSource": {"type": "row", "columns": {"fieldValue": "D"}}, - }, - }, - "1": { - "type": "collection", - "rows": { - "PartyRole": {"type": "row", "columns": {"fieldValue": "17"}}, - "PartyID": {"type": "row", "columns": {"fieldValue": "ARFQ01"}}, - "PartyIDSource": {"type": "row", "columns": {"fieldValue": "D"}}, - }, - }, - "2": { - "type": "collection", - "rows": { - "PartyRole": {"type": "row", "columns": {"fieldValue": "3"}}, - "PartyID": {"type": "row", "columns": {"fieldValue": "0"}}, - "PartyIDSource": {"type": "row", "columns": {"fieldValue": "P"}}, - }, - }, - "3": { - "type": "collection", - "rows": { - "PartyRole": {"type": "row", "columns": {"fieldValue": "122"}}, - "PartyID": {"type": "row", "columns": {"fieldValue": "0"}}, - "PartyIDSource": {"type": "row", "columns": {"fieldValue": "P"}}, - }, - }, - "4": { - "type": "collection", - "rows": { - "PartyRole": {"type": "row", "columns": {"fieldValue": "12"}}, - "PartyID": {"type": "row", "columns": {"fieldValue": "3"}}, - "PartyIDSource": {"type": "row", "columns": {"fieldValue": "P"}}, - }, - }, - }, - } - }, - }, - "header": { - "type": "collection", - "rows": { - "BeginString": {"type": "row", "columns": {"fieldValue": "FIXT.1.1"}}, - "SenderCompID": {"type": "row", "columns": {"fieldValue": "FGW"}}, - "SendingTime": {"type": "row", "columns": {"fieldValue": "2022-06-30T14:48:39.530311"}}, - "TargetCompID": {"type": "row", "columns": {"fieldValue": "ARFQ01FIX08"}}, - "ApplVerID": {"type": "row", "columns": {"fieldValue": "9"}}, - "MsgType": {"type": "row", "columns": {"fieldValue": "8"}}, - "MsgSeqNum": {"type": "row", "columns": {"fieldValue": "589"}}, - "BodyLength": {"type": "row", "columns": {"fieldValue": "432"}}, - }, - }, - "DisplayQty": {"type": "row", "columns": {"fieldValue": "0"}}, - }, - } - ], - } - ] - case3 = [ - { - "type": "message", - "timestamp": {"nano": 422000000, "epochSecond": 1656600504}, - "messageType": "NewOrderSingle", - "direction": "OUT", - "sessionId": "arfq01fix07", - "attachedEventIds": [], - "messageId": "arfq01fix07:second:1656599837520228626", - "body": { - "metadata": { - "id": { - "connectionId": {"sessionAlias": "arfq01fix07"}, - "direction": "SECOND", - "sequence": "1656599837520228626", - "subsequence": [1], - }, - "timestamp": "2022-06-30T14:48:24.422Z", - "messageType": "NewOrderSingle", - "protocol": "FIX", - }, - "fields": { - "OrderQty": {"simpleValue": "200"}, - "OrdType": {"simpleValue": "2"}, - "ClOrdID": {"simpleValue": "1830410"}, - "SecurityIDSource": {"simpleValue": "8"}, - "OrderCapacity": {"simpleValue": "A"}, - "TransactTime": {"simpleValue": "2022-06-30T14:47:59.032276"}, - "SecondaryClOrdID": {"simpleValue": "11111"}, - "AccountType": {"simpleValue": "1"}, - "trailer": {"messageValue": {"fields": {"CheckSum": {"simpleValue": "152"}}}}, - "Side": {"simpleValue": "1"}, - "Price": {"simpleValue": "55"}, - "TradingParty": { - "messageValue": { - "fields": { - "NoPartyIDs": { - "listValue": { - "values": [ - { - "messageValue": { - "fields": { - "PartyRole": {"simpleValue": "76"}, - "PartyID": {"simpleValue": "ARFQ01FIX07"}, - "PartyIDSource": {"simpleValue": "D"}, - } - } - }, - { - "messageValue": { - "fields": { - "PartyRole": {"simpleValue": "3"}, - "PartyID": {"simpleValue": "0"}, - "PartyIDSource": {"simpleValue": "P"}, - } - } - }, - { - "messageValue": { - "fields": { - "PartyRole": {"simpleValue": "122"}, - "PartyID": {"simpleValue": "0"}, - "PartyIDSource": {"simpleValue": "P"}, - } - } - }, - { - "messageValue": { - "fields": { - "PartyRole": {"simpleValue": "12"}, - "PartyID": {"simpleValue": "3"}, - "PartyIDSource": {"simpleValue": "P"}, - } - } - }, - ] - } - } - } - } - }, - "SecurityID": {"simpleValue": "5221001"}, - "header": { - "messageValue": { - "fields": { - "BeginString": {"simpleValue": "FIXT.1.1"}, - "SenderCompID": {"simpleValue": "ARFQ01FIX07"}, - "SendingTime": {"simpleValue": "2022-06-30T14:48:24.330"}, - "TargetCompID": {"simpleValue": "FGW"}, - "MsgType": {"simpleValue": "D"}, - "MsgSeqNum": {"simpleValue": "626"}, - "BodyLength": {"simpleValue": "263"}, - } - } - }, - "DisplayQty": {"simpleValue": "200"}, - }, - }, - "bodyBase64": "OD1GSVhULjEuMQE5PTI2MwEzNT1EATM0PTYyNgE0OT1BUkZRMDFGSVgwNwE1Mj0yMDIyMDYzMC0xNDo0ODoyNC4zMzAwMDABNTY9RkdXATExPTE4MzA0MTABMjI9OAEzOD0yMDABNDA9MgE0ND01NQE0OD01MjIxMDAxATU0PTEBNjA9MjAyMjA2MzAtMTQ6NDc6NTkuMDMyMjc2ATUyNj0xMTExMQE1Mjg9QQE1ODE9MQExMTM4PTIwMAE0NTM9NAE0NDg9QVJGUTAxRklYMDcBNDQ3PUQBNDUyPTc2ATQ0OD0wATQ0Nz1QATQ1Mj0zATQ0OD0wATQ0Nz1QATQ1Mj0xMjIBNDQ4PTMBNDQ3PVABNDUyPTEyATEwPTE1MgE=", - } - ] - assert list(demo_get_messages_with_one_filter) == case3 - assert list(demo_get_messages_with_filters) == case3 - assert list(demo_get_events_with_one_filter) == case and len(case) is 1 - assert list(demo_get_events_with_filters) == case1 and len(case1) is 1 diff --git a/tests/tests_unit/tests_diff_version/tests_v5/test_filter.py b/tests/tests_unit/tests_diff_version/tests_v5/test_filter.py deleted file mode 100644 index 0b6bd5fa..00000000 --- a/tests/tests_unit/tests_diff_version/tests_v5/test_filter.py +++ /dev/null @@ -1,9 +0,0 @@ -from tests.tests_unit.tests_diff_version.conftest import Filter - - -def test_repr(): - f = Filter(name="type", values=["one", 2, "three"]) - assert repr(f) == "Filter(name='type', values=['one', '2', 'three'], negative='False', conjunct='False')" - - f = Filter(name="type", values="abc") - assert repr(f) == "Filter(name='type', values=['abc'], negative='False', conjunct='False')" diff --git a/tests/tests_unit/tests_diff_version/tests_v5/tests_events_tree/test_events_tree.py b/tests/tests_unit/tests_diff_version/tests_v5/tests_events_tree/test_events_tree.py deleted file mode 100644 index e8f8dfec..00000000 --- a/tests/tests_unit/tests_diff_version/tests_v5/tests_events_tree/test_events_tree.py +++ /dev/null @@ -1,263 +0,0 @@ -from typing import List, NamedTuple - -from th2_data_services.provider.v5.events_tree.events_tree_collection import EventsTreeCollectionProvider5 -from th2_data_services.events_tree.events_tree import EventsTree -from th2_data_services.provider.v5.struct import provider5_event_struct - - -def test_build_tree(general_data: List[dict], test_events_tree: NamedTuple): - collection = EventsTreeCollectionProvider5(general_data) - tree = collection.get_trees()[0] - - assert [ - event[provider5_event_struct.EVENT_ID] for event in tree.get_all_events() - ] == test_events_tree.events and list(collection.detached_events.keys()) == test_events_tree.unknown_events - - -def test_append_unknown_element(general_data: List[dict]): - collection = EventsTreeCollectionProvider5(general_data) - parent_event_id = "122111-2112-3333-445544" - event_id = "111111-2222-3333-444444" - new_event = { - "eventId": event_id, - "parentEventId": parent_event_id, - "eventName": "testName", - } - collection.append_event(new_event) - - assert parent_event_id in collection.detached_events and event_id in [ - event["eventId"] for event in collection.detached_events[parent_event_id] - ] - - -def test_append_new_element(general_data: List[dict]): - collection = EventsTreeCollectionProvider5(general_data) - parent_event_id = "6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c035903-d1b4-11eb-9278-591e568ad66e" - event_id = "1111-3333-4444-5555" - new_event = { - "eventId": event_id, - "parentEventId": parent_event_id, - "eventName": "testName", - } - collection.append_event(new_event) - - assert event_id in collection - - -def test_build_parentless_trees(general_data: List[dict]): - general_data += [ - { - "eventId": "a3779b94-d051-11eb-986f-1e8d42132387", - "parentEventId": "a3777794-d051-11eb-986f-1eddddd387", - "eventName": "test", - } - ] - - collection = EventsTreeCollectionProvider5(general_data) - trees = collection.get_parentless_trees() - - assert trees[1]._tree.get_node("a3779b94-d051-11eb-986f-1e8d42132387") and not collection.detached_events - - -def test_contain_element(general_data: List[dict]): - collection = EventsTreeCollectionProvider5(general_data) - tree = collection.get_trees()[0] - event_id = "84db48fc-d1b4-11eb-b0fb-199708acc7bc" - - assert event_id in collection and event_id in tree - - -def test_append_new_tree(general_data: List[dict]): - collection = EventsTreeCollectionProvider5(general_data) - event_id = "1111-3333-4444-5555" - new_event = {"eventId": event_id, "eventName": "testName"} - collection.append_event(new_event) - - assert event_id in collection and event_id in collection.get_roots_ids() - - -def test_filter_all(general_data: List[dict]): - tree = EventsTreeCollectionProvider5(general_data).get_trees()[0] - - assert len(tree.findall(lambda event: "Checkpoint" in event["eventName"])) == 11 - - -def test_filter_all_max_count(general_data: List[dict]): - tree = EventsTreeCollectionProvider5(general_data).get_trees()[0] - - assert len(tree.findall(lambda event: "Checkpoint" in event["eventName"], max_count=5)) == 5 - - -def test_filter_stop_function(general_data: List[dict]): - tree = EventsTreeCollectionProvider5(general_data).get_trees()[0] - - assert ( - len( - tree.findall( - lambda event: "Checkpoint" in event["eventName"], - stop=lambda event: "th2-hand-demo" in event["eventName"], - ) - ) - == 1 - ) - - -def test_filter_one(general_data: List[dict]): - tree = EventsTreeCollectionProvider5(general_data).get_trees()[0] - - assert tree.find(lambda event: "Checkpoint" in event["eventName"]) == { - "batchId": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4", - "eventId": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c035903-d1b4-11eb-9278-591e568ad66e", - "eventName": "Checkpoint", - "eventType": "Checkpoint", - "isBatched": True, - "parentEventId": "8bc787fe-d1b4-11eb-bae5-57b0c4472880", - } - - -def test_filter_stop(general_data: List[dict]): - tree = EventsTreeCollectionProvider5(general_data).get_trees()[0] - - assert not tree.find( - lambda event: "Checkpoint" in event["eventName"], - stop=lambda event: "Checkpoint" in event["eventType"], - ) - - -def test_subtree(general_data: List[dict]): - tree = EventsTreeCollectionProvider5(general_data).get_trees()[0] - assert isinstance( - tree.get_subtree("6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c035903-d1b4-11eb-9278-591e568ad66e"), EventsTree - ) - assert len(tree.get_subtree("6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c035903-d1b4-11eb-9278-591e568ad66e")) == 11 - - -def test_get_all_events(general_data: List[dict]): - tree = EventsTreeCollectionProvider5(general_data).get_trees()[0] - - assert len(tree.get_all_events()) == 18 - - -def test_get_all_events_iter(general_data: List[dict]): - tree = EventsTreeCollectionProvider5(general_data).get_trees()[0] - - assert len(list(tree.get_all_events_iter())) == 18 - - -def test_get_event(general_data: List[dict]): - tree = EventsTreeCollectionProvider5(general_data).get_trees()[0] - - assert tree.get_event("6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c035903-d1b4-11eb-9278-591e568ad66e") - - -def test_get_full_path(general_data: List[dict]): - tree = EventsTreeCollectionProvider5(general_data).get_trees()[0] - - assert tree.get_full_path("8c3fec4f-d1b4-11eb-bae5-57b0c4472880") == [ - { - "batchId": None, - "eventId": "84db48fc-d1b4-11eb-b0fb-199708acc7bc", - "eventName": "[TS_1]Aggressive IOC vs two orders: second order's price is lower than first", - "eventType": "", - "isBatched": False, - "parentEventId": None, - }, - { - "batchId": None, - "eventId": "88a3ee80-d1b4-11eb-b0fb-199708acc7bc", - "eventName": "Case[TC_1.1]: Trader DEMO-CONN1 vs trader DEMO-CONN2 for instrument INSTR1", - "eventType": "", - "isBatched": False, - "parentEventId": "84db48fc-d1b4-11eb-b0fb-199708acc7bc", - }, - { - "batchId": None, - "eventId": "8bc787fe-d1b4-11eb-bae5-57b0c4472880", - "eventName": 'placeOrderFIX demo-conn1 - STEP1: Trader "DEMO-CONN1" sends request to create passive Order.', - "eventType": "placeOrderFIX", - "isBatched": False, - "parentEventId": "88a3ee80-d1b4-11eb-b0fb-199708acc7bc", - }, - { - "batchId": None, - "eventId": "8c3fec4f-d1b4-11eb-bae5-57b0c4472880", - "eventName": "Send 'NewOrderSingle' message to connectivity", - "eventType": "Outgoing message", - "isBatched": False, - "parentEventId": "8bc787fe-d1b4-11eb-bae5-57b0c4472880", - }, - ] - - -def test_get_full_path_with_field(general_data: List[dict]): - tree = EventsTreeCollectionProvider5(general_data).get_trees()[0] - - assert tree.get_full_path("8c3fec4f-d1b4-11eb-bae5-57b0c4472880", field="eventName") == [ - "[TS_1]Aggressive IOC vs two orders: second order's price is lower than first", - "Case[TC_1.1]: Trader DEMO-CONN1 vs trader DEMO-CONN2 for instrument INSTR1", - 'placeOrderFIX demo-conn1 - STEP1: Trader "DEMO-CONN1" sends request to create passive Order.', - "Send 'NewOrderSingle' message to connectivity", - ] - - -def test_get_leaves(general_data: List[dict]): - tree = EventsTreeCollectionProvider5(general_data).get_trees()[0] - - assert len(tree.get_leaves()) == 14 - - -def test_get_root_id(general_data: List[dict]): - tree = EventsTreeCollectionProvider5(general_data).get_trees()[0] - - assert tree.get_root_id() == "84db48fc-d1b4-11eb-b0fb-199708acc7bc" - - -def test_get_children(general_data: List[dict]): - tree = EventsTreeCollectionProvider5(general_data).get_trees()[0] - - assert len(tree.get_children("6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c035903-d1b4-11eb-9278-591e568ad66e")) == 10 - - -def test_get_children_iter(general_data: List[dict]): - tree = EventsTreeCollectionProvider5(general_data).get_trees()[0] - - assert ( - len(list(tree.get_children_iter("6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c035903-d1b4-11eb-9278-591e568ad66e"))) - == 10 - ) - - -def test_get_parent(general_data: List[dict]): - tree = EventsTreeCollectionProvider5(general_data).get_trees()[0] - - assert tree.get_parent("6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c035903-d1b4-11eb-9278-591e568ad66e") == { - "batchId": None, - "eventId": "8bc787fe-d1b4-11eb-bae5-57b0c4472880", - "eventName": 'placeOrderFIX demo-conn1 - STEP1: Trader "DEMO-CONN1" sends ' "request to create passive Order.", - "eventType": "placeOrderFIX", - "isBatched": False, - "parentEventId": "88a3ee80-d1b4-11eb-b0fb-199708acc7bc", - } - - -def test_find_ancestor(general_data: List[dict]): - tree = EventsTreeCollectionProvider5(general_data).get_trees()[0] - - assert tree.find_ancestor( - "6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c1114a4-d1b4-11eb-9278-591e568ad66e", - lambda event: "placeOrderFIX" in event["eventName"], - ) - - -def test_get_root(general_data: List[dict]): - collection = EventsTreeCollectionProvider5(general_data) - tree = collection.get_trees()[0] - - assert tree.get_root() == { - "batchId": None, - "eventId": "84db48fc-d1b4-11eb-b0fb-199708acc7bc", - "eventName": "[TS_1]Aggressive IOC vs two orders: second order's price is lower than first", - "eventType": "", - "isBatched": False, - "parentEventId": None, - } diff --git a/tests/tests_unit/tests_diff_version/tests_v5/tests_events_tree/test_events_tree_collection.py b/tests/tests_unit/tests_diff_version/tests_v5/tests_events_tree/test_events_tree_collection.py deleted file mode 100644 index 77607770..00000000 --- a/tests/tests_unit/tests_diff_version/tests_v5/tests_events_tree/test_events_tree_collection.py +++ /dev/null @@ -1,509 +0,0 @@ -from typing import List, Generator -import warnings -import pytest -from th2_data_services.events_tree.exceptions import EventIdNotInTree -from th2_data_services.provider.v5.events_tree.events_tree_collection import EventsTreeCollectionProvider5 - - -def test_get_parentless_trees(): - """It checks that parentless trees were created, added to roots and detached events removed.""" - # TODO - - -def test_len_trees(general_data: List[dict]): - etc = EventsTreeCollectionProvider5(general_data) - assert etc.len_trees == 18 - - -def test_len_detached_events(general_data: List[dict]): - etc = EventsTreeCollectionProvider5(general_data) - assert etc.len_detached_events == 3 - - -def test_len(general_data: List[dict]): - """Total events in whole collection.""" - etc = EventsTreeCollectionProvider5(general_data) - assert len(etc) == len(general_data) - - -def test_filter_all(general_data: List[dict]): - collection = EventsTreeCollectionProvider5(general_data) - - assert len(collection.findall(lambda event: "Checkpoint" in event["eventName"])) == 11 - - -def test_filter_all_max_count(general_data: List[dict]): - collection = EventsTreeCollectionProvider5(general_data) - - assert len(collection.findall(lambda event: "Checkpoint" in event["eventName"], max_count=5)) == 5 - - -def test_filter_stop_function(general_data: List[dict]): - collection = EventsTreeCollectionProvider5(general_data) - - assert ( - len( - collection.findall( - lambda event: "Checkpoint" in event["eventName"], - stop=lambda event: "th2-hand-demo" in event["eventName"], - ) - ) - == 1 - ) - - -def test_filter_one(general_data: List[dict]): - collection = EventsTreeCollectionProvider5(general_data) - - assert collection.find(lambda event: "Checkpoint" in event["eventName"]) == { - "batchId": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4", - "eventId": "6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c035903-d1b4-11eb-9278-591e568ad66e", - "eventName": "Checkpoint", - "eventType": "Checkpoint", - "isBatched": True, - "parentEventId": "8bc787fe-d1b4-11eb-bae5-57b0c4472880", - } - - -def test_filter_stop(general_data: List[dict]): - collection = EventsTreeCollectionProvider5(general_data) - - assert not collection.find( - lambda event: "Checkpoint" in event["eventName"], - stop=lambda event: "Checkpoint" in event["eventType"], - ) - - -def test_subtree(general_data: List[dict]): - collection = EventsTreeCollectionProvider5(general_data) - - assert ( - len(collection.get_subtree("6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c035903-d1b4-11eb-9278-591e568ad66e")) == 11 - ) - - -def test_get_roots_ids_with_parentless(parentless_data: List[dict]): - etc = EventsTreeCollectionProvider5(parentless_data) - assert etc.get_roots_ids() == ["a", "x"] - etc.get_parentless_trees() - assert etc.get_roots_ids() == ["a", "x", "e"] - - -def test_get_trees_with_parentless(parentless_data: List[dict]): - etc = EventsTreeCollectionProvider5(parentless_data) - full_fledged_trees = etc.get_trees() - parentless_trees = etc.get_parentless_trees() - assert etc.get_trees() == full_fledged_trees + parentless_trees - - -def test_get_root_by_id_with_parentless(parentless_data: List[dict]): - etc = EventsTreeCollectionProvider5(parentless_data) - assert etc.get_root_by_id("b") == {"type": "event", "eventId": "a", "eventName": "a", "parentEventId": None} - etc.get_parentless_trees() - assert etc.get_root_by_id("d") == etc._build_stub_event("e") - - with pytest.raises(EventIdNotInTree): - etc.get_root_by_id("EventIdNotInTree") - - -def test_get_tree_by_id_with_parentless(parentless_data: List[dict]): - etc = EventsTreeCollectionProvider5(parentless_data) - parentless_trees = etc.get_parentless_trees()[0] - assert etc.get_tree_by_id("d") == parentless_trees - - with pytest.raises(EventIdNotInTree): - etc.get_tree_by_id("EventIdNotInTree") - - -def test_len_with_parentless(parentless_data: List[dict]): - etc = EventsTreeCollectionProvider5(parentless_data) - assert etc.len_trees == 6 and etc.len_detached_events == 2 and etc.len_parentless == 0 - etc.get_parentless_trees() - assert etc.len_trees == 9 and etc.len_detached_events == 0 and etc.len_parentless == 3 - - -def test_get_all_events_iter_with_parentless(parentless_data: List[dict]): - etc = EventsTreeCollectionProvider5(parentless_data) - iter_events = etc.get_all_events_iter() - assert isinstance(iter_events, Generator) - assert list(iter_events) == parentless_data - etc.get_parentless_trees() - iter_events = etc.get_all_events_iter() - parentless_data.insert(6, etc._build_stub_event("e")) - assert list(iter_events) == parentless_data - - -def test_get_all_events_with_parentless(parentless_data: List[dict]): - etc = EventsTreeCollectionProvider5(parentless_data) - events = etc.get_all_events() - assert isinstance(events, list) - assert events == parentless_data - etc.get_parentless_trees() - events = etc.get_all_events() - parentless_data.insert(6, etc._build_stub_event("e")) - assert events == parentless_data - - -def test_get_event_with_parentless(parentless_data: List[dict]): - etc = EventsTreeCollectionProvider5(parentless_data) - assert etc.get_event("a") and etc.get_event("x") - assert etc.get_event("d") and etc.get_event("t") - etc.get_parentless_trees() - assert etc.get_event("d") and etc.get_event("t") and etc.get_event("e") - - with pytest.raises(EventIdNotInTree): - etc.get_event("EventIdNotInTree") - - -def test_get_leaves_iter_with_parentless(parentless_data: List[dict]): - etc = EventsTreeCollectionProvider5(parentless_data) - iter_leaves = etc.get_leaves_iter() - assert isinstance(iter_leaves, Generator) - assert list(iter_leaves) == [parentless_data[2], parentless_data[5]] - etc.get_parentless_trees() - iter_leaves = etc.get_leaves_iter() - assert list(iter_leaves) == [parentless_data[2], parentless_data[5], parentless_data[7]] - - -def test_get_leaves_with_parentless(parentless_data: List[dict]): - etc = EventsTreeCollectionProvider5(parentless_data) - leaves = etc.get_leaves() - assert isinstance(leaves, tuple) - assert leaves == (parentless_data[2], parentless_data[5]) - etc.get_parentless_trees() - leaves = etc.get_leaves() - assert leaves == (parentless_data[2], parentless_data[5], parentless_data[7]) - - -def test_get_children_iter_with_parentless(parentless_data: List[dict]): - etc = EventsTreeCollectionProvider5(parentless_data) - etc.get_parentless_trees() - iter_children_0 = etc.get_children_iter("e") - iter_children_1 = etc.get_children_iter("d") - assert isinstance(iter_children_0, Generator) - assert list(iter_children_0) == [parentless_data[6]] - assert list(iter_children_1) == [parentless_data[7]] - - with pytest.raises(EventIdNotInTree): - list(etc.get_children_iter("EventIdNotInTree")) - - -def test_get_children_with_parentless(parentless_data: List[dict]): - etc = EventsTreeCollectionProvider5(parentless_data) - etc.get_parentless_trees() - children_0 = etc.get_children("e") - children_1 = etc.get_children("d") - assert isinstance(children_0, tuple) - assert children_0 == (parentless_data[6],) - assert children_1 == (parentless_data[7],) - - with pytest.raises(EventIdNotInTree): - list(etc.get_children("EventIdNotInTree")) - - -def test_get_parent_with_parentless(parentless_data: List[dict]): - etc = EventsTreeCollectionProvider5(parentless_data) - with pytest.raises(EventIdNotInTree): - etc.get_parent("d") - assert etc.get_parent("t") == etc.get_event("d") - etc.get_parentless_trees() - assert etc.get_parent("d") == etc._build_stub_event("e") - - -def test_get_full_path_with_parentless(parentless_data: List[dict]): - etc = EventsTreeCollectionProvider5(parentless_data) - with pytest.raises(EventIdNotInTree): - etc.get_full_path("t") - - etc.get_parentless_trees() - assert etc.get_full_path("t") == [etc._build_stub_event("e"), parentless_data[6], parentless_data[7]] - - -def test_get_ancestors_with_parentless(parentless_data: List[dict]): - etc = EventsTreeCollectionProvider5(parentless_data) - with pytest.raises(EventIdNotInTree): - etc.get_ancestors("t") - etc.get_parentless_trees() - assert etc.get_ancestors("t") == [etc._build_stub_event("e"), parentless_data[6]] - - -def test_find_ancestor_with_parentless(parentless_data: List[dict]): - etc = EventsTreeCollectionProvider5(parentless_data) - assert etc.find_ancestor("t", lambda event: "t" in event["eventName"]) is None - etc.get_parentless_trees() - assert etc.find_ancestor("t", lambda event: "d" in event["eventName"]) == parentless_data[6] - - -def test_findall_iter_with_parentless(parentless_data: List[dict]): - etc = EventsTreeCollectionProvider5(parentless_data) - assert list(etc.findall_iter(lambda event: "Broken_Event" == event["eventName"])) == [] - etc.get_parentless_trees() - assert list(etc.findall_iter(lambda event: "Broken_Event" == event["eventName"]))[0] == etc._build_stub_event("e") - - -def test_findall_with_parentless(parentless_data: List[dict]): - etc = EventsTreeCollectionProvider5(parentless_data) - assert etc.findall(lambda event: "Broken_Event" == event["eventName"]) == [] - etc.get_parentless_trees() - assert etc.findall(lambda event: "Broken_Event" == event["eventName"])[0] == etc._build_stub_event("e") - - -def test_find_with_parentless(parentless_data: List[dict]): - etc = EventsTreeCollectionProvider5(parentless_data) - assert etc.find(lambda event: "Broken_Event" == event["eventName"]) is None - etc.get_parentless_trees() - assert etc.find(lambda event: "Broken_Event" == event["eventName"]) == etc._build_stub_event("e") - - -def test_subtree_with_parentless(parentless_data: List[dict]): - etc = EventsTreeCollectionProvider5(parentless_data) - parentless = etc.get_parentless_trees() - assert etc.len_detached_events == 0 and len(parentless[0]) == 3 - assert len(etc.get_subtree("d")) == 2 and len(etc.get_subtree("t")) == 1 - - with pytest.raises(EventIdNotInTree): - etc.get_subtree("EventIdNotInTree") - - -def test_contains_with_parentless(parentless_data: List[dict]): - etc = EventsTreeCollectionProvider5(parentless_data) - detached = ["a", "b", "c", "x", "y", "z"] - assert all([id in etc for id in detached]) - detached.extend(["e", "d", "t"]) - with pytest.raises(AssertionError): - assert all([id in etc for id in detached]) - etc.get_parentless_trees() - assert all([id in etc for id in detached]) - - -def test_get_all_events(general_data: List[dict]): - collection = EventsTreeCollectionProvider5(general_data) - - assert len(collection.get_all_events()) == len(general_data) - - -def test_get_all_events_iter(general_data: List[dict]): - collection = EventsTreeCollectionProvider5(general_data) - - assert len(list(collection.get_all_events_iter())) == len(general_data) - - -def test_get_event(general_data: List[dict]): - collection = EventsTreeCollectionProvider5(general_data) - - assert collection.get_event("6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c035903-d1b4-11eb-9278-591e568ad66e") - - -def test_get_full_path(general_data: List[dict]): - collection = EventsTreeCollectionProvider5(general_data) - - assert collection.get_full_path("8c3fec4f-d1b4-11eb-bae5-57b0c4472880") == [ - { - "batchId": None, - "eventId": "84db48fc-d1b4-11eb-b0fb-199708acc7bc", - "eventName": "[TS_1]Aggressive IOC vs two orders: second order's price is lower than first", - "eventType": "", - "isBatched": False, - "parentEventId": None, - }, - { - "batchId": None, - "eventId": "88a3ee80-d1b4-11eb-b0fb-199708acc7bc", - "eventName": "Case[TC_1.1]: Trader DEMO-CONN1 vs trader DEMO-CONN2 for instrument INSTR1", - "eventType": "", - "isBatched": False, - "parentEventId": "84db48fc-d1b4-11eb-b0fb-199708acc7bc", - }, - { - "batchId": None, - "eventId": "8bc787fe-d1b4-11eb-bae5-57b0c4472880", - "eventName": 'placeOrderFIX demo-conn1 - STEP1: Trader "DEMO-CONN1" sends request to create passive Order.', - "eventType": "placeOrderFIX", - "isBatched": False, - "parentEventId": "88a3ee80-d1b4-11eb-b0fb-199708acc7bc", - }, - { - "batchId": None, - "eventId": "8c3fec4f-d1b4-11eb-bae5-57b0c4472880", - "eventName": "Send 'NewOrderSingle' message to connectivity", - "eventType": "Outgoing message", - "isBatched": False, - "parentEventId": "8bc787fe-d1b4-11eb-bae5-57b0c4472880", - }, - ] - - -def test_get_full_path_with_field(general_data: List[dict]): - collection = EventsTreeCollectionProvider5(general_data) - - assert collection.get_full_path("8c3fec4f-d1b4-11eb-bae5-57b0c4472880", field="eventName") == [ - "[TS_1]Aggressive IOC vs two orders: second order's price is lower than first", - "Case[TC_1.1]: Trader DEMO-CONN1 vs trader DEMO-CONN2 for instrument INSTR1", - 'placeOrderFIX demo-conn1 - STEP1: Trader "DEMO-CONN1" sends request to create passive Order.', - "Send 'NewOrderSingle' message to connectivity", - ] - - -def test_get_leaves(general_data: List[dict]): - collection = EventsTreeCollectionProvider5(general_data) - - assert len(collection.get_leaves()) == 14 - - -def test_get_children(general_data: List[dict]): - collection = EventsTreeCollectionProvider5(general_data) - - assert ( - len(collection.get_children("6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c035903-d1b4-11eb-9278-591e568ad66e")) == 10 - ) - - -def test_get_children_iter(general_data: List[dict]): - collection = EventsTreeCollectionProvider5(general_data) - - assert ( - len( - list( - collection.get_children_iter( - "6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c035903-d1b4-11eb-9278-591e568ad66e" - ) - ) - ) - == 10 - ) - - -def test_get_parent(general_data: List[dict]): - collection = EventsTreeCollectionProvider5(general_data) - - assert collection.get_parent("6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c035903-d1b4-11eb-9278-591e568ad66e") == { - "batchId": None, - "eventId": "8bc787fe-d1b4-11eb-bae5-57b0c4472880", - "eventName": 'placeOrderFIX demo-conn1 - STEP1: Trader "DEMO-CONN1" sends ' "request to create passive Order.", - "eventType": "placeOrderFIX", - "isBatched": False, - "parentEventId": "88a3ee80-d1b4-11eb-b0fb-199708acc7bc", - } - - -def test_find_ancestor(general_data: List[dict]): - collection = EventsTreeCollectionProvider5(general_data) - - assert collection.find_ancestor( - "6e3be13f-cab7-4653-8cb9-6e74fd95ade4:8c1114a4-d1b4-11eb-9278-591e568ad66e", - lambda event: "placeOrderFIX" in event["eventName"], - ) - - -def test_build_parentless_tree(general_data: List[dict]): - collections = EventsTreeCollectionProvider5(general_data) - trees = collections.get_parentless_trees() - - template = { - "attachedMessageIds": [], - "batchId": "Broken_Event", - "endTimestamp": {"nano": 0, "epochSecond": 0}, - "startTimestamp": {"nano": 0, "epochSecond": 0}, - "type": "event", - "eventName": "Broken_Event", - "eventType": "Broken_Event", - "parentEventId": "Broken_Event", - "successful": None, - "isBatched": None, - } - - assert trees[0].get_all_events() == [ - {"eventId": "a3779b94-d051-11eb-986f-1e8d42132387", **template}, - { - "batchId": "654c2724-5202-460b-8e6c-a7ee9fb02ddf", - "eventId": "654c2724-5202-460b-8e6c-a7ee9fb02ddf:8ca20288-d1b4-11eb-986f-1e8d42132387", - "eventName": "Remove 'NewOrderSingle' id='demo-conn1:SECOND:1624005455622135205' Hash='7009491514226292581' Group='NOS_CONN' Hash['SecondaryClOrdID': 11111, 'SecurityID': INSTR1]", - "isBatched": True, - "eventType": "", - "parentEventId": "a3779b94-d051-11eb-986f-1e8d42132387", - }, - ] and trees[1].get_all_events() == [ - {"eventId": "845d70d2-9c68-11eb-8598-691ebd7f413d", **template}, - { - "batchId": None, - "eventId": "8ceb47f6-d1b4-11eb-a9ed-ffb57363e013", - "eventName": "Send 'ExecutionReport' message", - "isBatched": False, - "eventType": "Send message", - "parentEventId": "845d70d2-9c68-11eb-8598-691ebd7f413d", - }, - { - "batchId": None, - "eventId": "8ced1c93-d1b4-11eb-a9f4-b12655548efc", - "eventName": "Send 'ExecutionReport' message", - "isBatched": False, - "eventType": "Send message", - "parentEventId": "845d70d2-9c68-11eb-8598-691ebd7f413d", - }, - ] - - -def test_checker_tree_with_detached_events(log_checker, detached_data: List[dict]): - etc = EventsTreeCollectionProvider5(detached_data) - log_checker.detached_etc_created(etc) - - -def test_show_warning_about_detached_events(detached_data: List[dict]): - def create_etc(): - etc = EventsTreeCollectionProvider5(detached_data) - - with warnings.catch_warnings(record=True) as w: - warnings.simplefilter("always") - create_etc() - assert "The collection were built with detached events because there are no some events in the source" in str( - w[-1].message - ) - - -def test_get_tree_by_id(general_data: List[dict]): - collection = EventsTreeCollectionProvider5(general_data) - tree = collection.get_trees()[0] - - assert collection.get_tree_by_id("8d6e0c9e-d1b4-11eb-9278-591e568ad66e") == tree - assert collection.get_tree_by_id("84db48fc-d1b4-11eb-b0fb-199708acc7bc") == tree - assert collection.get_tree_by_id("8c3fec4f-d1b4-11eb-bae5-57b0c4472880") == tree - - -def test_get_root_by_id(general_data: List[dict]): - collection = EventsTreeCollectionProvider5(general_data) - tree = collection.get_trees()[0] - dict_root = tree.get_event("84db48fc-d1b4-11eb-b0fb-199708acc7bc") - assert collection.get_root_by_id("84db48fc-d1b4-11eb-b0fb-199708acc7bc") == dict_root - assert collection.get_root_by_id("88a3ee80-d1b4-11eb-b0fb-199708acc7bc") == dict_root - - -def test_get_detached_events_iter(parentless_data: List[dict]): - etc = EventsTreeCollectionProvider5(parentless_data) - iter_detached = etc.get_detached_events_iter() - assert isinstance(iter_detached, Generator) - assert list(iter_detached) == [parentless_data[6], parentless_data[7]] - - -def test_get_detached_events(parentless_data: List[dict]): - etc = EventsTreeCollectionProvider5(parentless_data) - detached = etc.get_detached_events() - assert isinstance(detached, list) - assert detached == [parentless_data[6], parentless_data[7]] - - -def test_get_parentless_tree_collection(parentless_data: List[dict]): - etc = EventsTreeCollectionProvider5(parentless_data) - expected_events = [ - parentless_data[6], - parentless_data[7], - {"type": "event", "eventId": "k", "eventName": "k", "parentEventId": "m"}, - {"type": "event", "eventId": "s", "eventName": "s", "parentEventId": "k"}, - ] - etc.append_event(expected_events[2]) - etc.append_event(expected_events[3]) - assert etc.len_trees == 6 and etc.len_detached_events == 4 - plt_c = etc.get_parentless_tree_collection() - expected_events.insert(0, etc._build_stub_event("e")) - expected_events.insert(3, etc._build_stub_event("m")) - assert plt_c.len_trees == 6 and plt_c.get_all_events() == expected_events - assert etc.get_detached_events() == [] diff --git a/tests/tests_unit/tests_diff_version/tests_v5/tests_events_tree/test_events_tree_local.py b/tests/tests_unit/tests_diff_version/tests_v5/tests_events_tree/test_events_tree_local.py deleted file mode 100644 index 56c59fd1..00000000 --- a/tests/tests_unit/tests_diff_version/tests_v5/tests_events_tree/test_events_tree_local.py +++ /dev/null @@ -1,114 +0,0 @@ -from datetime import datetime - -import pytest - -from th2_data_services import Data -from th2_data_services.provider.v5.commands.http import GetEvents -from th2_data_services.provider.v5.data_source import HTTPProvider5DataSource -from th2_data_services.provider.v5.events_tree.events_tree_collection import EventsTreeCollectionProvider5 - - -@pytest.mark.skip -def test_recover_unknown_events(): - data_source = HTTPProvider5DataSource("http://10.100.66.114:31787/") - events: Data = data_source.command( - GetEvents( - start_timestamp=datetime(year=2022, month=6, day=30, hour=14, minute=50, second=0, microsecond=0), - end_timestamp=datetime(year=2022, month=6, day=30, hour=15, minute=0, second=0, microsecond=0), - ) - ) - - before_tree = events.len - collection = EventsTreeCollectionProvider5(events, data_source=data_source) - after_tree = len(collection) - - assert not collection.detached_events and before_tree != after_tree - - -@pytest.mark.skip -def test_recover_unknown_events_ds_passed_into_method(): - data_source = HTTPProvider5DataSource("http://10.100.66.114:31787/") - events: Data = data_source.command( - GetEvents( - start_timestamp=datetime(year=2022, month=6, day=30, hour=14, minute=50, second=0, microsecond=0), - end_timestamp=datetime(year=2022, month=6, day=30, hour=15, minute=0, second=0, microsecond=0), - ) - ) - - before_tree = events.len - collection = EventsTreeCollectionProvider5(events) - collection.recover_unknown_events(data_source=data_source) - after_tree = len(collection) - - assert not collection.detached_events and before_tree != after_tree - - -@pytest.mark.skip -def test_recover_unknown_events_with_stub_events(): - data_source = HTTPProvider5DataSource("http://10.100.66.114:31787/") - events: Data = data_source.command( - GetEvents( - start_timestamp=datetime(year=2022, month=6, day=30, hour=14, minute=50, second=0, microsecond=0), - end_timestamp=datetime(year=2022, month=6, day=30, hour=15, minute=0, second=0, microsecond=0), - ) - ) - - broken_event = { - "attachedMessageIds": [], - "batchId": "Broken_Event", - "endTimestamp": {"nano": 0, "epochSecond": 0}, - "startTimestamp": {"nano": 0, "epochSecond": 0}, - "type": "event", - "eventId": f"33499-333-111-test-03221", - "eventName": "Broken_Event", - "eventType": "Broken_Event", - "parentEventId": "Broken_Event", - "successful": None, - "isBatched": None, - } - events: list = [event for event in events] + [broken_event] - - before_tree = len(events) - collection = EventsTreeCollectionProvider5(events, data_source=data_source, stub=True) - after_tree = len(collection) - - assert collection.detached_events == {"Broken_Event": [broken_event]} and before_tree != after_tree - - -@pytest.mark.skip -def test_preserve_body(): - data_source = HTTPProvider5DataSource("http://10.100.66.114:31787/") - events: Data = data_source.command( - GetEvents( - start_timestamp=datetime(year=2022, month=6, day=30, hour=14, minute=0, second=0, microsecond=0), - end_timestamp=datetime(year=2022, month=6, day=30, hour=15, minute=0, second=0, microsecond=0), - ) - ) - - collection = EventsTreeCollectionProvider5(events, data_source=data_source, preserve_body=True) - - assert all( - [True if event.get("body") is not None else False for event in collection.get_trees()[0].get_all_events()] - ) - - -@pytest.mark.skip -def test_create_subtree_incoming_data_stream(): - data_source = HTTPProvider5DataSource("http://10.100.66.114:31787/") - events: Data = data_source.command( - GetEvents( - start_timestamp=datetime(year=2022, month=6, day=30, hour=14, minute=0, second=0, microsecond=0), - end_timestamp=datetime(year=2022, month=6, day=30, hour=15, minute=0, second=0, microsecond=0), - ) - ) - tree = EventsTreeCollectionProvider5(events, preserve_body=True).get_trees()[0] - etc_1 = EventsTreeCollectionProvider5(tree.findall(lambda e: e["eventName"]), preserve_body=True) - sub_tree_0 = etc_1.get_trees()[0] - root_sub_tree_0 = sub_tree_0.get_root().copy() - etc_2 = EventsTreeCollectionProvider5(tree.findall(lambda e: e["eventName"])) - assert root_sub_tree_0 != etc_2.get_trees()[0] - assert root_sub_tree_0 == sub_tree_0.get_root() - assert ( - root_sub_tree_0.get("body") == [{"data": "Root event", "type": "message"}] - and etc_2.get_trees()[0].get_root().get("body") is None - ) diff --git a/tests/tests_unit/tests_diff_version/tests_v5/tests_events_tree/test_parent_events_tree.py b/tests/tests_unit/tests_diff_version/tests_v5/tests_events_tree/test_parent_events_tree.py deleted file mode 100644 index 6e240309..00000000 --- a/tests/tests_unit/tests_diff_version/tests_v5/tests_events_tree/test_parent_events_tree.py +++ /dev/null @@ -1,37 +0,0 @@ -from typing import List, NamedTuple - -from th2_data_services.provider.v5.events_tree import ParentEventsTreeCollectionProvider5 -from th2_data_services.provider.v5.struct import provider5_event_struct - - -def test_build_tree(general_data: List[dict], test_parent_events_tree: NamedTuple): - collection = ParentEventsTreeCollectionProvider5(general_data) - tree = collection.get_trees()[0] - - assert [ - event[provider5_event_struct.EVENT_ID] for event in tree.get_all_events() - ] == test_parent_events_tree.events and list( - collection.detached_events.keys() - ) == test_parent_events_tree.unknown_events - - -def test_build_parentless_tree(general_data: List[dict]): - collection = ParentEventsTreeCollectionProvider5(general_data) - trees = collection.get_parentless_trees() - - template = { - "attachedMessageIds": [], - "batchId": "Broken_Event", - "endTimestamp": {"nano": 0, "epochSecond": 0}, - "startTimestamp": {"nano": 0, "epochSecond": 0}, - "type": "event", - "eventName": "Broken_Event", - "eventType": "Broken_Event", - "parentEventId": "Broken_Event", - "successful": None, - "isBatched": None, - } - - assert trees[0].get_all_events() == [{"eventId": "a3779b94-d051-11eb-986f-1e8d42132387", **template}] and trees[ - 1 - ].get_all_events() == [{"eventId": "845d70d2-9c68-11eb-8598-691ebd7f413d", **template}] diff --git a/tests/tests_unit/tests_diff_version/tests_v5/tests_events_tree/test_parent_events_tree_local.py b/tests/tests_unit/tests_diff_version/tests_v5/tests_events_tree/test_parent_events_tree_local.py deleted file mode 100644 index 2606e127..00000000 --- a/tests/tests_unit/tests_diff_version/tests_v5/tests_events_tree/test_parent_events_tree_local.py +++ /dev/null @@ -1,76 +0,0 @@ -from datetime import datetime - -import pytest - -from th2_data_services import Data -from th2_data_services.provider.v5.commands.http import GetEvents -from th2_data_services.provider.v5.data_source import HTTPProvider5DataSource -from th2_data_services.provider.v5.events_tree.parent_events_tree_collection import ( - ParentEventsTreeCollectionProvider5, -) - - -@pytest.mark.skip -def test_recover_unknown_events(): - data_source = HTTPProvider5DataSource("http://10.100.66.114:31787/") - events: Data = data_source.command( - GetEvents( - start_timestamp=datetime(year=2022, month=6, day=30, hour=14, minute=0, second=0, microsecond=0), - end_timestamp=datetime(year=2022, month=6, day=30, hour=15, minute=0, second=0, microsecond=0), - ) - ) - - before_tree = events.len - collection = ParentEventsTreeCollectionProvider5(events, data_source=data_source) - after_tree = len(collection) - - assert not collection.detached_events and before_tree != after_tree - - -@pytest.mark.skip -def test_recover_unknown_events_with_stub_events(): - data_source = HTTPProvider5DataSource("http://10.100.66.114:31787/") - events: Data = data_source.command( - GetEvents( - start_timestamp=datetime(year=2022, month=6, day=30, hour=14, minute=0, second=0, microsecond=0), - end_timestamp=datetime(year=2022, month=6, day=30, hour=15, minute=0, second=0, microsecond=0), - ) - ) - - broken_event = { - "attachedMessageIds": [], - "batchId": "Broken_Event", - "endTimestamp": {"nano": 0, "epochSecond": 0}, - "startTimestamp": {"nano": 0, "epochSecond": 0}, - "type": "event", - "eventId": f"33499-333-111-test-03221", - "eventName": "Broken_Event", - "eventType": "Broken_Event", - "parentEventId": "Broken_Event", - "successful": None, - "isBatched": None, - } - events: list = [event for event in events] + [broken_event] - - before_tree = len(events) - collection = ParentEventsTreeCollectionProvider5(events, data_source=data_source, stub=True) - after_tree = len(collection) - - assert collection.detached_events == {"Broken_Event": [broken_event]} and before_tree != after_tree - - -@pytest.mark.skip -def test_preserve_body(): - data_source = HTTPProvider5DataSource("http://10.100.66.114:31787/") - events: Data = data_source.command( - GetEvents( - start_timestamp=datetime(year=2022, month=6, day=30, hour=14, minute=0, second=0, microsecond=0), - end_timestamp=datetime(year=2022, month=6, day=30, hour=15, minute=0, second=0, microsecond=0), - ) - ) - - collection = ParentEventsTreeCollectionProvider5(events, data_source=data_source, preserve_body=True) - - assert all( - [True if event.get("body") is not None else False for event in collection.get_trees()[0].get_all_events()] - ) diff --git a/tests/tests_unit/tests_diff_version/tests_v6/__init__.py b/tests/tests_unit/tests_diff_version/tests_v6/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/tests_unit/tests_diff_version/tests_v6/test_data_source_local.py b/tests/tests_unit/tests_diff_version/tests_v6/test_data_source_local.py deleted file mode 100644 index 7a3be846..00000000 --- a/tests/tests_unit/tests_diff_version/tests_v6/test_data_source_local.py +++ /dev/null @@ -1,493 +0,0 @@ -import pytest - -from ..conftest import HTTPProviderDataSource, http, Data -from th2_data_services.provider.exceptions import CommandError - - -@pytest.mark.skip -def test_find_events_by_id_from_data_provider(demo_data_source: HTTPProviderDataSource): - data_source = demo_data_source # TODO: Change on mock - - expected_event = { - "attachedMessageIds": [], - "batchId": None, - "body": {}, - "endTimestamp": "2022-06-30T14:37:31.420806000Z", - "eventId": "2c4b3a58-f882-11ec-b952-0a1e730db2c6", - "eventName": "Recon: Test", - "eventType": "", - "isBatched": False, - "parentEventId": None, - "startTimestamp": "2022-06-30T14:37:31.420806000Z", - "successful": False, - "type": "event", - } - - expected_events = [] - expected_events.append(expected_event) - expected_events.append( - { - "type": "event", - "eventId": "a5586d90-b83b-48a4-bd2b-b2059fb79374:b84cff2c-f883-11ec-b070-0a1e730db2c6", - "batchId": "a5586d90-b83b-48a4-bd2b-b2059fb79374", - "isBatched": True, - "eventName": "Match by ClOrdID: '7706360'", - "eventType": "", - "endTimestamp": "2022-06-30T14:48:35.809998000Z", - "startTimestamp": "2022-06-30T14:48:35.809998000Z", - "parentEventId": "b21a03c0-f883-11ec-b070-0a1e730db2c6", - "successful": True, - "attachedMessageIds": ["arfq01fix08:first:1656599887515453583", "arfq01fix08:second:1656599887515499581"], - "body": { - "type": "table", - "rows": [ - {"Name": "ClOrdId", "Value": "7706360"}, - {"Name": "Message Response", "Value": "ExecutionReport"}, - {"Name": "Message Request", "Value": "NewOrderSingle"}, - {"Name": "Latency type", "Value": "Trade"}, - {"Name": "Latency", "Value": 29000.0}, - ], - "_TableComponent__column_names": ["Name", "Value"], - }, - } - ) - - event = data_source.command(http.GetEventById("2c4b3a58-f882-11ec-b952-0a1e730db2c6")) - events = data_source.command( - http.GetEventsById( - [ - "2c4b3a58-f882-11ec-b952-0a1e730db2c6", - "a5586d90-b83b-48a4-bd2b-b2059fb79374:b84cff2c-f883-11ec-b070-0a1e730db2c6", - ] - ) - ) - events_with_one_element = data_source.command( - http.GetEventsById( - [ - "2c4b3a58-f882-11ec-b952-0a1e730db2c6", - ] - ) - ) - for event_ in events: - event_["attachedMessageIds"].sort() - - broken_event: dict = data_source.command(http.GetEventById("id", use_stub=True)) - broken_events: list = data_source.command(http.GetEventsById(["id", "ids"], use_stub=True)) - - plug_for_broken_event: dict = { - "attachedMessageIds": [], - "batchId": "Broken_Event", - "endTimestamp": {"nano": 0, "epochSecond": 0}, - "startTimestamp": {"nano": 0, "epochSecond": 0}, - "type": "event", - "eventId": "id", - "eventName": "Broken_Event", - "eventType": "Broken_Event", - "parentEventId": "Broken_Event", - "successful": None, - "isBatched": None, - } - - plug_for_broken_events: list = [ - plug_for_broken_event.copy(), - plug_for_broken_event.copy(), - ] - plug_for_broken_events[1]["eventId"] = "ids" - - # Check types - assert isinstance(event, dict) - assert isinstance(events, list) - assert isinstance(events_with_one_element, list) - assert isinstance(broken_event, dict) - assert isinstance(broken_events, list) - # Check content. - assert event == expected_event - assert events == expected_events - assert len(events) == 2 - assert len(events_with_one_element) == 1 - # Check Broken_Events - assert broken_event == plug_for_broken_event - assert broken_events == plug_for_broken_events - assert [event, broken_event] == data_source.command( - http.GetEventsById(["2c4b3a58-f882-11ec-b952-0a1e730db2c6", "id"], use_stub=True) - ) - with pytest.raises(CommandError): - data_source.command(http.GetEventsById(["2c4b3a58-f882-11ec-b952-0a1e730db2c6", "id"])) - with pytest.raises(CommandError): - data_source.command(http.GetEventById("id")) - - -@pytest.mark.skip -def test_find_messages_by_id_from_data_provider(demo_data_source: HTTPProviderDataSource): - data_source = demo_data_source # TODO: Change on mock - - expected_message = { - "attachedEventIds": [], - "direction": "SECOND", - "id": "arfq01fix08:second:1656599887515499033", - "parsedMessages": [ - { - "id": "arfq01fix08:second:1656599887515499033.1", - "match": True, - "message": { - "fields": { - "header": { - "messageValue": { - "fields": { - "BeginString": {"simpleValue": "FIXT.1.1"}, - "BodyLength": {"simpleValue": "61"}, - "MsgSeqNum": {"simpleValue": "33"}, - "MsgType": {"simpleValue": "0"}, - "SenderCompID": {"simpleValue": "ARFQ01FIX08"}, - "SendingTime": {"simpleValue": "2022-06-30T14:39:27.111"}, - "TargetCompID": {"simpleValue": "FGW"}, - } - } - }, - "trailer": {"messageValue": {"fields": {"CheckSum": {"simpleValue": "160"}}}}, - }, - "metadata": { - "id": { - "connectionId": {"sessionAlias": "arfq01fix08"}, - "direction": "SECOND", - "sequence": "1656599887515499033", - "subsequence": [1], - }, - "messageType": "Heartbeat", - "protocol": "FIX", - "timestamp": "2022-06-30T14:39:27.112Z", - }, - }, - } - ], - "rawMessageBase64": "OD1GSVhULjEuMQE5PTYxATM1PTABMzQ9MzMBNDk9QVJGUTAxRklYMDgBNTI9MjAyMjA2MzAtMTQ6Mzk6MjcuMTExMDAwATU2PUZHVwExMD0xNjAB", - "sequence": "1656599887515499033", - "sessionId": "arfq01fix08", - "timestamp": "2022-06-30T14:39:27.112000000Z", - "type": "message", - } - - expected_messages = [] - expected_messages.append(expected_message) - expected_messages.append( - { - "attachedEventIds": [], - "direction": "SECOND", - "id": "arfq01dc03:second:1656599850628059096", - "parsedMessages": [ - { - "id": "arfq01dc03:second:1656599850628059096.1", - "match": True, - "message": { - "fields": { - "DefaultApplVerID": {"simpleValue": "9"}, - "EncryptMethod": {"simpleValue": "0"}, - "HeartBtInt": {"simpleValue": "5"}, - "Password": {"simpleValue": "mit123"}, - "ResetSeqNumFlag": {"simpleValue": "true"}, - "header": { - "messageValue": { - "fields": { - "BeginString": {"simpleValue": "FIXT.1.1"}, - "BodyLength": {"simpleValue": "91"}, - "MsgSeqNum": {"simpleValue": "1"}, - "MsgType": {"simpleValue": "A"}, - "SenderCompID": {"simpleValue": "ARFQ01DC03"}, - "SendingTime": {"simpleValue": "2022-06-30T14:46:03.911"}, - "TargetCompID": {"simpleValue": "FGW"}, - } - } - }, - "trailer": {"messageValue": {"fields": {"CheckSum": {"simpleValue": "161"}}}}, - }, - "metadata": { - "id": { - "connectionId": {"sessionAlias": "arfq01dc03"}, - "direction": "SECOND", - "sequence": "1656599850628059096", - "subsequence": [1], - }, - "messageType": "Logon", - "protocol": "FIX", - "timestamp": "2022-06-30T14:46:03.915Z", - }, - }, - } - ], - "rawMessageBase64": "OD1GSVhULjEuMQE5PTkxATM1PUEBMzQ9MQE0OT1BUkZRMDFEQzAzATUyPTIwMjIwNjMwLTE0OjQ2OjAzLjkxMQE1Nj1GR1cBOTg9MAExMDg9NQExNDE9WQE1NTQ9bWl0MTIzATExMzc9OQExMD0xNjEB", - "sequence": "1656599850628059096", - "sessionId": "arfq01dc03", - "timestamp": "2022-06-30T14:46:03.915000000Z", - "type": "message", - } - ) - - message = data_source.command(http.GetMessageById("arfq01fix08:second:1656599887515499033")) - messages = data_source.command( - http.GetMessagesById(["arfq01fix08:second:1656599887515499033", "arfq01dc03:second:1656599850628059096"]) - ) - messages_with_one_element = data_source.command(http.GetMessagesById(["arfq01fix08:second:1656599887515499033"])) - # Check types - assert isinstance(message, dict) - assert isinstance(messages, list) - assert isinstance(messages_with_one_element, list) - # Check content. - assert message == expected_message - assert messages == expected_messages - assert len(messages) == 2 - assert len(messages_with_one_element) == 1 - - -@pytest.mark.skip -def test_get_x_with_filters( - demo_get_events_with_one_filter: Data, - demo_get_messages_with_one_filter: Data, - demo_get_events_with_filters: Data, - demo_get_messages_with_filters: Data, -): - # TODO: Change on mock - case = [ - { - "type": "event", - "eventId": "a2321a5b-f883-11ec-8225-52540095fac0", - "batchId": None, - "isBatched": False, - "eventName": "[TS_1]5 partfill trades and cancel.", - "eventType": "", - "endTimestamp": "2022-06-30T14:47:58.735114000Z", - "startTimestamp": "2022-06-30T14:47:58.735039000Z", - "parentEventId": None, - "successful": False, - "attachedMessageIds": [], - "body": {}, - } - ] - case1 = [ - { - "type": "event", - "eventId": "bb0da3a9-f883-11ec-aeb3-adf8526f5eec", - "batchId": None, - "isBatched": False, - "eventName": "Received 'ExecutionReport' response message", - "eventType": "message", - "endTimestamp": "2022-06-30T14:48:40.428471000Z", - "startTimestamp": "2022-06-30T14:48:40.428350000Z", - "parentEventId": "ba4e7257-f883-11ec-aeb3-adf8526f5eec", - "successful": True, - "attachedMessageIds": [], - "body": [ - { - "type": "treeTable", - "rows": { - "ExecID": {"type": "row", "columns": {"fieldValue": "E0AmqxctTQGw"}}, - "OrderQty": {"type": "row", "columns": {"fieldValue": "20"}}, - "LastQty": {"type": "row", "columns": {"fieldValue": "20"}}, - "OrderID": {"type": "row", "columns": {"fieldValue": "00Amr2Sw36j1"}}, - "TransactTime": {"type": "row", "columns": {"fieldValue": "2022-06-30T14:48:39.526758"}}, - "GroupID": {"type": "row", "columns": {"fieldValue": "0"}}, - "trailer": { - "type": "collection", - "rows": {"CheckSum": {"type": "row", "columns": {"fieldValue": "136"}}}, - }, - "Side": {"type": "row", "columns": {"fieldValue": "2"}}, - "OrdStatus": {"type": "row", "columns": {"fieldValue": "2"}}, - "TimeInForce": {"type": "row", "columns": {"fieldValue": "0"}}, - "SecurityID": {"type": "row", "columns": {"fieldValue": "5221001"}}, - "ExecType": {"type": "row", "columns": {"fieldValue": "F"}}, - "TradeLiquidityIndicator": {"type": "row", "columns": {"fieldValue": "R"}}, - "LastLiquidityInd": {"type": "row", "columns": {"fieldValue": "2"}}, - "LeavesQty": {"type": "row", "columns": {"fieldValue": "0"}}, - "CumQty": {"type": "row", "columns": {"fieldValue": "20"}}, - "LastPx": {"type": "row", "columns": {"fieldValue": "55"}}, - "TypeOfTrade": {"type": "row", "columns": {"fieldValue": "2"}}, - "TrdMatchID": {"type": "row", "columns": {"fieldValue": "L2N1AYTNPW"}}, - "OrdType": {"type": "row", "columns": {"fieldValue": "2"}}, - "ClOrdID": {"type": "row", "columns": {"fieldValue": "1985282"}}, - "SecurityIDSource": {"type": "row", "columns": {"fieldValue": "8"}}, - "LastMkt": {"type": "row", "columns": {"fieldValue": "XLOM"}}, - "OrderCapacity": {"type": "row", "columns": {"fieldValue": "A"}}, - "SecondaryClOrdID": {"type": "row", "columns": {"fieldValue": "33333"}}, - "AccountType": {"type": "row", "columns": {"fieldValue": "1"}}, - "Price": {"type": "row", "columns": {"fieldValue": "55"}}, - "MDEntryID": {"type": "row", "columns": {"fieldValue": "00Amr2Sw36j1"}}, - "TradingParty": { - "type": "collection", - "rows": { - "NoPartyIDs": { - "type": "collection", - "rows": { - "0": { - "type": "collection", - "rows": { - "PartyRole": {"type": "row", "columns": {"fieldValue": "76"}}, - "PartyID": {"type": "row", "columns": {"fieldValue": "ARFQ01FIX08"}}, - "PartyIDSource": {"type": "row", "columns": {"fieldValue": "D"}}, - }, - }, - "1": { - "type": "collection", - "rows": { - "PartyRole": {"type": "row", "columns": {"fieldValue": "17"}}, - "PartyID": {"type": "row", "columns": {"fieldValue": "ARFQ01"}}, - "PartyIDSource": {"type": "row", "columns": {"fieldValue": "D"}}, - }, - }, - "2": { - "type": "collection", - "rows": { - "PartyRole": {"type": "row", "columns": {"fieldValue": "3"}}, - "PartyID": {"type": "row", "columns": {"fieldValue": "0"}}, - "PartyIDSource": {"type": "row", "columns": {"fieldValue": "P"}}, - }, - }, - "3": { - "type": "collection", - "rows": { - "PartyRole": {"type": "row", "columns": {"fieldValue": "122"}}, - "PartyID": {"type": "row", "columns": {"fieldValue": "0"}}, - "PartyIDSource": {"type": "row", "columns": {"fieldValue": "P"}}, - }, - }, - "4": { - "type": "collection", - "rows": { - "PartyRole": {"type": "row", "columns": {"fieldValue": "12"}}, - "PartyID": {"type": "row", "columns": {"fieldValue": "3"}}, - "PartyIDSource": {"type": "row", "columns": {"fieldValue": "P"}}, - }, - }, - }, - } - }, - }, - "header": { - "type": "collection", - "rows": { - "BeginString": {"type": "row", "columns": {"fieldValue": "FIXT.1.1"}}, - "SenderCompID": {"type": "row", "columns": {"fieldValue": "FGW"}}, - "SendingTime": {"type": "row", "columns": {"fieldValue": "2022-06-30T14:48:39.530311"}}, - "TargetCompID": {"type": "row", "columns": {"fieldValue": "ARFQ01FIX08"}}, - "ApplVerID": {"type": "row", "columns": {"fieldValue": "9"}}, - "MsgType": {"type": "row", "columns": {"fieldValue": "8"}}, - "MsgSeqNum": {"type": "row", "columns": {"fieldValue": "589"}}, - "BodyLength": {"type": "row", "columns": {"fieldValue": "432"}}, - }, - }, - "DisplayQty": {"type": "row", "columns": {"fieldValue": "0"}}, - }, - } - ], - } - ] - case3 = [ - { - "attachedEventIds": [], - "direction": "SECOND", - "id": "arfq01fix07:second:1656599837520228626", - "parsedMessages": [ - { - "id": "arfq01fix07:second:1656599837520228626.1", - "match": True, - "message": { - "fields": { - "AccountType": {"simpleValue": "1"}, - "ClOrdID": {"simpleValue": "1830410"}, - "DisplayQty": {"simpleValue": "200"}, - "OrdType": {"simpleValue": "2"}, - "OrderCapacity": {"simpleValue": "A"}, - "OrderQty": {"simpleValue": "200"}, - "Price": {"simpleValue": "55"}, - "SecondaryClOrdID": {"simpleValue": "11111"}, - "SecurityID": {"simpleValue": "5221001"}, - "SecurityIDSource": {"simpleValue": "8"}, - "Side": {"simpleValue": "1"}, - "TradingParty": { - "messageValue": { - "fields": { - "NoPartyIDs": { - "listValue": { - "values": [ - { - "messageValue": { - "fields": { - "PartyID": {"simpleValue": "ARFQ01FIX07"}, - "PartyIDSource": {"simpleValue": "D"}, - "PartyRole": {"simpleValue": "76"}, - } - } - }, - { - "messageValue": { - "fields": { - "PartyID": {"simpleValue": "0"}, - "PartyIDSource": {"simpleValue": "P"}, - "PartyRole": {"simpleValue": "3"}, - } - } - }, - { - "messageValue": { - "fields": { - "PartyID": {"simpleValue": "0"}, - "PartyIDSource": {"simpleValue": "P"}, - "PartyRole": {"simpleValue": "122"}, - } - } - }, - { - "messageValue": { - "fields": { - "PartyID": {"simpleValue": "3"}, - "PartyIDSource": {"simpleValue": "P"}, - "PartyRole": {"simpleValue": "12"}, - } - } - }, - ] - } - } - } - } - }, - "TransactTime": {"simpleValue": "2022-06-30T14:47:59.032276"}, - "header": { - "messageValue": { - "fields": { - "BeginString": {"simpleValue": "FIXT.1.1"}, - "BodyLength": {"simpleValue": "263"}, - "MsgSeqNum": {"simpleValue": "626"}, - "MsgType": {"simpleValue": "D"}, - "SenderCompID": {"simpleValue": "ARFQ01FIX07"}, - "SendingTime": {"simpleValue": "2022-06-30T14:48:24.330"}, - "TargetCompID": {"simpleValue": "FGW"}, - } - } - }, - "trailer": {"messageValue": {"fields": {"CheckSum": {"simpleValue": "152"}}}}, - }, - "metadata": { - "id": { - "connectionId": {"sessionAlias": "arfq01fix07"}, - "direction": "SECOND", - "sequence": "1656599837520228626", - "subsequence": [1], - }, - "messageType": "NewOrderSingle", - "protocol": "FIX", - "timestamp": "2022-06-30T14:48:24.422Z", - }, - "parentEventId": {"id": "a4bee27b-f883-11ec-aeb3-adf8526f5eec"}, - }, - } - ], - "rawMessageBase64": "OD1GSVhULjEuMQE5PTI2MwEzNT1EATM0PTYyNgE0OT1BUkZRMDFGSVgwNwE1Mj0yMDIyMDYzMC0xNDo0ODoyNC4zMzAwMDABNTY9RkdXATExPTE4MzA0MTABMjI9OAEzOD0yMDABNDA9MgE0ND01NQE0OD01MjIxMDAxATU0PTEBNjA9MjAyMjA2MzAtMTQ6NDc6NTkuMDMyMjc2ATUyNj0xMTExMQE1Mjg9QQE1ODE9MQExMTM4PTIwMAE0NTM9NAE0NDg9QVJGUTAxRklYMDcBNDQ3PUQBNDUyPTc2ATQ0OD0wATQ0Nz1QATQ1Mj0zATQ0OD0wATQ0Nz1QATQ1Mj0xMjIBNDQ4PTMBNDQ3PVABNDUyPTEyATEwPTE1MgE=", - "sequence": "1656599837520228626", - "sessionId": "arfq01fix07", - "timestamp": "2022-06-30T14:48:24.422000000Z", - "type": "message", - } - ] - assert list(demo_get_messages_with_one_filter) == case3 - assert list(demo_get_messages_with_filters) == case3 - assert list(demo_get_events_with_one_filter) == case and len(case) is 1 - assert list(demo_get_events_with_filters) == case1 and len(case1) is 1 diff --git a/tests/tests_unit/tests_diff_version/tests_v6/test_filter.py b/tests/tests_unit/tests_diff_version/tests_v6/test_filter.py deleted file mode 100644 index 1f029b76..00000000 --- a/tests/tests_unit/tests_diff_version/tests_v6/test_filter.py +++ /dev/null @@ -1,9 +0,0 @@ -from tests.tests_unit.tests_diff_version.conftest import Filter - - -def test_repr(): - f = Filter(name="type", values=["one", 2, "three"]) - assert repr(f) == "Provider6Filter(name='type', values=['one', '2', 'three'], negative='False', conjunct='False')" - - f = Filter(name="type", values="abc") - assert repr(f) == "Provider6Filter(name='type', values=['abc'], negative='False', conjunct='False')" diff --git a/tests/tests_unit/tests_diff_version/tests_common/tests_adapters/__init__.py b/tests/tests_unit/tests_utils/aggregation_classes/__init__.py similarity index 100% rename from tests/tests_unit/tests_diff_version/tests_common/tests_adapters/__init__.py rename to tests/tests_unit/tests_utils/aggregation_classes/__init__.py diff --git a/tests/tests_unit/tests_utils/aggregation_classes/freq_category_table.py b/tests/tests_unit/tests_utils/aggregation_classes/freq_category_table.py new file mode 100644 index 00000000..2c1cd1f4 --- /dev/null +++ b/tests/tests_unit/tests_utils/aggregation_classes/freq_category_table.py @@ -0,0 +1,105 @@ +from th2_data_services.utils import misc_utils +from th2_data_services.utils.converters import DatetimeStringConverter + + +def test_frequency_table_data_has_the_same_header_every_time(frequency_table_data, capsys): + # tb = FrequencyCategoryTable(['timestamp', 'MessageType', 'direction', 'session'], frequency_table_data) + + tb = misc_utils.get_objects_frequencies2( + frequency_table_data, + categories=[], + categorizer=lambda m: m["MessageType"], + timestamp_function=lambda e: int( + DatetimeStringConverter.parse_timestamp(e["timestamp"])[0] + ), + aggregation_level="1d", + include_total=False, + ) + # metrics = Category('messagetype', lambda m: m['messagetype']) + # tb = get_category_frequencies2(frequency_table_data, metrics) + print(tb) + + captured = capsys.readouterr() + assert ( + captured.out + == """+--------+-------------------+-----------------+-------------------+------------+---------------+ +| | timestamp_start | timestamp_end | ExecutionReport | NewOrder | OrderCancel | ++========+===================+=================+===================+============+===============+ +| | 2023-08-13 | 2023-08-14 | 1 | 1 | 2 | ++--------+-------------------+-----------------+-------------------+------------+---------------+ +| | 2023-08-14 | 2023-08-15 | 1 | 1 | 2 | ++--------+-------------------+-----------------+-------------------+------------+---------------+ +| | 2023-08-16 | 2023-08-17 | 0 | 2 | 3 | ++--------+-------------------+-----------------+-------------------+------------+---------------+ +| | 2023-08-17 | 2023-08-18 | 1 | 0 | 1 | ++--------+-------------------+-----------------+-------------------+------------+---------------+ +| | 2023-08-19 | 2023-08-20 | 1 | 1 | 0 | ++--------+-------------------+-----------------+-------------------+------------+---------------+ +| | 2023-08-20 | 2023-08-21 | 0 | 0 | 2 | ++--------+-------------------+-----------------+-------------------+------------+---------------+ +| | 2023-08-21 | 2023-08-22 | 1 | 3 | 0 | ++--------+-------------------+-----------------+-------------------+------------+---------------+ +| | 2023-08-22 | 2023-08-23 | 1 | 0 | 0 | ++--------+-------------------+-----------------+-------------------+------------+---------------+ +| | 2023-08-23 | 2023-08-24 | 0 | 3 | 0 | ++--------+-------------------+-----------------+-------------------+------------+---------------+ +| | 2023-08-24 | 2023-08-25 | 0 | 2 | 1 | ++--------+-------------------+-----------------+-------------------+------------+---------------+ +| count | | | | | 10 | ++--------+-------------------+-----------------+-------------------+------------+---------------+ +| totals | | | 6 | 13 | 11 | ++--------+-------------------+-----------------+-------------------+------------+---------------+ +""" + ) + + +def test_frequency_table_data_has_the_same_header_every_time_with_total_column( + frequency_table_data, capsys +): + # tb = FrequencyCategoryTable(['timestamp', 'MessageType', 'direction', 'session'], frequency_table_data) + + tb = misc_utils.get_objects_frequencies2( + frequency_table_data, + categories=[], + categorizer=lambda m: m["MessageType"], + timestamp_function=lambda e: int( + DatetimeStringConverter.parse_timestamp(e["timestamp"])[0] + ), + aggregation_level="1d", + ) + # metrics = Category('messagetype', lambda m: m['messagetype']) + # tb = get_category_frequencies2(frequency_table_data, metrics) + print(tb) + + captured = capsys.readouterr() + assert ( + captured.out + == """+--------+-------------------+-----------------+-------------------+------------+---------------+---------+ +| | timestamp_start | timestamp_end | ExecutionReport | NewOrder | OrderCancel | Total | ++========+===================+=================+===================+============+===============+=========+ +| | 2023-08-13 | 2023-08-14 | 1 | 1 | 2 | 4 | ++--------+-------------------+-----------------+-------------------+------------+---------------+---------+ +| | 2023-08-14 | 2023-08-15 | 1 | 1 | 2 | 4 | ++--------+-------------------+-----------------+-------------------+------------+---------------+---------+ +| | 2023-08-16 | 2023-08-17 | 0 | 2 | 3 | 5 | ++--------+-------------------+-----------------+-------------------+------------+---------------+---------+ +| | 2023-08-17 | 2023-08-18 | 1 | 0 | 1 | 2 | ++--------+-------------------+-----------------+-------------------+------------+---------------+---------+ +| | 2023-08-19 | 2023-08-20 | 1 | 1 | 0 | 2 | ++--------+-------------------+-----------------+-------------------+------------+---------------+---------+ +| | 2023-08-20 | 2023-08-21 | 0 | 0 | 2 | 2 | ++--------+-------------------+-----------------+-------------------+------------+---------------+---------+ +| | 2023-08-21 | 2023-08-22 | 1 | 3 | 0 | 4 | ++--------+-------------------+-----------------+-------------------+------------+---------------+---------+ +| | 2023-08-22 | 2023-08-23 | 1 | 0 | 0 | 1 | ++--------+-------------------+-----------------+-------------------+------------+---------------+---------+ +| | 2023-08-23 | 2023-08-24 | 0 | 3 | 0 | 3 | ++--------+-------------------+-----------------+-------------------+------------+---------------+---------+ +| | 2023-08-24 | 2023-08-25 | 0 | 2 | 1 | 3 | ++--------+-------------------+-----------------+-------------------+------------+---------------+---------+ +| count | | | | | | 10 | ++--------+-------------------+-----------------+-------------------+------------+---------------+---------+ +| totals | | | 6 | 13 | 11 | 30 | ++--------+-------------------+-----------------+-------------------+------------+---------------+---------+ +""" + ) diff --git a/tests/tests_unit/tests_utils/test_path_utils.py b/tests/tests_unit/tests_utils/test_path_utils.py new file mode 100644 index 00000000..c151f22b --- /dev/null +++ b/tests/tests_unit/tests_utils/test_path_utils.py @@ -0,0 +1,15 @@ +from pathlib import Path + +import pytest + +from th2_data_services.utils.path_utils import check_if_file_exists + + +def test_check_if_file_exists_takes_str_filepath(): + with pytest.raises(FileNotFoundError): + check_if_file_exists(filename="no_such_file.xxx") + + +def test_check_if_file_exists_takes_path_filepath(): + with pytest.raises(FileNotFoundError): + check_if_file_exists(filename=Path("no_such_file.xxx")) diff --git a/tests/tests_unit/tests_utils/tests_converters/bench_results/2024.05.15 (2) - slava_test after all improvements b/tests/tests_unit/tests_utils/tests_converters/bench_results/2024.05.15 (2) - slava_test after all improvements new file mode 100644 index 00000000..3b647bfa --- /dev/null +++ b/tests/tests_unit/tests_utils/tests_converters/bench_results/2024.05.15 (2) - slava_test after all improvements @@ -0,0 +1,461 @@ +Speed test: + AMD Ryzen 7 6800H with Radeon Graphics 3.20 GHz + +> python.exe th2-data-services\tests\tests_unit\tests_utils\tests_converters\benchmark.py + +C:\Users\admin\exactpro\prj\th2\internal\DS\github\th2-data-services\ds_lib_venv_py39\Scripts\python.exe C:\Users\admin\exactpro\prj\th2\internal\DS\github\th2-data-services\tests\tests_unit\tests_utils\tests_converters\benchmark.py +################################################## +This benchmark shows how many seconds takes every converter operation in seconds. +################################################## +[1] DatetimeStringConverter +input: 2022-03-05T23:56:44.123456789Z +1. .parse_timestamp: 1.4974268 +2. .to_datetime: 0.12663259999999998 +3. .to_seconds: 1.5360991 +4. .to_microseconds: 1.7628856000000002 +5. .to_nanoseconds: 1.7114960000000004 +6. .to_milliseconds: 1.7688387000000008 +7. .to_datetime_str: 2.3781561 +8. .to_th2_timestamp: 1.5942235 +[2] DatetimeConverter +input: 2022-03-05 23:56:44.123456 +1. .parse_timestamp: 1.6007411000000005 +2. .to_datetime: 2.2600745000000018 +3. .to_seconds: 1.9851986000000004 +4. .to_microseconds: 1.9436871999999994 +5. .to_nanoseconds: 1.8517295000000011 +6. .to_milliseconds: 1.891514500000003 +7. .to_datetime_str: 2.6196756999999984 +8. .to_th2_timestamp: 2.0755786 +[3] ProtobufTimestampConverter +input: {'epochSecond': 1646524604, 'nano': 123456789} +1. .parse_timestamp: 0.33072310000000016 +2. .to_datetime: 0.4287202999999984 +3. .to_seconds: 0.08139189999999985 +4. .to_microseconds: 0.17610819999999805 +5. .to_nanoseconds: 0.1485732000000013 +6. .to_milliseconds: 0.1678935999999993 +7. .to_datetime_str: 1.1622389999999996 +8. .to_th2_timestamp: 0.21927750000000046 +[4] UniversalDatetimeStringConverter +input: 2022-03-05T23:56:44.123456789Z +1. .parse_timestamp: 1.5752227000000012 +2. .to_datetime: 0.12677979999999422 +3. .to_seconds: 1.645312699999998 +4. .to_microseconds: 1.8240784000000048 +5. .to_nanoseconds: 1.7930200999999997 +6. .to_milliseconds: 1.830885600000002 +7. .to_datetime_str: 2.459299200000004 +8. .to_th2_timestamp: 1.6856898999999999 +[5] UnixTimestampConverter +input: 1646524604123456789 +1. .parse_timestamp: 0.3967766000000026 +2. .to_datetime: 0.9629303000000036 +3. .to_seconds: 0.670658699999997 +4. .to_microseconds: 0.6415308999999993 +5. .to_nanoseconds: 0.5902038000000047 +6. .to_milliseconds: 0.6300464999999988 +7. .to_datetime_str: 1.2379169000000019 +8. .to_th2_timestamp: 0.7428973999999968 +[1] DatetimeStringConverter +input: 2022-03-05T23:56:44.123456789 +1. .parse_timestamp: 1.4492793000000006 +2. .to_datetime: 0.12661069999999341 +3. .to_seconds: 1.4978413000000046 +4. .to_microseconds: 1.7135958999999943 +5. .to_nanoseconds: 1.6754941000000017 +6. .to_milliseconds: 1.7021992999999966 +7. .to_datetime_str: 2.373305700000003 +8. .to_th2_timestamp: 1.5469332000000051 +[2] DatetimeConverter +input: 2022-03-05 23:56:44.123456 +1. .parse_timestamp: 1.6150836999999996 +2. .to_datetime: 2.2435761999999926 +3. .to_seconds: 1.9685240000000022 +4. .to_microseconds: 1.8871374999999944 +5. .to_nanoseconds: 1.8044499999999886 +6. .to_milliseconds: 1.832304999999991 +7. .to_datetime_str: 2.4458415999999943 +8. .to_th2_timestamp: 2.018431899999996 +[3] ProtobufTimestampConverter +input: {'epochSecond': 1646524604, 'nano': 123456789} +1. .parse_timestamp: 0.3252099000000044 +2. .to_datetime: 0.4199072999999913 +3. .to_seconds: 0.07616130000000965 +4. .to_microseconds: 0.16975320000000238 +5. .to_nanoseconds: 0.144433499999991 +6. .to_milliseconds: 0.1695650999999998 +7. .to_datetime_str: 1.1327502000000038 +8. .to_th2_timestamp: 0.21441249999999457 +[4] UniversalDatetimeStringConverter +input: 2022-03-05T23:56:44.123456789 +1. .parse_timestamp: 1.502366600000002 +2. .to_datetime: 0.12464769999999703 +3. .to_seconds: 1.5698945999999978 +4. .to_microseconds: 1.7625878999999998 +5. .to_nanoseconds: 2.3211549999999903 +6. .to_milliseconds: 1.9622326000000072 +7. .to_datetime_str: 2.5693859000000003 +8. .to_th2_timestamp: 2.765291099999999 +[5] UnixTimestampConverter +input: 1646524604123456789 +1. .parse_timestamp: 0.46615350000000433 +2. .to_datetime: 1.0124820999999997 +3. .to_seconds: 1.3525829000000016 +4. .to_microseconds: 1.2265198000000055 +5. .to_nanoseconds: 0.9917458000000039 +6. .to_milliseconds: 0.9178511000000071 +7. .to_datetime_str: 2.0432559000000055 +8. .to_th2_timestamp: 0.9360353000000003 +[1] DatetimeStringConverter +input: 2022-03-05T23:56:44.123Z +1. .parse_timestamp: 2.2059069000000022 +2. .to_datetime: 0.24907489999999655 +3. .to_seconds: 2.402906999999999 +4. .to_microseconds: 2.513467300000002 +5. .to_nanoseconds: 1.761641499999996 +6. .to_milliseconds: 1.7942473000000092 +7. .to_datetime_str: 2.4215030000000013 +8. .to_th2_timestamp: 1.6309887999999972 +[2] DatetimeConverter +input: 2022-03-05 23:56:44.123000 +1. .parse_timestamp: 1.5668742000000009 +2. .to_datetime: 2.2390840999999995 +3. .to_seconds: 1.941752600000001 +4. .to_microseconds: 1.8873220999999916 +5. .to_nanoseconds: 1.7717899000000017 +6. .to_milliseconds: 1.8046078999999793 +7. .to_datetime_str: 2.4334617000000094 +8. .to_th2_timestamp: 1.9880792999999812 +[3] ProtobufTimestampConverter +input: {'epochSecond': 1646524604, 'nano': 123000000} +1. .parse_timestamp: 0.33349949999998785 +2. .to_datetime: 0.437383600000004 +3. .to_seconds: 0.07738620000000651 +4. .to_microseconds: 0.17947540000000117 +5. .to_nanoseconds: 0.14794729999999845 +6. .to_milliseconds: 0.16377359999998475 +7. .to_datetime_str: 1.154179499999998 +8. .to_th2_timestamp: 0.21915039999998953 +[4] UniversalDatetimeStringConverter +input: 2022-03-05T23:56:44.123Z +1. .parse_timestamp: 1.5990983000000085 +2. .to_datetime: 0.12491930000001616 +3. .to_seconds: 1.6566985999999986 +4. .to_microseconds: 1.8883035000000064 +5. .to_nanoseconds: 1.8457087999999828 +6. .to_milliseconds: 1.8479039999999998 +7. .to_datetime_str: 2.5292346000000236 +8. .to_th2_timestamp: 1.7339832000000115 +[5] UnixTimestampConverter +input: 1646524604123000000 +1. .parse_timestamp: 0.39382530000000315 +2. .to_datetime: 0.9663509999999746 +3. .to_seconds: 0.6740771000000052 +4. .to_microseconds: 0.6368252999999982 +5. .to_nanoseconds: 0.5960875000000101 +6. .to_milliseconds: 0.6230550999999878 +7. .to_datetime_str: 1.2212251999999921 +8. .to_th2_timestamp: 0.7406153000000018 +[1] DatetimeStringConverter +input: 2022-03-05T23:56:44.123 +1. .parse_timestamp: 1.4667527999999947 +2. .to_datetime: 0.12365850000000478 +3. .to_seconds: 1.5211263000000201 +4. .to_microseconds: 1.7549597999999946 +5. .to_nanoseconds: 1.7028257000000053 +6. .to_milliseconds: 1.7436409000000026 +7. .to_datetime_str: 2.3526966999999956 +8. .to_th2_timestamp: 1.5749490000000037 +[2] DatetimeConverter +input: 2022-03-05 23:56:44.123000 +1. .parse_timestamp: 1.5693777000000182 +2. .to_datetime: 2.181586100000004 +3. .to_seconds: 1.9088816000000008 +4. .to_microseconds: 1.8467825999999832 +5. .to_nanoseconds: 1.7813547000000085 +6. .to_milliseconds: 1.814983500000011 +7. .to_datetime_str: 2.440810099999993 +8. .to_th2_timestamp: 1.9874836999999843 +[3] ProtobufTimestampConverter +input: {'epochSecond': 1646524604, 'nano': 123000000} +1. .parse_timestamp: 0.3318582999999933 +2. .to_datetime: 0.4293978999999979 +3. .to_seconds: 0.07678099999998267 +4. .to_microseconds: 0.17459289999999328 +5. .to_nanoseconds: 0.14835100000001944 +6. .to_milliseconds: 0.1640060999999946 +7. .to_datetime_str: 1.1508268000000044 +8. .to_th2_timestamp: 0.2206453999999951 +[4] UniversalDatetimeStringConverter +input: 2022-03-05T23:56:44.123 +1. .parse_timestamp: 1.5456639000000223 +2. .to_datetime: 0.12399429999999256 +3. .to_seconds: 1.6086243999999965 +4. .to_microseconds: 1.7994822 +5. .to_nanoseconds: 1.765654100000006 +6. .to_milliseconds: 1.806836000000004 +7. .to_datetime_str: 2.4866505000000245 +8. .to_th2_timestamp: 1.6724970999999869 +[5] UnixTimestampConverter +input: 1646524604123000000 +1. .parse_timestamp: 0.3947655999999995 +2. .to_datetime: 0.9668101999999976 +3. .to_seconds: 0.6764975000000106 +4. .to_microseconds: 0.6397958999999958 +5. .to_nanoseconds: 0.5915199000000086 +6. .to_milliseconds: 0.6304887000000008 +7. .to_datetime_str: 1.924970299999984 +8. .to_th2_timestamp: 1.0398509000000047 +[1] DatetimeStringConverter +input: 2022-03-05T23:56:44.00123Z +1. .parse_timestamp: 2.505150299999997 +2. .to_datetime: 0.2635961000000009 +3. .to_seconds: 2.766974800000014 +4. .to_microseconds: 1.9969352000000242 +5. .to_nanoseconds: 1.8177603999999974 +6. .to_milliseconds: 1.793355599999984 +7. .to_datetime_str: 2.4162497000000087 +8. .to_th2_timestamp: 1.624307200000004 +[2] DatetimeConverter +input: 2022-03-05 23:56:44.001230 +1. .parse_timestamp: 1.5744656999999904 +2. .to_datetime: 2.420125899999988 +3. .to_seconds: 2.2712012000000072 +4. .to_microseconds: 1.8500145000000146 +5. .to_nanoseconds: 1.8220627000000036 +6. .to_milliseconds: 1.8425663999999813 +7. .to_datetime_str: 2.4573297000000025 +8. .to_th2_timestamp: 2.010794500000003 +[3] ProtobufTimestampConverter +input: {'epochSecond': 1646524604, 'nano': 1230000} +1. .parse_timestamp: 0.34568459999999845 +2. .to_datetime: 0.4299407999999971 +3. .to_seconds: 0.07707040000002507 +4. .to_microseconds: 0.1819327000000044 +5. .to_nanoseconds: 0.1452865999999915 +6. .to_milliseconds: 0.16155889999998863 +7. .to_datetime_str: 1.1742128999999863 +8. .to_th2_timestamp: 0.2232879999999966 +[4] UniversalDatetimeStringConverter +input: 2022-03-05T23:56:44.00123Z +1. .parse_timestamp: 1.5956581999999742 +2. .to_datetime: 0.1269749999999874 +3. .to_seconds: 1.6612366999999892 +4. .to_microseconds: 1.8565273000000104 +5. .to_nanoseconds: 1.8220018000000096 +6. .to_milliseconds: 1.8386508000000106 +7. .to_datetime_str: 2.510077300000006 +8. .to_th2_timestamp: 1.7401048000000117 +[5] UnixTimestampConverter +input: 1646524604001230000 +1. .parse_timestamp: 0.403297699999996 +2. .to_datetime: 0.9951126999999929 +3. .to_seconds: 0.6799212000000239 +4. .to_microseconds: 0.6327714999999898 +5. .to_nanoseconds: 0.5945480000000316 +6. .to_milliseconds: 0.6294548999999847 +7. .to_datetime_str: 1.2172846999999933 +8. .to_th2_timestamp: 0.7391488000000095 +[1] DatetimeStringConverter +input: 2022-03-05T23:56:44.00123 +1. .parse_timestamp: 1.461738099999991 +2. .to_datetime: 0.1280451999999741 +3. .to_seconds: 1.5174448000000211 +4. .to_microseconds: 1.7385057000000188 +5. .to_nanoseconds: 1.6838496000000305 +6. .to_milliseconds: 1.7246347999999898 +7. .to_datetime_str: 2.338951199999997 +8. .to_th2_timestamp: 1.5887523999999758 +[2] DatetimeConverter +input: 2022-03-05 23:56:44.001230 +1. .parse_timestamp: 1.5780955999999833 +2. .to_datetime: 2.2243831000000114 +3. .to_seconds: 1.9468481999999767 +4. .to_microseconds: 1.8618515000000002 +5. .to_nanoseconds: 1.8044909000000189 +6. .to_milliseconds: 2.0308842000000027 +7. .to_datetime_str: 2.706094699999994 +8. .to_th2_timestamp: 2.0595372000000225 +[3] ProtobufTimestampConverter +input: {'epochSecond': 1646524604, 'nano': 1230000} +1. .parse_timestamp: 0.3542325999999889 +2. .to_datetime: 0.44528969999998935 +3. .to_seconds: 0.07967100000001892 +4. .to_microseconds: 0.17370549999998275 +5. .to_nanoseconds: 0.14407939999995278 +6. .to_milliseconds: 0.1647527000000082 +7. .to_datetime_str: 1.1753770000000259 +8. .to_th2_timestamp: 0.23263500000001613 +[4] UniversalDatetimeStringConverter +input: 2022-03-05T23:56:44.00123 +1. .parse_timestamp: 1.564405899999997 +2. .to_datetime: 0.12373969999998735 +3. .to_seconds: 1.6300871000000257 +4. .to_microseconds: 1.86991519999998 +5. .to_nanoseconds: 1.7757335000000012 +6. .to_milliseconds: 1.8656308000000195 +7. .to_datetime_str: 2.432435699999985 +8. .to_th2_timestamp: 1.6578042999999525 +[5] UnixTimestampConverter +input: 1646524604001230000 +1. .parse_timestamp: 0.392732599999988 +2. .to_datetime: 0.9590297000000305 +3. .to_seconds: 0.6716984999999909 +4. .to_microseconds: 0.6371480999999903 +5. .to_nanoseconds: 0.5852380000000039 +6. .to_milliseconds: 0.6327994000000103 +7. .to_datetime_str: 1.215516100000002 +8. .to_th2_timestamp: 0.7312158999999951 +[1] DatetimeStringConverter +input: 2024-05-07T05:49:47.742201 +1. .parse_timestamp: 1.4681181000000265 +2. .to_datetime: 0.1230963000000429 +3. .to_seconds: 1.5329492999999843 +4. .to_microseconds: 1.7468476000000237 +5. .to_nanoseconds: 1.9251242999999931 +6. .to_milliseconds: 2.442695200000003 +7. .to_datetime_str: 3.0155179000000203 +8. .to_th2_timestamp: 1.5955402000000163 +[2] DatetimeConverter +input: 2024-05-07 05:49:47.742201 +1. .parse_timestamp: 1.5930829999999787 +2. .to_datetime: 2.228495099999975 +3. .to_seconds: 1.9691497999999683 +4. .to_microseconds: 1.8661538000000064 +5. .to_nanoseconds: 1.827512000000013 +6. .to_milliseconds: 1.890102499999955 +7. .to_datetime_str: 2.48807290000002 +8. .to_th2_timestamp: 2.0262270999999714 +[3] ProtobufTimestampConverter +input: {'epochSecond': 1715060987, 'nano': 742201000} +1. .parse_timestamp: 0.3335800000000404 +2. .to_datetime: 0.4343524999999886 +3. .to_seconds: 0.07739579999997659 +4. .to_microseconds: 0.17489929999999276 +5. .to_nanoseconds: 0.14885149999997793 +6. .to_milliseconds: 0.17431420000002618 +7. .to_datetime_str: 1.157919100000015 +8. .to_th2_timestamp: 0.2201837999999725 +[4] UniversalDatetimeStringConverter +input: 2024-05-07T05:49:47.742201 +1. .parse_timestamp: 1.5616084000000114 +2. .to_datetime: 0.1257492999999954 +3. .to_seconds: 1.6232976000000008 +4. .to_microseconds: 1.8207759999999666 +5. .to_nanoseconds: 1.770919900000024 +6. .to_milliseconds: 1.8478595000000269 +7. .to_datetime_str: 2.4604448000000048 +8. .to_th2_timestamp: 1.6610038000000031 +[5] UnixTimestampConverter +input: 1715060987742201000 +1. .parse_timestamp: 0.3937804999999912 +2. .to_datetime: 0.9652260000000297 +3. .to_seconds: 0.6768874000000551 +4. .to_microseconds: 0.634618899999964 +5. .to_nanoseconds: 0.59322659999998 +6. .to_milliseconds: 0.6311441000000286 +7. .to_datetime_str: 1.2326779999999644 +8. .to_th2_timestamp: 0.7841406000000006 +[1] DatetimeStringConverter +input: 2024-05-07T05:49:47Z +1. .parse_timestamp: 1.371942400000023 +2. .to_datetime: 0.12559959999998682 +3. .to_seconds: 1.4023935000000165 +4. .to_microseconds: 1.6093956999999932 +5. .to_nanoseconds: 1.5708133999999632 +6. .to_milliseconds: 1.601497199999983 +7. .to_datetime_str: 2.2226543000000447 +8. .to_th2_timestamp: 1.4562257000000045 +[2] DatetimeConverter +input: 2024-05-07 05:49:47 +1. .parse_timestamp: 1.3784417999999619 +2. .to_datetime: 2.0089932000000204 +3. .to_seconds: 1.7454172000000199 +4. .to_microseconds: 1.6879695000000083 +5. .to_nanoseconds: 1.6927737999999977 +6. .to_milliseconds: 1.849189200000012 +7. .to_datetime_str: 2.2845987999999693 +8. .to_th2_timestamp: 1.8285743999999795 +[3] ProtobufTimestampConverter +input: {'epochSecond': 1715060987, 'nano': 0} +1. .parse_timestamp: 0.34537039999997887 +2. .to_datetime: 0.42714979999999514 +3. .to_seconds: 0.07851030000000492 +4. .to_microseconds: 0.16641659999999092 +5. .to_nanoseconds: 0.14868639999997413 +6. .to_milliseconds: 0.17001230000005307 +7. .to_datetime_str: 1.19519200000002 +8. .to_th2_timestamp: 0.22556980000001658 +[4] UniversalDatetimeStringConverter +input: 2024-05-07T05:49:47Z +1. .parse_timestamp: 1.4408897000000138 +2. .to_datetime: 0.12645050000003266 +3. .to_seconds: 1.5116335000000163 +4. .to_microseconds: 1.7302679000000012 +5. .to_nanoseconds: 1.6698284000000285 +6. .to_milliseconds: 2.030475700000011 +7. .to_datetime_str: 2.4472033000000124 +8. .to_th2_timestamp: 1.5494975000000295 +[5] UnixTimestampConverter +input: 1715060987000000000 +1. .parse_timestamp: 0.40707290000000285 +2. .to_datetime: 0.9780664000000456 +3. .to_seconds: 0.6866956000000073 +4. .to_microseconds: 0.6511007999999947 +5. .to_nanoseconds: 0.6053023000000053 +6. .to_milliseconds: 0.6668900000000235 +7. .to_datetime_str: 1.2631437000000005 +8. .to_th2_timestamp: 0.7595876000000317 +[1] DatetimeStringConverter +input: 2024-05-07T05:49:47 +1. .parse_timestamp: 1.470228700000007 +2. .to_datetime: 0.12934250000000702 +3. .to_seconds: 1.5087466999999606 +4. .to_microseconds: 1.730894199999966 +5. .to_nanoseconds: 1.6989463000000455 +6. .to_milliseconds: 1.722833000000037 +7. .to_datetime_str: 2.353792300000009 +8. .to_th2_timestamp: 1.5718886000000225 +[2] DatetimeConverter +input: 2024-05-07 05:49:47 +1. .parse_timestamp: 1.4036939999999731 +2. .to_datetime: 2.0506606000000147 +3. .to_seconds: 1.759401299999979 +4. .to_microseconds: 1.6807122000000163 +5. .to_nanoseconds: 1.6269599999999969 +6. .to_milliseconds: 1.6690078000000312 +7. .to_datetime_str: 2.283247700000004 +8. .to_th2_timestamp: 1.8282054999999673 +[3] ProtobufTimestampConverter +input: {'epochSecond': 1715060987, 'nano': 0} +1. .parse_timestamp: 0.3323836000000142 +2. .to_datetime: 0.42104489999996986 +3. .to_seconds: 0.0781605999999897 +4. .to_microseconds: 0.16788400000001502 +5. .to_nanoseconds: 0.1464674000000059 +6. .to_milliseconds: 0.1692888000000039 +7. .to_datetime_str: 1.1905018999999584 +8. .to_th2_timestamp: 0.2219099000000142 +[4] UniversalDatetimeStringConverter +input: 2024-05-07T05:49:47 +1. .parse_timestamp: 1.5585773999999901 +2. .to_datetime: 0.12158449999998311 +3. .to_seconds: 1.6130526000000032 +4. .to_microseconds: 1.8449909999999932 +5. .to_nanoseconds: 1.7457770000000323 +6. .to_milliseconds: 1.7650401999999872 +7. .to_datetime_str: 2.403167499999995 +8. .to_th2_timestamp: 1.673896500000012 +[5] UnixTimestampConverter +input: 1715060987000000000 +1. .parse_timestamp: 0.6431311000000051 +2. .to_datetime: 1.4845300999999722 +3. .to_seconds: 0.9396767999999724 +4. .to_microseconds: 0.9754753999999934 +5. .to_nanoseconds: 0.8631558999999811 +6. .to_milliseconds: 0.8880545000000097 +7. .to_datetime_str: 1.7504626999999573 +8. .to_th2_timestamp: 1.0363998999999922 + +Process finished with exit code 0 diff --git a/tests/tests_unit/tests_utils/tests_converters/bench_results/2024.05.15 (3) - slava_test before all improvements b/tests/tests_unit/tests_utils/tests_converters/bench_results/2024.05.15 (3) - slava_test before all improvements new file mode 100644 index 00000000..6289bc0e --- /dev/null +++ b/tests/tests_unit/tests_utils/tests_converters/bench_results/2024.05.15 (3) - slava_test before all improvements @@ -0,0 +1,418 @@ +Speed test: + AMD Ryzen 7 6800H with Radeon Graphics 3.20 GHz + +> python.exe th2-data-services\tests\tests_unit\tests_utils\tests_converters\benchmark.py + +################################################## +This benchmark shows how many seconds takes every converter operation in seconds. +################################################## +[1] DatetimeStringConverter +input: 2022-03-05T23:56:44.123456789Z +1. .parse_timestamp: 7.1721964 +2. .to_datetime: 8.9945099 +3. .to_seconds: 8.6180093 +4. .to_microseconds: 7.906644000000004 +5. .to_nanoseconds: 7.678750700000002 +6. .to_milliseconds: 7.6059985999999995 +7. .to_datetime_str: 8.3861742 +8. .to_th2_timestamp: 7.770203300000006 +[2] DatetimeConverter +input: 2022-03-05 23:56:44.123456 +1. .parse_timestamp: 1.6111448000000053 +2. .to_datetime: 2.1905054000000064 +3. .to_seconds: 1.935892999999993 +4. .to_microseconds: 1.872012699999999 +5. .to_nanoseconds: 1.8386296000000044 +6. .to_milliseconds: 1.8632599999999968 +7. .to_datetime_str: 2.4831389 +8. .to_th2_timestamp: 1.988814000000005 +[3] ProtobufTimestampConverter +input: {'epochSecond': 1646524604, 'nano': 123456789} +1. .parse_timestamp: 0.3315159999999935 +2. .to_datetime: 0.4273725999999982 +3. .to_seconds: 0.16459509999999966 +4. .to_microseconds: 0.1726522000000017 +5. .to_nanoseconds: 0.14877989999999386 +6. .to_milliseconds: 0.16233510000000706 +7. .to_datetime_str: 1.1645869000000033 +8. .to_th2_timestamp: 0.220164699999998 +[4] UniversalDatetimeStringConverter +input: 2022-03-05T23:56:44.123456789Z +1. .parse_timestamp: 7.4161371 +2. .to_datetime: 8.210821800000005 +3. .to_seconds: 7.7745484000000005 +4. .to_microseconds: 7.75692939999999 +5. .to_nanoseconds: 7.787970000000001 +6. .to_milliseconds: 7.816871099999986 +7. .to_datetime_str: 8.738852999999978 +8. .to_th2_timestamp: 7.897267900000003 +[5] UnixTimestampConverter +input: 1646524604123456789 +1. .parse_timestamp: 0.42223010000000727 +2. .to_datetime: 1.2154596000000026 +3. .to_seconds: 0.8905898999999806 +4. .to_microseconds: 0.6749834999999962 +5. .to_nanoseconds: 0.6083508000000108 +6. .to_milliseconds: 0.7276246999999785 +7. .to_datetime_str: 1.7325338999999929 +8. .to_th2_timestamp: 1.0240924000000007 +[1] DatetimeStringConverter +input: 2022-03-05T23:56:44.123456789 +1. .parse_timestamp: 10.119866600000023 +2. .to_datetime: 11.735621500000008 +3. .to_seconds: 8.6062613 +4. .to_microseconds: 8.087100499999991 +5. .to_nanoseconds: 8.110706300000004 +6. .to_milliseconds: 7.8625544999999875 +7. .to_datetime_str: 8.357205099999987 +8. .to_th2_timestamp: 7.707271900000023 +[2] DatetimeConverter +input: 2022-03-05 23:56:44.123456 +1. .parse_timestamp: 1.5895392000000186 +2. .to_datetime: 2.190610399999997 +3. .to_seconds: 1.9107153999999866 +4. .to_microseconds: 1.884073299999983 +5. .to_nanoseconds: 1.8134540000000072 +6. .to_milliseconds: 1.8737672000000032 +7. .to_datetime_str: 2.4750672000000122 +8. .to_th2_timestamp: 1.9981686000000138 +[3] ProtobufTimestampConverter +input: {'epochSecond': 1646524604, 'nano': 123456789} +1. .parse_timestamp: 0.33912140000001045 +2. .to_datetime: 0.4316795000000013 +3. .to_seconds: 0.16504079999998567 +4. .to_microseconds: 0.173901399999977 +5. .to_nanoseconds: 0.14414279999999735 +6. .to_milliseconds: 0.16064119999998638 +7. .to_datetime_str: 1.1581917000000033 +8. .to_th2_timestamp: 0.214441800000003 +[4] UniversalDatetimeStringConverter +input: 2022-03-05T23:56:44.123456789 +1. .parse_timestamp: 7.449685399999993 +2. .to_datetime: 8.132023500000003 +3. .to_seconds: 7.795435599999962 +4. .to_microseconds: 7.696761700000025 +5. .to_nanoseconds: 7.662100800000019 +6. .to_milliseconds: 7.711291999999958 +7. .to_datetime_str: 8.51888260000004 +8. .to_th2_timestamp: 7.835917800000004 +[5] UnixTimestampConverter +input: 1646524604123456789 +1. .parse_timestamp: 0.3979739999999765 +2. .to_datetime: 0.9766083999999751 +3. .to_seconds: 0.6806018999999992 +4. .to_microseconds: 0.64399370000001 +5. .to_nanoseconds: 0.5935724999999934 +6. .to_milliseconds: 0.6387361999999825 +7. .to_datetime_str: 1.2226068999999598 +8. .to_th2_timestamp: 0.7408821999999873 +[1] DatetimeStringConverter +input: 2022-03-05T23:56:44.123Z +1. .parse_timestamp: 7.1918818999999985 +2. .to_datetime: 8.090070200000014 +3. .to_seconds: 7.667461099999969 +4. .to_microseconds: 7.706679500000007 +5. .to_nanoseconds: 7.712137900000016 +6. .to_milliseconds: 7.770383100000004 +7. .to_datetime_str: 8.504255299999954 +8. .to_th2_timestamp: 7.7090932999999495 +[2] DatetimeConverter +input: 2022-03-05 23:56:44.123000 +1. .parse_timestamp: 1.5487863999999831 +2. .to_datetime: 2.154199100000028 +3. .to_seconds: 1.8708242000000155 +4. .to_microseconds: 1.854664600000035 +5. .to_nanoseconds: 1.7831456000000117 +6. .to_milliseconds: 1.8324594000000047 +7. .to_datetime_str: 2.4936318999999685 +8. .to_th2_timestamp: 2.1774196000000074 +[3] ProtobufTimestampConverter +input: {'epochSecond': 1646524604, 'nano': 123000000} +1. .parse_timestamp: 0.3740071999999941 +2. .to_datetime: 0.4518289000000095 +3. .to_seconds: 0.16601929999995946 +4. .to_microseconds: 0.18181129999999257 +5. .to_nanoseconds: 0.15331299999996872 +6. .to_milliseconds: 0.16819079999999076 +7. .to_datetime_str: 1.169017800000006 +8. .to_th2_timestamp: 0.21251960000000736 +[4] UniversalDatetimeStringConverter +input: 2022-03-05T23:56:44.123Z +1. .parse_timestamp: 7.9720075999999835 +2. .to_datetime: 8.463932 +3. .to_seconds: 7.972972200000015 +4. .to_microseconds: 7.9450444999999945 +5. .to_nanoseconds: 7.812846200000024 +6. .to_milliseconds: 8.14439010000001 +7. .to_datetime_str: 8.641455299999961 +8. .to_th2_timestamp: 7.909200199999987 +[5] UnixTimestampConverter +input: 1646524604123000000 +1. .parse_timestamp: 0.3951384999999732 +2. .to_datetime: 0.9816507000000456 +3. .to_seconds: 0.6654113000000166 +4. .to_microseconds: 0.6441783000000214 +5. .to_nanoseconds: 0.5906861000000276 +6. .to_milliseconds: 0.6332893000000013 +7. .to_datetime_str: 1.2237997999999948 +8. .to_th2_timestamp: 0.747531400000014 +[1] DatetimeStringConverter +input: 2022-03-05T23:56:44.123 +1. .parse_timestamp: 7.193952500000023 +2. .to_datetime: 8.01869210000001 +3. .to_seconds: 7.618924499999991 +4. .to_microseconds: 7.589920500000005 +5. .to_nanoseconds: 7.564426900000001 +6. .to_milliseconds: 7.96010990000002 +7. .to_datetime_str: 8.622357399999942 +8. .to_th2_timestamp: 7.734187299999917 +[2] DatetimeConverter +input: 2022-03-05 23:56:44.123000 +1. .parse_timestamp: 1.5498681999999917 +2. .to_datetime: 2.1644505000000436 +3. .to_seconds: 1.8940933000000086 +4. .to_microseconds: 1.8735040000000254 +5. .to_nanoseconds: 1.7765328000000409 +6. .to_milliseconds: 1.814903099999924 +7. .to_datetime_str: 2.444460100000015 +8. .to_th2_timestamp: 1.9447567999999364 +[3] ProtobufTimestampConverter +input: {'epochSecond': 1646524604, 'nano': 123000000} +1. .parse_timestamp: 0.32527279999999337 +2. .to_datetime: 0.42912310000008347 +3. .to_seconds: 0.1670325000000048 +4. .to_microseconds: 0.17790930000001026 +5. .to_nanoseconds: 0.14934069999992516 +6. .to_milliseconds: 0.1655547000000297 +7. .to_datetime_str: 1.147257100000047 +8. .to_th2_timestamp: 0.21375100000000202 +[4] UniversalDatetimeStringConverter +input: 2022-03-05T23:56:44.123 +1. .parse_timestamp: 7.316611899999998 +2. .to_datetime: 9.06912520000003 +3. .to_seconds: 7.770292599999948 +4. .to_microseconds: 7.757206600000018 +5. .to_nanoseconds: 7.733612099999959 +6. .to_milliseconds: 7.740806399999997 +7. .to_datetime_str: 8.944680300000073 +8. .to_th2_timestamp: 7.839518600000019 +[5] UnixTimestampConverter +input: 1646524604123000000 +1. .parse_timestamp: 0.3904235999999628 +2. .to_datetime: 1.0137995999999703 +3. .to_seconds: 0.6830463000000009 +4. .to_microseconds: 0.6476643999999396 +5. .to_nanoseconds: 0.5904385999999704 +6. .to_milliseconds: 0.6354539999999815 +7. .to_datetime_str: 1.221368200000029 +8. .to_th2_timestamp: 0.7439444999999978 +[1] DatetimeStringConverter +input: 2022-03-05T23:56:44.00123Z +1. .parse_timestamp: 7.663631099999975 +2. .to_datetime: 8.14004829999999 +3. .to_seconds: 8.342049100000054 +4. .to_microseconds: 10.768012399999975 +5. .to_nanoseconds: 11.578620800000067 +6. .to_milliseconds: 8.332774599999993 +7. .to_datetime_str: 8.62202549999995 +8. .to_th2_timestamp: 9.712369500000023 +[2] DatetimeConverter +input: 2022-03-05 23:56:44.001230 +1. .parse_timestamp: 2.205115699999965 +2. .to_datetime: 3.125138799999945 +3. .to_seconds: 2.6203506000000516 +4. .to_microseconds: 2.5896208000000343 +5. .to_nanoseconds: 2.4905476000000135 +6. .to_milliseconds: 2.5974738999999545 +7. .to_datetime_str: 3.6285138999999162 +8. .to_th2_timestamp: 3.414094900000009 +[3] ProtobufTimestampConverter +input: {'epochSecond': 1646524604, 'nano': 1230000} +1. .parse_timestamp: 0.3366894000000684 +2. .to_datetime: 0.4242671000000655 +3. .to_seconds: 0.16384640000001127 +4. .to_microseconds: 0.1747401999999738 +5. .to_nanoseconds: 0.14379680000001827 +6. .to_milliseconds: 0.16139210000005733 +7. .to_datetime_str: 1.1671893999999838 +8. .to_th2_timestamp: 0.21078980000004321 +[4] UniversalDatetimeStringConverter +input: 2022-03-05T23:56:44.00123Z +1. .parse_timestamp: 7.3768982999999935 +2. .to_datetime: 8.336610500000006 +3. .to_seconds: 7.867413199999987 +4. .to_microseconds: 7.792132200000083 +5. .to_nanoseconds: 8.130505400000061 +6. .to_milliseconds: 11.225203299999976 +7. .to_datetime_str: 9.963105799999994 +8. .to_th2_timestamp: 11.663552099999947 +[5] UnixTimestampConverter +input: 1646524604001230000 +1. .parse_timestamp: 0.5423750999999584 +2. .to_datetime: 1.4116088000000673 +3. .to_seconds: 1.092082899999923 +4. .to_microseconds: 0.9166100999999571 +5. .to_nanoseconds: 0.8595927999999731 +6. .to_milliseconds: 0.8899970999999596 +7. .to_datetime_str: 2.1571126999999706 +8. .to_th2_timestamp: 1.0291214999999738 +[1] DatetimeStringConverter +input: 2022-03-05T23:56:44.00123 +1. .parse_timestamp: 10.266192799999999 +2. .to_datetime: 11.708400299999994 +3. .to_seconds: 10.837973499999976 +4. .to_microseconds: 10.714744599999904 +5. .to_nanoseconds: 10.584031200000027 +6. .to_milliseconds: 10.579064700000004 +7. .to_datetime_str: 11.578284300000064 +8. .to_th2_timestamp: 10.793956800000046 +[2] DatetimeConverter +input: 2022-03-05 23:56:44.001230 +1. .parse_timestamp: 2.1788654999999153 +2. .to_datetime: 3.0716215999999577 +3. .to_seconds: 2.648762799999986 +4. .to_microseconds: 2.635675200000037 +5. .to_nanoseconds: 1.993366100000003 +6. .to_milliseconds: 1.828549300000077 +7. .to_datetime_str: 2.4403310000000147 +8. .to_th2_timestamp: 1.9580807999999479 +[3] ProtobufTimestampConverter +input: {'epochSecond': 1646524604, 'nano': 1230000} +1. .parse_timestamp: 0.3340438999999833 +2. .to_datetime: 0.42486559999997553 +3. .to_seconds: 0.16564229999994495 +4. .to_microseconds: 0.17523800000003575 +5. .to_nanoseconds: 0.1451816000000008 +6. .to_milliseconds: 0.1628117000000202 +7. .to_datetime_str: 1.1657399000000623 +8. .to_th2_timestamp: 0.21519039999998313 +[4] UniversalDatetimeStringConverter +input: 2022-03-05T23:56:44.00123 +1. .parse_timestamp: 7.369267699999909 +2. .to_datetime: 8.226974100000007 +3. .to_seconds: 7.768311600000061 +4. .to_microseconds: 7.800921000000017 +5. .to_nanoseconds: 7.690494400000034 +6. .to_milliseconds: 7.740710599999943 +7. .to_datetime_str: 8.552925999999957 +8. .to_th2_timestamp: 7.852125699999988 +[5] UnixTimestampConverter +input: 1646524604001230000 +1. .parse_timestamp: 0.39585829999998623 +2. .to_datetime: 0.9767267999999376 +3. .to_seconds: 0.6745611000000054 +4. .to_microseconds: 0.6441604999999981 +5. .to_nanoseconds: 0.6021672999999055 +6. .to_milliseconds: 0.6321972999999161 +7. .to_datetime_str: 1.2212197999999717 +8. .to_th2_timestamp: 0.7379410999999436 +[1] DatetimeStringConverter +input: 2024-05-07T05:49:47.742201 +1. .parse_timestamp: 7.194651399999998 +2. .to_datetime: 8.874355700000024 +3. .to_seconds: 7.648217499999987 +4. .to_microseconds: 7.922543599999926 +5. .to_nanoseconds: 7.613019200000053 +6. .to_milliseconds: 7.702751000000035 +7. .to_datetime_str: 8.373585400000024 +8. .to_th2_timestamp: 7.778714100000116 +[2] DatetimeConverter +input: 2024-05-07 05:49:47.742201 +1. .parse_timestamp: 1.593132100000048 +2. .to_datetime: 2.219165700000076 +3. .to_seconds: 1.9304399999998623 +4. .to_microseconds: 1.8787944999999127 +5. .to_nanoseconds: 1.8237501000000975 +6. .to_milliseconds: 1.8803766000000905 +7. .to_datetime_str: 2.4800986999998713 +8. .to_th2_timestamp: 1.9785910000000513 +[3] ProtobufTimestampConverter +input: {'epochSecond': 1715060987, 'nano': 742201000} +1. .parse_timestamp: 0.32882930000005217 +2. .to_datetime: 0.4304193000000396 +3. .to_seconds: 0.16601489999993646 +4. .to_microseconds: 0.17487710000000334 +5. .to_nanoseconds: 0.14563179999981912 +6. .to_milliseconds: 0.17438730000003488 +7. .to_datetime_str: 1.1603312999998252 +8. .to_th2_timestamp: 0.21971179999991364 +[4] UniversalDatetimeStringConverter +input: 2024-05-07T05:49:47.742201 +1. .parse_timestamp: 7.426433300000099 +2. .to_datetime: 8.670984799999815 +3. .to_seconds: 8.056592500000079 +4. .to_microseconds: 7.972125200000164 +5. .to_nanoseconds: 7.771402699999953 +6. .to_milliseconds: 7.83897520000005 +7. .to_datetime_str: 8.704525500000045 +8. .to_th2_timestamp: 7.897576999999956 +[5] UnixTimestampConverter +input: 1715060987742201000 +1. .parse_timestamp: 0.39613340000005337 +2. .to_datetime: 0.9925742000000355 +3. .to_seconds: 0.7138772999999219 +4. .to_microseconds: 0.749780200000032 +5. .to_nanoseconds: 0.6582542000001013 +6. .to_milliseconds: 0.7532022000000325 +7. .to_datetime_str: 1.346767600000021 +8. .to_th2_timestamp: 0.7958074000000579 +[1] DatetimeStringConverter +input: 2024-05-07T05:49:47Z +1. .parse_timestamp: 7.939616300000125 +2. .to_datetime: 8.64984329999993 +3. .to_seconds: 8.21792359999995 +4. .to_microseconds: 8.284971600000063 +5. .to_nanoseconds: 8.205392300000085 +6. .to_milliseconds: 8.187096099999962 +7. .to_datetime_str: 8.840702500000134 +8. .to_th2_timestamp: 8.332551199999898 +[2] DatetimeConverter +input: 2024-05-07 05:49:47 +1. .parse_timestamp: 1.3917327999999998 +2. .to_datetime: 2.003172799999902 +3. .to_seconds: 1.7056637999999111 +4. .to_microseconds: 1.6674965999998221 +5. .to_nanoseconds: 1.617796799999951 +6. .to_milliseconds: 1.6645157000000381 +7. .to_datetime_str: 2.292171000000053 +8. .to_th2_timestamp: 1.778795799999898 +[3] ProtobufTimestampConverter +input: {'epochSecond': 1715060987, 'nano': 0} +1. .parse_timestamp: 0.32817260000001625 +2. .to_datetime: 0.41567220000001726 +3. .to_seconds: 0.16836220000004687 +4. .to_microseconds: 0.1726194000000305 +5. .to_nanoseconds: 0.14601799999991272 +6. .to_milliseconds: 0.17073509999977432 +7. .to_datetime_str: 1.1862195000001066 +8. .to_th2_timestamp: 0.2181554999999662 +[4] UniversalDatetimeStringConverter +input: 2024-05-07T05:49:47Z +1. .parse_timestamp: 8.050805399999945 +2. .to_datetime: 9.141925700000002 +3. .to_seconds: 8.705379399999856 +4. .to_microseconds: 10.652987899999971 +5. .to_nanoseconds: 11.714843099999825 +6. .to_milliseconds: 11.700495100000126 +7. .to_datetime_str: 12.956908799999837 +8. .to_th2_timestamp: 12.184501400000045 +[5] UnixTimestampConverter +input: 1715060987000000000 +1. .parse_timestamp: 0.5352742000000035 +2. .to_datetime: 1.4503383999999642 +3. .to_seconds: 0.9819064000000708 +4. .to_microseconds: 1.0444664999999986 +5. .to_nanoseconds: 0.817567199999985 +6. .to_milliseconds: 0.9459798999998839 +7. .to_datetime_str: 1.720381800000041 +8. .to_th2_timestamp: 1.0127864999999474 +[1] DatetimeStringConverter +input: 2024-05-07T05:49:47 (not applicable format before, so you see the error) + +Traceback (most recent call last): + File "th2-data-services\th2_data_services\utils\converters.py", line 45, in parse_timestamp + dt_tuple = _DatetimeTuple(*datetime_string.rsplit(".")) +TypeError: () missing 1 required positional argument: 'mantissa' + +During handling of the above exception, another exception occurred: +ValueError: time data '2024-05-07T05:49:47' does not match format '%Y-%m-%dT%H:%M:%SZ' diff --git a/tests/tests_unit/tests_utils/tests_converters/bench_results/2024.05.15 - slava_test b/tests/tests_unit/tests_utils/tests_converters/bench_results/2024.05.15 - slava_test new file mode 100644 index 00000000..2e7c40e1 --- /dev/null +++ b/tests/tests_unit/tests_utils/tests_converters/bench_results/2024.05.15 - slava_test @@ -0,0 +1,455 @@ +Speed test: + AMD Ryzen 7 6800H with Radeon Graphics 3.20 GHz + +> python.exe th2-data-services\tests\tests_unit\tests_utils\tests_converters\benchmark.py + +[1] DatetimeStringConverter +input: 2022-03-05T23:56:44.123456789Z +1. .parse_timestamp: 1.8927287000000002 +2. .to_datetime: 3.2828667 +3. .to_seconds: 1.9376730000000002 +4. .to_microseconds: 2.0108901 +5. .to_nanoseconds: 2.0102408999999994 +6. .to_milliseconds: 2.0692888000000007 +7. .to_datetime_str: 2.6827977999999995 +8. .to_th2_timestamp: 2.1542844000000017 +[2] DatetimeConverter +input: 2022-03-05 23:56:44.123456 +1. .parse_timestamp: 1.5851472999999991 +2. .to_datetime: 2.761737 +3. .to_seconds: 1.760802599999998 +4. .to_microseconds: 1.8606939999999987 +5. .to_nanoseconds: 1.8507057000000025 +6. .to_milliseconds: 1.890964799999999 +7. .to_datetime_str: 2.4742972000000023 +8. .to_th2_timestamp: 1.9972042000000059 +[3] ProtobufTimestampConverter +input: {'epochSecond': 1646524604, 'nano': 123456789} +1. .parse_timestamp: 0.33477419999999825 +2. .to_datetime: 1.043011100000001 +3. .to_seconds: 0.17178410000000355 +4. .to_microseconds: 0.17845179999999772 +5. .to_nanoseconds: 0.15012639999999777 +6. .to_milliseconds: 0.16479700000000008 +7. .to_datetime_str: 1.1646684000000036 +8. .to_th2_timestamp: 0.22861890000000074 +[4] UniversalDatetimeStringConverter +input: 2022-03-05T23:56:44.123456789Z +1. .parse_timestamp: 1.8529044 +2. .to_datetime: 3.0888861000000034 +3. .to_seconds: 2.071152000000005 +4. .to_microseconds: 2.1966672000000003 +5. .to_nanoseconds: 2.1428145 +6. .to_milliseconds: 2.113243599999997 +7. .to_datetime_str: 2.838190399999995 +8. .to_th2_timestamp: 2.7606534000000025 +[5] UnixTimestampConverter +input: 1646524604123456789 +1. .parse_timestamp: 0.41358340000000027 +2. .to_datetime: 1.5727192000000016 +3. .to_seconds: 0.5479090999999983 +4. .to_microseconds: 0.6473261999999949 +5. .to_nanoseconds: 0.6146342999999987 +6. .to_milliseconds: 0.6480366999999987 +7. .to_datetime_str: 1.270939999999996 +8. .to_th2_timestamp: 0.7818102999999965 +[1] DatetimeStringConverter +input: 2022-03-05T23:56:44.123456789 +1. .parse_timestamp: 2.2235998999999964 +2. .to_datetime: 3.948166400000005 +3. .to_seconds: 2.5067649000000074 +4. .to_microseconds: 2.4177078000000023 +5. .to_nanoseconds: 2.430183900000003 +6. .to_milliseconds: 2.267869200000007 +7. .to_datetime_str: 2.6838499999999925 +8. .to_th2_timestamp: 2.1424711000000087 +[2] DatetimeConverter +input: 2022-03-05 23:56:44.123456 +1. .parse_timestamp: 1.638743699999992 +2. .to_datetime: 2.9116070000000036 +3. .to_seconds: 1.7815068999999966 +4. .to_microseconds: 1.8994538999999975 +5. .to_nanoseconds: 1.8692955000000069 +6. .to_milliseconds: 1.9199399000000028 +7. .to_datetime_str: 2.518968700000002 +8. .to_th2_timestamp: 1.9979397000000034 +[3] ProtobufTimestampConverter +input: {'epochSecond': 1646524604, 'nano': 123456789} +1. .parse_timestamp: 0.3310115999999965 +2. .to_datetime: 1.0578451000000086 +3. .to_seconds: 0.1805251000000112 +4. .to_microseconds: 0.18775839999999278 +5. .to_nanoseconds: 0.15823380000000498 +6. .to_milliseconds: 0.17560179999999548 +7. .to_datetime_str: 1.1866887999999989 +8. .to_th2_timestamp: 0.22983410000000504 +[4] UniversalDatetimeStringConverter +input: 2022-03-05T23:56:44.123456789 +1. .parse_timestamp: 1.785397400000008 +2. .to_datetime: 3.038070700000006 +3. .to_seconds: 2.0203798000000006 +4. .to_microseconds: 2.1227379999999982 +5. .to_nanoseconds: 2.1039399999999944 +6. .to_milliseconds: 2.146468100000007 +7. .to_datetime_str: 2.7783622000000037 +8. .to_th2_timestamp: 2.2326651000000055 +[5] UnixTimestampConverter +input: 1646524604123456789 +1. .parse_timestamp: 0.40194759999999974 +2. .to_datetime: 1.5359188000000046 +3. .to_seconds: 0.5437225000000012 +4. .to_microseconds: 0.6343444000000034 +5. .to_nanoseconds: 0.6007445999999987 +6. .to_milliseconds: 0.6322474000000113 +7. .to_datetime_str: 1.2373525999999941 +8. .to_th2_timestamp: 0.7395526000000103 +[1] DatetimeStringConverter +input: 2022-03-05T23:56:44.123Z +1. .parse_timestamp: 1.7539086000000168 +2. .to_datetime: 2.868971899999991 +3. .to_seconds: 1.9573993999999857 +4. .to_microseconds: 2.0517487000000187 +5. .to_nanoseconds: 2.0249905000000012 +6. .to_milliseconds: 2.0801794999999856 +7. .to_datetime_str: 2.7197670000000187 +8. .to_th2_timestamp: 2.1914490000000058 +[2] DatetimeConverter +input: 2022-03-05 23:56:44.123000 +1. .parse_timestamp: 1.6074090000000183 +2. .to_datetime: 2.6539047999999923 +3. .to_seconds: 1.755619700000011 +4. .to_microseconds: 1.8506788999999912 +5. .to_nanoseconds: 1.801578400000011 +6. .to_milliseconds: 1.8087876000000165 +7. .to_datetime_str: 2.4213129000000038 +8. .to_th2_timestamp: 1.940777799999978 +[3] ProtobufTimestampConverter +input: {'epochSecond': 1646524604, 'nano': 123000000} +1. .parse_timestamp: 0.3318361999999979 +2. .to_datetime: 0.9406206000000168 +3. .to_seconds: 0.17253499999998212 +4. .to_microseconds: 0.1824837000000059 +5. .to_nanoseconds: 0.15369559999999183 +6. .to_milliseconds: 0.16600230000000238 +7. .to_datetime_str: 1.1728947999999946 +8. .to_th2_timestamp: 0.22607449999998153 +[4] UniversalDatetimeStringConverter +input: 2022-03-05T23:56:44.123Z +1. .parse_timestamp: 1.8526551999999867 +2. .to_datetime: 2.991807499999993 +3. .to_seconds: 2.050377200000014 +4. .to_microseconds: 2.158428999999984 +5. .to_nanoseconds: 2.124037900000019 +6. .to_milliseconds: 2.151489199999986 +7. .to_datetime_str: 2.8132969999999773 +8. .to_th2_timestamp: 2.2950381999999934 +[5] UnixTimestampConverter +input: 1646524604123000000 +1. .parse_timestamp: 0.40292789999998035 +2. .to_datetime: 1.47074760000001 +3. .to_seconds: 0.5526959999999974 +4. .to_microseconds: 0.6516709999999932 +5. .to_nanoseconds: 0.6175217999999916 +6. .to_milliseconds: 0.628027899999978 +7. .to_datetime_str: 1.234347200000002 +8. .to_th2_timestamp: 0.7518077000000005 +[1] DatetimeStringConverter +input: 2022-03-05T23:56:44.123 +1. .parse_timestamp: 1.7227267000000097 +2. .to_datetime: 2.8411595999999975 +3. .to_seconds: 1.9001301000000126 +4. .to_microseconds: 1.9987932999999884 +5. .to_nanoseconds: 1.9653095999999834 +6. .to_milliseconds: 1.9981731000000025 +7. .to_datetime_str: 2.6187837999999886 +8. .to_th2_timestamp: 2.12082190000001 +[2] DatetimeConverter +input: 2022-03-05 23:56:44.123000 +1. .parse_timestamp: 1.5795474999999897 +2. .to_datetime: 2.6532344999999964 +3. .to_seconds: 1.736732599999982 +4. .to_microseconds: 1.8224056999999902 +5. .to_nanoseconds: 1.8018467999999928 +6. .to_milliseconds: 1.817460699999998 +7. .to_datetime_str: 2.4872583000000077 +8. .to_th2_timestamp: 1.9534256000000028 +[3] ProtobufTimestampConverter +input: {'epochSecond': 1646524604, 'nano': 123000000} +1. .parse_timestamp: 0.3350242999999864 +2. .to_datetime: 0.9531532000000027 +3. .to_seconds: 0.1799194999999827 +4. .to_microseconds: 0.18870830000000183 +5. .to_nanoseconds: 0.15726159999999823 +6. .to_milliseconds: 0.17800090000000068 +7. .to_datetime_str: 1.2048328999999853 +8. .to_th2_timestamp: 0.23630719999999883 +[4] UniversalDatetimeStringConverter +input: 2022-03-05T23:56:44.123 +1. .parse_timestamp: 1.8635937999999896 +2. .to_datetime: 2.9726331000000243 +3. .to_seconds: 2.02398629999999 +4. .to_microseconds: 2.1065791999999988 +5. .to_nanoseconds: 2.2012063999999896 +6. .to_milliseconds: 2.5096491000000185 +7. .to_datetime_str: 3.574054600000011 +8. .to_th2_timestamp: 2.6861068999999986 +[5] UnixTimestampConverter +input: 1646524604123000000 +1. .parse_timestamp: 0.4546589999999924 +2. .to_datetime: 2.0732928000000186 +3. .to_seconds: 0.5498948999999982 +4. .to_microseconds: 0.6457259000000022 +5. .to_nanoseconds: 0.8416612000000043 +6. .to_milliseconds: 0.9891335000000083 +7. .to_datetime_str: 1.3635706999999968 +8. .to_th2_timestamp: 0.7533512999999914 +[1] DatetimeStringConverter +input: 2022-03-05T23:56:44.00123Z +1. .parse_timestamp: 2.7927712000000326 +2. .to_datetime: 4.278535599999998 +3. .to_seconds: 1.96002679999998 +4. .to_microseconds: 2.6636616000000117 +5. .to_nanoseconds: 2.0322440000000483 +6. .to_milliseconds: 2.0658420999999976 +7. .to_datetime_str: 2.712115900000015 +8. .to_th2_timestamp: 2.186618399999986 +[2] DatetimeConverter +input: 2022-03-05 23:56:44.001230 +1. .parse_timestamp: 2.0295946000000527 +2. .to_datetime: 2.7257055000000037 +3. .to_seconds: 1.7945263999999952 +4. .to_microseconds: 2.259978999999987 +5. .to_nanoseconds: 1.8524441000000138 +6. .to_milliseconds: 1.8677707999999598 +7. .to_datetime_str: 2.5165106000000037 +8. .to_th2_timestamp: 2.24383499999999 +[3] ProtobufTimestampConverter +input: {'epochSecond': 1646524604, 'nano': 1230000} +1. .parse_timestamp: 0.5747887999999648 +2. .to_datetime: 1.0656904999999597 +3. .to_seconds: 0.1798658999999816 +4. .to_microseconds: 0.18566889999999603 +5. .to_nanoseconds: 0.15646090000001323 +6. .to_milliseconds: 0.17381710000000794 +7. .to_datetime_str: 1.2329169000000206 +8. .to_th2_timestamp: 0.23786830000000236 +[4] UniversalDatetimeStringConverter +input: 2022-03-05T23:56:44.00123Z +1. .parse_timestamp: 2.1028848999999923 +2. .to_datetime: 4.075680700000021 +3. .to_seconds: 2.2136122 +4. .to_microseconds: 2.857879300000036 +5. .to_nanoseconds: 2.6316708999999605 +6. .to_milliseconds: 2.191912900000034 +7. .to_datetime_str: 2.8738817999999924 +8. .to_th2_timestamp: 2.4033068999999614 +[5] UnixTimestampConverter +input: 1646524604001230000 +1. .parse_timestamp: 0.42741860000001 +2. .to_datetime: 1.5135296000000267 +3. .to_seconds: 0.57334689999999 +4. .to_microseconds: 0.6405912000000171 +5. .to_nanoseconds: 0.6063179999999875 +6. .to_milliseconds: 0.6352689999999939 +7. .to_datetime_str: 1.2570949000000269 +8. .to_th2_timestamp: 0.7535694999999691 +[1] DatetimeStringConverter +input: 2022-03-05T23:56:44.00123 +1. .parse_timestamp: 1.7231020999999487 +2. .to_datetime: 2.8772983999999724 +3. .to_seconds: 1.9266242999999577 +4. .to_microseconds: 2.0356643000000076 +5. .to_nanoseconds: 2.0088810999999964 +6. .to_milliseconds: 2.0727196000000276 +7. .to_datetime_str: 2.682436600000017 +8. .to_th2_timestamp: 2.174801899999977 +[2] DatetimeConverter +input: 2022-03-05 23:56:44.001230 +1. .parse_timestamp: 1.6071357999999805 +2. .to_datetime: 2.688362199999972 +3. .to_seconds: 1.7714391000000091 +4. .to_microseconds: 1.88166590000003 +5. .to_nanoseconds: 1.8491403000000446 +6. .to_milliseconds: 1.8585317999999802 +7. .to_datetime_str: 2.454929199999981 +8. .to_th2_timestamp: 1.9987780000000157 +[3] ProtobufTimestampConverter +input: {'epochSecond': 1646524604, 'nano': 1230000} +1. .parse_timestamp: 0.3551714999999831 +2. .to_datetime: 0.9593300999999883 +3. .to_seconds: 0.17599599999999782 +4. .to_microseconds: 0.18806569999998146 +5. .to_nanoseconds: 0.15809910000001537 +6. .to_milliseconds: 0.17242310000000316 +7. .to_datetime_str: 1.2015005000000087 +8. .to_th2_timestamp: 0.2336581999999794 +[4] UniversalDatetimeStringConverter +input: 2022-03-05T23:56:44.00123 +1. .parse_timestamp: 1.8565461000000028 +2. .to_datetime: 2.9778078000000505 +3. .to_seconds: 2.052798399999972 +4. .to_microseconds: 2.0783374000000094 +5. .to_nanoseconds: 2.0925841000000105 +6. .to_milliseconds: 2.135246499999994 +7. .to_datetime_str: 2.754793599999971 +8. .to_th2_timestamp: 2.219951100000003 +[5] UnixTimestampConverter +input: 1646524604001230000 +1. .parse_timestamp: 0.4033084999999801 +2. .to_datetime: 1.4263313000000153 +3. .to_seconds: 0.5524769999999535 +4. .to_microseconds: 0.6582905999999866 +5. .to_nanoseconds: 0.6179709000000457 +6. .to_milliseconds: 0.6462448999999992 +7. .to_datetime_str: 1.2541344999999637 +8. .to_th2_timestamp: 0.7460042000000158 +[1] DatetimeStringConverter +input: 2024-05-07T05:49:47.742201 +1. .parse_timestamp: 1.7986928999999918 +2. .to_datetime: 2.9512927000000104 +3. .to_seconds: 1.8997878000000128 +4. .to_microseconds: 2.011026300000026 +5. .to_nanoseconds: 2.622288700000013 +6. .to_milliseconds: 2.3463134000000423 +7. .to_datetime_str: 2.693044499999985 +8. .to_th2_timestamp: 2.1493244999999774 +[2] DatetimeConverter +input: 2024-05-07 05:49:47.742201 +1. .parse_timestamp: 1.5734567000000084 +2. .to_datetime: 2.7939475000000016 +3. .to_seconds: 1.763776699999994 +4. .to_microseconds: 1.8329658999999765 +5. .to_nanoseconds: 1.8119760999999812 +6. .to_milliseconds: 1.885582099999965 +7. .to_datetime_str: 2.5727628999999865 +8. .to_th2_timestamp: 2.0383752999999842 +[3] ProtobufTimestampConverter +input: {'epochSecond': 1715060987, 'nano': 742201000} +1. .parse_timestamp: 0.3439764999999966 +2. .to_datetime: 1.0850958000000333 +3. .to_seconds: 0.18347340000002532 +4. .to_microseconds: 0.19106729999998606 +5. .to_nanoseconds: 0.16425040000001445 +6. .to_milliseconds: 0.1908798000000047 +7. .to_datetime_str: 1.1906695999999783 +8. .to_th2_timestamp: 0.22793780000000652 +[4] UniversalDatetimeStringConverter +input: 2024-05-07T05:49:47.742201 +1. .parse_timestamp: 1.8191489999999817 +2. .to_datetime: 3.0709906999999816 +3. .to_seconds: 1.9844393999999852 +4. .to_microseconds: 2.088538299999982 +5. .to_nanoseconds: 2.0277700000000323 +6. .to_milliseconds: 2.0889773000000105 +7. .to_datetime_str: 2.731978599999991 +8. .to_th2_timestamp: 2.2259778999999753 +[5] UnixTimestampConverter +input: 1715060987742201000 +1. .parse_timestamp: 0.4044696000000272 +2. .to_datetime: 1.5167165999999952 +3. .to_seconds: 0.5417951000000016 +4. .to_microseconds: 0.6278556999999978 +5. .to_nanoseconds: 0.5957706000000371 +6. .to_milliseconds: 0.6255803000000242 +7. .to_datetime_str: 1.2666568999999868 +8. .to_th2_timestamp: 0.7581746999999837 +[1] DatetimeStringConverter +input: 2024-05-07T05:49:47Z +1. .parse_timestamp: 1.5526128000000199 +2. .to_datetime: 2.6979243999999767 +3. .to_seconds: 1.7580983000000288 +4. .to_microseconds: 1.8693389000000025 +5. .to_nanoseconds: 1.8402322000000026 +6. .to_milliseconds: 1.7703877999999804 +7. .to_datetime_str: 2.411778199999958 +8. .to_th2_timestamp: 1.9289490000000455 +[2] DatetimeConverter +input: 2024-05-07 05:49:47 +1. .parse_timestamp: 1.3750248999999712 +2. .to_datetime: 2.4582655000000386 +3. .to_seconds: 1.5334473000000344 +4. .to_microseconds: 1.6636192000000278 +5. .to_nanoseconds: 1.628617399999996 +6. .to_milliseconds: 1.6749172000000385 +7. .to_datetime_str: 2.463564099999985 +8. .to_th2_timestamp: 2.080080599999974 +[3] ProtobufTimestampConverter +input: {'epochSecond': 1715060987, 'nano': 0} +1. .parse_timestamp: 0.33526750000004313 +2. .to_datetime: 0.9373094999999694 +3. .to_seconds: 0.1705258999999728 +4. .to_microseconds: 0.17097389999997858 +5. .to_nanoseconds: 0.14908659999997553 +6. .to_milliseconds: 0.17249959999998055 +7. .to_datetime_str: 1.1971168000000034 +8. .to_th2_timestamp: 0.23058119999996052 +[4] UniversalDatetimeStringConverter +input: 2024-05-07T05:49:47Z +1. .parse_timestamp: 1.7495157999999833 +2. .to_datetime: 2.8203322999999614 +3. .to_seconds: 1.9152512999999658 +4. .to_microseconds: 2.028153599999996 +5. .to_nanoseconds: 2.0279858000000104 +6. .to_milliseconds: 2.048659499999985 +7. .to_datetime_str: 2.7272466999999665 +8. .to_th2_timestamp: 2.2131420999999705 +[5] UnixTimestampConverter +input: 1715060987000000000 +1. .parse_timestamp: 0.4028023999999846 +2. .to_datetime: 1.4344328999999902 +3. .to_seconds: 0.559107900000015 +4. .to_microseconds: 0.6569743999999673 +5. .to_nanoseconds: 0.6203462999999942 +6. .to_milliseconds: 0.6452158999999824 +7. .to_datetime_str: 1.2669619999999782 +8. .to_th2_timestamp: 0.7805349999999862 +[1] DatetimeStringConverter +input: 2024-05-07T05:49:47 +1. .parse_timestamp: 1.5867704000000344 +2. .to_datetime: 2.7075549999999566 +3. .to_seconds: 1.7601975000000607 +4. .to_microseconds: 1.8501774000000069 +5. .to_nanoseconds: 1.8049101999999948 +6. .to_milliseconds: 1.849394400000051 +7. .to_datetime_str: 2.419302000000016 +8. .to_th2_timestamp: 1.925330899999949 +[2] DatetimeConverter +input: 2024-05-07 05:49:47 +1. .parse_timestamp: 1.4117416000000276 +2. .to_datetime: 2.457634799999937 +3. .to_seconds: 1.5707395000000588 +4. .to_microseconds: 1.6736742000000504 +5. .to_nanoseconds: 1.6255122000000028 +6. .to_milliseconds: 1.671733599999925 +7. .to_datetime_str: 2.267350499999907 +8. .to_th2_timestamp: 1.7517073999999866 +[3] ProtobufTimestampConverter +input: {'epochSecond': 1715060987, 'nano': 0} +1. .parse_timestamp: 0.3411700000000337 +2. .to_datetime: 0.9285133999999289 +3. .to_seconds: 0.17773560000000543 +4. .to_microseconds: 0.16666129999998702 +5. .to_nanoseconds: 0.1475870000000441 +6. .to_milliseconds: 0.16884079999999813 +7. .to_datetime_str: 1.1762307999999848 +8. .to_th2_timestamp: 0.22749960000010105 +[4] UniversalDatetimeStringConverter +input: 2024-05-07T05:49:47 +1. .parse_timestamp: 1.6710871000000225 +2. .to_datetime: 2.71772169999997 +3. .to_seconds: 1.8432619000000159 +4. .to_microseconds: 1.9740376000000879 +5. .to_nanoseconds: 1.8985461000000896 +6. .to_milliseconds: 1.942737999999963 +7. .to_datetime_str: 2.5851454999999532 +8. .to_th2_timestamp: 2.075654200000031 +[5] UnixTimestampConverter +input: 1715060987000000000 +1. .parse_timestamp: 0.41012030000001687 +2. .to_datetime: 1.4361000000000104 +3. .to_seconds: 0.5557732999999416 +4. .to_microseconds: 0.6449311999999736 +5. .to_nanoseconds: 0.6228153000000702 +6. .to_milliseconds: 0.6426851999999599 +7. .to_datetime_str: 1.2725322999999662 +8. .to_th2_timestamp: 0.7681495000000496 diff --git a/tests/tests_unit/tests_utils/tests_converters/benchmark.py b/tests/tests_unit/tests_utils/tests_converters/benchmark.py new file mode 100644 index 00000000..b692a933 --- /dev/null +++ b/tests/tests_unit/tests_utils/tests_converters/benchmark.py @@ -0,0 +1,80 @@ +import timeit + + +def compare_times(datetime_strings): + datetime_string = datetime_strings.datetime_string + datetime_obj = datetime_strings.datetime_obj + th2_timestamp = datetime_strings.th2_timestamp + expected_ns = datetime_strings.expected_ns + + globals = { + "datetime_string": datetime_string, + "datetime_obj": datetime_obj, + "th2_timestamp": th2_timestamp, + "expected_ns": expected_ns, + } + + params = { + "DatetimeStringConverter": "datetime_string", + "DatetimeConverter": "datetime_obj", + "ProtobufTimestampConverter": "th2_timestamp", + "UniversalDatetimeStringConverter": "datetime_string", + "UnixTimestampConverter": "expected_ns", + } + + converters = [ + "DatetimeStringConverter", + "DatetimeConverter", + "ProtobufTimestampConverter", + "UniversalDatetimeStringConverter", + "UnixTimestampConverter", + ] + + for i, converter in enumerate(converters): + param = params[converter] + print(f"[{i + 1}] {converter}") + print("input:", globals[param]) + setup = f"from th2_data_services.utils.converters import {converter}" + print( + "1. .parse_timestamp:", + timeit.timeit(f"{converter}.parse_timestamp({param})", setup=setup, globals=globals), + ) + print( + "2. .to_datetime:", + timeit.timeit(f"{converter}.to_datetime({param})", setup=setup, globals=globals), + ) + print( + "3. .to_seconds:", + timeit.timeit(f"{converter}.to_seconds({param})", setup=setup, globals=globals), + ) + print( + "4. .to_microseconds:", + timeit.timeit(f"{converter}.to_microseconds({param})", setup=setup, globals=globals), + ) + print( + "5. .to_nanoseconds:", + timeit.timeit(f"{converter}.to_nanoseconds({param})", setup=setup, globals=globals), + ) + print( + "6. .to_milliseconds:", + timeit.timeit(f"{converter}.to_milliseconds({param})", setup=setup, globals=globals), + ) + print( + "7. .to_datetime_str:", + timeit.timeit(f"{converter}.to_datetime_str({param})", setup=setup, globals=globals), + ) + print( + "8. .to_th2_timestamp:", + timeit.timeit(f"{converter}.to_th2_timestamp({param})", setup=setup, globals=globals), + ) + + +if __name__ == "__main__": + print("#" * 50) + print("This benchmark shows how many seconds takes every converter operation in seconds.") + print("#" * 50) + + from tests.tests_unit.tests_utils.tests_converters.conftest import converter_test_cases + + for case in converter_test_cases: + compare_times(case) diff --git a/tests/tests_unit/tests_utils/tests_converters/conftest.py b/tests/tests_unit/tests_utils/tests_converters/conftest.py index 868118ff..09ab8524 100644 --- a/tests/tests_unit/tests_utils/tests_converters/conftest.py +++ b/tests/tests_unit/tests_utils/tests_converters/conftest.py @@ -1,72 +1,290 @@ from collections import namedtuple -from datetime import datetime, timezone +from datetime import datetime import pytest +from th2_data_services.utils.converters import ( + DatetimeStringConverter, + DatetimeConverter, + ProtobufTimestampConverter, +) TestCase = namedtuple( - "TestCase", ["datetime_string", "th2_timestamp", "expected_datetime", "expected_ns", "expected_us"] + "TestCase", + [ + "datetime_string", + "datetime_obj", + "th2_timestamp", + "expected_datetime", + "expected_ns", + "expected_us", + "expected_ms", + "expected_s", + "expected_datestring", + "expected_th2_timestamp", + "expected_th2_timestamp_datetime", + ], ) # For 2022-03-05T23:56:44 nanoseconds = 1646524604_000_000_000 microseconds = 1646524604_000_000 +milliseconds = 1646524604_000 seconds = 1646524604 +converter_test_cases = [ + # 0 + # TestCase( + # datetime_string="2022-03-05T23:56:44.0Z", + # datetime_obj=datetime(year=2022, month=3, day=5, hour=23, minute=56, second=44), + # th2_timestamp={"epochSecond": seconds, "nano": 0}, + # expected_datetime=datetime( + # year=2022, month=3, day=5, hour=23, minute=56, second=44 + # ), + # expected_ns=nanoseconds, + # expected_us=microseconds, + # expected_ms=milliseconds, + # expected_datestring='2022-03-05T23:56:44.000000000', + # ), + # # 1 + # TestCase( + # datetime_string="2022-03-05T23:56:44Z", + # datetime_obj=datetime(year=2022, month=3, day=5, hour=23, minute=56, second=44), + # th2_timestamp={"epochSecond": seconds, "nano": 0}, + # expected_datetime=datetime( + # year=2022, month=3, day=5, hour=23, minute=56, second=44 + # ), + # expected_ns=nanoseconds, + # expected_us=microseconds, + # expected_ms=milliseconds, + # expected_datestring='2022-03-05T23:56:44.000000000', + # ), + # # 2 + # TestCase( + # datetime_string="2022-03-05T23:56:44.123456Z", + # datetime_obj=datetime( + # year=2022, month=3, day=5, hour=23, minute=56, second=44, microsecond=123456 + # ), + # th2_timestamp={"epochSecond": seconds, "nano": 123_456_000}, + # expected_datetime=datetime( + # year=2022, + # month=3, + # day=5, + # hour=23, + # minute=56, + # second=44, + # microsecond=123456 + # ), + # expected_ns=nanoseconds + 123_456_000, + # expected_us=microseconds + 123_456, + # expected_ms=milliseconds + 123, + # expected_datestring='2022-03-05T23:56:44.123456000', + # ), + # 3.1 + TestCase( + datetime_string="2022-03-05T23:56:44.123456789Z", + datetime_obj=datetime( + year=2022, month=3, day=5, hour=23, minute=56, second=44, microsecond=123456 + ), + th2_timestamp={"epochSecond": seconds, "nano": 123_456_789}, + expected_datetime=datetime( + year=2022, month=3, day=5, hour=23, minute=56, second=44, microsecond=123456 + ), + expected_ns=nanoseconds + 123_456_789, + expected_us=microseconds + 123_456, + expected_ms=milliseconds + 123, + expected_s=seconds, + # expected_datestring -- + # DatetimeConverter will have '2022-03-05T23:56:44.123456000' + expected_datestring="2022-03-05T23:56:44.123456789", + expected_th2_timestamp={"epochSecond": seconds, "nano": 123_456_789}, + expected_th2_timestamp_datetime={"epochSecond": seconds, "nano": 123_456_000}, + ), + # 3.2 + TestCase( + datetime_string="2022-03-05T23:56:44.123456789", + datetime_obj=datetime( + year=2022, month=3, day=5, hour=23, minute=56, second=44, microsecond=123456 + ), + th2_timestamp={"epochSecond": seconds, "nano": 123_456_789}, + expected_datetime=datetime( + year=2022, month=3, day=5, hour=23, minute=56, second=44, microsecond=123456 + ), + expected_ns=nanoseconds + 123_456_789, + expected_us=microseconds + 123_456, + expected_ms=milliseconds + 123, + expected_s=seconds, + # expected_datestring -- + # DatetimeConverter will have '2022-03-05T23:56:44.123456000' + expected_datestring="2022-03-05T23:56:44.123456789", + expected_th2_timestamp={"epochSecond": seconds, "nano": 123_456_789}, + expected_th2_timestamp_datetime={"epochSecond": seconds, "nano": 123_456_000}, + ), + # 4.1 + TestCase( + datetime_string="2022-03-05T23:56:44.123Z", + datetime_obj=datetime( + year=2022, month=3, day=5, hour=23, minute=56, second=44, microsecond=123000 + ), + th2_timestamp={"epochSecond": seconds, "nano": 123_000_000}, + expected_datetime=datetime( + year=2022, month=3, day=5, hour=23, minute=56, second=44, microsecond=123000 + ), + expected_ns=nanoseconds + 123_000_000, + expected_us=microseconds + 123_000, + expected_ms=milliseconds + 123, + expected_s=seconds, + expected_datestring="2022-03-05T23:56:44.123000000", + expected_th2_timestamp={"epochSecond": seconds, "nano": 123_000_000}, + expected_th2_timestamp_datetime={"epochSecond": seconds, "nano": 123_000_000}, + ), + # 4.2 + TestCase( + datetime_string="2022-03-05T23:56:44.123", + datetime_obj=datetime( + year=2022, month=3, day=5, hour=23, minute=56, second=44, microsecond=123000 + ), + th2_timestamp={"epochSecond": seconds, "nano": 123_000_000}, + expected_datetime=datetime( + year=2022, month=3, day=5, hour=23, minute=56, second=44, microsecond=123000 + ), + expected_ns=nanoseconds + 123_000_000, + expected_us=microseconds + 123_000, + expected_ms=milliseconds + 123, + expected_s=seconds, + expected_datestring="2022-03-05T23:56:44.123000000", + expected_th2_timestamp={"epochSecond": seconds, "nano": 123_000_000}, + expected_th2_timestamp_datetime={"epochSecond": seconds, "nano": 123_000_000}, + ), + # 5.1 + TestCase( + datetime_string="2022-03-05T23:56:44.00123Z", + datetime_obj=datetime( + year=2022, month=3, day=5, hour=23, minute=56, second=44, microsecond=1230 + ), + th2_timestamp={"epochSecond": seconds, "nano": 1_230_000}, + expected_datetime=datetime( + year=2022, month=3, day=5, hour=23, minute=56, second=44, microsecond=1230 + ), + expected_ns=nanoseconds + 1_230_000, + expected_us=microseconds + 1_230, + expected_ms=milliseconds + 1, + expected_s=seconds, + expected_datestring="2022-03-05T23:56:44.001230000", + expected_th2_timestamp={"epochSecond": seconds, "nano": 1_230_000}, + expected_th2_timestamp_datetime={"epochSecond": seconds, "nano": 1_230_000}, + ), + # 5.2 + TestCase( + datetime_string="2022-03-05T23:56:44.00123", + datetime_obj=datetime( + year=2022, month=3, day=5, hour=23, minute=56, second=44, microsecond=1230 + ), + th2_timestamp={"epochSecond": seconds, "nano": 1_230_000}, + expected_datetime=datetime( + year=2022, month=3, day=5, hour=23, minute=56, second=44, microsecond=1230 + ), + expected_ns=nanoseconds + 1_230_000, + expected_us=microseconds + 1_230, + expected_ms=milliseconds + 1, + expected_s=seconds, + expected_datestring="2022-03-05T23:56:44.001230000", + expected_th2_timestamp={"epochSecond": seconds, "nano": 1_230_000}, + expected_th2_timestamp_datetime={"epochSecond": seconds, "nano": 1_230_000}, + ), + # 6 + TestCase( + datetime_string="2024-05-07T05:49:47.742201", + datetime_obj=datetime( + year=2024, month=5, day=7, hour=5, minute=49, second=47, microsecond=742201 + ), + th2_timestamp={"epochSecond": 1715060987, "nano": 742201000}, + expected_datetime=datetime( + year=2024, month=5, day=7, hour=5, minute=49, second=47, microsecond=742201 + ), + expected_ns=1715060987742201000, + expected_us=1715060987742201, + expected_ms=1715060987742, + expected_s=1715060987, + expected_datestring="2024-05-07T05:49:47.742201000", + expected_th2_timestamp={"epochSecond": 1715060987, "nano": 742201000}, + expected_th2_timestamp_datetime={"epochSecond": 1715060987, "nano": 742201000}, + ), + # 7.1 + TestCase( + datetime_string="2024-05-07T05:49:47Z", + datetime_obj=datetime( + year=2024, month=5, day=7, hour=5, minute=49, second=47, microsecond=0 + ), + th2_timestamp={"epochSecond": 1715060987, "nano": 0}, + expected_datetime=datetime( + year=2024, month=5, day=7, hour=5, minute=49, second=47, microsecond=0 + ), + expected_ns=1715060987000000000, + expected_us=1715060987000000, + expected_ms=1715060987000, + expected_s=1715060987, + expected_datestring="2024-05-07T05:49:47.000000000", + expected_th2_timestamp={"epochSecond": 1715060987, "nano": 0}, + expected_th2_timestamp_datetime={"epochSecond": 1715060987, "nano": 0}, + ), + # 7.2 + TestCase( + datetime_string="2024-05-07T05:49:47", + datetime_obj=datetime( + year=2024, month=5, day=7, hour=5, minute=49, second=47, microsecond=0 + ), + th2_timestamp={"epochSecond": 1715060987, "nano": 0}, + expected_datetime=datetime( + year=2024, month=5, day=7, hour=5, minute=49, second=47, microsecond=0 + ), + expected_ns=1715060987000000000, + expected_us=1715060987000000, + expected_ms=1715060987000, + expected_s=1715060987, + expected_datestring="2024-05-07T05:49:47.000000000", + expected_th2_timestamp={"epochSecond": 1715060987, "nano": 0}, + expected_th2_timestamp_datetime={"epochSecond": 1715060987, "nano": 0}, + ), +] + +universal_converter_test_cases = [ + TestCase( + datetime_string="2024-05-07 05:49:47", + datetime_obj=datetime( + year=2024, month=5, day=7, hour=5, minute=49, second=47, microsecond=0 + ), + th2_timestamp={"epochSecond": 1715060987, "nano": 0}, + expected_datetime=datetime( + year=2024, month=5, day=7, hour=5, minute=49, second=47, microsecond=0 + ), + expected_ns=1715060987000000000, + expected_us=1715060987000000, + expected_ms=1715060987000, + expected_s=1715060987, + expected_datestring="2024-05-07T05:49:47.000000000", + expected_th2_timestamp={"epochSecond": 1715060987, "nano": 0}, + expected_th2_timestamp_datetime={"epochSecond": 1715060987, "nano": 0}, + ), +] + + +@pytest.fixture(params=converter_test_cases) +def datetime_strings(request) -> TestCase: + return request.param + + +@pytest.fixture(params=converter_test_cases + universal_converter_test_cases) +def universal_datetime_strings(request) -> TestCase: + return request.param + @pytest.fixture( params=[ - TestCase( - datetime_string="2022-03-05T23:56:44.0Z", - th2_timestamp={"epochSecond": seconds, "nano": 0}, - expected_datetime=datetime(year=2022, month=3, day=5, hour=23, minute=56, second=44, tzinfo=timezone.utc), - expected_ns=nanoseconds, - expected_us=microseconds, - ), - TestCase( - datetime_string="2022-03-05T23:56:44Z", - th2_timestamp={"epochSecond": seconds, "nano": 0}, - expected_datetime=datetime(year=2022, month=3, day=5, hour=23, minute=56, second=44, tzinfo=timezone.utc), - expected_ns=nanoseconds, - expected_us=microseconds, - ), - TestCase( - datetime_string="2022-03-05T23:56:44.123456Z", - th2_timestamp={"epochSecond": seconds, "nano": 123_456_000}, - expected_datetime=datetime( - year=2022, month=3, day=5, hour=23, minute=56, second=44, microsecond=123456, tzinfo=timezone.utc - ), - expected_ns=nanoseconds + 123_456_000, - expected_us=microseconds + 123_456, - ), - TestCase( - datetime_string="2022-03-05T23:56:44.123456789Z", - th2_timestamp={"epochSecond": seconds, "nano": 123_456_789}, - expected_datetime=datetime( - year=2022, month=3, day=5, hour=23, minute=56, second=44, microsecond=123456, tzinfo=timezone.utc - ), - expected_ns=nanoseconds + 123_456_789, - expected_us=microseconds + 123_456, - ), - TestCase( - datetime_string="2022-03-05T23:56:44.123Z", - th2_timestamp={"epochSecond": seconds, "nano": 123_000_000}, - expected_datetime=datetime( - year=2022, month=3, day=5, hour=23, minute=56, second=44, microsecond=123000, tzinfo=timezone.utc - ), - expected_ns=nanoseconds + 123_000_000, - expected_us=microseconds + 123_000, - ), - TestCase( - datetime_string="2022-03-05T23:56:44.00123Z", - th2_timestamp={"epochSecond": seconds, "nano": 1_230_000}, - expected_datetime=datetime( - year=2022, month=3, day=5, hour=23, minute=56, second=44, microsecond=1230, tzinfo=timezone.utc - ), - expected_ns=nanoseconds + 1_230_000, - expected_us=microseconds + 1_230, - ), + DatetimeStringConverter, + DatetimeConverter, + ProtobufTimestampConverter, ] ) -def datetime_strings(request) -> TestCase: +def converters(request) -> TestCase: return request.param diff --git a/tests/tests_unit/tests_utils/tests_converters/flatten_dict.py b/tests/tests_unit/tests_utils/tests_converters/flatten_dict.py new file mode 100644 index 00000000..71a9be63 --- /dev/null +++ b/tests/tests_unit/tests_utils/tests_converters/flatten_dict.py @@ -0,0 +1,20 @@ +from th2_data_services.utils.converters import flatten_dict + + +def test_flatten_dict(): + rv = flatten_dict({"a": 1, "c": {"a": 2, "b": {"x": 5, "y": 10}}, "d": [1, 2, 3]}) + assert rv == {"a": 1, "c.a": 2, "c.b.x": 5, "c.b.y": 10, "d.0": 1, "d.1": 2, "d.2": 3} + + rv = flatten_dict( + {"d": [{"a": 1, "c": {"z": 2, "b": [{"x": 5, "y": 10}, "str-in-lst"]}}, "str", 3]} + ) + + assert rv == { + "d.0.a": 1, + "d.0.c.z": 2, + "d.0.c.b.0.x": 5, + "d.0.c.b.0.y": 10, + "d.0.c.b.1": "str-in-lst", + "d.1": "str", + "d.2": 3, + } diff --git a/tests/tests_unit/tests_utils/tests_converters/test_datetime_converter.py b/tests/tests_unit/tests_utils/tests_converters/test_datetime_converter.py new file mode 100644 index 00000000..6b814e16 --- /dev/null +++ b/tests/tests_unit/tests_utils/tests_converters/test_datetime_converter.py @@ -0,0 +1,50 @@ +from th2_data_services.utils.converters import DatetimeConverter + + +def test_to_datetime(datetime_strings): + assert ( + DatetimeConverter.to_datetime(datetime_strings.datetime_obj) + == datetime_strings.expected_datetime + ) + + +def test_to_seconds(datetime_strings): + assert ( + DatetimeConverter.to_seconds(datetime_strings.datetime_obj) == datetime_strings.expected_s + ) + + +def test_to_microseconds(datetime_strings): + assert ( + DatetimeConverter.to_microseconds(datetime_strings.datetime_obj) + == datetime_strings.expected_us + ) + + +def test_to_nanoseconds(datetime_strings): + """If you request nanoseconds, last 3 number will be zeros, because datatime object doesn't have nanoseconds.""" + assert ( + DatetimeConverter.to_nanoseconds(datetime_strings.datetime_obj) + == datetime_strings.expected_us * 1000 + ) + + +def test_to_milliseconds(datetime_strings): + assert ( + DatetimeConverter.to_milliseconds(datetime_strings.datetime_obj) + == datetime_strings.expected_ms + ) + + +def test_to_datetime_string(datetime_strings): + assert ( + DatetimeConverter.to_datetime_str(datetime_strings.datetime_obj) + == datetime_strings.expected_datestring[:-3] + "000" + ) + + +def test_to_th2_timestamp(datetime_strings): + assert ( + DatetimeConverter.to_th2_timestamp(datetime_strings.datetime_obj) + == datetime_strings.expected_th2_timestamp_datetime + ) diff --git a/tests/tests_unit/tests_utils/tests_converters/test_datetime_string_converter.py b/tests/tests_unit/tests_utils/tests_converters/test_datetime_string_converter.py index 2e0b2850..00949824 100644 --- a/tests/tests_unit/tests_utils/tests_converters/test_datetime_string_converter.py +++ b/tests/tests_unit/tests_utils/tests_converters/test_datetime_string_converter.py @@ -2,12 +2,49 @@ def test_to_datetime(datetime_strings): - assert DatetimeStringConverter.to_datetime(datetime_strings.datetime_string) == datetime_strings.expected_datetime + assert ( + DatetimeStringConverter.to_datetime(datetime_strings.datetime_string) + == datetime_strings.expected_datetime + ) + + +def test_to_seconds(datetime_strings): + assert ( + DatetimeStringConverter.to_seconds(datetime_strings.datetime_string) + == datetime_strings.expected_s + ) def test_to_microseconds(datetime_strings): - assert DatetimeStringConverter.to_microseconds(datetime_strings.datetime_string) == datetime_strings.expected_us + assert ( + DatetimeStringConverter.to_microseconds(datetime_strings.datetime_string) + == datetime_strings.expected_us + ) def test_to_nanoseconds(datetime_strings): - assert DatetimeStringConverter.to_nanoseconds(datetime_strings.datetime_string) == datetime_strings.expected_ns + assert ( + DatetimeStringConverter.to_nanoseconds(datetime_strings.datetime_string) + == datetime_strings.expected_ns + ) + + +def test_to_milliseconds(datetime_strings): + assert ( + DatetimeStringConverter.to_milliseconds(datetime_strings.datetime_string) + == datetime_strings.expected_ms + ) + + +def test_to_datetime_string(datetime_strings): + assert ( + DatetimeStringConverter.to_datetime_str(datetime_strings.datetime_string) + == datetime_strings.expected_datestring + ) + + +def test_to_th2_timestamp(datetime_strings): + assert ( + DatetimeStringConverter.to_th2_timestamp(datetime_strings.datetime_string) + == datetime_strings.expected_th2_timestamp + ) diff --git a/tests/tests_unit/tests_utils/tests_converters/test_protobuf_timestamp_converter.py b/tests/tests_unit/tests_utils/tests_converters/test_protobuf_timestamp_converter.py new file mode 100644 index 00000000..589bf469 --- /dev/null +++ b/tests/tests_unit/tests_utils/tests_converters/test_protobuf_timestamp_converter.py @@ -0,0 +1,50 @@ +from th2_data_services.utils.converters import ProtobufTimestampConverter + + +def test_to_datetime(datetime_strings): + assert ( + ProtobufTimestampConverter.to_datetime(datetime_strings.th2_timestamp) + == datetime_strings.expected_datetime + ) + + +def test_to_seconds(datetime_strings): + assert ( + ProtobufTimestampConverter.to_seconds(datetime_strings.th2_timestamp) + == datetime_strings.expected_s + ) + + +def test_to_microseconds(datetime_strings): + assert ( + ProtobufTimestampConverter.to_microseconds(datetime_strings.th2_timestamp) + == datetime_strings.expected_us + ) + + +def test_to_nanoseconds(datetime_strings): + assert ( + ProtobufTimestampConverter.to_nanoseconds(datetime_strings.th2_timestamp) + == datetime_strings.expected_ns + ) + + +def test_to_milliseconds(datetime_strings): + assert ( + ProtobufTimestampConverter.to_milliseconds(datetime_strings.th2_timestamp) + == datetime_strings.expected_ms + ) + + +def test_to_datetime_string(datetime_strings): + assert ( + ProtobufTimestampConverter.to_datetime_str(datetime_strings.th2_timestamp) + == datetime_strings.expected_datestring + ) + + +def test_to_th2_timestamp(datetime_strings): + assert ( + ProtobufTimestampConverter.to_th2_timestamp(datetime_strings.th2_timestamp) + == datetime_strings.th2_timestamp + ) diff --git a/tests/tests_unit/tests_utils/tests_converters/test_th2_timestamp_converter.py b/tests/tests_unit/tests_utils/tests_converters/test_th2_timestamp_converter.py deleted file mode 100644 index 83be1643..00000000 --- a/tests/tests_unit/tests_utils/tests_converters/test_th2_timestamp_converter.py +++ /dev/null @@ -1,13 +0,0 @@ -from th2_data_services.provider.utils.converters import Th2TimestampConverter - - -def test_to_datetime(datetime_strings): - assert Th2TimestampConverter.to_datetime(datetime_strings.th2_timestamp) == datetime_strings.expected_datetime - - -def test_to_microseconds(datetime_strings): - assert Th2TimestampConverter.to_microseconds(datetime_strings.th2_timestamp) == datetime_strings.expected_us - - -def test_to_nanoseconds(datetime_strings): - assert Th2TimestampConverter.to_nanoseconds(datetime_strings.th2_timestamp) == datetime_strings.expected_ns diff --git a/tests/tests_unit/tests_utils/tests_converters/test_universal_datetime_string_converter.py b/tests/tests_unit/tests_utils/tests_converters/test_universal_datetime_string_converter.py new file mode 100644 index 00000000..0e9c7306 --- /dev/null +++ b/tests/tests_unit/tests_utils/tests_converters/test_universal_datetime_string_converter.py @@ -0,0 +1,52 @@ +from th2_data_services.utils.converters import UniversalDatetimeStringConverter + + +def test_to_datetime(universal_datetime_strings): + assert ( + UniversalDatetimeStringConverter.to_datetime(universal_datetime_strings.datetime_string) + == universal_datetime_strings.expected_datetime + ) + + +def test_to_seconds(universal_datetime_strings): + assert ( + UniversalDatetimeStringConverter.to_seconds(universal_datetime_strings.datetime_string) + == universal_datetime_strings.expected_s + ) + + +def test_to_microseconds(universal_datetime_strings): + assert ( + UniversalDatetimeStringConverter.to_microseconds(universal_datetime_strings.datetime_string) + == universal_datetime_strings.expected_us + ) + + +def test_to_nanoseconds(universal_datetime_strings): + assert ( + UniversalDatetimeStringConverter.to_nanoseconds(universal_datetime_strings.datetime_string) + == universal_datetime_strings.expected_ns + ) + + +def test_to_milliseconds(universal_datetime_strings): + assert ( + UniversalDatetimeStringConverter.to_milliseconds(universal_datetime_strings.datetime_string) + == universal_datetime_strings.expected_ms + ) + + +def test_to_datetime_string(universal_datetime_strings): + assert ( + UniversalDatetimeStringConverter.to_datetime_str(universal_datetime_strings.datetime_string) + == universal_datetime_strings.expected_datestring + ) + + +def test_to_th2_timestamp(universal_datetime_strings): + assert ( + UniversalDatetimeStringConverter.to_th2_timestamp( + universal_datetime_strings.datetime_string + ) + == universal_datetime_strings.expected_th2_timestamp + ) diff --git a/tests/tests_unit/tests_utils/tests_converters/test_unix_timestamp_converter.py b/tests/tests_unit/tests_utils/tests_converters/test_unix_timestamp_converter.py new file mode 100644 index 00000000..64eb6caf --- /dev/null +++ b/tests/tests_unit/tests_utils/tests_converters/test_unix_timestamp_converter.py @@ -0,0 +1,50 @@ +from th2_data_services.utils.converters import UnixTimestampConverter + + +def test_to_datetime(datetime_strings): + assert ( + UnixTimestampConverter.to_datetime(datetime_strings.expected_ns) + == datetime_strings.expected_datetime + ) + + +def test_to_seconds(datetime_strings): + assert ( + UnixTimestampConverter.to_seconds(datetime_strings.expected_ns) + == datetime_strings.expected_s + ) + + +def test_to_microseconds(datetime_strings): + assert ( + UnixTimestampConverter.to_microseconds(datetime_strings.expected_ns) + == datetime_strings.expected_us + ) + + +def test_to_nanoseconds(datetime_strings): + assert ( + UnixTimestampConverter.to_nanoseconds(datetime_strings.expected_ns) + == datetime_strings.expected_ns + ) + + +def test_to_milliseconds(datetime_strings): + assert ( + UnixTimestampConverter.to_milliseconds(datetime_strings.expected_ns) + == datetime_strings.expected_ms + ) + + +def test_to_datetime_string(datetime_strings): + assert ( + UnixTimestampConverter.to_datetime_str(datetime_strings.expected_ns) + == datetime_strings.expected_datestring + ) + + +def test_to_th2_timestamp(datetime_strings): + assert ( + UnixTimestampConverter.to_th2_timestamp(datetime_strings.expected_ns) + == datetime_strings.expected_th2_timestamp + ) diff --git a/tests/tests_unit/tests_diff_version/tests_v5/__init__.py b/tests/tests_unit/tests_utils/tests_message_utils/__init__.py similarity index 100% rename from tests/tests_unit/tests_diff_version/tests_v5/__init__.py rename to tests/tests_unit/tests_utils/tests_message_utils/__init__.py diff --git a/tests/tests_unit/tests_utils/tests_message_utils/conftest.py b/tests/tests_unit/tests_utils/tests_message_utils/conftest.py new file mode 100644 index 00000000..2f940b97 --- /dev/null +++ b/tests/tests_unit/tests_utils/tests_message_utils/conftest.py @@ -0,0 +1,146 @@ +import pytest + + +@pytest.fixture +def messages_frequencies_test_data(): + messages = [ + { + "timestamp": {"epochSecond": 1682308224 - 4 * 60 * 60}, + "messageType": "ERROR", + }, # 2023-04-23 23:50:24 + { + "timestamp": {"epochSecond": 1682308827 - 4 * 60 * 60}, + "messageType": "ERROR", + }, # 2023-04-24 00:00:27 + { + "timestamp": {"epochSecond": 1682308828 - 4 * 60 * 60}, + "messageType": "ERROR", + }, # 2023-04-24 00:00:28 + { + "timestamp": {"epochSecond": 1682308829 - 4 * 60 * 60}, + "messageType": "ERROR", + }, # 2023-04-24 00:00:29 + { + "timestamp": {"epochSecond": 1682316031 - 4 * 60 * 60}, + "messageType": "ERROR", + }, # 2023-04-24 02:00:31 + { + "timestamp": {"epochSecond": 1682323233 + 4 * 60 * 60}, + "messageType": "ERROR", + }, # 2023-04-24 12:00:33 + { + "timestamp": {"epochSecond": 1682679854 + 4 * 60 * 60}, + "messageType": "ERROR", + }, # 2023-04-28 15:04:14 + ] + return messages + + +@pytest.fixture +def messages_frequencies_expected_values_5s(): + expected_values = { + "GAP_1_ANCHOR_FALSE": [ + ("2023-04-23T23:50:24", "2023-04-23T23:50:29", 1), + ("2023-04-24T00:00:27", "2023-04-24T00:00:32", 3), + ("2023-04-24T02:00:31", "2023-04-24T02:00:36", 1), + ("2023-04-24T12:00:33", "2023-04-24T12:00:38", 1), + ("2023-04-28T15:04:14", "2023-04-28T15:04:19", 1), + ], + "GAP_2_ANCHOR_FALSE": [ + ("2023-04-23T23:50:24", "2023-04-23T23:50:29", 1), + ("2023-04-24T00:00:24", "2023-04-24T00:00:29", 2), + ("2023-04-24T00:00:29", "2023-04-24T00:00:34", 1), + ("2023-04-24T02:00:29", "2023-04-24T02:00:34", 1), + ("2023-04-24T12:00:29", "2023-04-24T12:00:34", 1), + ("2023-04-28T15:04:14", "2023-04-28T15:04:19", 1), + ], + "GAP_3_ANCHOR_FALSE_LEN": 80087, + "GAP_2_ANCHOR_TRUE": [ + ("2023-04-23T23:50:20", "2023-04-23T23:50:25", 1), + ("2023-04-24T00:00:25", "2023-04-24T00:00:30", 3), + ("2023-04-24T02:00:30", "2023-04-24T02:00:35", 1), + ("2023-04-24T12:00:30", "2023-04-24T12:00:35", 1), + ("2023-04-28T15:04:10", "2023-04-28T15:04:15", 1), + ], + "GAP_3_ANCHOR_TRUE_LEN": 80087, + } + return expected_values + + +@pytest.fixture +def messages_frequencies_expected_values_1h(): + expected_values = { + "GAP_1_ANCHOR_FALSE": [ + ("2023-04-23T23:00", "2023-04-24T00:00", 1), + ("2023-04-24T00:00", "2023-04-24T01:00", 3), + ("2023-04-24T02:00", "2023-04-24T03:00", 1), + ("2023-04-24T12:00", "2023-04-24T13:00", 1), + ("2023-04-28T15:00", "2023-04-28T16:00", 1), + ], + "GAP_2_ANCHOR_FALSE": [ + ("2023-04-23T23:00", "2023-04-24T00:00", 1), + ("2023-04-24T00:00", "2023-04-24T01:00", 3), + ("2023-04-24T02:00", "2023-04-24T03:00", 1), + ("2023-04-24T12:00", "2023-04-24T13:00", 1), + ("2023-04-28T15:00", "2023-04-28T16:00", 1), + ], + "GAP_3_ANCHOR_FALSE_LEN": 113, + "GAP_2_ANCHOR_TRUE": [ + ("2023-04-23T23:00", "2023-04-24T00:00", 1), + ("2023-04-24T00:00", "2023-04-24T01:00", 3), + ("2023-04-24T02:00", "2023-04-24T03:00", 1), + ("2023-04-24T12:00", "2023-04-24T13:00", 1), + ("2023-04-28T15:00", "2023-04-28T16:00", 1), + ], + "GAP_3_ANCHOR_TRUE_LEN": 113, + } + return expected_values + + +@pytest.fixture +def messages_frequencies_expected_values_2h(): + expected_values = { + "GAP_1_ANCHOR_FALSE": [ + ("2023-04-23T23:00", "2023-04-24T01:00", 4), + ("2023-04-24T02:00", "2023-04-24T04:00", 1), + ("2023-04-24T12:00", "2023-04-24T14:00", 1), + ("2023-04-28T15:00", "2023-04-28T17:00", 1), + ], + "GAP_2_ANCHOR_FALSE": [ + ("2023-04-23T23:00", "2023-04-24T01:00", 4), + ("2023-04-24T01:00", "2023-04-24T03:00", 1), + ("2023-04-24T11:00", "2023-04-24T13:00", 1), + ("2023-04-28T15:00", "2023-04-28T17:00", 1), + ], + "GAP_3_ANCHOR_FALSE_LEN": 57, + "GAP_2_ANCHOR_TRUE": [ + ("2023-04-23T22:00", "2023-04-24T00:00", 1), + ("2023-04-24T00:00", "2023-04-24T02:00", 3), + ("2023-04-24T02:00", "2023-04-24T04:00", 1), + ("2023-04-24T12:00", "2023-04-24T14:00", 1), + ("2023-04-28T14:00", "2023-04-28T16:00", 1), + ], + "GAP_3_ANCHOR_TRUE_LEN": 57, + } + return expected_values + + +@pytest.fixture +def messages_frequencies_expected_values_2d(): + expected_values = { + "GAP_1_ANCHOR_FALSE": [ + ("2023-04-23", "2023-04-25", 6), + ("2023-04-28", "2023-04-30", 1), + ], + "GAP_2_ANCHOR_FALSE": [ + ("2023-04-23", "2023-04-25", 6), + ("2023-04-27", "2023-04-29", 1), + ], + "GAP_3_ANCHOR_FALSE_LEN": 3, + "GAP_2_ANCHOR_TRUE": [ + ("2023-04-23", "2023-04-25", 6), + ("2023-04-27", "2023-04-29", 1), + ], + "GAP_3_ANCHOR_TRUE_LEN": 3, + } + return expected_values diff --git a/tests/tests_unit/tests_utils/tests_message_utils/test_frequencies.py b/tests/tests_unit/tests_utils/tests_message_utils/test_frequencies.py new file mode 100644 index 00000000..9ae1661b --- /dev/null +++ b/tests/tests_unit/tests_utils/tests_message_utils/test_frequencies.py @@ -0,0 +1,240 @@ +from th2_data_services.data_source import lwdp # to init resolvers +from th2_data_services.utils import message_utils + + +def test_message_get_category_frequencies_5s( + messages_frequencies_test_data, messages_frequencies_expected_values_5s +): + table = message_utils.frequencies.get_category_frequencies( + messages_frequencies_test_data, + [], + lambda a: a["messageType"], + aggregation_level="5s", + gap_mode=1, + zero_anchor=False, + object_expander=None, + ) + assert messages_frequencies_expected_values_5s["GAP_1_ANCHOR_FALSE"] == list(table) + + table = message_utils.frequencies.get_category_frequencies( + messages_frequencies_test_data, + [], + lambda a: a["messageType"], + aggregation_level="5s", + gap_mode=2, + zero_anchor=False, + object_expander=None, + ) + assert messages_frequencies_expected_values_5s["GAP_2_ANCHOR_FALSE"] == list(table) + + table = message_utils.frequencies.get_category_frequencies( + messages_frequencies_test_data, + [], + lambda a: a["messageType"], + aggregation_level="5s", + gap_mode=3, + zero_anchor=False, + object_expander=None, + ) + assert messages_frequencies_expected_values_5s["GAP_3_ANCHOR_FALSE_LEN"] == len(list(table)) + + table = message_utils.frequencies.get_category_frequencies( + messages_frequencies_test_data, + [], + lambda a: a["messageType"], + aggregation_level="5s", + gap_mode=2, + zero_anchor=True, + object_expander=None, + ) + assert messages_frequencies_expected_values_5s["GAP_2_ANCHOR_TRUE"] == list(table) + + table = message_utils.frequencies.get_category_frequencies( + messages_frequencies_test_data, + [], + lambda a: a["messageType"], + aggregation_level="5s", + gap_mode=3, + zero_anchor=False, + object_expander=None, + ) + assert messages_frequencies_expected_values_5s["GAP_3_ANCHOR_TRUE_LEN"] == len(list(table)) + + +def test_message_get_category_frequencies_1h( + messages_frequencies_test_data, messages_frequencies_expected_values_1h +): + table = message_utils.frequencies.get_category_frequencies( + messages_frequencies_test_data, + [], + lambda a: a["messageType"], + aggregation_level="1h", + gap_mode=1, + zero_anchor=False, + object_expander=None, + ) + print(list(table)) + print(messages_frequencies_expected_values_1h["GAP_1_ANCHOR_FALSE"]) + assert messages_frequencies_expected_values_1h["GAP_1_ANCHOR_FALSE"] == list(table) + + table = message_utils.frequencies.get_category_frequencies( + messages_frequencies_test_data, + [], + lambda a: a["messageType"], + aggregation_level="1h", + gap_mode=2, + zero_anchor=False, + object_expander=None, + ) + assert messages_frequencies_expected_values_1h["GAP_2_ANCHOR_FALSE"] == list(table) + + table = message_utils.frequencies.get_category_frequencies( + messages_frequencies_test_data, + [], + lambda a: a["messageType"], + aggregation_level="1h", + gap_mode=3, + zero_anchor=False, + object_expander=None, + ) + assert messages_frequencies_expected_values_1h["GAP_3_ANCHOR_FALSE_LEN"] == len(list(table)) + + table = message_utils.frequencies.get_category_frequencies( + messages_frequencies_test_data, + [], + lambda a: a["messageType"], + aggregation_level="1h", + gap_mode=2, + zero_anchor=True, + object_expander=None, + ) + assert messages_frequencies_expected_values_1h["GAP_2_ANCHOR_TRUE"] == list(table) + + table = message_utils.frequencies.get_category_frequencies( + messages_frequencies_test_data, + [], + lambda a: a["messageType"], + aggregation_level="1h", + gap_mode=3, + zero_anchor=False, + object_expander=None, + ) + assert messages_frequencies_expected_values_1h["GAP_3_ANCHOR_TRUE_LEN"] == len(list(table)) + + +def test_message_get_category_frequencies_2h( + messages_frequencies_test_data, messages_frequencies_expected_values_2h +): + table = message_utils.frequencies.get_category_frequencies( + messages_frequencies_test_data, + [], + lambda a: a["messageType"], + aggregation_level="2h", + gap_mode=1, + zero_anchor=False, + object_expander=None, + ) + assert messages_frequencies_expected_values_2h["GAP_1_ANCHOR_FALSE"] == list(table) + + table = message_utils.frequencies.get_category_frequencies( + messages_frequencies_test_data, + [], + lambda a: a["messageType"], + aggregation_level="2h", + gap_mode=2, + zero_anchor=False, + object_expander=None, + ) + assert messages_frequencies_expected_values_2h["GAP_2_ANCHOR_FALSE"] == list(table) + + table = message_utils.frequencies.get_category_frequencies( + messages_frequencies_test_data, + [], + lambda a: a["messageType"], + aggregation_level="2h", + gap_mode=3, + zero_anchor=False, + object_expander=None, + ) + assert messages_frequencies_expected_values_2h["GAP_3_ANCHOR_FALSE_LEN"] == len(list(table)) + + table = message_utils.frequencies.get_category_frequencies( + messages_frequencies_test_data, + [], + lambda a: a["messageType"], + aggregation_level="2h", + gap_mode=2, + zero_anchor=True, + object_expander=None, + ) + assert messages_frequencies_expected_values_2h["GAP_2_ANCHOR_TRUE"] == list(table) + + table = message_utils.frequencies.get_category_frequencies( + messages_frequencies_test_data, + [], + lambda a: a["messageType"], + aggregation_level="2h", + gap_mode=3, + zero_anchor=False, + object_expander=None, + ) + assert messages_frequencies_expected_values_2h["GAP_3_ANCHOR_TRUE_LEN"] == len(list(table)) + + +def test_message_get_category_frequencies_2d( + messages_frequencies_test_data, messages_frequencies_expected_values_2d +): + table = message_utils.frequencies.get_category_frequencies( + messages_frequencies_test_data, + [], + lambda a: a["messageType"], + aggregation_level="2d", + gap_mode=1, + zero_anchor=False, + object_expander=None, + ) + assert messages_frequencies_expected_values_2d["GAP_1_ANCHOR_FALSE"] == list(table) + + table = message_utils.frequencies.get_category_frequencies( + messages_frequencies_test_data, + [], + lambda a: a["messageType"], + aggregation_level="2d", + gap_mode=2, + zero_anchor=False, + object_expander=None, + ) + assert messages_frequencies_expected_values_2d["GAP_2_ANCHOR_FALSE"] == list(table) + + table = message_utils.frequencies.get_category_frequencies( + messages_frequencies_test_data, + [], + lambda a: a["messageType"], + aggregation_level="2d", + gap_mode=3, + zero_anchor=False, + object_expander=None, + ) + assert messages_frequencies_expected_values_2d["GAP_3_ANCHOR_FALSE_LEN"] == len(list(table)) + + table = message_utils.frequencies.get_category_frequencies( + messages_frequencies_test_data, + [], + lambda a: a["messageType"], + aggregation_level="2d", + gap_mode=2, + zero_anchor=True, + object_expander=None, + ) + assert messages_frequencies_expected_values_2d["GAP_2_ANCHOR_TRUE"] == list(table) + + table = message_utils.frequencies.get_category_frequencies( + messages_frequencies_test_data, + [], + lambda a: a["messageType"], + aggregation_level="2d", + gap_mode=3, + zero_anchor=False, + object_expander=None, + ) + assert messages_frequencies_expected_values_2d["GAP_3_ANCHOR_TRUE_LEN"] == len(list(table)) diff --git a/tests/tests_unit/tests_diff_version/tests_v5/tests_events_tree/__init__.py b/tests/tests_unit/tests_utils/tests_stream_utils/__init__.py similarity index 100% rename from tests/tests_unit/tests_diff_version/tests_v5/tests_events_tree/__init__.py rename to tests/tests_unit/tests_utils/tests_stream_utils/__init__.py diff --git a/tests/tests_unit/tests_utils/tests_stream_utils/test_stream_utils.py b/tests/tests_unit/tests_utils/tests_stream_utils/test_stream_utils.py new file mode 100644 index 00000000..da558c1e --- /dev/null +++ b/tests/tests_unit/tests_utils/tests_stream_utils/test_stream_utils.py @@ -0,0 +1,34 @@ +from th2_data_services.data import Data +from th2_data_services.utils.stream_utils.stream_utils import is_sorted + + +def test_stream_is_sorted_empty(): + assert is_sorted([], lambda e: e["timestamp"]["epochSecond"]) + + +def test_stream_is_sorted_sorted(): + data = Data( + [ + {"timestamp": {"epochSecond": 1632400658, "nano": 4000000}}, + {"timestamp": {"epochSecond": 1632400658, "nano": 4000023}}, + {"timestamp": {"epochSecond": 1632400659, "nano": 4000000}}, + {"timestamp": {"epochSecond": 1632400670, "nano": 4000000}}, + {"timestamp": {"epochSecond": 1632400689, "nano": 4000000}}, + ] + ) + result = is_sorted(data, lambda e: e["timestamp"]["epochSecond"]) + assert result and result.first_unsorted is None + + +def test_stream_is_sorted_not_sorted(): + data = Data( + [ + {"timestamp": {"epochSecond": 1632400658, "nano": 4000000}}, + {"timestamp": {"epochSecond": 1632400656, "nano": 3000023}}, + {"timestamp": {"epochSecond": 1632400659, "nano": 4000000}}, + {"timestamp": {"epochSecond": 1632400670, "nano": 4000000}}, + {"timestamp": {"epochSecond": 1632400689, "nano": 4000000}}, + ] + ) + result = is_sorted(data, lambda e: e["timestamp"]["epochSecond"]) + assert not result and result.first_unsorted == 1 diff --git a/tests/tests_unit/utils.py b/tests/tests_unit/utils.py index 8f9246d4..459e64d8 100644 --- a/tests/tests_unit/utils.py +++ b/tests/tests_unit/utils.py @@ -1,12 +1,9 @@ from __future__ import annotations -from typing import Optional, TYPE_CHECKING +from typing import Optional from _pytest.logging import LogCaptureFixture -from th2_data_services import Data - -if TYPE_CHECKING: - from th2_data_services.provider.v5.events_tree import EventsTreeCollectionProvider5 +from th2_data_services.data import Data class LogsChecker: @@ -30,7 +27,7 @@ def used_own_cache_file(self, data: Data): msg = f"Data[{data._id}] Iterating using own cache file '{path}'" assert msg in self.messages, self._exception_message(msg) - def detached_etc_created(self, etc: EventsTreeCollectionProvider5): + def detached_etc_created(self, etc): msg = "ETC[%s] %s" % ( id(etc), "The collection were built with detached events because there are no some events in the source", @@ -46,10 +43,13 @@ def iterate_data(data: Data, *, to_return=True) -> Optional[list]: pass -def iterate_data_and_do_checks(data: Data, log_checker: LogsChecker) -> list: +def iterate_data_and_do_cache_checks(data: Data, log_checker: LogsChecker = None) -> list: r = iterate_data(data, to_return=True) # Just to iterate and create cache files. - assert is_cache_file_exists(data) - log_checker.cache_file_created(data) + if data.cache_status: + assert is_cache_file_exists(data) + else: + assert not is_cache_file_exists(data) + # log_checker.cache_file_created(data) return r @@ -59,3 +59,28 @@ def is_cache_file_exists(data_obj: Data) -> bool: def is_pending_cache_file_exists(data_obj: Data) -> bool: return data_obj.get_pending_cache_filepath().is_file() + + +def double_generator(stream): + for item in stream: + yield item + yield item + + +def triple_generator(stream): + for item in stream: + yield item + yield item + yield item + + +def event_type_generator(stream): + for item in stream: + yield item.get("eventType") + + +def return_two_items_if_value_greater_than_10(item): + if item > 10: + return [item, item] + else: + return item diff --git a/tests/unittestV5.py b/tests/unittestV5.py deleted file mode 100644 index 1b941cd8..00000000 --- a/tests/unittestV5.py +++ /dev/null @@ -1,23 +0,0 @@ -import pip -import pytest - -PATH_DIFF_VERSION = "tests_unit/tests_diff_version" -PACKAGE_NAME = "th2-grpc-data-provider" - -grpc_version_5 = "0.1.6" - - -def install_package(name: str, version: str) -> int: - return pip.main(["install", f"{name}=={version}", "--upgrade"]) - - -def run_tests(source_dir: str = ".", ignore_dir=None) -> int: - args = [source_dir] - if ignore_dir is not None: - args.append(f"--ignore={ignore_dir}") - return pytest.main(args) - - -if __name__ == "__main__": - install_package(PACKAGE_NAME, grpc_version_5) - run_tests(source_dir=f"./tests_unit", ignore_dir=f"./{PATH_DIFF_VERSION}/tests_v6") diff --git a/tests/unittestV6.py b/tests/unittestV6.py deleted file mode 100644 index ff3ecd02..00000000 --- a/tests/unittestV6.py +++ /dev/null @@ -1,23 +0,0 @@ -import pip -import pytest - -PATH_DIFF_VERSION = "tests_unit/tests_diff_version" -PACKAGE_NAME = "th2-grpc-data-provider" - -grpc_version_6 = "1.1.0" - - -def install_package(name: str, version: str) -> int: - return pip.main(["install", f"{name}=={version}", "--upgrade"]) - - -def run_tests(source_dir: str = ".", ignore_dir=None) -> int: - args = [source_dir] - if ignore_dir is not None: - args.append(f"--ignore={ignore_dir}") - return pytest.main(args) - - -if __name__ == "__main__": - install_package(PACKAGE_NAME, grpc_version_6) - run_tests(source_dir="./tests_unit", ignore_dir=f"./{PATH_DIFF_VERSION}/tests_v5") diff --git a/th2_data_services/__init__.py b/th2_data_services/__init__.py deleted file mode 100644 index d811c633..00000000 --- a/th2_data_services/__init__.py +++ /dev/null @@ -1,61 +0,0 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from th2_data_services.data import Data -from th2_data_services.filter import Filter -import logging -from logging import NullHandler - -# Set default logging handler to avoid "No handler found" warnings. -logging.getLogger(__name__).addHandler(NullHandler()) - -# INTERACTIVE_MODE - is a global variable that tells the library not to delete -# the Data cache file if data iteration is interrupted. -INTERACTIVE_MODE = False # Script mode by default. - - -def add_stderr_logger(level=logging.DEBUG): - """Helper for quickly adding a StreamHandler to the logger. - - Useful for debugging. - - Returns the handler after adding it. - """ - # This method needs to be in this __init__.py to get the __name__ correct - # even if the lib is vendored within another package. - logger = logging.getLogger(__name__) - handler = logging.StreamHandler() - handler.setFormatter(logging.Formatter("%(asctime)s %(levelname)s %(name)s : %(message)s")) - logger.addHandler(handler) - logger.setLevel(level) - logger.debug("Added a stderr logging handler to logger: %s", __name__) - return handler - - -def add_file_logger(filename="dslib.log", mode="w", level=logging.DEBUG): - """Helper for quickly adding a StreamHandler to the logger. - - Useful for debugging. - - Returns the handler after adding it. - """ - # This method needs to be in this __init__.py to get the __name__ correct - # even if the lib is vendored within another package. - logger = logging.getLogger(__name__) - handler = logging.FileHandler(filename, mode=mode) - handler.setFormatter(logging.Formatter("%(asctime)s %(levelname)s %(name)s : %(message)s")) - logger.addHandler(handler) - logger.setLevel(level) - logger.debug("Added a file logging handler to logger: %s", __name__) - return handler diff --git a/th2_data_services/provider/v6/__init__.py b/th2_data_services/_internal/__init__.py similarity index 90% rename from th2_data_services/provider/v6/__init__.py rename to th2_data_services/_internal/__init__.py index c46552ee..a126e90d 100644 --- a/th2_data_services/provider/v6/__init__.py +++ b/th2_data_services/_internal/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) +# Copyright 2023-2025 Exactpro (Exactpro Systems Limited) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/th2_data_services/_internal/perf_tests.py b/th2_data_services/_internal/perf_tests.py new file mode 100644 index 00000000..af319211 --- /dev/null +++ b/th2_data_services/_internal/perf_tests.py @@ -0,0 +1,173 @@ +# Copyright 2023-2025 Exactpro (Exactpro Systems Limited) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +import sys +from pathlib import Path +import csv +from faker import Faker + +from th2_data_services.data import Data +from th2_data_services.utils.time import calculate_time + + +def _create_csv(filename, rows, cols): + faker = Faker() + with open(filename, "w", newline="") as csvfile: + writer = csv.writer(csvfile) + header = [f"Column {i + 1}" for i in range(cols)] + writer.writerow(header) + + for _ in range(rows): + row = [faker.word() for _ in range(cols)] + writer.writerow(row) + + +@calculate_time(return_as_last_value=True) +def _build_cache_file(data_obj: Data, filename): + ftype = filename.split(".")[-1] + if ftype == "pickle": + data_obj.build_cache(filename) + elif ftype == "jsons": + data_obj.to_json_lines(filename) + elif ftype == "gz": + data_obj.to_json_lines(filename, gzip=True) + elif ftype == "csv": + data_obj.to_csv(filename) + + +def _read_from_cache_file(filename): + ftype = filename.split(".")[-1] + if ftype == "pickle": + return Data.from_cache_file(filename) + elif ftype == "jsons": + return Data.from_json(filename) + elif ftype == "gz": + return Data.from_json(filename, gzip=True) + elif ftype == "csv": + if "header" in filename: + return Data.from_csv(filename, header_first_line=True) + return Data.from_csv(filename) + + +@calculate_time(return_as_last_value=True) +def _iter_data_obj(do: Data): + for o in do: + pass + + +@calculate_time(return_as_last_value=True) +def _iter_data_obj_with_3_filters(do: Data): + for o in do.filter(lambda x: True).filter(lambda x: True).filter(lambda x: True): + pass + + +def _test_xx(data_obj: Data): + filenames = [ + "cache_test.pickle", + "cache_test.jsons", + "cache_test.jsons.gz", + "cache_test.csv", + "cache_test_header.csv", + ] + name_to_option = {"cache_test_header.csv": "header_first_line=True"} + + try: + # data_obj.use_cache() + do_len = data_obj.len + + print("Store cache files for test:") + for filename in filenames: + print(f" -> {filename}", end="") + val, calc_time = _build_cache_file(data_obj, filename) + print(f" -- {calc_time} s") + + print() + print(f"Data length: {do_len}") + for filename in filenames: + suffix = name_to_option.get(filename, "") + if suffix: + suffix = f" ({suffix})" + print(f"Iterate {'.'.join(filename.split('.')[1:])}{suffix}:", end="") + data_obj_file = _read_from_cache_file(filename) + _, calc_time = _iter_data_obj(data_obj_file) + print(f" -- {calc_time} s", end="") + _, calc_time = _iter_data_obj_with_3_filters(data_obj_file) + print(f", with 3 filters -- {calc_time} s") + + print() + + except: + print("\nException") + print("Remove cache files") + for filename in filenames: + p = Path(filename) + p.unlink(missing_ok=True) + + raise + + else: + for filename in filenames: + p = Path(filename) + p.unlink(missing_ok=True) + + +@calculate_time +def cache_files_reading_speed(data): # noqa + if isinstance(data, Data): + _test_xx(data) + + elif isinstance(data, str): + if data.endswith(".pickle"): + data_obj = Data.from_cache_file(data) + _test_xx(data_obj) + + elif data.endswith(".jsons"): + data_obj = Data.from_json(data) + _test_xx(data_obj) + + elif data.endswith(".gz"): + data_obj = Data.from_json(data, gzip=True) + _test_xx(data_obj) + + elif data.endswith(".csv"): + data_obj = Data.from_csv(data) + _test_xx(data_obj) + + +if __name__ == "__main__": + + if len(sys.argv) > 1: + """ + python -m th2_data_services._internal.perf_test FILE_FOR_DATA_OBJ + """ + arg = sys.argv[1] + cache_files_reading_speed(arg) + else: + # cache_files_reading_speed() + # cache_files_reading_speed( + # data=Data([1, 2, 3, 4, 5, 6, 7, 8, 9, 0]) + # ) + # cache_files_reading_speed( + # data=Data.from_cache_file( + # "C:/Users/admin/exactpro/prj/th2/pickles/cache_2.5kk_events.pickle" + # ).limit(5) + # ) + + _create_csv("dataset.csv", 10_000_000, 15) + cache_files_reading_speed("dataset.csv") + + # cache_files_reading_speed( + # "C:/Users/admin/exactpro/prj/th2/pickles/cache_2.5kk_events.pickle" + # ) diff --git a/th2_data_services/provider/interfaces/filter.py b/th2_data_services/config/__init__.py similarity index 83% rename from th2_data_services/provider/interfaces/filter.py rename to th2_data_services/config/__init__.py index b21d7c20..6081d292 100644 --- a/th2_data_services/provider/interfaces/filter.py +++ b/th2_data_services/config/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) +# Copyright 2023-2025 Exactpro (Exactpro Systems Limited) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -12,8 +12,5 @@ # See the License for the specific language governing permissions and # limitations under the License. -from abc import ABC - -class IProviderFilter(ABC): - pass +from th2_data_services.config.config import options diff --git a/th2_data_services/config/config.py b/th2_data_services/config/config.py new file mode 100644 index 00000000..e4f3962a --- /dev/null +++ b/th2_data_services/config/config.py @@ -0,0 +1,89 @@ +# Copyright 2023-2025 Exactpro (Exactpro Systems Limited) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from typing import Optional + +from th2_data_services.interfaces.utils.resolver import ( + EventFieldResolver, + MessageFieldResolver, + SubMessageFieldResolver, + ExpandedMessageFieldResolver, +) + + +class TH2Config: + def __init__(self) -> None: + """Global configuration for the DS library.""" + # TODO - try to import here data_source in available. + + self.INTERACTIVE_MODE = False + self.EVENT_FIELDS_RESOLVER: Optional[EventFieldResolver] = None + self.MESSAGE_FIELDS_RESOLVER: Optional[MessageFieldResolver] = None + self.SUBMESSAGE_FIELDS_RESOLVER: Optional[SubMessageFieldResolver] = None + self.EXPANDED_MESSAGE_FIELDS_RESOLVER: Optional[ExpandedMessageFieldResolver] = None + self.MAX_PATH: int = 255 # OS limitation. Both Windows and Linux + self.FORBIDDEN_CHARACTERS_IN_FILENAME: str = '<>:"|?*/\\' + self.FORBIDDEN_CHARACTERS_IN_FILENAME_CHANGE_TO: str = "_" + self.DEFAULT_PICKLE_VERSION = 4 + + # Aliases + self.efr = self.EVENT_FIELDS_RESOLVER + self.mfr = self.MESSAGE_FIELDS_RESOLVER + self.smfr = self.SUBMESSAGE_FIELDS_RESOLVER + self.emfr = self.EXPANDED_MESSAGE_FIELDS_RESOLVER + + def __str__(self): + s = ( + f"INTERACTIVE_MODE={self.INTERACTIVE_MODE}\n" + f"EVENT_FIELDS_RESOLVER={self.EVENT_FIELDS_RESOLVER}\n" + f"MESSAGE_FIELDS_RESOLVER={self.MESSAGE_FIELDS_RESOLVER}\n" + f"SUBMESSAGE_FIELDS_RESOLVER={self.SUBMESSAGE_FIELDS_RESOLVER}\n" + f"EXPANDED_MESSAGE_FIELDS_RESOLVER={self.EXPANDED_MESSAGE_FIELDS_RESOLVER}\n" + f"MAX_PATH={self.MAX_PATH}\n" + f"FORBIDDEN_CHARACTERS_IN_FILENAME={self.FORBIDDEN_CHARACTERS_IN_FILENAME}\n" + f"FORBIDDEN_CHARACTERS_IN_FILENAME_CHANGE_TO={self.FORBIDDEN_CHARACTERS_IN_FILENAME_CHANGE_TO}\n" + ) + return s + + def setup_resolvers( + self, + for_event: EventFieldResolver, + for_message: MessageFieldResolver, + for_submessage: SubMessageFieldResolver, + for_expanded_message: ExpandedMessageFieldResolver, + ) -> "TH2Config": + """Use this to set up your custom resolvers. + + Args: + for_event: + for_message: + for_submessage: + for_expanded_message: + + Returns: + self + """ + self.EVENT_FIELDS_RESOLVER: EventFieldResolver = for_event + self.MESSAGE_FIELDS_RESOLVER: MessageFieldResolver = for_message + self.SUBMESSAGE_FIELDS_RESOLVER: SubMessageFieldResolver = for_submessage + self.EXPANDED_MESSAGE_FIELDS_RESOLVER: ExpandedMessageFieldResolver = for_expanded_message + self.efr = self.EVENT_FIELDS_RESOLVER + self.mfr = self.MESSAGE_FIELDS_RESOLVER + self.smfr = self.SUBMESSAGE_FIELDS_RESOLVER + self.emfr = self.EXPANDED_MESSAGE_FIELDS_RESOLVER + + return self + + +options = TH2Config() diff --git a/th2_data_services/data.py b/th2_data_services/data.py index 46fadbd0..76311f73 100644 --- a/th2_data_services/data.py +++ b/th2_data_services/data.py @@ -1,4 +1,4 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) +# Copyright 2022-2025 Exactpro (Exactpro Systems Limited) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -11,94 +11,326 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. + + import copy +import csv +import heapq +import os +import re +import shutil +from dataclasses import dataclass +import orjson as json +import gc import pickle import pprint +from warnings import warn from functools import partial from os import rename from pathlib import Path from time import time -from typing import Callable, Dict, Generator, List, Optional, Union, Iterable, Iterator, Any +from typing import ( + Callable, + Dict, + Generator, + List, + Optional, + Union, + Iterable, + Iterator, + Any, + Generic, + BinaryIO, +) from weakref import finalize -import logging +import types +from inspect import isgeneratorfunction +from typing import TypeVar +from th2_data_services.interfaces.adapter import IStreamAdapter, IRecordAdapter +from th2_data_services.config import options as o +from th2_data_services.utils._json import iter_json_file, iter_json_gzip_file +from th2_data_services.utils._is_sorted_result import IsSortedResult +from th2_data_services.utils.stream_utils.stream_utils import is_sorted +import gzip as gzip_ + +# LOG import logging + +# LOG logger = logging.getLogger(__name__) + + +# LOG class _DataLogger(logging.LoggerAdapter): +# LOG def process(self, msg, kwargs): +# LOG return "Data[%s] %s" % (self.extra["id"], msg), kwargs +from th2_data_services.utils.path_utils import check_if_filename_valid, check_if_file_exists +from deprecated.classic import deprecated + + +DataIterValues = TypeVar("DataIterValues") +DataGenerator = Generator[DataIterValues, None, None] +DataSet = Union[Iterator, Callable[..., DataGenerator], List[Iterable], Iterable] + + +def _build_limit_callback(num) -> Callable: + def callback(r): + callback.pushed += 1 + if callback.pushed > num: + raise StopIteration(r) + else: + return r + + callback.limit = num + callback.pushed = 0 + return callback + + +@dataclass +class WfRecord: + type: str + callback: Callable + + +@dataclass +class WfLimitRecord(WfRecord): + limit: int + + +class DataWorkflow: + def __init__(self): + """Data object workflow.""" + self._data: List[WfRecord] = [] + + def __bool__(self): + return bool(self._data) + + def __str__(self): + return f"DataWorkflow({pprint.pformat(self._data)})" -logger = logging.getLogger(__name__) + def __repr__(self): + return str(self) + def add(self, wfr: WfRecord): + """Add callback to workflow. -class _DataLogger(logging.LoggerAdapter): - def process(self, msg, kwargs): - return "Data[%s] %s" % (self.extra["id"], msg), kwargs + Args: + wfr: WfRecord + + Returns: + self + """ + self._data.append(wfr) + return self + + # def update(self, upd_func: Callable[[List[WfRecord]], List[WfRecord]]): + # self._data = upd_func(self._data) + + def apply_records(self, records: Iterator): + """Execute workflow against some stream. + + Args: + records: some stream. + + Yields: + workflow-handled records. + """ + map_chain = records + for wfr in self._data: + if wfr.type == "map_stream": + map_chain = wfr.callback(map_chain) + else: + map_chain = map(wfr.callback, map_chain) + + yield from map_chain + def refresh_limit_callbacks(self): + """Updates limit callbacks each time when Data object is iterated. -DataGenerator = Generator[dict, None, None] -DataSet = Union[Iterator, Callable[..., DataGenerator], List[Iterator]] -WorkFlow = List[Dict[str, Union[Callable, str]]] + It used to have the possibility to iterate the same Data object + several times in the loops. + """ + for wfr in self._data: + if isinstance(wfr, WfLimitRecord): + wfr.callback = _build_limit_callback(wfr.limit) -class Data: +class Data(Generic[DataIterValues]): """A wrapper for data/data_stream. The class provides methods for working with data as a stream. - Such approach to data analysis called streaming transformation. + Such an approach to data analysis called streaming transformation. """ - def __init__(self, data: DataSet, cache: bool = False, workflow: WorkFlow = None): + def __init__( + self, + data: DataSet, + cache: bool = False, + pickle_version: int = o.DEFAULT_PICKLE_VERSION, + ): """Data constructor. Args: - data: Data source. Any iterable, Data object or function that creates generator. + data: Data source. Any iterable, Data object or a function that creates generator. cache: Set True if you want to write and read from cache. - workflow: Workflow. + pickle_version: Pickle protocol version. Set if using cache. + """ + if isinstance(data, types.GeneratorType) and cache is False: + warn( + "Provided data has a generator type. " + "Data object will work wrong in non-cache mode because generators " + "are iterates only once. That's ok if you want to iterate it " + "only once. " + "Expected data types: Iterator, Callable[..., DataGenerator], List[Iterator]", + RuntimeWarning, + stacklevel=2, + ) + self._is_data_generate_type = True + else: + self._is_data_generate_type = False + + self._iterated_cnt = 0 # How many times the obj was iterated. + if self._is_iterables_list(data): - self._data_stream = self._create_data_set_from_iterables(data) + self._data_source = self._create_data_set_from_iterables(data) else: - self._data_stream = data + self._data_source = data self._id = id(self) self._cache_filename = f"{self._id}_{time()}.pickle" - self._cache_path = Path(f"./temp/{self._cache_filename}").resolve() - self._len = None - self._workflow = [] if workflow is None else workflow # Normally it has empty list or one Step. - self._length_hint = None # The value is populated when we use limit method. - self._cache_status = cache + self._cache_path = Path("temp", self._cache_filename).resolve().absolute() + self._pending_cache_path = ( + self._cache_path.with_name("[PENDING]" + self._cache_filename).resolve().absolute() + ) + self._data_list = [self] + self._cache_file_obj: Optional[BinaryIO] = None + self._len: Optional[int] = None + self.workflow = DataWorkflow() + + self._length_hint: Optional[int] = None # The value is populated when we use limit method. + self._cache_status: bool = cache + # We use finalize instead of __del__ because __del__ won't be executed sometimes. + # Read more about __del__ problems here: https://stackoverflow.com/a/2452895 self._finalizer = finalize(self, self.__remove) - self._logger = _DataLogger(logger, {"id": self._id}) + # LOG self._logger = _DataLogger(logger, {"id": self._id}) # It used to indicate the number of current iteration of the Data object. # It's required if the same instance iterates several times in for-in loops. - self.iter_num = 0 - self.stop_iteration = None + self.iter_num = 0 # Indicates what level of the loop the Data object is in. + self._stop_iteration: Optional[bool] = None + self.__metadata = {} + self._pickle_version = pickle_version # Default pickle protocol version + + # LOG self._logger.info( + # LOG "New data object with data stream = '%s', cache = '%s' initialized", id(self._data_stream), cache + # LOG ) - self._logger.info( - "New data object with data stream = '%s', cache = '%s' initialized", id(self._data_stream), cache + def __str__(self): + if self._cache_status: + path = self.get_cache_filepath() + is_exists = "Exists" if self.is_cache_file_exists() else "Not exists" + cache_str = f" ([{is_exists}] {path})" + else: + cache_str = "" + + s = ( + f"Data({id(self)}\n" + f" {self.workflow}\n" + f" metadata={self.metadata})\n" + f" cache={self._cache_status}{cache_str}" ) + return s + + def __repr__(self): + return str(self) + + def __bool__(self): + for _ in self: + return True + return False + + def __add__(self, other_data: "Data") -> "Data[DataIterValues]": + """Joining feature. + + Don't keep cache status. + + e.g. data3 = data1 + data2 -- data3 will have cache_status = False. + """ + if not isinstance(other_data, Data): + raise TypeError("Addition only works between Data objects") + new_data_list = self._data_list + other_data._data_list + data = Data(new_data_list) + data._data_list = new_data_list + data._set_metadata(self.metadata) + if "source_file" in data.metadata: + data.update_metadata({"source_files": [data.metadata["source_file"]]}) + if isinstance(other_data, Data): + if "source_file" in other_data.metadata: + data.update_metadata({"source_files": [other_data.metadata["source_file"]]}) + data.update_metadata(other_data.metadata) + if "source_file" in data.metadata: + data.metadata.pop("source_file") + return data + + def __iadd__(self, other_data: "Data") -> "Data[DataIterValues]": + """Joining feature. + + Keeps cache status. + + e.g. data1 += data2 -- will keep the cache status of data1. + """ + return self.__add__(other_data).use_cache(self._cache_status) + + def _copy_cache_file(self, new_name): + from shutil import copy2 + + copy2(self.get_cache_filepath(), new_name) + + def __copy__(self): + if self._cache_status and self.is_cache_file_exists(): + + def read_from_existed_cache(): + if self.is_cache_file_exists(): + yield from self.__load_file(self.get_cache_filepath()) + else: + yield from self._build_data_source() + + data_source = read_from_existed_cache + else: + data_source = self._data_source + + obj = Data(data_source, pickle_version=self._pickle_version) + obj._set_metadata(self.metadata) + obj.workflow = copy.deepcopy(self.workflow) + + return obj def __remove(self): """Data class destructor.""" - if self.__is_cache_file_exists(): + if self.is_cache_file_exists(): self.__delete_cache() - del self._data_stream + del self._data_source def __delete_cache(self) -> None: """Removes cache file.""" path = self.get_cache_filepath() if path.exists(): - self._logger.debug("Deleting cache file '%s'" % path) + # LOG self._logger.debug("Deleting cache file '%s'" % path) path.unlink() def __delete_pending_cache(self) -> None: """Removes cache file.""" path = self.get_pending_cache_filepath() if path.exists(): - self._logger.debug("Deleting cache file '%s'" % path) + # LOG self._logger.debug("Deleting cache file '%s'" % path) + self._cache_file_obj.close() path.unlink() def _create_data_set_from_iterables(self, iterables_list: List[Iterable]) -> DataSet: """Creates a generator from the list of iterables.""" return partial(self._create_generator_data_source_from_iterables, iterables_list) - def _create_generator_data_source_from_iterables(self, iterables_list: List[Iterable]) -> Generator: + def _create_generator_data_source_from_iterables( + self, iterables_list: List[Iterable] + ) -> Generator: """Creates a generator from the list of iterables.""" for data in iterables_list: yield from data @@ -106,26 +338,7 @@ def _create_generator_data_source_from_iterables(self, iterables_list: List[Iter def _is_iterables_list(self, data: DataSet) -> bool: if not isinstance(data, (list, tuple)): return False - - return all([isinstance(d, (Data, tuple, list)) for d in data]) - - @property - def len(self) -> int: - """int: How many records in the Data stream. - - Notes: - 1. It is a wasteful operation if you are performing it on the Data object that has never been iterated before. - - 2. If you want just to check emptiness, use is_empty property instead. - """ - return self._len if self._len is not None else self.__calc_len() - - @property - def is_empty(self) -> bool: - """bool: Indicates that the Data object doesn't contain data.""" - for _ in self.__load_data(): - return False - return True + return all(isinstance(d, Data) for d in data) def __calc_len(self) -> int: for _ in self: @@ -145,9 +358,11 @@ def __length_hint__(self): def _iter_logic(self): interruption = True - if self._cache_status and self.__is_cache_file_exists(): + if self._cache_status and self.is_cache_file_exists(): is_data_writes_cache = False else: + # FIXME -- bug -- we think that we are writing a file when it + # already exists and we are just reading it is_data_writes_cache = True try: @@ -155,41 +370,47 @@ def _iter_logic(self): yield record else: # Loop successfully finished. Do not delete cache file. - self._logger.debug("Successfully iterated") + # LOG self._logger.debug("Successfully iterated") interruption = False finally: if interruption: - if self.stop_iteration: # When limit was reached. + if self._stop_iteration: # When limit was reached. # You can save _len in this case because iteration was stopped by limit. - self._logger.info("Iteration was interrupted because limit reached") - + # LOG self._logger.info("Iteration was interrupted because limit reached") + pass else: # When something went wrong but NOT StopIteration - self._logger.info("Iteration was interrupted") + # LOG self._logger.info("Iteration was interrupted") # You shouldn't save _len in this case because iteration was interrupted. if self.iter_num == 1: self._len = None # Delete cache if it was interrupted and the file was not complete. # https://exactpro.atlassian.net/browse/TH2-3546 - if is_data_writes_cache: - self._logger.info("The cache file is not written to the end. Delete tmp cache file") + # Do not delete cache if iter_num != 1 (loop level > 1). + if is_data_writes_cache and self.iter_num == 1: + # LOG self._logger.info("The cache file is not written to the end. Delete tmp cache file") self.__delete_pending_cache() - else: # Data reads cache. - from th2_data_services import INTERACTIVE_MODE # To escape circular import problem. - - # Do not delete cache file if it's interactive mode and Data has read cache. - if not INTERACTIVE_MODE: - self.__delete_cache() self.iter_num -= 1 - self.stop_iteration = False + self._stop_iteration = False def __iter__(self) -> DataGenerator: - self.stop_iteration = False + self._stop_iteration = False self.iter_num += 1 - self._logger.info("Starting iteration, iter_num = %s", self.iter_num) + self._iterated_cnt += 1 + # LOG self._logger.info("Starting iteration, iter_num = %s", self.iter_num) + + if self._is_data_generate_type and self._iterated_cnt > 1: + warn( + "Provided data has a generator type and the generator " + "was already iterated. That should mean that you try to " + "iterate the empty generator.", + RuntimeWarning, + stacklevel=2, + ) + if self._len is None and self.iter_num == 1: self._len = 0 for record in self._iter_logic(): @@ -199,19 +420,38 @@ def __iter__(self) -> DataGenerator: # Do not calculate self._len if it is not None. yield from self._iter_logic() - def _build_workflow(self, workflow): - """Updates limit callbacks each time when Data object is iterated. + def _build_workflow(self, workflow: DataWorkflow): + """Updates limit callbacks each time when the Data object is iterated. + + It used to have the possibility to iterate the same Data object + in the different loops at the same time. + + We copy workflow to don't affect iteration in different loops. + + Note: + As a side effect, object variables of the Adapter don't work. + We also cannot put the external variable to adapter. This + variable won't be updated during iteration, because we will + iterate its copy. + + The workaround is to add the following to adapter class + ``` + def __copy__(self): + return self - It used to have possibility iterate the same Data object several times in the loops. + Def __deepcopy__(self, memo): + return self + ``` """ new_workflow = copy.deepcopy(workflow) - for w in new_workflow[::-1]: - if w["type"] == "limit": - w["callback"] = self._build_limit_callback(w["callback"].limit) + new_workflow.refresh_limit_callbacks() return new_workflow - def __load_data(self, cache: bool = False) -> DataGenerator: + def _build_data_source(self): + return self._data_source() if callable(self._data_source) else self._data_source + + def __load_data(self, cache: bool) -> DataGenerator: """Loads data from cache or data. Args: @@ -220,20 +460,41 @@ def __load_data(self, cache: bool = False) -> DataGenerator: Returns: obj: Generator """ - if cache and self.__is_cache_file_exists(): - self._logger.info("Iterating using own cache file '%s'" % self.get_cache_filepath()) - data_stream = self.__load_file(self.get_cache_filepath()) - yield from data_stream + if cache and self.is_cache_file_exists(): + # LOG self._logger.info("Iterating using own cache file '%s'" % self.get_cache_filepath()) + data_source = self.__load_file(self.get_cache_filepath()) + yield from data_source else: - data_stream = self._data_stream() if callable(self._data_stream) else self._data_stream - workflow = self._build_workflow(self._workflow) + data_source = self._build_data_source() # we do it for every iterable data object. + workflow = self._build_workflow(self.workflow) if self.__check_file_recording(): # Do not read from the cache file if it has PENDING status (if the file is not filled yet). - # It used to handle case when Data object iterates in the loop several times. + # It used to handle a case when the Data object iterates in the loop several times. cache = False - yield from self.__change_data(data_stream=data_stream, workflow=workflow, cache=cache) + if workflow: + iteration_obj = workflow.apply_records(data_source) + else: + iteration_obj = data_source + + if cache: + filepath = self.get_pending_cache_filepath() + filepath.parent.mkdir(exist_ok=True) + # LOG self._logger.debug("Recording cache file '%s'" % filepath) + self._cache_file_obj = open(filepath, "wb") + + for modified_record in iteration_obj: + pickle.dump( + modified_record, self._cache_file_obj, protocol=self._pickle_version + ) + yield modified_record + + self._cache_file_obj.close() + rename(self._cache_file_obj.name, str(self.get_cache_filepath())) + # LOG self._logger.debug("Cache file was created '%s'" % self.get_cache_filepath()) + else: + yield from iteration_obj def __check_file_recording(self) -> bool: """Checks whether there is a current recording in the file. @@ -244,78 +505,11 @@ def __check_file_recording(self) -> bool: path = self.get_pending_cache_filepath() return path.is_file() - def get_pending_cache_filepath(self) -> Path: - """Returns filepath for a pending cache file.""" - filepath = self.get_cache_filepath() - return filepath.with_name("[PENDING]" + self._cache_filename) - - def get_cache_filepath(self) -> Optional[Path]: - """Returns filepath for a cache file.""" - return self._cache_path - - def _iterate_modified_data_stream(self, data_stream: DataGenerator, workflow: WorkFlow) -> DataGenerator: - """Returns generator that iterates data stream with applied workflow. - - StopIteration from limit function will be handled here. - """ - self._logger.debug("Iterating data stream = '%s'", id(data_stream)) - for record in data_stream: - try: - modified_records = self.__apply_workflow(record, workflow) - except StopIteration as e: - self._logger.debug("Handle StopIteration") - modified_records = e.value - - if modified_records is not None: - if isinstance(modified_records, (list, tuple)): - yield from modified_records - else: # Just one record. - yield modified_records - - # There is some magic. - # It'll stop data stream and will be handled in the finally statements. - # If you put return not under except block it will NOT work. - return - - if modified_records is None: - continue - elif isinstance(modified_records, (list, tuple)): - yield from modified_records - else: # Just one record. - yield modified_records - - def __change_data(self, data_stream: DataGenerator, workflow: WorkFlow, cache: bool = False) -> DataGenerator: - """Applies workflow for data. - - Args: - data_stream: Data for apply workflow. - workflow: Workflow. - cache: Set True if you are going to write and read from the cache. - - Yields: - obj: Generator - """ - if cache: - filepath = self.get_pending_cache_filepath() - filepath.parent.mkdir(exist_ok=True) # Create dir if does not exist. - self._logger.debug("Recording cache file '%s'" % filepath) - file = open(filepath, "wb") - - for modified_record in self._iterate_modified_data_stream(data_stream, workflow): - pickle.dump(modified_record, file) - yield modified_record - - file.close() - rename(file.name, str(self.get_cache_filepath())) - self._logger.debug("Cache file was created '%s'" % self.get_cache_filepath()) - else: - yield from self._iterate_modified_data_stream(data_stream, workflow) - - def __is_cache_file_exists(self) -> bool: - """Checks whether cache file exist.""" + def is_cache_file_exists(self) -> bool: + """Returns whether cache file exists or not.""" path = self.get_cache_filepath() r = path.is_file() - self._logger.debug("Cache file exists" if r else "Cache file doesn't exist") + # LOG self._logger.debug("Cache file exists" if r else "Cache file doesn't exist") return r def __load_file(self, filepath: Path) -> DataGenerator: @@ -327,69 +521,44 @@ def __load_file(self, filepath: Path) -> DataGenerator: Yields: obj: Generator records. """ - if not filepath.exists(): - raise FileNotFoundError(f"{filepath} doesn't exist") + check_if_file_exists(filepath) + yield from _iter_pickle_file_logic(filepath) - if not filepath.is_file(): - raise FileExistsError(f"{filepath} isn't file") + @property + def metadata(self): + return self.__metadata - if filepath.suffix != ".pickle": - raise FileNotFoundError(f"File hasn't pickle extension") + @property + def len(self) -> int: + """int: How many records in the Data stream. - with open(filepath, "rb") as file: - while True: - try: - decoded_data = pickle.load(file) - yield decoded_data - except EOFError: - break + Notes: + 1. It is a wasteful operation if you are performing it on the Data object that has never been iterated before. - def _process_step(self, step: dict, record): - res = step["callback"](record) - self._logger.debug(" - step '%s' -> %s", step["type"], res) - return res + 2. If you want just to check emptiness, use is_empty property instead. + """ + return self._len if self._len is not None else self.__calc_len() - def __apply_workflow(self, record: Any, workflow: WorkFlow) -> Optional[Union[dict, List[dict]]]: - """Creates generator records with apply workflow. + @property + def is_empty(self) -> bool: + """bool: Indicates that the Data object doesn't contain data.""" + for _ in self: + return False + return True - Returns: - obj: Generator records. + @property + def cache_status(self) -> bool: + return self._cache_status - """ - self._logger.debug("Apply workflow for %s", record) - for step in workflow: - if isinstance(record, (list, tuple)): - result = [] - for r in record: - step_res = None - try: - step_res = self._process_step(step, r) - except StopIteration as e: - step_res = e.value - raise StopIteration(result if result else None) - finally: - if step_res is not None: - if isinstance(step_res, (list, tuple)): - result += step_res # To make flat list. - else: - result.append(step_res) - - record = result - if not record: - record = None - break # Break iteration if step result is None. - else: - try: - record = self._process_step(step, record) - if record is None: - break # Break workflow iteration if step result is None. - except StopIteration: - raise + def get_pending_cache_filepath(self) -> Path: + """Returns filepath for a pending cache file.""" + return self._pending_cache_path - self._logger.debug("-> %s", record) - return record + def get_cache_filepath(self) -> Path: + """Returns filepath for a cache file.""" + return self._cache_path - def filter(self, callback: Callable) -> "Data": + def filter(self, callback: Callable) -> "Data[DataIterValues]": """Append `filter` to workflow. Args: @@ -401,43 +570,125 @@ def filter(self, callback: Callable) -> "Data": Data: Data object. """ - self._logger.info("Apply filter") - new_workflow = [ - {"type": "filter", "callback": lambda record: record if callback(record) else None}, - ] - return Data(data=self, workflow=new_workflow) - def map(self, callback: Callable) -> "Data": + def filter_yield(stream): + try: + for record in stream: + if callback(record): + yield record + except Exception: + try: + print("Exception during filtering the message: \n" f"{pprint.pformat(record)}") + except UnboundLocalError: + pass + + raise + + new_data = self.map_stream(filter_yield) + # TODO - rename workflow type map_stream to filter + + return new_data + + def map(self, callback_or_adapter: Union[Callable, IRecordAdapter]) -> "Data[DataIterValues]": """Append `transform` function to workflow. Args: - callback: Transform function. + callback_or_adapter: Transform function or an Adapter with IRecordAdapter + interface implementation. + Note: + - If the function returns None value, this value will be + pushed to the next workflow function. + If you want to skip None values -- use `map_stream` instead. Returns: Data: Data object. """ - self._logger.info("Apply map") - new_workflow = [{"type": "map", "callback": callback}] - return Data(data=self, workflow=new_workflow) + # LOG self._logger.info("Apply map") - def _build_limit_callback(self, num) -> Callable: - self._logger.debug("Build limit callback with limit = %s", num) + new_data = copy.copy(self) - def callback(r): - callback.pushed += 1 - if callback.pushed == num: - callback.pushed = 0 - self._logger.debug("Limit reached - raise StopIteration") - raise StopIteration(r) - else: - return r + if isinstance(callback_or_adapter, IRecordAdapter): + new_data.workflow.add(WfRecord(type="map", callback=callback_or_adapter.handle)) + else: + new_data.workflow.add(WfRecord(type="map", callback=callback_or_adapter)) + + return new_data + + def map_stream( + self, adapter_or_generator: Union[IStreamAdapter, Callable[..., Generator]] + ) -> "Data[DataIterValues]": + """Append `stream-transform` function to workflow. + + If StreamAdapter is passed StreamAdapter.handle method will be used as a map function. + + Difference between map and map_stream: + 1. map_stream allows you return None values. + 2. map_stream allows you work with the whole stream but not with only 1 element, + so you can implement some buffers inside handler. + 3. map_stream works slightly efficient (faster on 5-10%). + + Args: + adapter_or_generator: StreamAdapter object or generator function. + + Returns: + Data: Data object. + + """ + new_data = copy.copy(self) + + if isinstance(adapter_or_generator, IStreamAdapter) and isgeneratorfunction( + adapter_or_generator.handle + ): + callback = adapter_or_generator.handle + + elif isgeneratorfunction(adapter_or_generator): + callback = adapter_or_generator + + else: + raise Exception( + "map_stream Only accepts IStreamAdapter class with generator function or Generator function" + ) + + new_data.workflow.add(WfRecord(type="map_stream", callback=callback)) + + return new_data + + # data = Data(source) + # data._set_metadata(self.metadata) + # return data + + # TODO - probably it's better to rename to map_iter or something else .. + def map_yield( + self, callback_or_adapter: Union[Callable, IRecordAdapter] + ) -> "Data[DataIterValues]": + """Maps the stream using callback function or adapter. - callback.limit = num - callback.pushed = 0 - return callback + Differences between map and map yield: + 1. map_yield is a wrapper function using map_stream. + 2. map_yield iterates over each item in record if callback returns + a value, which is a list or tuple. - def limit(self, num: int) -> "Data": + Args: + callback_or_adapter: Transform function or an Adapter with IRecordAdapter interface implementation. + + Returns: + Data: Data object. + + """ + + def generator(stream): + for record in stream: + modified_record = callback_or_adapter(record) + if isinstance(modified_record, (list, tuple)): + for item in modified_record: + yield item + else: + yield modified_record + + return self.map_stream(generator) + + def limit(self, num: int) -> "Data[DataIterValues]": """Limits the stream to `num` entries. Args: @@ -446,13 +697,17 @@ def limit(self, num: int) -> "Data": Returns: Data: Data object. """ - self._logger.info("Apply limit = %s", num) - new_workflow = [{"type": "limit", "callback": self._build_limit_callback(num)}] - data_obj = Data(data=self, workflow=new_workflow) + # LOG self._logger.info("Apply limit = %s", num) + data_obj = copy.copy(self) + data_obj.workflow.add( + WfLimitRecord(type="limit", callback=_build_limit_callback(num), limit=num) + ) data_obj._length_hint = num return data_obj - def sift(self, limit: int = None, skip: int = None) -> Generator[dict, None, None]: + def sift( + self, limit: Optional[int] = None, skip: Optional[int] = None + ) -> Generator[dict, None, None]: """Skips and limits records. Args: @@ -466,7 +721,7 @@ def sift(self, limit: int = None, skip: int = None) -> Generator[dict, None, Non skipped = 0 pushed = 0 - for record in self.__load_data(): + for record in self: if skip is not None and skipped < skip: skipped += 1 continue @@ -475,7 +730,102 @@ def sift(self, limit: int = None, skip: int = None) -> Generator[dict, None, Non yield record pushed += 1 - def use_cache(self, status: bool = True) -> "Data": + def sort( + self, key: Callable, replace=False, sorted_path=None, buffer_size=300 * 1024 * 1024 + ) -> "Data[DataIterValues]": + """Sorts the Data. Uses External sort, thus it can also work with huge amounts of Data. + + Args: + key: Function to sort data by. + replace: If True, the file that stores the data will be overwritten by sorted data, if False a new file + will be created. Default - False. + sorted_path: Path to the sorted file. + buffer_size: Size of the buffer. Buffer stores a chunk of the data that needs to be sorted. + + Returns: + Data: Data object. + + """ + if not sorted_path: + sorted_path = f"{self.metadata['source_file']}.sorted" + if replace: + sorted_path = f"{self.metadata['source_file']}" + folder = str(time()) + temp = Path(folder) + chunk_names = [] + + buffer = [] + temp.mkdir(parents=True, exist_ok=True) + + def sort_chunks(): + chunk_counter = 0 + current_size = 0 + for obj in self: + if current_size < buffer_size: + buffer.append(obj) + current_size += len(str(obj)) + else: + buffer.sort(key=key) + chunk_name = f"{folder}/chunk{chunk_counter}.chunk" + with open(chunk_name, "w") as chunk: + for o in buffer: + chunk.write(f"{key(o)}|{json.dumps(o)}\n") + chunk_names.append(chunk_name) + chunk_counter += 1 + buffer.clear() + buffer.append(obj) + current_size = len(str(obj)) + buffer.sort(key=key) + chunk_name = f"{folder}/chunk{chunk_counter}.chunk" + with open(chunk_name, "w") as chunk: + for o in buffer: + chunk.write(f"{key(o)}|{json.dumps(o)}\n") + chunk_names.append(chunk_name) + buffer.clear() + + def merge_back(): + heap = [] + for i, file in enumerate(chunk_names): + f = open(file, "r") + line = f.readline() + if line: + k = line[: line.find("|")] + v = line[line.find("|") + 1 :] + v = re.sub(r"(^b'|'$)", "", v) + heapq.heappush(heap, (k, v, f)) + with open(sorted_path, "w") as output_file: + while heap: + k, v, file = heapq.heappop(heap) + output_file.write(v) + line = file.readline() + if line: + k = line[: line.find("|")] + v = line[line.find("|") + 1 :] + v = re.sub(r"(^b'|'$)", "", v) + heapq.heappush(heap, (k, v, file)) + else: + file.close() + + try: + sort_chunks() + self = None + merge_back() + finally: + shutil.rmtree(temp) + return Data.from_json(sorted_path) + + def is_sorted(self, get_timestamp_func: Callable[[Any], Any]) -> IsSortedResult: + """Checks whether Data is sorted. + + Args: + get_timestamp_func: This function is responsible for getting the timestamp. + + Returns: + IsSortedResult: Whether data is sorted and additional info (e.g. index of the first unsorted element). + """ + return is_sorted(self, get_timestamp_func) + + def use_cache(self, status: bool = True) -> "Data[DataIterValues]": """Changes cache flag and returns self. Args: @@ -486,36 +836,44 @@ def use_cache(self, status: bool = True) -> "Data": Data: Data object. """ - self._logger.info("Cache using activated" if status else "Cache using deactivated") + # LOG self._logger.info("Cache using activated" if status else "Cache using deactivated") self._cache_status = status return self - def find_by(self, record_field, field_values) -> Generator: + def find_by(self, record_field: str, field_values: list) -> Generator: """Get the records whose field value is written in the field_values list. When to use: - You have IDs of some messages and you want get them in the stream and stop searching - when you find all elements. + You have IDs of some messages, and you want to get them in the + stream and stop searching when you find all elements. Args: record_field: The record field to be searched for in the field_values list. field_values: List of elements among which will be searched record[record_field]. + Current limitation: + Searches on for fields on the top level of the record. + Yields: dict: Generator records. """ - values_for_find = list(field_values) + values_to_find = set(field_values) for record in self: - if values_for_find: - if record[record_field] in values_for_find: - values_for_find.remove(record[record_field]) + if values_to_find: + if record[record_field] in values_to_find: + values_to_find.remove(record[record_field]) yield record else: continue else: break + # @overload + # def find_by_substring(self, substrings: ): + # pass + # # https://adamj.eu/tech/2021/05/29/python-type-hints-how-to-use-overload/ + def write_to_file(self, file: str) -> None: """Writes the stream data to txt file. @@ -527,18 +885,519 @@ def write_to_file(self, file: str) -> None: for record in self: txt_file.write(f"{pprint.pformat(record)}\n" + ("-" * 50) + "\n") - def __str__(self): - output = "------------- Printed first 5 records -------------\n" - for index, record in enumerate(self.__load_data()): - if index == 5: + def _show_print_one_line(self, index, idx_print, extra_prints: dict, record): + if idx_print: + print(f"[{index}] ------") + + for field_name, func in extra_prints.items(): + try: + val = func(record) + except Exception as e: + val = f"FUNC_ERROR ({e})" + print(f"{field_name}: {val}") + + pprint.pprint(record) + + def show( + self, n: int = 5, idx_print: bool = True, extra_prints: Optional[Dict[str, Callable]] = None + ): + """Prints first N records in human-readable format. + + Args: + n: number of elements to print. + Use -1, if you want to print the whole stream. + idx_print: + - True - will print message index before the message (Default) + - False - will Not print message index before the message + extra_prints: + Sometimes you want to highlight some fields in the message. + This parameter allows you to do this. + It will print extra print before the message. + E.g.: + extra_prints = { + 'SendingTime': get_sending_time_human_func, + 'TransactTime': get_sending_time_human_func, + } + + Returns: + None + """ + if extra_prints is None: + extra_prints = {} + + if n == -1: + print("------------- Printed all stream records -------------") + for index, record in enumerate(self, start=1): + self._show_print_one_line(index, idx_print, extra_prints, record) + return + + print(f"------------- Printed first {n} records -------------") + for index, record in enumerate(self, start=1): + if index > n: break - output += pprint.pformat(record) + "\n" - return output - def __bool__(self): - for _ in self.__load_data(): - return True - return False + self._show_print_one_line(index, idx_print, extra_prints, record) + + def build_cache(self, filename, pickle_version: Optional[int] = None): + """Creates cache file with provided name. + + Important: + If the Data object cache status is True, it'll iterate itself. As a result the cache file + will be created and copied. + When you iterate the Data object next time, it'll iterate created cache file. + + NOTE! If you build cache file, Data.cache_status was False and after that you'll set + Data.cache_status == TRUE -- the Data object WON'T iterate build file because it doesn't + keep the path to built cache file.. + + Args: + filename: Name or path to cache file. + pickle_version: Pickle protocol version. Change the default value + if you want to create pickle file with another pickle version. + + """ + path_name = Path(filename).name + status, reason = check_if_filename_valid(path_name) + if not status: + raise Exception(f"Cannot build cache file. {reason}") + + if pickle_version is None: + pickle_version = self._pickle_version + + if self.is_cache_file_exists(): + self._copy_cache_file(filename) + else: + gc.disable() # https://exactpro.atlassian.net/browse/TH2-4775 + if self._cache_status: + _ = self.len # Just to iterate + self._copy_cache_file(filename) + else: + file = open(filename, "wb") + + for record in self: + pickle.dump(record, file, protocol=pickle_version) + + file.close() + gc.enable() + + def clear_cache(self): + """Clears related to data object cache file. + + This function won't remove external cache file. + """ + if self.is_cache_file_exists(): + self.__delete_cache() + + @classmethod + def from_cache_file(cls, filename, pickle_version: int = o.DEFAULT_PICKLE_VERSION) -> "Data": + """Creates a Data object from cache file with the provided name. + + Args: + filename: Name or path to cache file. + pickle_version: Pickle protocol version. Change the default value + if your pickle file was created with another pickle version. + + Returns: + Data: Data object. + + Raises: + FileNotFoundError if provided file does not exist. + + """ + check_if_file_exists(filename) + + path = Path(filename).resolve() + data_obj = cls(_iter_pickle_cache_builder(path)) + data_obj.update_metadata({"source_file": path}) + data_obj._pickle_version = pickle_version + return data_obj + + @classmethod + def from_json(cls, filename, buffer_limit=250, gzip=False) -> "Data[dict]": + """Creates Data object from json-lines file with provided name. + + Args: + filename: Name or path to cache file. + buffer_limit: If limit is 0 buffer will not be used. Number of messages in buffer before parsing. + gzip: Set to true if file is json file compressed using gzip. + + Returns: + Data: Data object. + + Raises: + FileNotFoundError if provided file does not exist. + + """ + check_if_file_exists(filename) + if gzip: + data = cls(iter_json_gzip_file(filename, buffer_limit)) + else: + data = cls(iter_json_file(filename, buffer_limit)) + data.update_metadata({"source_file": filename}) + return data + + @classmethod + def from_any_file(cls, filename, mode="r") -> "Data[str]": + """Creates a Data object from any file with the provided name. + + It will just iterate file and return data line be line. + + Args: + filename: Name or path to the file. + mode: Read mode of open function. + + Returns: + Data: Data object. + + Raises: + FileNotFoundError if provided file does not exist. + + """ + check_if_file_exists(filename) + data = cls(_iter_any_file(filename, mode)) + data.update_metadata({"source_file": filename}) + return data + + @classmethod + def from_csv( + cls, + filename: Union[str, Path], + header=None, + header_first_line=False, + mode="r", + delimiter=",", + ) -> "Data": + """Creates a Data object from CSV file with the provided name. + + It will iterate the CSV file as if you were doing it with CSV module. + + Args: + filename: Name or path to the file. + header: If provided header for csv, Data object will yield Dict[str]. + Note, if your first line is header in csv, it also will be yielded. + header_first_line: If the first line of the csv file is header, + it'll take header from the first line. Data object will yield + Dict[str]. `header` argument is not required in this case. + First line of the CSV file will be skipped (header line). + mode: Read mode of open function. + delimiter: CSV file delimiter. + + Note: + If `header` provided and `header_first_line == True`, + Data object will yield Dict[str] where key names (columns) as + described in the `header`. First line of the CSV file will be skipped. + + Returns: + Data: Data object. + + Raises: + FileNotFoundError if provided file does not exist. + + """ + check_if_file_exists(filename) + data = cls(_iter_csv(filename, header, header_first_line, mode, delimiter)) + data.update_metadata({"source_file": filename}) + return data + + def _set_metadata(self, metadata: Dict) -> None: + """Set metadata of object to metadata argument. + + Args: + metadata (dict): New Metadata + + Raises: + Exception: If metadata isn't dict, error will be raised. + """ + if not isinstance(metadata, Dict): + raise Exception("metadata must be dictionary!") + + self.__metadata = copy.deepcopy(metadata) + + def update_metadata(self, metadata: Dict, change_type="update") -> "Data[DataIterValues]": + """Update metadata of object with metadata argument. + + If value of change_type is 'update' then metadata is updated with new values, + meaning previous values are kept and added with new values. + + | Example: + | data = Data(...) + | # data.metadata => {'num': 1, 'nums': [1], 'letters': {'a': 97}} + | new_metadata = {'num': 9, 'nums': [7], 'letters': {'z': 122}, 'new': 'key'} + | data.update_metadata(new_metadata) + | # data.metadata => {'num': 9, 'nums': [1,7], 'letters': {'a': 97, 'z': 122}, 'new': 'key'} + + If at least one value with is a list in one Data object, update_metadata adds both values in a list. + + | Example: + | data = Data(...) + | # data.metadata => {'str_example_one': ['str1'], 'str_example_two': 'str1'} + | new_metadata = {'str_example_one': 'str2', 'str_example_two': ['str2']} + | data.update_metadata(new_metadata) + | # data.metadata => {'str_example_one': ['str1', 'str2'], 'str_example_two': ['str1', 'str2']} + + However, if change_type is 'change' then metadata is overwritten with new values. + + | Example: + | data = Data(...) + | # data.metadata => {'num': 1, 'nums': [1], 'letters': {'a': 97}} + | new_metadata = {'num': 9, 'nums': [7], 'letters': {'z': 122}, 'new': 'key'} + | data.update_metadata(new_metadata) + | # data.metadata => {'num': 9, 'nums': [7], 'letters': {'z': 122}, 'new': 'key'} + + Args: + metadata (dict): New Metadata + change_type (str): Denotes whether to update values or overwrite it. Possible values: 'update', 'change'. + + Returns: + Data objects (itself) + + Raises: + Exception: If metadata isn't dict, error will be raised. + AttributeError: If you're trying to update key value with dict which isn't a dict. + """ + if not isinstance(metadata, Dict): + raise Exception("metadata must be dictionary!") + + for k, v in metadata.items(): + if k in self.metadata: + current = self.metadata[k] + if change_type == "update": + # Check For Iterable Types + if isinstance(v, dict): + self.__metadata[k].update({**current, **v}) + elif isinstance(v, Iterable) and not (isinstance(v, str)): + if isinstance(current, Iterable) and not isinstance(current, str): + self.__metadata[k] = [*current, *v] + else: + self.__metadata[k] = [current, *v] + else: # Single Item + if isinstance(current, Iterable) and not isinstance(current, str): + self.__metadata[k] = [*current, v] + else: + self.__metadata[k] = v + elif change_type == "change": + self.__metadata[k] = v + else: + raise Exception("change_type must be either 'update' or 'change'") + else: + # Add New Item + self.__metadata[k] = v + + return self + + def to_json(self, filename: Union[str, Path], indent: int = 0, overwrite: bool = False): + """Converts data to valid json format. + + Args: + filename (str): Output JSON filename + indent (int, optional): JSON format indent. Defaults to 0. + overwrite (bool, optional): Overwrite if filename exists. Defaults to False. + + NOTE: + Data object can iterate not only dicts. So not every data can be + saved as json. + + Raises: + FileExistsError: If file exists and overwrite=False + """ + if Path(filename).absolute().exists() and not overwrite: + raise FileExistsError( + f"{filename} already exists. If you want to overwrite current file set `overwrite=True`" + ) + + with open(filename, "w", encoding="utf-8") as file: + if self.is_empty: + file.write("[\n]\n") + return + file.write("[\n") # Start list + for record in self: + dump = json.dumps(record) + file.write(indent * " " + dump.decode()) + file.write(",\n") + file.seek(file.tell() - len(os.linesep) - 1) # Delete last comma for valid JSON + file.write("\n]\n") # Close list + + @deprecated( + reason="Use `to_json_lines` instead. " "`to_jsons` will be removed on 2.0.0 release." + ) + def to_jsons( + self, + filename: Union[str, Path], + indent: int = None, + overwrite: bool = False, + gzip=False, + compresslevel=5, + ): + """[DEPRECATED] Converts data to json lines. + + Every line is a valid json, but the whole file - not. + + Args: + filename (str): Output JSON filename. + indent (int, optional): DON'T used now. + overwrite (bool, optional): Overwrite if filename exists. Defaults to False. + gzip: Set to True if you want to compress the file using gzip. + compresslevel: gzip compression level. + + Raises: + FileExistsError: If file exists and overwrite=False + """ + return self.to_json_lines(filename, indent, overwrite, gzip, compresslevel) + + def to_json_lines( + self, + filename: Union[str, Path], + indent: int = None, + overwrite: bool = False, + gzip: bool = False, + compresslevel: int = 5, + ): + """Converts Data to json lines. + + Every line is a valid json, but the whole file - not. + + Args: + filename (str): Output JSON filename. + indent (int, optional): DON'T used now. + overwrite (bool, optional): Overwrite if filename exists. Defaults to False. + gzip: Set to True if you want to compress the file using gzip. + compresslevel: gzip compression level. + + NOTE: + Data object can iterate not only dicts. So not every data can be + saved as json. + + Raises: + FileExistsError: If file exists and overwrite=False + """ + if Path(filename).absolute().exists() and not overwrite: + raise FileExistsError( + f"{filename} already exists. If you want to overwrite current file set `overwrite=True`" + ) + + if gzip: + with gzip_.open(filename, "wb", compresslevel=compresslevel) as f: + for record in self: + f.write(json.dumps(record) + b"\n") + else: + with open(filename, "w", encoding="UTF-8") as file: + for record in self: + file.write((json.dumps(record) + b"\n").decode()) + + def to_csv( + self, + filename: Union[str, Path], + overwrite: bool = False, + ): + """Converts Data to csv. + + Args: + filename (str): Output CSV filename. + overwrite (bool, optional): Overwrite if filename exists. Defaults to False. + + NOTE: + Data object can iterate not only dicts. So not every data can be + saved as csv. Works with dicts and lists. + + Raises: + FileExistsError: If file exists and overwrite=False + """ + if Path(filename).absolute().exists() and not overwrite: + raise FileExistsError( + f"{filename} already exists. If you want to overwrite current file set `overwrite=True`" + ) + + is_list = False + for record in self: + if type(record) is list: + is_list = True + break + + with open(filename, "w", encoding="UTF-8", newline="") as file: + if is_list: + writer = csv.writer(file) + writer.writerows(self) + else: + writer = csv.DictWriter( + file, fieldnames=sorted(set().union(*[d.keys() for d in self])) + ) + writer.writeheader() + for row_dict in self: + writer.writerow(row_dict) + + +def _iter_any_file(filename: Union[str, Path], mode="r"): + """Returns the function that returns generators.""" + + def iter_any_file_logic(): + with open(filename, mode) as data: + while True: + try: + v = data.readline() + if not v: + break + + yield v + except Exception: + print(f"Error string: {v}") + raise + + def iter_any_file_wrapper(*args, **kwargs): + """Wrapper function that allows passing arguments to the generator.""" + return iter_any_file_logic(*args, **kwargs) + + return iter_any_file_wrapper + + +def _iter_csv( + filename: Union[str, Path], header=None, header_first_line=False, mode="r", delimiter="," +): + """Returns the function that returns generators.""" + + def iter_logic(): + with open(filename, mode) as data: + if header is not None and header_first_line: + reader = csv.DictReader(data, fieldnames=header, delimiter=delimiter) + next(reader) # Skip first line with header. + elif header is not None: + reader = csv.DictReader(data, fieldnames=header, delimiter=delimiter) + elif header_first_line: + reader = csv.DictReader(data, delimiter=delimiter) + else: + reader = csv.reader(data, delimiter=delimiter) + + for row in reader: + yield row + + def iter_wrapper(*args, **kwargs): + """Wrapper function that allows passing arguments to the generator.""" + return iter_logic(*args, **kwargs) + + return iter_wrapper + + +def _iter_pickle_file_logic(filepath): + """Generator that reads and yields decoded JSON objects from a file. + + The protocol version of the pickle is detected automatically, + so no protocol argument is needed. Bytes past the pickled representation + of the object are ignored. + """ + with open(filepath, "rb") as file: + while True: + try: + decoded_data = pickle.load(file) + yield decoded_data + except EOFError: + break + except pickle.UnpicklingError: + print(f"Cannot read {filepath} cache file") + raise + + +def _iter_pickle_cache_builder(filepath: Path): + def iter_pickle_cache(*args, **kwargs): + """Wrapper function that allows passing arguments to the generator.""" + return _iter_pickle_file_logic(filepath) - def __add__(self, other_data: Iterable) -> "Data": - return Data(self._create_data_set_from_iterables([self, other_data])) + return iter_pickle_cache diff --git a/th2_data_services/provider/v5/provider_api/__init__.py b/th2_data_services/dummy/__init__.py similarity index 81% rename from th2_data_services/provider/v5/provider_api/__init__.py rename to th2_data_services/dummy/__init__.py index 431af5eb..7f0840d1 100644 --- a/th2_data_services/provider/v5/provider_api/__init__.py +++ b/th2_data_services/dummy/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) +# Copyright 2024-2025 Exactpro (Exactpro Systems Limited) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -12,5 +12,5 @@ # See the License for the specific language governing permissions and # limitations under the License. -from .grpc import GRPCProvider5API -from .http import HTTPProvider5API + +from th2_data_services.dummy.data_source import DummyDataSource diff --git a/th2_data_services/provider/interfaces/source_api.py b/th2_data_services/dummy/data_source.py similarity index 54% rename from th2_data_services/provider/interfaces/source_api.py rename to th2_data_services/dummy/data_source.py index 782abb6c..ccc7bc07 100644 --- a/th2_data_services/provider/interfaces/source_api.py +++ b/th2_data_services/dummy/data_source.py @@ -1,4 +1,4 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) +# Copyright 2024-2025 Exactpro (Exactpro Systems Limited) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -12,16 +12,20 @@ # See the License for the specific language governing permissions and # limitations under the License. -from th2_data_services.interfaces.source_api import ISourceAPI +from th2_data_services.interfaces import IDataSource, ISourceAPI, ICommand -class IProviderSourceAPI(ISourceAPI): - """Interface for Source API of rpt-data-provider.""" +class DummyDataSource(IDataSource): + """Dummy DataSource. -class IHTTPProviderSourceAPI(IProviderSourceAPI): - """Interface for Source API of rpt-data-provider which works via HTTP.""" + Can be useful to create ETCDriver without concrete DataSource or to + in unit tests. + """ + def command(self, cmd: ICommand): # noqa + raise NotImplementedError -class IGRPCProviderSourceAPI(IProviderSourceAPI): - """Interface for Source API of rpt-data-provider which works via GRPC.""" + @property + def source_api(self) -> ISourceAPI: # noqa + raise NotImplementedError diff --git a/th2_data_services/provider/interfaces/__init__.py b/th2_data_services/event_tree/__init__.py similarity index 68% rename from th2_data_services/provider/interfaces/__init__.py rename to th2_data_services/event_tree/__init__.py index 1ada06db..231a3806 100644 --- a/th2_data_services/provider/interfaces/__init__.py +++ b/th2_data_services/event_tree/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) +# Copyright 2022-2025 Exactpro (Exactpro Systems Limited) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -12,8 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -from .command import * -from .data_source import * -from .source_api import * -from .struct import * -from .stub_builder import * + +from .event_tree import EventTree +from .event_tree_collection import EventTreeCollection +from .parent_event_tree_collection import ParentEventTreeCollection +from .etc_driver import IETCDriver diff --git a/th2_data_services/event_tree/etc_driver.py b/th2_data_services/event_tree/etc_driver.py new file mode 100644 index 00000000..201ea22c --- /dev/null +++ b/th2_data_services/event_tree/etc_driver.py @@ -0,0 +1,68 @@ +# Copyright 2023-2025 Exactpro (Exactpro Systems Limited) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +from abc import ABC, abstractmethod +from typing import TypeVar, Generic, Sequence + +from th2_data_services.interfaces import IEventStruct, IDataSource + +Th2EventType = TypeVar("Th2EventType") + + +class IETCDriver(ABC, Generic[Th2EventType]): + def __init__( + self, + event_struct: IEventStruct, + data_source: IDataSource, + use_stub: bool = False, + ): + """The driver for EventsTreeCollection and its inheritors. + + Args: + event_struct: Structure of the event. + data_source: DataSource object. + use_stub: Build stubs or not. + """ + self.event_struct = event_struct + self.use_stub = use_stub + self._data_source = data_source + + @abstractmethod + def build_stub_event(self, id_: str) -> Th2EventType: + """Builds stub event to generate parentless trees. + + Args: + id_: Event Id. + """ + + @abstractmethod + def get_parent_event_id(self, event: Th2EventType): + """Returns parent event id from the event.""" + + @abstractmethod + def get_event_id(self, event: Th2EventType): + """Returns event id from the event.""" + + @abstractmethod + def get_event_name(self, event: Th2EventType): + """Returns event name from the event.""" + + @abstractmethod + def get_events_by_id_from_source(self, ids: Sequence) -> list: + """Downloads the list of events from the provided data_source.""" + + @abstractmethod + def stub_event_name(self): + """Returns stub event name.""" diff --git a/th2_data_services/events_tree/events_tree.py b/th2_data_services/event_tree/event_tree.py similarity index 63% rename from th2_data_services/events_tree/events_tree.py rename to th2_data_services/event_tree/event_tree.py index 8253b7a0..4e3350fe 100644 --- a/th2_data_services/events_tree/events_tree.py +++ b/th2_data_services/event_tree/event_tree.py @@ -1,4 +1,4 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) +# Copyright 2022-2025 Exactpro (Exactpro Systems Limited) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -12,26 +12,31 @@ # See the License for the specific language governing permissions and # limitations under the License. + from typing import List, Tuple, Generator, Callable, Optional, Union from treelib import Tree, Node -from treelib.exceptions import NodeIDAbsentError +from treelib.exceptions import NodeIDAbsentError, LoopError -from th2_data_services.events_tree.exceptions import EventIdNotInTree +from th2_data_services.event_tree.exceptions import ( + EventIdNotInTree, + EventAlreadyExist, + EventRootExist, + TreeLoop, +) -Th2Event = dict +Th2Event = dict # TODO - move to types. Also this class knows that th2-event is a dict, but it cannot to know. -class EventsTree: - """EventsTree is a tree-based data structure of events. +class EventTree: + """EventTree is a tree-based data structure of events. - get_x methods raise Exceptions if no result is found. - find_x methods return None if no result is found. - - EventsTree stores events as Nodes and interacts with them using an internal tree. - - EventsTree removes the 'body' field by default to save memory, but you can keep it. - - Note that EventsTree stores only one tree. - If you want to store all trees, use EventsTreeCollections. - - EventsTree contains all events in memory. + - EventTree stores events as Nodes and interacts with them using an internal tree. + - Note that EventTree stores only one tree. + If you want to store all trees, use EventTreeCollections. + - EventTree contains all events in memory. Take a look at the following HTML tree to understand some important terms. @@ -45,25 +50,54 @@ class EventsTree: ``` """ - def __init__(self, tree: Tree): - """EventsTree constructor. + def __init__(self, event_name: str, event_id: str, data: dict = None): + """EventTree constructor. Args: - tree (treelib.Tree): Tree. + event_name: Event Name. + event_id: Event Id. + data: Data of event. """ - self._tree = tree + self._tree = Tree() + self._create_root_event(event_name, event_id, data) - def _append_node(self, node: Node, parent_id: str) -> None: - """Appends a node to the tree. + def _create_root_event(self, event_name: str, event_id: str, data: dict = None) -> None: + """Appends a root event to the tree. Args: - node: Node. - parent_id: Parent event id. + event_name: Event Name. + event_id: Event Id. + data: Data of event. """ - if parent_id not in self._tree: - raise NodeIDAbsentError(f"Node {parent_id} is not in the tree.") + if self._tree.root is not None: + raise EventRootExist(event_id) + if event_id in self._tree: + raise EventAlreadyExist(event_id) + + self._tree.create_node(tag=event_name, identifier=event_id, parent=None, data=data) + + def append_event( + self, event_name: str, event_id: str, parent_id: str, data: dict = None + ) -> None: + """Appends the event to the tree. + + Args: + event_name: Event Name. + event_id: Event Id. + parent_id: Parent Id. + data: Data of event. + """ + if event_id in self._tree: + raise EventAlreadyExist(event_id) + if parent_id is None: + raise ValueError( + "The param 'parent_id' must be not None. If you want create root event then use 'create_root_event'" + ) - self._tree.add_node(node, parent_id) + try: + self._tree.create_node(tag=event_name, identifier=event_id, parent=parent_id, data=data) + except NodeIDAbsentError: + raise EventIdNotInTree(parent_id) def get_all_events_iter(self) -> Generator[Th2Event, None, None]: """Returns all events from the tree as iterator.""" @@ -88,9 +122,53 @@ def get_event(self, id: str) -> Th2Event: raise EventIdNotInTree(id) return node.data - # TODO: In future it will be added. - # def __getitem__(self, item): - # pass + def __getitem__(self, id_: str) -> Th2Event: + """e.g. ET['id1'] returns event.data.""" + try: + return self._tree[id_].data + except NodeIDAbsentError: + raise EventIdNotInTree(id_) + + def __setitem__(self, id_: str, data: dict) -> None: + # TODO - It shouldn't raise an exception. + # It should create new Node or change existing + try: + self._tree[id_].data = data + except NodeIDAbsentError: + raise EventIdNotInTree(id_) + + def update_event_name(self, event_id: str, event_name: str) -> None: + """Updates Event name in the tree. Note that it doesn't change internal data. + + Args: + event_id: Event id. + event_name: Event name. + + Raises: + EventIdNotInTree: If event id is not in the tree. + """ + try: + self._tree.update_node(event_id, tag=event_name) + except NodeIDAbsentError: + raise EventIdNotInTree(event_id) + + def update_parent_link(self, event_id: str, parent_id: str) -> None: + """Updates the link to parent. + + Args: + event_id: Event id. + parent_id: New parent id. + + Raises: + EventIdNotInTree: If event id is not in the tree. + TreeLoop: If parent id will point to the descendant event. + """ + try: + self._tree.move_node(event_id, parent_id) + except NodeIDAbsentError: + raise EventIdNotInTree(event_id) + except LoopError: + raise TreeLoop(event_id, parent_id) def get_root_id(self) -> str: """Returns the root id.""" @@ -143,9 +221,11 @@ def get_children_iter(self, id: str) -> Generator[Th2Event, None, None]: except NodeIDAbsentError: raise EventIdNotInTree(id) - def get_parent(self, id: str) -> Th2Event: + def get_parent(self, id: str) -> Optional[Th2Event]: """Returns a parent for the event by its id. + Returns None if the provided ID is a root of the tree. + Args: id: Event id. @@ -153,7 +233,15 @@ def get_parent(self, id: str) -> Th2Event: EventIdNotInTree: If event id is not in the tree. """ try: - return self._tree.parent(id).data + parent = self._tree.parent(id) + + if self.get_root_id() == id: + return None + + if parent is None: + raise EventIdNotInTree(id) + + return parent.data except NodeIDAbsentError: raise EventIdNotInTree(id) @@ -341,7 +429,7 @@ def find(self, filter: Callable, stop: Callable = None) -> Optional[Th2Event]: return event return None - def get_subtree(self, id: str) -> "EventsTree": + def get_subtree(self, id: str) -> "EventTree": """Returns subtree of the event by its id. Args: @@ -356,10 +444,31 @@ def get_subtree(self, id: str) -> "EventsTree": subtree = self._tree.subtree(id) if not subtree: raise EventIdNotInTree(id) - return EventsTree(subtree) + + et = EventTree(event_name="0", event_id="0") + et._tree = subtree + + return et + + def merge_tree( + self, parent_id: str, other_tree: "EventTree", use_deepcopy: bool = False + ) -> None: + """Merges a EventTree to specified identifier. + + Args: + parent_id: Event id to which merge. + other_tree: EventTree. + use_deepcopy: True if you need deepcopy for your objects in event. + + Raises: + EventIdNotInTree: If event id is not in the tree. + """ + if parent_id not in self._tree: + raise EventIdNotInTree(parent_id) + self._tree.merge(parent_id, other_tree._tree, use_deepcopy) def show(self) -> None: - """Prints the EventsTree as tree view. + """Prints the EventTree as tree view. For example: @@ -374,6 +483,20 @@ def show(self) -> None: | |___ C31 ``` """ + # TODO + # et.append_event('a', '2', et.get_root_id()) + # et.show() + # Traceback (most recent call last): + # File "C:\Users\admin\AppData\Local\Programs\Python\Python39\lib\code.py", line 90, in runcode + # exec(code, self.locals) + # File "", line 1, in + # File "C:\Users\admin\exactpro\prj\th2\internal\DS\github\th2-data-services\th2_data_services\event_tree\event_tree.py", line 475, in show + # self._tree.show() + # File "C:\Users\admin\exactpro\prj\th2\internal\DS\github\th2-data-services\ds_lib_venv_py39\lib\site-packages\treelib\tree.py", line 854, in show + # print(self._reader) + # File "C:\Users\admin\AppData\Local\Programs\Python\Python39\lib\encodings\cp1251.py", line 19, in encode + # return codecs.charmap_encode(input,self.errors,encoding_table)[0] + # UnicodeEncodeError: 'charmap' codec can't encode characters in position 6-8: character maps to self._tree.show() def __len__(self) -> int: diff --git a/th2_data_services/interfaces/events_tree/events_tree_collection.py b/th2_data_services/event_tree/event_tree_collection.py similarity index 66% rename from th2_data_services/interfaces/events_tree/events_tree_collection.py rename to th2_data_services/event_tree/event_tree_collection.py index f5d60b10..37350636 100644 --- a/th2_data_services/interfaces/events_tree/events_tree_collection.py +++ b/th2_data_services/event_tree/event_tree_collection.py @@ -1,4 +1,4 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) +# Copyright 2022-2025 Exactpro (Exactpro Systems Limited) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -12,90 +12,45 @@ # See the License for the specific language governing permissions and # limitations under the License. -from abc import ABC, abstractmethod + from collections import defaultdict -from typing import List, Dict, Optional, Union, Generator, Tuple, Callable +from typing import Callable, Dict, Generator, Iterable, List, Optional, Tuple, Union -from treelib import Node, Tree from treelib.exceptions import NodeIDAbsentError - -from th2_data_services import Data -from th2_data_services.events_tree.events_tree import EventsTree -from th2_data_services.events_tree.events_tree import Th2Event -from th2_data_services.events_tree.exceptions import EventIdNotInTree -from th2_data_services.provider.interfaces.data_source import IProviderDataSource - -import logging +from th2_data_services.event_tree.event_tree import EventTree +from th2_data_services.event_tree.event_tree import Th2Event +from th2_data_services.event_tree.exceptions import EventIdNotInTree import warnings -logger = logging.getLogger(__name__) +from th2_data_services.event_tree.etc_driver import IETCDriver -class _EventsTreeCollectionLogger(logging.LoggerAdapter): - def process(self, msg, kwargs): - return "ETC[%s] %s" % (self.extra["id"], msg), kwargs +class EventTreeCollection: + """EventTreeCollection objective is building 'EventsTree's and storing them. - -class EventsTreeCollection(ABC): - """EventsTreeCollection objective is building 'EventsTree's and storing them. - - - EventsTreeCollection stores all EventsTree. You can to refer to each of them. + - EventTreeCollection stores all EventsTree. You can to refer to each of them. - Recovery of missing events occurs when you have passed DataSource class to constructor. Otherwise you should execute the method 'recover_unknown_events' manually. Note that there is no point in the method if the list of detached events is empty. """ - def __init__( - self, - data: Data, - data_source: IProviderDataSource = None, - preserve_body: bool = False, - stub: bool = False, - ): - """EventsTreeCollection constructor. + def __init__(self, driver: IETCDriver): + """EventTreeCollection constructor. Args: - data: Data object with events. - data_source: Provider Data Source object. - preserve_body: If True it will preserve 'body' field in the Events. - stub: If True it will create stub when event is broken. + driver: initialized driver object. """ - self._id = id(self) - self._preserve_body = preserve_body - self._roots: List[EventsTree] = [] - self._parentless: Optional[List[EventsTree]] = None - self._detached_nodes: Dict[Optional[str], List[Node]] = defaultdict(list) # {parent_event_id: [Node1, ..]} - self._stub_status = stub - self._data_source = data_source - self._logger = _EventsTreeCollectionLogger(logger, {"id": self._id}) + self._driver = driver + self._roots: List[EventTree] = [] + self._parentless: Optional[List[EventTree]] = None + # {parent_event_id: [event1, ..]} + self._detached_nodes: Dict[Optional[str], List[dict]] = defaultdict(list) - events_nodes = self._build_event_nodes(data) - self._build_trees(events_nodes) - - if data_source is not None: - self.recover_unknown_events(self._data_source) - - if self._detached_nodes: - w = "The collection were built with detached events because there are no some events in the source" - self._logger.warning(w) - warnings.warn(w) - - def get_parentless_trees(self) -> List[EventsTree]: - """Builds and returns parentless trees by detached events. - - Detached events will be removed from the tree. - - Returns: - List of parentless trees if they exist, otherwise empty list. - """ - if self._parentless is not None: - return self._parentless - else: - self._parentless = self._build_parentless_trees() - return self._parentless + def _detached_parent_ids(self): + return self._detached_nodes.keys() - def _build_parentless_trees(self) -> List[EventsTree]: + def _build_parentless_trees(self) -> List[EventTree]: """Builds parentless trees by detached events. Returns: @@ -103,30 +58,25 @@ def _build_parentless_trees(self) -> List[EventsTree]: """ self._parentless = [] - stub_roots = list(self._detached_nodes.keys()) - for nodes in self._detached_nodes.values(): - for node in nodes: - if node.identifier in stub_roots: - stub_roots.remove(node.identifier) + stub_roots = set(self._detached_parent_ids()) + for event in self.get_detached_events_iter(): + event_id = self._driver.get_event_id(event) + if event_id in stub_roots: + stub_roots.remove(event_id) for id_ in stub_roots: - tree = Tree() - tree.create_node(tag="Stub", identifier=id_, data=self._build_stub_event(id_)) + stub_event = self._driver.build_stub_event(id_) + event_id, event_name = self._driver.get_event_id( + stub_event + ), self._driver.get_event_name(stub_event) + tree = EventTree(event_id=event_id, event_name=event_name, data=stub_event) self._fill_tree(self._detached_nodes, tree, id_) - self._parentless.append(EventsTree(tree)) + self._parentless.append(tree) return self._parentless - @abstractmethod - def _build_stub_event(self, id_: str) -> dict: - """Builds stub event. - - Args: - id_: Event Id. - """ - - def _build_event_nodes(self, data: Data) -> Dict[Optional[str], List[Node]]: - """Builds event nodes and group them by parent_event_id. + def _build_events_store(self, data: Iterable) -> Dict[Optional[str], List[dict]]: + """Builds events store, grouping them by parent_event_id. Args: data: Data. @@ -134,93 +84,74 @@ def _build_event_nodes(self, data: Data) -> Dict[Optional[str], List[Node]]: Returns: Nodes. """ - events_nodes: Dict[Optional[str], List[Node]] = defaultdict(list) # {parent_event_id: [Node1, Node2, ..]} + events_store: Dict[Optional[str], List[dict]] = defaultdict( + list + ) # {parent_event_id: [event1, event2, ..]} - for event in self._parse_events(data): - parent_event_id: str = self._get_parent_event_id(event) - node = self._build_node(event) - events_nodes[parent_event_id].append(node) + for event in data: + parent_event_id: str = self._driver.get_parent_event_id(event) + events_store[parent_event_id].append(event) - return events_nodes + return events_store - def _build_trees(self, nodes: Dict[Optional[str], List[Node]]) -> None: + def _build_trees(self, events_nodes: Dict[Optional[str], List[dict]]) -> None: """Builds trees and saves detached events. Args: - nodes: Events nodes. + events_nodes: Events nodes. """ roots = [] - for root_node in nodes[None]: # None - is parent_event_id for root events. - tree = Tree() - tree.add_node(root_node) + for root_event in events_nodes[None]: # None - is parent_event_id for root events. + event_name, event_id = self._driver.get_event_name( + root_event + ), self._driver.get_event_id(root_event) + tree = EventTree(event_name=event_name, event_id=event_id, data=root_event) roots.append(tree) - root_event_id: str = root_node.identifier - self._fill_tree(nodes, tree, root_event_id) - nodes.pop(None) - - self._roots = [EventsTree(root) for root in roots] + self._fill_tree(events_nodes, tree, event_id) + events_nodes.pop(None) - self._detached_nodes = nodes + self._roots = roots + self._detached_nodes = events_nodes - def _fill_tree(self, nodes: Dict[Optional[str], List[Node]], current_tree: Tree, parent_id: str) -> None: + def _fill_tree( + self, events_store: Dict[Optional[str], List[dict]], current_tree: EventTree, parent_id: str + ) -> None: """Fills tree recursively. Args: - nodes: Events nodes. + events_store: Events nodes. current_tree: Tree for fill. parent_id: Parent even id. """ - for node in nodes[parent_id].copy(): - event_id: str = node.identifier + for event in events_store[parent_id].copy(): + event_name, event_id, = self._driver.get_event_name( + event + ), self._driver.get_event_id(event) if event_id not in current_tree: - current_tree.add_node(node, parent=parent_id) - nodes[parent_id].remove(node) - self._fill_tree(nodes, current_tree, event_id) # Recursive fill. - nodes.pop(parent_id) - - def _parse_event(self, event: Th2Event) -> Th2Event: - """Parses event. - - Args: - event: Event. - - Returns: - Parsed event. - """ - if not self._preserve_body: - try: - event.pop("body") - except KeyError: - pass - return event - - def _parse_events(self, data: Union[Data, List[dict]]) -> Generator[dict, None, None]: - """Parses events. - - Args: - data: Data. - - Returns: - Parsed events iterator. - """ - for event in data: - event = self._parse_event(event) - yield event - - def _build_node(self, event: dict) -> Node: - """Builds event as dict into event as Node. + current_tree.append_event( + event_name=event_name, event_id=event_id, parent_id=parent_id, data=event + ) + events_store[parent_id].remove(event) + self._fill_tree(events_store, current_tree, event_id) # Recursive fill. + events_store.pop(parent_id) + + def build(self, data: Iterable): + events_nodes = self._build_events_store(data) # {parent_event_id: [event1, event2, ..]} + self._build_trees(events_nodes) # Produces _detached_nodes. + + def get_parentless_trees(self) -> List[EventTree]: + """Builds and returns parentless trees by detached events. - Args: - event: Event. + Detached events will be removed from the tree. Returns: - Node. + List of parentless trees if they exist, otherwise empty list. """ - event_id: str = self._get_event_id(event) - event_name: str = self._get_event_name(event) - - node = Node(tag=event_name, identifier=event_id, data=event) - return node + if self._parentless is not None: + return self._parentless + else: + self._parentless = self._build_parentless_trees() + return self._parentless def append_event(self, event: dict) -> None: """Appends event into a tree. @@ -228,46 +159,46 @@ def append_event(self, event: dict) -> None: Args: event: Event. """ - event: dict = self._parse_event(event) - node: Node = self._build_node(event) - parent_event_id: str = self._get_parent_event_id(event) + parent_event_id: str = self._driver.get_parent_event_id(event) - if parent_event_id is not None: + if parent_event_id is not None: # Is root? events_trees = list(filter(lambda tree: parent_event_id in tree, self._roots)) if events_trees: event_tree = events_trees[0] - if node.identifier in event_tree: + event_id, event_name = self._driver.get_event_id( + event + ), self._driver.get_event_name(event) + if event_id in event_tree: pass else: - event_tree._append_node(node, parent_event_id) - self._fill_tree(self._detached_nodes, event_tree._tree, parent_event_id) + event_tree.append_event( + event_name=event_name, + event_id=event_id, + parent_id=parent_event_id, + data=event, + ) + self._fill_tree(self._detached_nodes, event_tree, parent_event_id) else: - self._detached_nodes[parent_event_id].append(node) + self._detached_nodes[parent_event_id].append(event) else: - tree = Tree() - tree.add_node(node) - self._roots.append(EventsTree(tree)) - self._fill_tree(self._detached_nodes, tree, node.identifier) + event_id, event_name = self._driver.get_event_id(event), self._driver.get_event_name( + event + ) + tree = EventTree(event_id=event_id, event_name=event_name, data=event) + self._roots.append(tree) - @property - def detached_events(self) -> dict: - """Returns detached events as a dict that looks like {'parent_id': ['referenced event', ...]}.""" - w = ( - f"This method is deprecated since v1.1.0, and will be removed in the future. " - f"Please use get_detached_events_iter or get_detached_events." - ) - warnings.warn(message=w, category=DeprecationWarning, stacklevel=2) - return self._detached_events() + event_id = self._driver.get_event_id(event) + self._fill_tree(self._detached_nodes, tree, event_id) - def _detached_events(self) -> dict: + def _detached_events_dict(self) -> dict: """Returns detached events as a dict that looks like {'parent_id': ['referenced event', ...]}.""" - return {id_: [node.data for node in nodes] for id_, nodes in self._detached_nodes.items()} + return {id_: events.copy() for id_, events in self._detached_nodes.items()} def get_detached_events_iter(self) -> Generator[Th2Event, None, None]: """Yields detached events.""" - for nodes in self._detached_nodes.values(): - for node in nodes: - yield node.data + for events in self._detached_nodes.values(): + for event in events: + yield event def get_detached_events(self) -> List[Th2Event]: """Returns detached events list.""" @@ -279,10 +210,12 @@ def get_roots_ids(self) -> List[str]: If there are parentless trees, they also will be return. """ if self._parentless is not None: - return [tree.get_root_id() for tree in self._roots] + [tree.get_root_id() for tree in self._parentless] + return [tree.get_root_id() for tree in self._roots] + [ + tree.get_root_id() for tree in self._parentless + ] return [tree.get_root_id() for tree in self._roots] - def get_trees(self) -> List[EventsTree]: + def get_trees(self) -> List[EventTree]: """Returns the list of trees inside the collection. If there are parentless trees, they also will be return. @@ -310,7 +243,7 @@ def get_root_by_id(self, id) -> Th2Event: except EventIdNotInTree: raise EventIdNotInTree(id) - def get_tree_by_id(self, id) -> EventsTree: + def get_tree_by_id(self, id) -> EventTree: """Returns a tree by id of any event in this tree. If event id of parentless tree is passed, stub of this parentless tree will be returnd. @@ -334,6 +267,7 @@ def get_tree_by_id(self, id) -> EventsTree: raise EventIdNotInTree(id) def show(self): + # TODO - works in linux only now. """Prints all EventsTrees as tree view. For example: @@ -353,22 +287,6 @@ def show(self): for tree in trees: tree.show() - @abstractmethod - def _get_parent_event_id(self, event): - """Gets parent event id from the event.""" - - @abstractmethod - def _get_event_id(self, event): - """Gets event id from the event.""" - - @abstractmethod - def _get_event_name(self, event): - """Gets event name from the event.""" - - @abstractmethod - def _get_events_by_id_resolver(self) -> Callable: - """Gets a function that solve which protocol command to choose.""" - def __len__(self) -> int: """Returns the number of all events, including detached events.""" return self.len_trees + self.len_detached_events @@ -390,9 +308,7 @@ def __repr__(self) -> str: if self._parentless: len_parentless_trees = len(self.get_parentless_trees()) - trees_parentless_info = ( - f"[regular={len_regular_trees - len_parentless_trees}, parentless={len_parentless_trees}]" - ) + trees_parentless_info = f"[regular={len_regular_trees - len_parentless_trees}, parentless={len_parentless_trees}]" else: trees_parentless_info = "" @@ -404,7 +320,7 @@ def __repr__(self) -> str: def summary(self) -> str: """Returns the collection summary. - The same as repr(EventsTreeCollection). + The same as repr(EventTreeCollection). """ return self.__repr__() @@ -425,7 +341,7 @@ def len_parentless(self) -> int: @property def len_detached_events(self) -> int: """Returns number of detached events in the collection.""" - return sum([len(nodes_lst) for nodes_lst in self._detached_nodes.values()]) + return sum([len(events_lst) for events_lst in self._detached_nodes.values()]) def get_all_events_iter(self) -> Generator[Th2Event, None, None]: """Yields all events from the collection.""" @@ -457,7 +373,7 @@ def get_event(self, id: str) -> Optional[Th2Event]: continue if self._detached_nodes: for event in self.get_detached_events_iter(): - if self._get_event_id(event) == id: + if self._driver.get_event_id(event) == id: return event if self._parentless is not None: for tree in self._parentless: @@ -506,7 +422,8 @@ def get_children(self, id: str) -> Tuple[Th2Event]: def get_children_iter(self, id: str) -> Generator[Th2Event, None, None]: """Yields children of the event by its id. - This method applicable only for trees (regular or parentless), not for detached events. + This method is applicable only for trees (regular or parentless), + not for detached events. Args: id: Event id. @@ -531,14 +448,16 @@ def get_children_iter(self, id: str) -> Generator[Th2Event, None, None]: if not is_iter: raise EventIdNotInTree(id) - def get_parent(self, id: str) -> Th2Event: + def get_parent(self, id: str) -> Optional[Th2Event]: """Returns a parent of the event by its id. + Returns None if the provided ID is a root of any of the trees in ETC. + Args: id: Event id. Raises: - NodeIDAbsentError: If event id is not in the trees. + EventIdNotInTree: If event id is not in the tree. """ for tree in self._roots: try: @@ -548,11 +467,11 @@ def get_parent(self, id: str) -> Th2Event: if self._detached_nodes: parent_id = None for event in self.get_detached_events_iter(): - if self._get_event_id(event) == id: - parent_id = self._get_parent_event_id(event) + if self._driver.get_event_id(event) == id: + parent_id = self._driver.get_parent_event_id(event) break for event in self.get_detached_events_iter(): - if self._get_event_id(event) == parent_id: + if self._driver.get_event_id(event) == parent_id: return event if self._parentless is not None: for tree in self._parentless: @@ -560,6 +479,7 @@ def get_parent(self, id: str) -> Th2Event: return tree.get_parent(id) except EventIdNotInTree: continue + raise EventIdNotInTree(id) def get_full_path(self, id: str, field: str = None) -> List[Union[str, Th2Event]]: # noqa: D412 @@ -687,11 +607,25 @@ def findall_iter( Yields: Matching events. """ - for tree in self._roots: - yield from tree.findall_iter(filter=filter, stop=stop, max_count=max_count) + + def finder_wrapper(iterator): + nonlocal max_count + if max_count: + for tree in iterator: + if max_count <= 0: + break + for node in tree.findall_iter(filter=filter, stop=stop, max_count=max_count): + if max_count <= 0: + break + yield node + max_count -= 1 + else: + for tree in iterator: + yield from tree.findall_iter(filter=filter, stop=stop, max_count=max_count) + + yield from finder_wrapper(self._roots) if self._parentless is not None: - for tree in self._parentless: - yield from tree.findall_iter(filter=filter, stop=stop, max_count=max_count) + yield from finder_wrapper(self._parentless) def findall( self, @@ -745,7 +679,7 @@ def find(self, filter: Callable, stop: Callable = None) -> Optional[Th2Event]: return event return None - def get_subtree(self, id: str) -> "EventsTree": + def get_subtree(self, id: str) -> "EventTree": """Returns subtree of the event by its id. This method applicable only for trees (regular or parentless), not for detached events. @@ -772,38 +706,43 @@ def get_subtree(self, id: str) -> "EventsTree": continue raise EventIdNotInTree(id) - def recover_unknown_events(self, data_source: IProviderDataSource) -> None: - """Loads missed events and recover events. + def recover_unknown_events(self, preprocessor=None) -> None: + """Loads missed events and finish tree building. Args: - data_source: Data Source. - """ - resolver = self._get_events_by_id_resolver() - instance_command = resolver(data_source) + preprocessor: the function that will be executed for each recovered event before store. - previous_detached_events = list(self._detached_events().keys()) + """ + previous_detached_events = list(self._detached_parent_ids()) while previous_detached_events: - called_command = instance_command(self._detached_events().keys(), use_stub=self._stub_status) - events = data_source.command(called_command) + events = self._driver.get_events_by_id_from_source(ids=self._detached_parent_ids()) + if preprocessor is not None: + events = preprocessor(events) for event in events: - if not self._get_event_name(event) == "Broken_Event": + if not self._driver.get_event_name(event) == self._driver.stub_event_name(): self.append_event(event) - if previous_detached_events == list(self._detached_events().keys()): + dp_ids = list(self._detached_parent_ids()) + if previous_detached_events == dp_ids: + # If previous_detached_events == current, it means that we cannot recover some data. + # So break iteration to escape recursive exception. break - previous_detached_events = list(self._detached_events().keys()) + else: + previous_detached_events = dp_ids - def get_parentless_tree_collection(self) -> "EventsTreeCollection": - """Builds and returns parentless trees by detached events as EventsTreeCollection. + if self._detached_nodes: + w = "The collection were built with detached events because there are no some events in the source" + warnings.warn(w) + + def get_parentless_tree_collection(self) -> "EventTreeCollection": + """Builds and returns parentless trees by detached events as EventTreeCollection. Detached events will be removed from the collection. Returns: - EventsTreeCollection. + EventTreeCollection. """ - new_etc = self.__class__( - data=[], data_source=self._data_source, preserve_body=self._preserve_body, stub=self._stub_status - ) + new_etc = self.__class__(self._driver) new_etc._roots = self.get_parentless_trees() return new_etc diff --git a/th2_data_services/event_tree/exceptions.py b/th2_data_services/event_tree/exceptions.py new file mode 100644 index 00000000..53137223 --- /dev/null +++ b/th2_data_services/event_tree/exceptions.py @@ -0,0 +1,83 @@ +# Copyright 2022-2025 Exactpro (Exactpro Systems Limited) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +class EventIdNotInTree(Exception): + def __init__(self, id_: str): + """Exception for the case when the tree hasn't the event. + + Args: + id_: Event id. + """ + self._id = id_ + + def __str__(self): + return f"Event with the id '{self._id}' doesn't exist in the tree" + + +class FieldIsNotExist(Exception): + def __init__(self, field_name: str): + """Exception for the case when event as dict hasn't field. + + Args: + field_name: Field name. + """ + self._field_name = field_name + + def __str__(self): + return f"Event doesn't have '{self._field_name}' field" + + +class EventAlreadyExist(Exception): + def __init__(self, event_id: str): + """Exception for the case when event already exist in tree. + + Args: + event_id: Event id. + """ + self._event_id = event_id + + def __str__(self): + return f"Event with the id '{self._event_id}' already exist in tree." + + +class EventRootExist(Exception): + def __init__(self, event_id: str): + """Exception for the case when root already added in tree. + + Args: + event_id: Event id. + """ + self._event_id = event_id + + def __str__(self): + return f"Event with the id '{self._event_id}' can't be added in tree. Root event already exist." + + +class TreeLoop(Exception): + def __init__(self, event_id: str, parent_id: str): + """Exception for the case when an event has link to a parent which is its descendant. + + Args: + event_id: Event id. + parent_id: Parent id. + """ + self._event_id = event_id + self._parent_id = parent_id + + def __str__(self): + return ( + f"Event with the id '{self._event_id}' can't link to parent with id '{self._parent_id}'. " + f"The parent is descendant." + ) diff --git a/th2_data_services/event_tree/parent_event_tree_collection.py b/th2_data_services/event_tree/parent_event_tree_collection.py new file mode 100644 index 00000000..f84cc7eb --- /dev/null +++ b/th2_data_services/event_tree/parent_event_tree_collection.py @@ -0,0 +1,66 @@ +# Copyright 2022-2025 Exactpro (Exactpro Systems Limited) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +from typing import Dict, List, Optional +from th2_data_services.event_tree.event_tree import EventTree +from th2_data_services.event_tree.event_tree_collection import EventTreeCollection + + +class ParentEventTreeCollection(EventTreeCollection): + """ParentEventTreeCollections is a class like an EventsTreeCollections. + + ParentEventsTree contains all parent events that are referenced. + """ + + def _build_trees(self, events_nodes: Dict[Optional[str], List[dict]]) -> None: + """Builds trees and saves detached events. + + Args: + events_nodes: Events nodes. + """ + roots = [] + for event in events_nodes[None]: # None - is parent_event_id for root events. + event_id, event_name = self._driver.get_event_id(event), self._driver.get_event_name( + event + ) + if events_nodes[event_id]: + tree = EventTree(event_name=event_name, event_id=event_id, data=event) + roots.append(tree) + self._fill_tree(events_nodes, tree, event_id) + events_nodes.pop(None) + + self._roots = roots + self._detached_nodes = events_nodes + + def _fill_tree( + self, events_store: Dict[Optional[str], List[dict]], current_tree: EventTree, parent_id: str + ) -> None: + """Fills tree recursively. + + Args: + events_store: Events nodes. + current_tree: Tree for fill. + parent_id: Parent even id. + """ + for event in events_store[parent_id]: + event_id, event_name = self._driver.get_event_id(event), self._driver.get_event_name( + event + ) + if events_store.get(event_id): + current_tree.append_event( + event_name=event_name, event_id=event_id, parent_id=parent_id, data=event + ) + self._fill_tree(events_store, current_tree, event_id) # recursive fill + events_store.pop(parent_id) diff --git a/th2_data_services/events_tree/exceptions.py b/th2_data_services/events_tree/exceptions.py deleted file mode 100644 index f057a553..00000000 --- a/th2_data_services/events_tree/exceptions.py +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - - -class EventIdNotInTree(Exception): - def __init__(self, id_): - """Exception for the case when the tree hasn't the event. - - Args: - id_: Event id. - """ - self._id = id_ - - def __str__(self): - return f"Event with the id '{self._id}' doesn't exist in the tree" - - -class FieldIsNotExist(Exception): - def __init__(self, field_name): - """Exception for the case when event as dict hasn't field. - - Args: - field_name: Field name. - """ - self._field_name = field_name - - def __str__(self): - return f"Event doesn't have '{self._field_name}' field" diff --git a/th2_data_services/provider/exceptions.py b/th2_data_services/exceptions.py similarity index 51% rename from th2_data_services/provider/exceptions.py rename to th2_data_services/exceptions.py index 56393d47..a957c561 100644 --- a/th2_data_services/provider/exceptions.py +++ b/th2_data_services/exceptions.py @@ -1,4 +1,4 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) +# Copyright 2022-2025 Exactpro (Exactpro Systems Limited) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -14,29 +14,39 @@ class EventNotFound(Exception): - def __init__(self, id_): - """Exception for the case when the the event was not found in data source. + def __init__(self, id_, error_description): + """Exception for the case when the event was not found in data source. Args: id_: Event id. + error_description: Description of error """ self._id = id_ + self._error_description = error_description def __str__(self): - return f"Unable to find the event with id '{self._id}'" + return ( + f"An error occurred while trying to get event with id: {self._id}. " + f"Description of error: {self._error_description}" + ) class MessageNotFound(Exception): - def __init__(self, id_): - """Exception for the case when the the message was not found in data source. + def __init__(self, id_, error_description): + """Exception for the case when the message was not found in data source. Args: id_: Event id. + error_description: Description of error """ self._id = id_ + self._error_description = error_description def __str__(self): - return f"Unable to find the message with id '{self._id}'" + return ( + f"An error occurred while trying to get message with id: {self._id}. " + f"Description of error: {self._error_description}" + ) class CommandError(Exception): diff --git a/th2_data_services/filter.py b/th2_data_services/filter.py deleted file mode 100644 index b30236b3..00000000 --- a/th2_data_services/filter.py +++ /dev/null @@ -1,51 +0,0 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -from importlib_metadata import version -from typing import Sequence, Union -from warnings import warn - -v = version("th2_grpc_data_provider") - -if v == "1.1.0": # v6 - from th2_data_services.provider.v6.filters.filter import Provider6Filter as ProviderFilter # noqa -elif v == "0.1.6": # v5 - from th2_data_services.provider.v5.filters.filter import Provider5Filter as ProviderFilter # noqa - - -class Filter(ProviderFilter): - """The class for using rpt-data-provider filters API.""" - - def __init__( - self, - name: str, - values: Union[str, int, float, Sequence[Union[str, int, float]]], - negative: bool = False, - conjunct: bool = False, - ): - """Filter constructor. - - Args: - name (str): Filter name. - values (Union[str, int, float, Sequence[Union[str, int, float]]]): One string with filter value or list of filter values. - negative (bool): If true, will match events/messages that do not match those specified values. - If false, will match the events/messages by their values. Defaults to false. - conjunct (bool): If true, each of the specific filter values should be applied - If false, at least one of the specific filter values must be applied. - """ - warn( - f"{self.__class__.__name__} is deprecated. Use Filters of certain DataSource instead.", - DeprecationWarning, - stacklevel=2, - ) - super().__init__(name=name, values=values, negative=negative, conjunct=conjunct) diff --git a/th2_data_services/interfaces/__init__.py b/th2_data_services/interfaces/__init__.py index 5b6dcf9e..b04d6c59 100644 --- a/th2_data_services/interfaces/__init__.py +++ b/th2_data_services/interfaces/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) +# Copyright 2022-2025 Exactpro (Exactpro Systems Limited) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -12,6 +12,13 @@ # See the License for the specific language governing permissions and # limitations under the License. -from .adapter import * -from .command import * -from .source_api import * + +from th2_data_services.interfaces.adapter import ( + IStreamAdapter, + IRecordAdapter, +) +from th2_data_services.interfaces.command import ICommand +from th2_data_services.interfaces.data_source import IDataSource +from th2_data_services.interfaces.source_api import ISourceAPI +from th2_data_services.interfaces.struct import IEventStruct, IMessageStruct +from th2_data_services.interfaces.stub_builder import IStub, IEventStub, IMessageStub diff --git a/th2_data_services/interfaces/adapter.py b/th2_data_services/interfaces/adapter.py index 23bc7d2c..68f65b05 100644 --- a/th2_data_services/interfaces/adapter.py +++ b/th2_data_services/interfaces/adapter.py @@ -1,4 +1,4 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) +# Copyright 2022-2025 Exactpro (Exactpro Systems Limited) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -12,29 +12,22 @@ # See the License for the specific language governing permissions and # limitations under the License. -from abc import ABC, abstractmethod -from typing import Any - - -class IAdapter(ABC): - """High level interface for Adapter.""" - @abstractmethod - def handle(self, record: Any) -> Any: - pass +from abc import ABC, abstractmethod +from typing import Any, Iterable -class IMessageAdapter(IAdapter): - """Interface of Adapter for messages.""" +class IStreamAdapter(ABC): + """Interface of Adapter for streams.""" @abstractmethod - def handle(self, message: dict) -> Any: - pass + def handle(self, stream: Iterable) -> Any: + """Stream handle function that should yield data (not return).""" -class IEventAdapter(IAdapter): - """Interface of Adapter for events.""" +class IRecordAdapter(ABC): + """Interface of Adapter for record.""" @abstractmethod - def handle(self, event: dict) -> Any: - pass + def handle(self, record: dict) -> Any: + """One record handle function that should return data.""" diff --git a/th2_data_services/interfaces/command.py b/th2_data_services/interfaces/command.py index bf4ace9b..247315ca 100644 --- a/th2_data_services/interfaces/command.py +++ b/th2_data_services/interfaces/command.py @@ -1,4 +1,4 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) +# Copyright 2022-2025 Exactpro (Exactpro Systems Limited) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. + from __future__ import annotations from abc import ABC, abstractmethod diff --git a/th2_data_services/interfaces/data_source.py b/th2_data_services/interfaces/data_source.py index 776289b8..2f5c61ff 100644 --- a/th2_data_services/interfaces/data_source.py +++ b/th2_data_services/interfaces/data_source.py @@ -1,4 +1,4 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) +# Copyright 2022-2025 Exactpro (Exactpro Systems Limited) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -12,15 +12,16 @@ # See the License for the specific language governing permissions and # limitations under the License. + from __future__ import annotations from abc import ABC, abstractmethod from th2_data_services.interfaces.command import ICommand from th2_data_services.interfaces.source_api import ISourceAPI -import logging +# LOG import logging -logger = logging.getLogger(__name__) +# LOG logger = logging.getLogger(__name__) class IDataSource(ABC): diff --git a/th2_data_services/interfaces/events_tree/parent_events_tree_collection.py b/th2_data_services/interfaces/events_tree/parent_events_tree_collection.py deleted file mode 100644 index b7f9864b..00000000 --- a/th2_data_services/interfaces/events_tree/parent_events_tree_collection.py +++ /dev/null @@ -1,80 +0,0 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from typing import Dict, List, Optional - -from treelib import Node, Tree - -from th2_data_services import Data -from th2_data_services.events_tree import EventsTree -from th2_data_services.interfaces.events_tree.events_tree_collection import EventsTreeCollection -from th2_data_services.provider.interfaces.data_source import IProviderDataSource - - -class ParentEventsTreeCollection(EventsTreeCollection): - """ParentEventsTreeCollections is a class like an EventsTreeCollections. - - ParentEventsTree contains all parent events that are referenced. - """ - - def __init__( - self, - data: Data, - data_source: IProviderDataSource = None, - preserve_body: bool = False, - stub: bool = False, - ): - """ParentEventsTreeCollection constructor. - - Args: - data: Data object. - data_source: Data Source object. - preserve_body: If True then save body of event. - stub: If True it will create stub when event is broken. - """ - super().__init__(data, data_source, preserve_body, stub) - - def _build_trees(self, nodes: Dict[Optional[str], List[Node]]) -> None: - """Builds trees and saves detached events. - - Args: - nodes: Events nodes. - """ - roots = [] - for node in nodes[None]: # None - is parent_event_id for root events. - if nodes[node.identifier]: - tree = Tree() - tree.add_node(node) - roots.append(tree) - event_id: str = node.identifier - self._fill_tree(nodes, tree, event_id) - nodes.pop(None) - - self._roots = [EventsTree(root) for root in roots] - self._detached_nodes = nodes - - def _fill_tree(self, nodes: Dict[Optional[str], List[Node]], current_tree: Tree, parent_id: str) -> None: - """Fills tree recursively. - - Args: - nodes: Events nodes. - current_tree: Tree for fill. - parent_id: Parent even id. - """ - for node in nodes[parent_id]: - event_id: str = node.identifier - if nodes.get(event_id): - current_tree.add_node(node, parent=parent_id) - self._fill_tree(nodes, current_tree, event_id) # recursive fill - nodes.pop(parent_id) diff --git a/th2_data_services/interfaces/source_api.py b/th2_data_services/interfaces/source_api.py index eaa77658..eb4547d5 100644 --- a/th2_data_services/interfaces/source_api.py +++ b/th2_data_services/interfaces/source_api.py @@ -1,4 +1,4 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) +# Copyright 2022-2025 Exactpro (Exactpro Systems Limited) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. + from abc import ABC diff --git a/th2_data_services/provider/interfaces/struct.py b/th2_data_services/interfaces/struct.py similarity index 78% rename from th2_data_services/provider/interfaces/struct.py rename to th2_data_services/interfaces/struct.py index 3a536e82..ea13b477 100644 --- a/th2_data_services/provider/interfaces/struct.py +++ b/th2_data_services/interfaces/struct.py @@ -1,4 +1,4 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) +# Copyright 2022-2025 Exactpro (Exactpro Systems Limited) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -12,12 +12,15 @@ # See the License for the specific language governing permissions and # limitations under the License. + from abc import ABC class IEventStruct(ABC): """Just to mark Event Struct class. + Actually, this class doesn't describe the structure, it describes filed names. + It should look like a class with constants. """ @@ -25,5 +28,7 @@ class IEventStruct(ABC): class IMessageStruct(ABC): """Just to mark Message Struct class. + Actually, this class doesn't describe the structure, it describes filed names. + It should look like a class with constants. """ diff --git a/th2_data_services/provider/interfaces/stub_builder.py b/th2_data_services/interfaces/stub_builder.py similarity index 72% rename from th2_data_services/provider/interfaces/stub_builder.py rename to th2_data_services/interfaces/stub_builder.py index 0336b2f4..0e3edb6e 100644 --- a/th2_data_services/provider/interfaces/stub_builder.py +++ b/th2_data_services/interfaces/stub_builder.py @@ -1,4 +1,4 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) +# Copyright 2022-2025 Exactpro (Exactpro Systems Limited) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. + from abc import ABC, abstractmethod from typing import List @@ -37,22 +38,41 @@ def _define_required_fields(self) -> List[str]: def _check_req_fields(self, fields): for rf in self._required_fields: if rf not in fields: - raise TypeError(f"Required field '{rf}' is absent in changed fields list ({fields})") + raise TypeError( + f"Required field '{rf}' is absent in changed fields list ({fields})" + ) + + def _build_by_template(self, fields: dict) -> dict: + """Builds new dict by template. + + All keys will be overwrited by fields. + New keys from fields will be added to stub. + + Args: + fields: - def _build_by_template(self, fields) -> dict: + Returns: + Stub Dict + + """ template = self.template.copy() for k, v in fields.items(): - if k in template: - template[k] = v + template[k] = v return template def build(self, fields: dict) -> dict: - """Builds a stub. + """Builds a stub by template. + + All keys will be overwrited by fields. + New keys from fields will be added to stub. Args: - fields: + fields: Fields that will overwrite template. Returns: + Stub dict. + + Raises: TypeError: If required fields is absent in changed fields list. """ self._check_req_fields(fields) diff --git a/th2_data_services/interfaces/utils/__init__.py b/th2_data_services/interfaces/utils/__init__.py index e69de29b..c4e3cce3 100644 --- a/th2_data_services/interfaces/utils/__init__.py +++ b/th2_data_services/interfaces/utils/__init__.py @@ -0,0 +1,16 @@ +# Copyright 2023-2025 Exactpro (Exactpro Systems Limited) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +from th2_data_services.interfaces.utils import converter diff --git a/th2_data_services/interfaces/utils/converter.py b/th2_data_services/interfaces/utils/converter.py index aaaabaca..1e4df0b9 100644 --- a/th2_data_services/interfaces/utils/converter.py +++ b/th2_data_services/interfaces/utils/converter.py @@ -1,24 +1,77 @@ +# Copyright 2023-2025 Exactpro (Exactpro Systems Limited) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + from abc import ABC, abstractmethod -from datetime import datetime, timezone -from typing import Generic, TypeVar +from datetime import datetime +from typing import Generic, TypeVar, Tuple TimestampType = TypeVar("TimestampType") +""" +Some speed tests: +========================= + +1) Seconds to UTC datetime conversion + + [1] + %timeit datetime.fromtimestamp(seconds, tz=timezone.utc) + 329 ns � 1.16 ns per loop (mean � std. dev. of 7 runs, 1,000,000 loops each) + + [2] + %timeit datetime.utcfromtimestamp(seconds).replace(tzinfo=timezone.utc) + 781 ns � 10.8 ns per loop (mean � std. dev. of 7 runs, 1,000,000 loops each) + + [3] + %timeit datetime.utcfromtimestamp(seconds) + 116 ns � 8.47 ns per loop (mean � std. dev. of 7 runs, 10,000,000 loops each) +""" + + +# TODO -- add timezone. UTC by default. +# so we expect that user provide ts in UTC or its own timezone. +# we always return UTC, but also can configure it. + class ITimestampConverter(ABC, Generic[TimestampType]): @classmethod @abstractmethod - def parse_timestamp(cls, timestamp: TimestampType) -> (str, str): - """Returns string representation of Unix time separated to seconds and nanoseconds. + def parse_timestamp(cls, timestamp: TimestampType) -> Tuple[str, str]: + """Returns string representation of Unix time. + + Separated for seconds and nanoseconds. + + Please note, nanoseconds can have zeroes from left. e.g. 2022-03-05T23:56:44.00123Z -> ('1646524604', '001230000') """ + @classmethod + @abstractmethod + def parse_timestamp_int(cls, timestamp: TimestampType) -> Tuple[int, int]: + """Returns int representation of Unix time. + + Separated for seconds and nanoseconds. + + e.g. 2022-03-05T23:56:44.00123Z -> (1646524604, 001230000) + """ + @classmethod def to_datetime(cls, timestamp: TimestampType) -> datetime: - """Converts timestamp to datetime object. + """Converts timestamp to UTC datetime object. - If your timestamp has nanoseconds, they will be just cut (not rounding). + If your timestamp has nanoseconds, they will be just cut (not rounded). Args: timestamp: TimestampType object to convert. @@ -26,9 +79,38 @@ def to_datetime(cls, timestamp: TimestampType) -> datetime: Returns: datetime: Timestamp in python datetime format. """ + seconds, nanoseconds = cls.parse_timestamp_int(timestamp) + return datetime.utcfromtimestamp(seconds + nanoseconds // 1000 / 1_000_000) + + @classmethod + def to_seconds(cls, timestamp: TimestampType): + """Converts timestamp to seconds. + + If your timestamp has nanoseconds, they will be just cut (not rounding). + + Args: + timestamp: TimestampType object to convert. + + Returns: + int: Timestamp in seconds format. + """ + seconds, nanoseconds = cls.parse_timestamp_int(timestamp) + return seconds + + @classmethod + def to_milliseconds(cls, timestamp: TimestampType) -> int: + """Converts timestamp to milliseconds. + + If your timestamp has nanoseconds, they will be just cut (not rounding). + + Args: + timestamp: TimestampType object to convert. + + Returns: + int: Timestamp in microseconds format. + """ seconds, nanoseconds = cls.parse_timestamp(timestamp) - microseconds = nanoseconds[:-3] - return datetime.utcfromtimestamp(seconds).replace(tzinfo=timezone.utc, microsecond=int(microseconds)) + return int(f"{seconds}{nanoseconds[:-6]}") @classmethod def to_microseconds(cls, timestamp: TimestampType) -> int: @@ -57,3 +139,34 @@ def to_nanoseconds(cls, timestamp: TimestampType) -> int: """ seconds, nanoseconds = cls.parse_timestamp(timestamp) return int(f"{seconds}{nanoseconds}") + + @classmethod + def to_datetime_str(cls, timestamp: TimestampType) -> str: + """Converts timestamp to UTC datetime string in ISO format. + + Format example: + - 2022-03-06T04:56:44.123456789 + - 2022-03-06T04:56:44.000000000 + + Args: + timestamp: TimestampType object to convert. + + Returns: + str: datetime string in YYYY-MM-DDTHH:MM:SS.mmmmmm format. + """ + seconds, nanoseconds = cls.parse_timestamp(timestamp) + dt = datetime.utcfromtimestamp(int(seconds)) + return f"{dt.isoformat()}.{nanoseconds}" + + @classmethod + def to_th2_timestamp(cls, timestamp: TimestampType) -> dict: + """Converts timestamp to th2 timestamp. + + Args: + timestamp: int object to convert. + + Returns: + dict: {"epochSecond": seconds, "nano": nanoseconds} + """ + seconds, nanoseconds = cls.parse_timestamp_int(timestamp) + return {"epochSecond": seconds, "nano": nanoseconds} diff --git a/th2_data_services/interfaces/utils/resolver.py b/th2_data_services/interfaces/utils/resolver.py new file mode 100644 index 00000000..3df58c36 --- /dev/null +++ b/th2_data_services/interfaces/utils/resolver.py @@ -0,0 +1,280 @@ +# Copyright 2023-2025 Exactpro (Exactpro Systems Limited) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +from abc import ABC, abstractmethod +from typing import Any, Dict, List, Union + +""" +The idea of using resolvers: + It solves the problem of having a few DataSources with the same data, + but with different ways to get it. + + These classes provide you getter methods. + Using these classes allows you to freely switch between different data + formats and don't change your code. + + Resolvers solve the problem of data-format migration. + - fields place can be changed + - fields names can be changed + + Resolvers can work only with one event/message. + It means, if your message has sub-messages it won't work, because resolver will not + know with which sub-message should it work. + +Implementation advice: + 1. raise NotImplementedError -- if your Implementation doesn't support this getter. + +Performance impact: + It a bit slower than using naked field access `dict['key']`. + + Data len: 2521467 + Every test has 10 takes of field. It means that the total number of them: 25214670 + + get_and_return_10_fields_directly + Total time taken in : test_iterate 14.274808883666992 ~ 1766970 + get_and_return_10_fields_by_resolvers + Total time taken in : test_iterate 16.307125568389893 ~ 1546912 + DIRECT LwdpEventFieldsResolver get_and_return_10_fields_by_direct_resolvers + Total time taken in : test_iterate 16.423101902008057 ~ 1546912 + Via http_event_struct get_and_return_10_fields_via_http_event_struct + Total time taken in : test_iterate 14.83995270729065 ~ 1700247 +""" + + +class EventFieldResolver(ABC): + @staticmethod + @abstractmethod + def get_id(event) -> str: + pass + + @staticmethod + @abstractmethod + def get_parent_id(event) -> str: + pass + + @staticmethod + @abstractmethod + def get_status(event) -> str: + pass + + @staticmethod + @abstractmethod + def get_name(event) -> str: + pass + + @staticmethod + @abstractmethod + def get_batch_id(event) -> str: + pass + + @staticmethod + @abstractmethod + def get_is_batched(event) -> bool: + pass + + @staticmethod + @abstractmethod + def get_type(event) -> str: + pass + + @staticmethod + @abstractmethod + def get_start_timestamp(event) -> Dict[str, int]: + pass + + @staticmethod + @abstractmethod + def get_end_timestamp(event) -> Dict[str, int]: + pass + + @staticmethod + @abstractmethod + def get_attached_messages_ids(event) -> List[str]: + pass + + @staticmethod + @abstractmethod + def get_body(event) -> Any: + pass + + +class MessageFieldResolver(ABC): + @staticmethod + @abstractmethod + def get_direction(message) -> str: + pass + + @staticmethod + @abstractmethod + def get_session_id(message) -> str: + pass + + @staticmethod + @abstractmethod + def get_type(message) -> str: + """This field was removed since LwDP3. + + Don't use it in new scripts. + """ + + @staticmethod + @abstractmethod + def get_sequence(message) -> str: + pass + + @staticmethod + @abstractmethod + def get_timestamp(message) -> Dict[str, int]: + pass + + @staticmethod + @abstractmethod + def get_body(message) -> Union[Dict[str, Any], List[Dict[str, Any]]]: + pass + + @staticmethod + @abstractmethod + def get_body_base64(message) -> str: + pass + + @staticmethod + @abstractmethod + def get_id(message) -> str: + pass + + @staticmethod + @abstractmethod + def get_attached_event_ids(message) -> List[str]: + pass + + @staticmethod + @abstractmethod + def expand_message(message) -> List[Dict[str, Any]]: + """Extract a compounded message into a list of individual messages. + + Use it with `data.map_yield` instead of `data.map`. + + Warnings: + expand_message function is not backward-compatible. + If you use it in your scripts, there is no guarantee that everything + will work if you change data-source because different data-sources + have different messages structure. + + Args: + message: Th2Message + + Returns: + Iterable[Th2Message] + """ + + +class SubMessageFieldResolver(ABC): + @staticmethod + @abstractmethod + def get_subsequence(message) -> List[int]: + pass + + @staticmethod + @abstractmethod + def get_type(message) -> str: + pass + + @staticmethod + @abstractmethod + def get_fields(message) -> Dict[str, Any]: + pass + + @staticmethod + @abstractmethod + def get_metadata(message) -> Dict[str, Any]: + pass + + @staticmethod + @abstractmethod + def get_protocol(message) -> str: + pass + + +class ExpandedMessageFieldResolver(ABC): + @staticmethod + @abstractmethod + def get_direction(message) -> str: + pass + + @staticmethod + @abstractmethod + def get_session_id(message) -> str: + pass + + @staticmethod + @abstractmethod + def get_type(message) -> str: + pass + + @staticmethod + @abstractmethod + def get_sequence(message) -> str: + pass + + @staticmethod + @abstractmethod + def get_timestamp(message) -> Dict[str, int]: + pass + + @staticmethod + @abstractmethod + def get_body(message) -> Union[Dict[str, Any]]: + pass + + @staticmethod + @abstractmethod + def get_body_base64(message) -> str: + pass + + @staticmethod + @abstractmethod + def get_id(message) -> str: + pass + + @staticmethod + @abstractmethod + def get_attached_event_ids(message) -> List[str]: + pass + + @staticmethod + @abstractmethod + def get_subsequence(message) -> List[int]: + pass + + @staticmethod + @abstractmethod + def get_fields(message) -> Dict[str, Any]: + pass + + @staticmethod + @abstractmethod + def get_metadata(message) -> Dict[str, Any]: + pass + + @staticmethod + @abstractmethod + def get_protocol(message) -> str: + pass + + +# TODO - should be remove during release. +MessageFieldsResolver = MessageFieldResolver # For backward compatibility. +# TODO - should be remove during release. +EventFieldsResolver = EventFieldResolver # For backward compatibility. diff --git a/th2_data_services/provider/__init__.py b/th2_data_services/provider/__init__.py deleted file mode 100644 index c46552ee..00000000 --- a/th2_data_services/provider/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. diff --git a/th2_data_services/provider/adapters/__init__.py b/th2_data_services/provider/adapters/__init__.py deleted file mode 100644 index b552af90..00000000 --- a/th2_data_services/provider/adapters/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .adapter_sse import SSEAdapter diff --git a/th2_data_services/provider/adapters/adapter_sse.py b/th2_data_services/provider/adapters/adapter_sse.py deleted file mode 100644 index 534b7512..00000000 --- a/th2_data_services/provider/adapters/adapter_sse.py +++ /dev/null @@ -1,40 +0,0 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from sseclient import Event as SSEEvent -from urllib3.exceptions import HTTPError -import json - -from th2_data_services.interfaces import IAdapter - - -class SSEAdapter(IAdapter): - """SSE Adapter handles bytes from sse-stream into Dict object.""" - - def handle(self, record: SSEEvent) -> dict: - """Adapter handler. - - Args: - record: SSE Event. - - Returns: - Dict object. - """ - if record.event == "error": - raise HTTPError(record.data) - if record.event not in ["close", "keep_alive", "message_ids"]: - try: - return json.loads(record.data) - except json.JSONDecodeError as e: - raise ValueError(f"json.decoder.JSONDecodeError: Invalid json received.\n" f"{e}\n" f"{record.data}") diff --git a/th2_data_services/provider/command.py b/th2_data_services/provider/command.py deleted file mode 100644 index 57c56115..00000000 --- a/th2_data_services/provider/command.py +++ /dev/null @@ -1,43 +0,0 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -from __future__ import annotations - -from typing import Callable - -from th2_data_services.provider.interfaces.command import IProviderCommand - - -class ProviderAdaptableCommand(IProviderCommand): - def __init__(self): - """Class to make Command classes adaptable.""" - self._workflow = [] - - def apply_adapter(self, adapter: Callable) -> "ProviderAdaptableCommand": - """Adds adapter to the Command workflow. - - Note, sequence that you will add adapters make sense. - - Args: - adapter: Callable function that will be used as adapter. - - Returns: - self - """ - self._workflow.append(adapter) - return self - - def _handle_adapters(self, data): - for step in self._workflow: - data = step(data) - return data diff --git a/th2_data_services/provider/interfaces/command.py b/th2_data_services/provider/interfaces/command.py deleted file mode 100644 index c05e04e6..00000000 --- a/th2_data_services/provider/interfaces/command.py +++ /dev/null @@ -1,54 +0,0 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - - -"""Interfaces for Provider Commands.""" - -from __future__ import annotations - -from abc import abstractmethod -from typing import TYPE_CHECKING - -from th2_data_services.interfaces import ICommand - -if TYPE_CHECKING: - from th2_data_services.provider.interfaces.data_source import ( - IProviderDataSource, - IHTTPProviderDataSource, - IGRPCProviderDataSource, - ) - - -class IProviderCommand(ICommand): - """Interface of command for rpt-data-provider.""" - - @abstractmethod - def handle(self, data_source: IProviderDataSource): - pass - - -class IHTTPProviderCommand(IProviderCommand): - """Interface of command for rpt-data-provider which works via HTTP.""" - - @abstractmethod - def handle(self, data_source: IHTTPProviderDataSource): - pass - - -class IGRPCProviderCommand(IProviderCommand): - """Interface of command for rpt-data-provider which works via GRPC.""" - - @abstractmethod - def handle(self, data_source: IGRPCProviderDataSource): - pass diff --git a/th2_data_services/provider/interfaces/data_source.py b/th2_data_services/provider/interfaces/data_source.py deleted file mode 100644 index 9249d7b0..00000000 --- a/th2_data_services/provider/interfaces/data_source.py +++ /dev/null @@ -1,133 +0,0 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - - -"""Interfaces for Provider Data Source.""" - -from abc import abstractmethod - -import requests -import urllib3 - -from th2_data_services.provider.interfaces.command import IGRPCProviderCommand, IHTTPProviderCommand, IProviderCommand -from th2_data_services.interfaces.data_source import IDataSource -from th2_data_services.provider.interfaces.source_api import ( - IHTTPProviderSourceAPI, - IGRPCProviderSourceAPI, - IProviderSourceAPI, -) -from th2_data_services.provider.interfaces.struct import IEventStruct, IMessageStruct -from th2_data_services.provider.interfaces.stub_builder import IEventStub, IMessageStub - - -class IProviderDataSource(IDataSource): - def __init__( - self, - url: str, - event_struct: IEventStruct, - message_struct: IMessageStruct, - event_stub_builder: IEventStub, - message_stub_builder: IMessageStub, - ): - """Interface of DataSource that provides work with rpt-data-provider. - - Args: - url: Url address to data provider. - event_struct: Event struct class. - message_struct: Message struct class. - event_stub_builder: Event stub builder class. - message_stub_builder: Message stub builder class. - """ - if url[-1] == "/": - url = url[:-1] - self._url = url - self._event_struct = event_struct - self._message_struct = message_struct - self._event_stub_builder = event_stub_builder - self._message_stub_builder = message_stub_builder - - @property - def url(self) -> str: - """str: URL of rpt-data-provider.""" - return self._url - - @property - def event_struct(self) -> IEventStruct: - """Returns event structure class.""" - return self._event_struct - - @property - def message_struct(self) -> IMessageStruct: - """Returns message structure class.""" - return self._message_struct - - @property - def event_stub_builder(self) -> IEventStub: - """Returns event stub template.""" - return self._event_stub_builder - - @property - def message_stub_builder(self) -> IMessageStub: - """Returns message stub template.""" - return self._message_stub_builder - - @abstractmethod - def command(self, cmd: IProviderCommand): - """Execute the transmitted command.""" - - @property - @abstractmethod - def source_api(self) -> IProviderSourceAPI: - """Returns Provider API.""" - - -class IHTTPProviderDataSource(IProviderDataSource): - """Interface of DataSource that provides work with rpt-data-provider via HTTP.""" - - @abstractmethod - def command(self, cmd: IHTTPProviderCommand): - """Execute the transmitted HTTP command.""" - - def check_connect(self, timeout: (int, float), certification: bool = True) -> None: - """Checks whether url is working. - - Args: - timeout: How many seconds to wait for the server to send data before giving up. - certification: Checking SSL certification. - - Raises: - urllib3.exceptions.HTTPError: If unable to connect to host. - """ - try: - requests.get(self.url, timeout=timeout, verify=certification) - except ConnectionError as error: - raise urllib3.exceptions.HTTPError(f"Unable to connect to host '{self.url}'\nReason: {error}") - - @property - @abstractmethod - def source_api(self) -> IHTTPProviderSourceAPI: - """Returns HTTP Provider API.""" - - -class IGRPCProviderDataSource(IProviderDataSource): - """Interface of DataSource that provides work with rpt-data-provider via GRPC.""" - - @abstractmethod - def command(self, cmd: IGRPCProviderCommand): - """Execute the transmitted GRPC command.""" - - @property - @abstractmethod - def source_api(self) -> IGRPCProviderSourceAPI: - """Returns GRPC Provider API.""" diff --git a/th2_data_services/provider/utils/__init__.py b/th2_data_services/provider/utils/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/th2_data_services/provider/utils/converters.py b/th2_data_services/provider/utils/converters.py deleted file mode 100644 index 30eccf99..00000000 --- a/th2_data_services/provider/utils/converters.py +++ /dev/null @@ -1,15 +0,0 @@ -from th2_data_services.interfaces.utils.converter import ITimestampConverter - - -class Th2TimestampConverter(ITimestampConverter[dict]): - """Converts Th2 timestamps. - - If you request microseconds but your timestamp has nanoseconds, they will be just cut (not rounding). - - Expected timestamp format {'epochSecond': 123, 'nano': 500}. - """ - - @classmethod - def parse_timestamp(cls, timestamp: dict) -> (str, str): - seconds, nanoseconds = timestamp["epochSecond"], f"{timestamp['nano']:0>9}" - return seconds, nanoseconds diff --git a/th2_data_services/provider/utils/version_checker.py b/th2_data_services/provider/utils/version_checker.py deleted file mode 100644 index 8109ba16..00000000 --- a/th2_data_services/provider/utils/version_checker.py +++ /dev/null @@ -1,33 +0,0 @@ -import os -import re -import subprocess -import sys -from typing import List - - -def get_version_by_pip(package_name: str): # noqa: D103 - pip_run = subprocess.run([sys.executable, "-m", "pip", "show", package_name], capture_output=True) - if pip_run.returncode != 0: - return None - - output = pip_run.stdout.decode() - matches = re.findall(r"Version: (.*)", output) - return matches[0] - - -def get_package_version(package_name: str): # noqa: D103 - version = get_version_by_pip(package_name) - # TODO: get version in case of conda - return version - - -def verify_grpc_version(valid: List[str]): # noqa: D103 - if os.environ.get("TH2_DS_SKIP_GRPC_VERIFY", "0") == "1": - return - version = get_package_version("th2_grpc_data_provider") - - if not version: - raise SystemError(f"Package th2_grpc_data_provider not found") - - if version not in valid: - raise SystemError(f"There is unsupported version of th2_grpc_data_provider for v5 provider api ({version})") diff --git a/th2_data_services/provider/v5/adapters/__init__.py b/th2_data_services/provider/v5/adapters/__init__.py deleted file mode 100644 index 92eaf36f..00000000 --- a/th2_data_services/provider/v5/adapters/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .basic_adapters import GRPCObjectToDictAdapter -from .event_adapters import DeleteEventWrappersAdapter -from .message_adapters import CodecPipelinesAdapter, DeleteMessageWrappersAdapter diff --git a/th2_data_services/provider/v5/adapters/basic_adapters.py b/th2_data_services/provider/v5/adapters/basic_adapters.py deleted file mode 100644 index faa26ae4..00000000 --- a/th2_data_services/provider/v5/adapters/basic_adapters.py +++ /dev/null @@ -1,55 +0,0 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -import json -from typing import Union - -from th2_data_services.interfaces.adapter import IAdapter - -from google.protobuf.json_format import MessageToDict -from th2_grpc_data_provider.data_provider_template_pb2 import EventData, MessageData - - -class GRPCObjectToDictAdapter(IAdapter): - """GRPC Adapter decodes a GRPC object into a Dict object.""" - - def handle(self, record: Union[MessageData, EventData]) -> dict: - """Decodes MessageData or EventData as GRPC object into a Dict object. - - Args: - record: MessageData/EventData. - - Returns: - Dict object. - """ - new_record = MessageToDict(record, including_default_value_fields=True) - - if isinstance(record, EventData): - new_record["startTimestamp"] = { - "epochSecond": record.start_timestamp.seconds, - "nano": record.start_timestamp.nanos, - } - new_record["endTimestamp"] = { - "epochSecond": record.end_timestamp.seconds, - "nano": record.end_timestamp.nanos, - } - elif isinstance(record, MessageData): - new_record["timestamp"] = {"epochSecond": record.timestamp.seconds, "nano": record.timestamp.nanos} - - try: - new_record["body"] = json.loads(record.body) - except (KeyError, AttributeError, json.JSONDecodeError): - return new_record - except Exception as e: - raise Exception(f"{e}; Current record: {record}") - return new_record diff --git a/th2_data_services/provider/v5/adapters/event_adapters.py b/th2_data_services/provider/v5/adapters/event_adapters.py deleted file mode 100644 index fc2bb6ac..00000000 --- a/th2_data_services/provider/v5/adapters/event_adapters.py +++ /dev/null @@ -1,65 +0,0 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from th2_data_services.interfaces.adapter import IEventAdapter -from th2_data_services.provider.v5.struct import Provider5EventStruct, provider5_event_struct - - -class DeleteEventWrappersAdapter(IEventAdapter): - """Adapter that deletes unnecessary wrappers in events. - - It used for events to which an AdaptorGRPCObjectToDict has been applied. - """ - - def __init__(self, event_struct: Provider5EventStruct = provider5_event_struct): - """AdapterDeleteEventWrappers constructor. - - Args: - event_struct: Event struct. - """ - self._event_struct = event_struct - - def handle(self, event: dict) -> dict: - """Deletes unnecessary wrappers for fields eventId, parentEventId and BatchId. - - Args: - event: Event. - - Returns: - Event without wrappers. - """ - event_id_field = self._event_struct.EVENT_ID - parent_event_id_field = self._event_struct.PARENT_EVENT_ID - batch_id_field = self._event_struct.BATCH_ID - - event_id = self.__get_id_from_wrapper(event, event_id_field) - parent_event_id = self.__get_id_from_wrapper(event, parent_event_id_field) - batch_id = self.__get_id_from_wrapper(event, batch_id_field) - - if event_id: - event[event_id_field] = event_id - if parent_event_id: - event[parent_event_id_field] = parent_event_id - if batch_id: - event[batch_id_field] = batch_id - - return event - - @staticmethod - def __get_id_from_wrapper(event: dict, field: str): - """Opens the wrapper and getting the id.""" - wrapper: dict = event.get(field) - if wrapper: - return wrapper["id"] - return None diff --git a/th2_data_services/provider/v5/adapters/message_adapters.py b/th2_data_services/provider/v5/adapters/message_adapters.py deleted file mode 100644 index 6962fcbd..00000000 --- a/th2_data_services/provider/v5/adapters/message_adapters.py +++ /dev/null @@ -1,140 +0,0 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -import pprint -from _warnings import warn -from typing import Union, List - -from th2_data_services.interfaces.adapter import IMessageAdapter -from th2_data_services.provider.v5.struct import Provider5MessageStruct, provider5_message_struct - - -class DeleteMessageWrappersAdapter(IMessageAdapter): - """Adapter that deletes unnecessary wrappers in messages. - - It used for the message to which an AdaptorGRPCObjectToDict has been applied. - """ - - def __init__(self, message_struct: Provider5MessageStruct = provider5_message_struct): - """AdapterDeleteMessageWrappers constructor. - - Args: - message_struct: Message struct. - """ - self._message_struct = message_struct - - def handle(self, message: dict) -> dict: - """Deletes unnecessary wrappers for field message_id. - - Args: - message: Message. - - Returns: - Message without wrappers. - """ - message_id_field = self._message_struct.MESSAGE_ID - - message_id = message[message_id_field] - - session = message_id[self._message_struct.CONNECTION_ID][self._message_struct.SESSION_ALIAS] - direction = message_id[self._message_struct.DIRECTION] - sequence = message_id[self._message_struct.SEQUENCE] - - message_id = f"{session}:{direction}:{sequence}" - message[message_id_field] = message_id - - return message - - -class CodecPipelinesAdapter(IMessageAdapter): - """Adapter for codec-pipeline messages from provider v5. - - Codec-pipeline messages have sub-messages in the body. - This adapter used for split codec-pipeline message to separate messages. - """ - - def __init__(self, ignore_errors=False): - """AdapterCodecPipelines constructor. - - Args: - ignore_errors: If True it will ignore errors and return message as is. - """ - self._ignore_errors = ignore_errors - - def handle(self, message: dict) -> Union[List[dict], dict]: - """Adapter handler. - - Args: - message: Th2Message dict. - - Returns: - Th2Message dict. - """ - msg_type = message.get("messageType") - if msg_type is None: - if self._ignore_errors: - warn( - "Please note, some messages don't have a messageType field. Perhaps a codec didn't decode them.", - stacklevel=3, - ) - return message - else: - raise ValueError( - "The messages doesn't have a messageType field. Message:\n" f"{pprint.pformat(message)}" - ) - - if "/" not in msg_type: - return message - - body = message["body"] - if not body: - return message - - sub_messages = [] - fields = body["fields"] - if not fields: - return message - - for sub_msg in fields: - split_msg_name = sub_msg.split("-") - if len(split_msg_name) > 1: - sub_msg_type, index = "".join(split_msg_name[:-1]), int(split_msg_name[-1]) - else: - index = msg_type.split("/").index(sub_msg) + 1 - sub_msg_type = sub_msg - - new_record = message.copy() - - metadata = new_record["body"]["metadata"].copy() - id_field = metadata["id"].copy() - id_field["subsequence"] = [index] - metadata["id"] = id_field - - body_fields = fields[sub_msg] - metadata.update(body_fields.get("metadata", {})) - - body = {"metadata": metadata} - if body_fields.get("messageValue"): - body = {**body_fields["messageValue"], **body} - elif body_fields.get("fields"): - body = {**body_fields["fields"], **body} - else: - body = {"fields": {}, **body} - - new_record["body"] = body - new_record["body"]["metadata"]["messageType"] = sub_msg_type - new_record["messageType"] = sub_msg_type - new_record["messageId"] = f"{message['messageId']}.{index}" - sub_messages.append(new_record) - - return sub_messages diff --git a/th2_data_services/provider/v5/command_resolver.py b/th2_data_services/provider/v5/command_resolver.py deleted file mode 100644 index e94624a3..00000000 --- a/th2_data_services/provider/v5/command_resolver.py +++ /dev/null @@ -1,63 +0,0 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from typing import Union, Type - -from th2_data_services.provider.interfaces import IProviderDataSource -from th2_data_services.provider.v5.commands.grpc import GetEventsById as GetEventsByIdFromGRPC -from th2_data_services.provider.v5.commands.http import GetEventsById as GetEventsByIdFromHTTP - -from th2_data_services.provider.v5.commands.grpc import GetEventById as GetEventByIdFromGRPC -from th2_data_services.provider.v5.commands.http import GetEventById as GetEventByIdFromHTTP - -from th2_data_services.provider.v5.data_source.grpc import GRPCProvider5DataSource -from th2_data_services.provider.v5.data_source.http import HTTPProvider5DataSource - - -def resolver_get_event_by_id( - data_source: IProviderDataSource, -) -> Union[Type[GetEventByIdFromHTTP], Type[GetEventByIdFromGRPC]]: - """Resolves what 'GetEventById' command you need to use based Data Source. - - Args: - data_source: DataSource instance. - - Returns: - GetEventById command. - """ - if isinstance(data_source, GRPCProvider5DataSource): - return GetEventByIdFromGRPC - elif isinstance(data_source, HTTPProvider5DataSource): - return GetEventByIdFromHTTP - else: - raise ValueError("Unknown DataSource Object") - - -def resolver_get_events_by_id( - data_source: IProviderDataSource, -) -> Union[Type[GetEventsByIdFromHTTP], Type[GetEventsByIdFromGRPC]]: - """Resolves what 'GetEventsById' command you need to use based Data Source. - - Args: - data_source: DataSource instance. - - Returns: - GetEventsById command. - """ - if isinstance(data_source, GRPCProvider5DataSource): - return GetEventsByIdFromGRPC - elif isinstance(data_source, HTTPProvider5DataSource): - return GetEventsByIdFromHTTP - else: - raise ValueError("Unknown DataSource Object") diff --git a/th2_data_services/provider/v5/commands/grpc.py b/th2_data_services/provider/v5/commands/grpc.py deleted file mode 100644 index 2dbbc6c6..00000000 --- a/th2_data_services/provider/v5/commands/grpc.py +++ /dev/null @@ -1,559 +0,0 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from datetime import datetime, timezone -from functools import partial -from typing import List, Iterable, Generator - -from grpc._channel import _InactiveRpcError -from th2_grpc_data_provider.data_provider_template_pb2 import ( - EventData, - MessageData, -) - -from th2_data_services import Filter, Data -from th2_data_services.provider.command import ProviderAdaptableCommand -from th2_data_services.provider.exceptions import EventNotFound, MessageNotFound -from th2_data_services.provider.v5.adapters.basic_adapters import GRPCObjectToDictAdapter -from th2_data_services.provider.v5.adapters.event_adapters import DeleteEventWrappersAdapter -from th2_data_services.provider.v5.adapters.message_adapters import DeleteMessageWrappersAdapter -from th2_data_services.provider.v5.interfaces.command import IGRPCProvider5Command - -from th2_data_services.provider.v5.data_source.grpc import GRPCProvider5DataSource -from th2_data_services.provider.v5.provider_api import GRPCProvider5API - -import logging - -logger = logging.getLogger(__name__) - - -class GetEventByIdGRPCObject(IGRPCProvider5Command, ProviderAdaptableCommand): - """A Class-Command for request to rpt-data-provider. - - It retrieves the event by id as GRPC object. - - Returns: - EventData: Th2 event. - """ - - def __init__(self, id: str): - """GetEventByIdGRPCObject constructor. - - Args: - id: Event id. - - """ - super().__init__() - self._id = id - - def handle(self, data_source: GRPCProvider5DataSource) -> EventData: # noqa: D102 - api: GRPCProvider5API = data_source.source_api - event = api.get_event(self._id) - - event = self._handle_adapters(event) - return event - - -class GetEventById(IGRPCProvider5Command, ProviderAdaptableCommand): - """A Class-Command for request to rpt-data-provider. - - It retrieves the event by id with `attachedMessageIds` list. - - Returns: - dict: Th2 event. - - Raises: - EventNotFound: If event by Id wasn't found. - """ - - def __init__(self, id: str, use_stub=False): - """GetEventById constructor. - - Args: - id: Event id. - use_stub: If True the command returns stub instead of exception. - - """ - super().__init__() - self._id = id - self._grpc_decoder = GRPCObjectToDictAdapter() - self._wrapper_deleter = DeleteEventWrappersAdapter() - self._stub_status = use_stub - - def handle(self, data_source: GRPCProvider5DataSource) -> dict: # noqa: D102 - try: - event = GetEventByIdGRPCObject(self._id).handle(data_source) - event = self._grpc_decoder.handle(event) - event = self._wrapper_deleter.handle(event) - except _InactiveRpcError: - if self._stub_status: - event = data_source.event_stub_builder.build({data_source.event_struct.EVENT_ID: self._id}) - else: - logger.error(f"Unable to find the event. Id: {self._id}") - raise EventNotFound(self._id) - - event = self._handle_adapters(event) - return event - - -class GetEventsById(IGRPCProvider5Command, ProviderAdaptableCommand): - """A Class-Command for request to rpt-data-provider. - - It retrieves the events by ids with `attachedMessageIds` list. - - Returns: - List[dict]: Th2 events. - - Raises: - EventNotFound: If any event by Id wasn't found. - """ - - def __init__(self, ids: List[str], use_stub=False): - """GetEventsById constructor. - - Args: - ids: Events ids. - use_stub: If True the command returns stub instead of exception. - - """ - super().__init__() - self.ids = ids - self._stub_status = use_stub - - def handle(self, data_source: GRPCProvider5DataSource) -> List[dict]: # noqa: D102 - response = [] - for event_id in self.ids: - event = GetEventById(event_id, use_stub=self._stub_status).handle(data_source=data_source) - event = self._handle_adapters(event) - response.append(event) - - return response - - -class GetEventsGRPCObjects(IGRPCProvider5Command, ProviderAdaptableCommand): - """A Class-Command for request to rpt-data-provider. - - It searches events stream as GRPC object by options. - - Returns: - Iterable[EventData]: Stream of Th2 events. - """ - - def __init__( - self, - start_timestamp: datetime, - end_timestamp: datetime = None, - parent_event: str = None, - search_direction: str = "NEXT", - resume_from_id: str = None, - result_count_limit: int = None, - keep_open: bool = False, - limit_for_parent: int = None, - attached_messages: bool = False, - filters: List[Filter] = None, - ): - """GetEventsGRPCObjects constructor. - - Args: - start_timestamp: Start timestamp of search. - end_timestamp: End timestamp of search. - resume_from_id: Event id from which search starts. - parent_event: Match events to the specified parent. - search_direction: Search direction. - result_count_limit: Result count limit. - keep_open: If the search has reached the current moment. - It is need to wait further for the appearance of new data. - the one closest to the specified timestamp. - limit_for_parent: How many children events for each parent do we want to request. - attached_messages: Gets messages ids which linked to events. - filters: Filters using in search for messages. - - """ - super().__init__() - self._start_timestamp = start_timestamp - self._end_timestamp = end_timestamp - self._parent_event = parent_event - self._search_direction = search_direction - self._resume_from_id = resume_from_id - self._result_count_limit = result_count_limit - self._keep_open = keep_open - self._limit_for_parent = limit_for_parent - self._metadata_only = False - self._attached_messages = attached_messages - self._filters = filters - - def handle(self, data_source: GRPCProvider5DataSource) -> Iterable[EventData]: # noqa: D102 - api: GRPCProvider5API = data_source.source_api - - start_timestamp = int(self._start_timestamp.replace(tzinfo=timezone.utc).timestamp() * 10 ** 9) - end_timestamp = int(self._end_timestamp.replace(tzinfo=timezone.utc).timestamp() * 10 ** 9) - - stream_response = api.search_events( - start_timestamp=start_timestamp, - end_timestamp=end_timestamp, - parent_event=self._parent_event, - search_direction=self._search_direction, - resume_from_id=self._resume_from_id, - result_count_limit=self._result_count_limit, - keep_open=self._keep_open, - limit_for_parent=self._limit_for_parent, - metadata_only=self._metadata_only, - attached_messages=self._attached_messages, - filters=self._filters, - ) - for response in stream_response: - if response.WhichOneof("data") == "event": - response = self._handle_adapters(response) - yield response.event - - -class GetEvents(IGRPCProvider5Command, ProviderAdaptableCommand): - """A Class-Command for request to rpt-data-provider. - - It searches events stream by options. - - Returns: - Iterable[dict]: Stream of Th2 events. - """ - - def __init__( - self, - start_timestamp: datetime, - end_timestamp: datetime = None, - parent_event: str = None, - search_direction: str = "NEXT", - resume_from_id: str = None, - result_count_limit: int = None, - keep_open: bool = False, - limit_for_parent: int = None, - attached_messages: bool = False, - filters: List[Filter] = None, - cache: bool = False, - ): - """GetEvents constructor. - - Args: - start_timestamp: Start timestamp of search. - end_timestamp: End timestamp of search. - resume_from_id: Event id from which search starts. - parent_event: Match events to the specified parent. - search_direction: Search direction. - result_count_limit: Result count limit. - keep_open: If the search has reached the current moment. - It is need to wait further for the appearance of new data. - the one closest to the specified timestamp. - limit_for_parent: How many children events for each parent do we want to request. - attached_messages: Gets messages ids which linked to events. - filters: Filters using in search for messages. - cache: If True, all requested data from rpt-data-provider will be saved to cache. - - """ - super().__init__() - self._start_timestamp = start_timestamp - self._end_timestamp = end_timestamp - self._parent_event = parent_event - self._search_direction = search_direction - self._resume_from_id = resume_from_id - self._result_count_limit = result_count_limit - self._keep_open = keep_open - self._limit_for_parent = limit_for_parent - self._metadata_only = False - self._attached_messages = attached_messages - self._filters = filters - self._cache = cache - - self._grpc_decoder = GRPCObjectToDictAdapter() - self._wrapper_deleter = DeleteEventWrappersAdapter() - - def handle(self, data_source: GRPCProvider5DataSource) -> Data: # noqa: D102 - source = partial(self.__handle_stream, data_source) - return Data(source, cache=self._cache) - - def __handle_stream(self, data_source: GRPCProvider5DataSource) -> Generator[dict, None, None]: - stream = GetEventsGRPCObjects( - start_timestamp=self._start_timestamp, - end_timestamp=self._end_timestamp, - parent_event=self._parent_event, - search_direction=self._search_direction, - resume_from_id=self._resume_from_id, - result_count_limit=self._result_count_limit, - keep_open=self._keep_open, - limit_for_parent=self._limit_for_parent, - attached_messages=self._attached_messages, - filters=self._filters, - ).handle(data_source) - for event in stream: - event = self._grpc_decoder.handle(event) - event = self._wrapper_deleter.handle(event) - event = self._handle_adapters(event) - yield event - - -class GetMessageByIdGRPCObject(IGRPCProvider5Command, ProviderAdaptableCommand): # noqa: D102 - """A Class-Command for request to rpt-data-provider. - - It retrieves the message by id as GRPC Object. - - Returns: - MessageData: Th2 message. - """ - - def __init__(self, id: str): - """GetMessageByIdGRPCObject constructor. - - Args: - id: Message id. - - """ - super().__init__() - self._id = id - - def handle(self, data_source: GRPCProvider5DataSource) -> MessageData: - api: GRPCProvider5API = data_source.source_api - response = api.get_message(self._id) - response = self._handle_adapters(response) - return response - - -class GetMessageById(IGRPCProvider5Command, ProviderAdaptableCommand): # noqa: D102 - """A Class-Command for request to rpt-data-provider. - - It retrieves the message by id. - - Please note, Provider5 doesn't return `attachedEventIds`. It will be == []. - It's expected that Provider7 will be support it. - - Returns: - dict: Th2 message. - - Raises: - MessageNotFound: If message by id wasn't found. - """ - - def __init__(self, id: str, use_stub=False): - """GetMessageById constructor. - - Args: - id: Message id. - use_stub: If True the command returns stub instead of exception. - - """ - super().__init__() - self._id = id - self._decoder = GRPCObjectToDictAdapter() - self._wrapper_deleter = DeleteMessageWrappersAdapter() - self._stub_status = use_stub - - def handle(self, data_source: GRPCProvider5DataSource) -> dict: # noqa: D102 - try: - message = GetMessageByIdGRPCObject(self._id).handle(data_source) - message = self._decoder.handle(message) - message = self._wrapper_deleter.handle(message) - except _InactiveRpcError: - if self._stub_status: - message = data_source.message_stub_builder.build({data_source.message_struct.MESSAGE_ID: self._id}) - else: - logger.error(f"Unable to find the message. Id: {self._id}") - raise MessageNotFound(self._id) - message = self._handle_adapters(message) - return message - - -class GetMessagesById(IGRPCProvider5Command, ProviderAdaptableCommand): - """A Class-Command for request to rpt-data-provider. - - It retrieves the messages by id. - - Please note, Provider5 doesn't return `attachedEventIds`. It will be == []. - It's expected that Provider7 will be support it. - - Returns: - List[dict]: Th2 messages. - - Raises: - MessageNotFound: If any message by id wasn't found. - """ - - def __init__(self, ids: List[str], use_stub=False): - """GetMessagesById constructor. - - Args: - ids: Messages id. - use_stub: If True the command returns stub instead of exception. - - """ - super().__init__() - self._ids = ids - self._stub_status = use_stub - - def handle(self, data_source: GRPCProvider5DataSource) -> List[dict]: # noqa: D102 - response = [] - for id_ in self._ids: - message = GetMessageById(id_, use_stub=self._stub_status).handle(data_source) - message = self._handle_adapters(message) - response.append(message) - - return response - - -class GetMessagesGRPCObject(IGRPCProvider5Command, ProviderAdaptableCommand): - """A Class-Command for request to rpt-data-provider. - - It searches messages stream as GRPC object by options. - - Returns: - Iterable[MessageData]: Stream of Th2 messages. - """ - - def __init__( - self, - start_timestamp: datetime, - stream: List[str], - end_timestamp: datetime = None, - resume_from_id: str = None, - search_direction: str = "NEXT", - result_count_limit: int = None, - keep_open: bool = False, - message_id: List[str] = None, - attached_events: bool = False, - filters: List[Filter] = None, - ): - """GetMessagesGRPCObject constructor. - - Args: - start_timestamp: Start timestamp of search. - end_timestamp: End timestamp of search. - stream: Alias of messages. - resume_from_id: Message id from which search starts. - search_direction: Search direction. - result_count_limit: Result count limit. - keep_open: If the search has reached the current moment. - It is need to wait further for the appearance of new data. - message_id: List of message ids to restore the search - attached_events: If true, it will additionally load attachedEventsIds. - filters: Filters using in search for messages. - """ - super().__init__() - self._start_timestamp = start_timestamp - self._end_timestamp = end_timestamp - self._stream = stream - self._resume_from_id = resume_from_id - self._search_direction = search_direction - self._result_count_limit = result_count_limit - self._keep_open = keep_open - self._filters = filters - self._message_id = message_id - self._attached_events = attached_events - - def handle(self, data_source: GRPCProvider5DataSource) -> List[MessageData]: - api = data_source.source_api - - start_timestamp = int(self._start_timestamp.replace(tzinfo=timezone.utc).timestamp() * 10 ** 9) - end_timestamp = int(self._end_timestamp.replace(tzinfo=timezone.utc).timestamp() * 10 ** 9) - - stream_response = api.search_messages( - start_timestamp=start_timestamp, - end_timestamp=end_timestamp, - stream=self._stream, - resume_from_id=self._resume_from_id, - search_direction=self._search_direction, - result_count_limit=self._result_count_limit, - keep_open=self._keep_open, - filters=self._filters, - message_id=self._message_id, - attached_events=self._attached_events, - ) - for response in stream_response: - if response.WhichOneof("data") == "message": - response = self._handle_adapters(response) - yield response.message - - -class GetMessages(IGRPCProvider5Command, ProviderAdaptableCommand): - """A Class-Command for request to rpt-data-provider. - - It searches messages stream by options. - - Returns: - Iterable[dict]: Stream of Th2 messages. - """ - - def __init__( - self, - start_timestamp: datetime, - stream: List[str], - end_timestamp: datetime = None, - resume_from_id: str = None, - search_direction: str = "NEXT", - result_count_limit: int = None, - keep_open: bool = False, - filters: List[Filter] = None, - message_id: List[str] = None, - attached_events: bool = False, - cache: bool = False, - ): - """GetMessages constructor. - - Args: - start_timestamp: Start timestamp of search. - end_timestamp: End timestamp of search. - stream: Alias of messages. - resume_from_id: Message id from which search starts. - search_direction: Search direction. - result_count_limit: Result count limit. - keep_open: If the search has reached the current moment. - It is need to wait further for the appearance of new data. - filters: Filters using in search for messages. - message_id: List of message ids to restore the search - attached_events: If true, it will additionally load attachedEventsIds. - cache: If True, all requested data from rpt-data-provider will be saved to cache. - """ - super().__init__() - self._start_timestamp = start_timestamp - self._end_timestamp = end_timestamp - self._stream = stream - self._resume_from_id = resume_from_id - self._search_direction = search_direction - self._result_count_limit = result_count_limit - self._keep_open = keep_open - self._filters = filters - self._message_id = message_id - self._attached_events = attached_events - self._cache = cache - - self._decoder = GRPCObjectToDictAdapter() - self._wrapper_deleter = DeleteMessageWrappersAdapter() - - def handle(self, data_source: GRPCProvider5DataSource) -> Data: - source = partial(self.__handle_stream, data_source) - return Data(source, cache=self._cache) - - def __handle_stream(self, data_source: GRPCProvider5DataSource) -> Iterable[dict]: - stream = GetMessagesGRPCObject( - start_timestamp=self._start_timestamp, - end_timestamp=self._end_timestamp, - stream=self._stream, - resume_from_id=self._resume_from_id, - search_direction=self._search_direction, - result_count_limit=self._result_count_limit, - keep_open=self._keep_open, - message_id=self._message_id, - attached_events=self._attached_events, - filters=self._filters, - ).handle(data_source) - for message in stream: - message = self._decoder.handle(message) - message = self._wrapper_deleter.handle(message) - message = self._handle_adapters(message) - yield message diff --git a/th2_data_services/provider/v5/commands/http.py b/th2_data_services/provider/v5/commands/http.py deleted file mode 100644 index e9632b7e..00000000 --- a/th2_data_services/provider/v5/commands/http.py +++ /dev/null @@ -1,699 +0,0 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from typing import Generator, List, Sequence, Union -from datetime import datetime, timezone -from functools import partial - -from th2_data_services import Filter, Data -from th2_data_services.provider.exceptions import EventNotFound, MessageNotFound -from th2_data_services.provider.v5.interfaces.command import IHTTPProvider5Command -from th2_data_services.provider.v5.data_source.http import HTTPProvider5DataSource -from th2_data_services.provider.v5.filters.filter import ( - Provider5EventFilter, - Provider5MessageFilter, -) -from th2_data_services.provider.v5.provider_api import HTTPProvider5API -from th2_data_services.provider.command import ProviderAdaptableCommand -from th2_data_services.sse_client import SSEClient -from th2_data_services.provider.adapters.adapter_sse import SSEAdapter -from th2_data_services.decode_error_handler import UNICODE_REPLACE_HANDLER - -import logging - -logger = logging.getLogger(__name__) - -EventFilters = Union[Filter, Provider5EventFilter, Sequence[Union[Filter, Provider5EventFilter]]] -MessageFilters = Union[Filter, Provider5MessageFilter, Sequence[Union[Filter, Provider5MessageFilter]]] - - -def _convert_filters_to_string(filters): - if not filters: - return None - filters_res = filters - if not isinstance(filters_res, (tuple, list)): - filters_res = [filters_res] - - return "".join([filter_.url() for filter_ in filters_res]) - - -class GetEventById(IHTTPProvider5Command, ProviderAdaptableCommand): - """A Class-Command for request to rpt-data-provider. - - It retrieves the event by id with `attachedMessageIds` list. - - Returns: - dict: Th2 event. - - Raises: - EventNotFound: If event by Id wasn't found. - """ - - def __init__(self, id: str, use_stub: bool = False): - """GetEventById constructor. - - Args: - id: Event id. - use_stub: If True the command returns stub instead of exception. - """ - super().__init__() - self._id = id - self._stub_status = use_stub - - def handle(self, data_source: HTTPProvider5DataSource) -> dict: # noqa: D102 - api: HTTPProvider5API = data_source.source_api - url = api.get_url_find_event_by_id(self._id) - - logger.info(url) - - response = api.execute_request(url) - - if response.status_code == 404 and self._stub_status: - return data_source.event_stub_builder.build({data_source.event_struct.EVENT_ID: self._id}) - elif response.status_code == 404: - logger.error(f"Unable to find the message. Id: {self._id}") - raise EventNotFound(self._id) - else: - return self._handle_adapters(response.json()) - - -class GetEventsById(IHTTPProvider5Command, ProviderAdaptableCommand): - """A Class-Command for request to rpt-data-provider. - - It retrieves the events by ids with `attachedMessageIds` list. - - Returns: - List[dict]: Th2 events. - - Raises: - EventNotFound: If any event by Id wasn't found. - """ - - def __init__(self, ids: List[str], use_stub: bool = False): - """GetEventsById constructor. - - Args: - ids: Event id list. - use_stub: If True the command returns stub instead of exception. - """ - super().__init__() - self._ids: ids = ids - self._stub_status = use_stub - - def handle(self, data_source: HTTPProvider5DataSource): # noqa: D102 - result = [] - for event_id in self._ids: - event = GetEventById(event_id, use_stub=self._stub_status).handle(data_source) - result.append(self._handle_adapters(event)) - - return result - - -class GetEventsSSEBytes(IHTTPProvider5Command, ProviderAdaptableCommand): - """A Class-Command for request to rpt-data-provider. - - It searches events stream by options. - - Returns: - Iterable[dict]: Stream of Th2 events. - """ - - def __init__( - self, - start_timestamp: datetime, - end_timestamp: datetime = None, - parent_event: str = None, - search_direction: str = "next", - resume_from_id: str = None, - result_count_limit: int = None, - keep_open: bool = False, - limit_for_parent: int = None, - attached_messages: bool = False, - filters: EventFilters = None, - ): - """GetEventsSSEBytes constructor. - - Args: - start_timestamp: Start timestamp of search. - end_timestamp: End timestamp of search. - parent_event: Match events to the specified parent. - search_direction: Search direction. - resume_from_id: Event id from which search starts. - result_count_limit: Result count limit. - keep_open: If the search has reached the current moment. - It is need to wait further for the appearance of new data. - the one closest to the specified timestamp. - limit_for_parent: How many children events for each parent do we want to request. - attached_messages: Gets messages ids which linked to events. - filters: Filters using in search for messages. - - """ - super().__init__() - self._start_timestamp = int(1000 * start_timestamp.replace(tzinfo=timezone.utc).timestamp()) - self._end_timestamp = int(1000 * end_timestamp.replace(tzinfo=timezone.utc).timestamp()) - self._parent_event = parent_event - self._search_direction = search_direction - self._resume_from_id = resume_from_id - self._result_count_limit = result_count_limit - self._keep_open = keep_open - self._limit_for_parent = limit_for_parent - self._metadata_only = False - self._attached_messages = attached_messages - self._filters = filters - - def handle(self, data_source: HTTPProvider5DataSource): # noqa: D102 - api: HTTPProvider5API = data_source.source_api - url = api.get_url_search_sse_events( - start_timestamp=self._start_timestamp, - end_timestamp=self._end_timestamp, - parent_event=self._parent_event, - search_direction=self._search_direction, - resume_from_id=self._resume_from_id, - result_count_limit=self._result_count_limit, - keep_open=self._keep_open, - limit_for_parent=self._limit_for_parent, - metadata_only=self._metadata_only, - attached_messages=self._attached_messages, - filters=_convert_filters_to_string(self._filters), - ) - - logger.info(url) - - for response in api.execute_sse_request(url): - response = self._handle_adapters(response) - if response is not None: - yield response - - -class GetEventsSSEEvents(IHTTPProvider5Command, ProviderAdaptableCommand): - """A Class-Command for request to rpt-data-provider. - - It searches events stream by options. - - Returns: - Iterable[dict]: Stream of Th2 events. - """ - - def __init__( - self, - start_timestamp: datetime, - end_timestamp: datetime = None, - parent_event: str = None, - search_direction: str = "next", - resume_from_id: str = None, - result_count_limit: int = None, - keep_open: bool = False, - limit_for_parent: int = None, - attached_messages: bool = False, - filters: EventFilters = None, - char_enc: str = "utf-8", - decode_error_handler: str = UNICODE_REPLACE_HANDLER, - ): - """GetEventsSSEEvents constructor. - - Args: - start_timestamp: Start timestamp of search. - end_timestamp: End timestamp of search. - parent_event: Match events to the specified parent. - search_direction: Search direction. - resume_from_id: Event id from which search starts. - result_count_limit: Result count limit. - keep_open: If the search has reached the current moment. - It is need to wait further for the appearance of new data. - the one closest to the specified timestamp. - limit_for_parent: How many children events for each parent do we want to request. - attached_messages: Gets messages ids which linked to events. - filters: Filters using in search for messages. - char_enc: Encoding for the byte stream. - decode_error_handler: Registered decode error handler. - """ - super().__init__() - self._start_timestamp = start_timestamp - self._end_timestamp = end_timestamp - self._parent_event = parent_event - self._search_direction = search_direction - self._resume_from_id = resume_from_id - self._result_count_limit = result_count_limit - self._keep_open = keep_open - self._limit_for_parent = limit_for_parent - self._attached_messages = attached_messages - self._filters = filters - self._char_enc = char_enc - self._decode_error_handler = decode_error_handler - - def handle(self, data_source: HTTPProvider5DataSource): # noqa: D102 - response = GetEventsSSEBytes( - start_timestamp=self._start_timestamp, - end_timestamp=self._end_timestamp, - parent_event=self._parent_event, - search_direction=self._search_direction, - resume_from_id=self._resume_from_id, - result_count_limit=self._result_count_limit, - keep_open=self._keep_open, - limit_for_parent=self._limit_for_parent, - attached_messages=self._attached_messages, - filters=self._filters, - ).handle(data_source) - client = SSEClient( - response, - char_enc=self._char_enc, - decode_errors_handler=self._decode_error_handler, - ) - for record in client.events(): - record = self._handle_adapters(record) - if record is not None: - yield record - - -class GetEvents(IHTTPProvider5Command, ProviderAdaptableCommand): - """A Class-Command for request to rpt-data-provider. - - It searches events stream by options. - - Returns: - Iterable[dict]: Stream of Th2 events. - """ - - def __init__( - self, - start_timestamp: datetime, - end_timestamp: datetime = None, - parent_event: str = None, - search_direction: str = "next", - resume_from_id: str = None, - result_count_limit: int = None, - keep_open: bool = False, - limit_for_parent: int = None, - attached_messages: bool = False, - filters: EventFilters = None, - cache: bool = False, - ): - """GetEvents constructor. - - Args: - start_timestamp: Start timestamp of search. - end_timestamp: End timestamp of search. - parent_event: Match events to the specified parent. - search_direction: Search direction. - resume_from_id: Event id from which search starts. - result_count_limit: Result count limit. - keep_open: If the search has reached the current moment. - It is need to wait further for the appearance of new data. - the one closest to the specified timestamp. - limit_for_parent: How many children events for each parent do we want to request. - attached_messages: Gets messages ids which linked to events. - filters: Filters using in search for messages. - cache: If True, all requested data from rpt-data-provider will be saved to cache. - """ - super().__init__() - self._start_timestamp = start_timestamp - self._end_timestamp = end_timestamp - self._parent_event = parent_event - self._search_direction = search_direction - self._resume_from_id = resume_from_id - self._result_count_limit = result_count_limit - self._keep_open = keep_open - self._limit_for_parent = limit_for_parent - self._attached_messages = attached_messages - self._filters = filters - self._cache = cache - - def handle(self, data_source: HTTPProvider5DataSource) -> Data: # noqa: D102 - source = partial(self.__handle_stream, data_source) - adapter = SSEAdapter() - return Data(source).map(adapter.handle).use_cache(self._cache) - - def __handle_stream(self, data_source: HTTPProvider5DataSource) -> Generator[dict, None, None]: - stream = GetEventsSSEEvents( - start_timestamp=self._start_timestamp, - end_timestamp=self._end_timestamp, - parent_event=self._parent_event, - search_direction=self._search_direction, - resume_from_id=self._resume_from_id, - result_count_limit=self._result_count_limit, - keep_open=self._keep_open, - limit_for_parent=self._limit_for_parent, - attached_messages=self._attached_messages, - filters=self._filters, - ).handle(data_source) - - for event in stream: - event = self._handle_adapters(event) - yield event - - -class GetMessageById(IHTTPProvider5Command, ProviderAdaptableCommand): - """A Class-Command for request to rpt-data-provider. - - It retrieves the message by id. - - Please note, Provider5 doesn't return `attachedEventIds`. It will be == []. - It's expected that Provider7 will be support it. - - Returns: - dict: Th2 message. - - Raises: - MessageNotFound: If message by id wasn't found. - """ - - def __init__(self, id: str, use_stub: bool = False): - """GetMessageById constructor. - - Args: - id: Message id. - use_stub: If True the command returns stub instead of exception. - """ - super().__init__() - self._id = id - self._stub_status = use_stub - - def handle(self, data_source: HTTPProvider5DataSource) -> dict: # noqa: D102 - api: HTTPProvider5API = data_source.source_api - url = api.get_url_find_message_by_id(self._id) - - logger.info(url) - - response = api.execute_request(url) - - if response.status_code == 404 and self._stub_status: - return data_source.message_stub_builder.build({data_source.message_struct.MESSAGE_ID: self._id}) - elif response.status_code == 404: - logger.error(f"Unable to find the message. Id: {self._id}") - raise MessageNotFound(self._id) - else: - return self._handle_adapters(response.json()) - - -class GetMessagesById(IHTTPProvider5Command, ProviderAdaptableCommand): - """A Class-Command for request to rpt-data-provider. - - It retrieves the messages by ids. - - Please note, Provider5 doesn't return `attachedEventIds`. It will be == []. - It's expected that Provider7 will be support it. - - Returns: - List[dict]: Th2 messages. - - Raises: - MessageNotFound: If any message by id wasn't found. - """ - - def __init__(self, ids: List[str], use_stub: bool = False): - """GetMessagesById constructor. - - Args: - ids: Message id list. - use_stub: If True the command returns stub instead of exception. - """ - super().__init__() - self._ids: ids = ids - self._stub_status = use_stub - - def handle(self, data_source: HTTPProvider5DataSource) -> List[dict]: # noqa: D102 - result = [] - for message_id in self._ids: - message = GetMessageById( - message_id, - use_stub=self._stub_status, - ).handle(data_source) - result.append(self._handle_adapters(message)) - - return result - - -class GetMessagesSSEBytes(IHTTPProvider5Command, ProviderAdaptableCommand): - """A Class-Command for request to rpt-data-provider. - - It searches messages stream by options. - - Returns: - Iterable[dict]: Stream of Th2 messages. - """ - - def __init__( - self, - start_timestamp: datetime, - stream: List[str], - end_timestamp: datetime = None, - resume_from_id: str = None, - search_direction: str = "next", - result_count_limit: int = None, - keep_open: bool = False, - message_id: List[str] = None, - attached_events: bool = False, - lookup_limit_days: int = None, - filters: MessageFilters = None, - ): - """GetMessagesSSEBytes constructor. - - Args: - start_timestamp: Start timestamp of search. - end_timestamp: End timestamp of search. - stream: Alias of messages. - resume_from_id: Message id from which search starts. - search_direction: Search direction. - result_count_limit: Result count limit. - keep_open: If the search has reached the current moment. - It is need to wait further for the appearance of new data. - message_id: List of message IDs to restore search. If given, it has - the highest priority and ignores stream (uses streams from ids), startTimestamp and resumeFromId. - attached_events: If true, additionally load attached_event_ids - lookup_limit_days: The number of days that will be viewed on - the first request to get the one closest to the specified timestamp. - filters: Filters using in search for messages. - """ - super().__init__() - self._start_timestamp = int(1000 * start_timestamp.replace(tzinfo=timezone.utc).timestamp()) - self._end_timestamp = ( - end_timestamp - if end_timestamp is None - else int(1000 * end_timestamp.replace(tzinfo=timezone.utc).timestamp()) - ) - self._stream = stream - self._resume_from_id = resume_from_id - self._search_direction = search_direction - self._result_count_limit = result_count_limit - self._keep_open = keep_open - self._message_id = message_id - self._attached_events = attached_events - self._lookup_limit_days = lookup_limit_days - self._filters = filters - - def handle(self, data_source: HTTPProvider5DataSource) -> Generator[dict, None, None]: # noqa: D102 - api: HTTPProvider5API = data_source.source_api - url = api.get_url_search_sse_messages( - start_timestamp=self._start_timestamp, - end_timestamp=self._end_timestamp, - stream=[""], - resume_from_id=self._resume_from_id, - search_direction=self._search_direction, - result_count_limit=self._result_count_limit, - keep_open=self._keep_open, - attached_events=self._attached_events, - lookup_limit_days=self._lookup_limit_days, - filters=_convert_filters_to_string(self._filters), - ).replace("&stream=", "") - - fixed_part_len = len(url) - current_url, resulting_urls = "", [] - for stream in self._stream: - stream = f"&stream={stream}" - if fixed_part_len + len(current_url) + len(stream) >= 2048: - resulting_urls.append(url + current_url) - current_url = "" - current_url += stream - if current_url: - resulting_urls.append(url + current_url) - - for url in resulting_urls: - logger.info(url) - for response in api.execute_sse_request(url): - response = self._handle_adapters(response) - if response is not None: - yield response - - -class GetMessagesSSEEvents(IHTTPProvider5Command, ProviderAdaptableCommand): - """A Class-Command for request to rpt-data-provider. - - It searches messages stream by options. - - Returns: - Iterable[dict]: Stream of Th2 messages. - """ - - def __init__( - self, - start_timestamp: datetime, - stream: List[str], - end_timestamp: datetime = None, - resume_from_id: str = None, - search_direction: str = "next", - result_count_limit: int = None, - keep_open: bool = False, - message_id: List[str] = None, - attached_events: bool = False, - lookup_limit_days: int = None, - filters: MessageFilters = None, - char_enc: str = "utf-8", - decode_error_handler: str = UNICODE_REPLACE_HANDLER, - ): - """GetMessagesSSEEvents constructor. - - Args: - start_timestamp: Start timestamp of search. - end_timestamp: End timestamp of search. - stream: Alias of messages. - resume_from_id: Message id from which search starts. - search_direction: Search direction. - result_count_limit: Result count limit. - keep_open: If the search has reached the current moment. - It is need to wait further for the appearance of new data. - message_id: List of message IDs to restore search. If given, it has - the highest priority and ignores stream (uses streams from ids), startTimestamp and resumeFromId. - attached_events: If true, additionally load attached_event_ids - lookup_limit_days: The number of days that will be viewed on - the first request to get the one closest to the specified timestamp. - filters: Filters using in search for messages. - char_enc: Character encode that will use SSEClient. - decode_error_handler: Decode error handler. - """ - super().__init__() - self._start_timestamp = start_timestamp - self._end_timestamp = end_timestamp - self._stream = stream - self._resume_from_id = resume_from_id - self._search_direction = search_direction - self._result_count_limit = result_count_limit - self._keep_open = keep_open - self._message_id = message_id - self._attached_events = attached_events - self._lookup_limit_days = lookup_limit_days - self._filters = filters - self._char_enc = char_enc - self._decode_error_handler = decode_error_handler - - def handle(self, data_source: HTTPProvider5DataSource) -> Generator[dict, None, None]: # noqa: D102 - response = GetMessagesSSEBytes( - start_timestamp=self._start_timestamp, - end_timestamp=self._end_timestamp, - stream=self._stream, - resume_from_id=self._resume_from_id, - search_direction=self._search_direction, - result_count_limit=self._result_count_limit, - keep_open=self._keep_open, - attached_events=self._attached_events, - lookup_limit_days=self._lookup_limit_days, - filters=self._filters, - ).handle(data_source) - - client = SSEClient( - response, - char_enc=self._char_enc, - decode_errors_handler=self._decode_error_handler, - ) - - for record in client.events(): - record = self._handle_adapters(record) - if record is not None: - yield record - - -class GetMessages(IHTTPProvider5Command, ProviderAdaptableCommand): - """A Class-Command for request to rpt-data-provider. - - It searches messages stream by options. - - Returns: - Iterable[dict]: Stream of Th2 messages. - """ - - def __init__( - self, - start_timestamp: datetime, - stream: List[str], - end_timestamp: datetime = None, - resume_from_id: str = None, - search_direction: str = "next", - result_count_limit: int = None, - keep_open: bool = False, - message_id: List[str] = None, - attached_events: bool = False, - lookup_limit_days: int = None, - filters: MessageFilters = None, - char_enc: str = "utf-8", - decode_error_handler: str = UNICODE_REPLACE_HANDLER, - cache: bool = False, - ): - """GetMessages constructor. - - Args: - start_timestamp: Start timestamp of search. - end_timestamp: End timestamp of search. - stream: Alias of messages. - resume_from_id: Message id from which search starts. - search_direction: Search direction. - result_count_limit: Result count limit. - keep_open: If the search has reached the current moment. - It is need to wait further for the appearance of new data. - message_id: List of message IDs to restore search. If given, it has - the highest priority and ignores stream (uses streams from ids), startTimestamp and resumeFromId. - attached_events: If true, additionally load attached_event_ids - lookup_limit_days: The number of days that will be viewed on - the first request to get the one closest to the specified timestamp. - filters: Filters using in search for messages. - char_enc: Encoding for the byte stream. - decode_error_handler: Registered decode error handler. - cache: If True, all requested data from rpt-data-provider will be saved to cache. - """ - super().__init__() - self._start_timestamp = start_timestamp - self._end_timestamp = end_timestamp - self._stream = stream - self._resume_from_id = resume_from_id - self._search_direction = search_direction - self._result_count_limit = result_count_limit - self._keep_open = keep_open - self._message_id = message_id - self._attached_events = attached_events - self._lookup_limit_days = lookup_limit_days - self._filters = filters - self._char_enc = char_enc - self._decode_error_handler = decode_error_handler - self._cache = cache - - def handle(self, data_source: HTTPProvider5DataSource) -> Data: # noqa: D102 - source = partial(self.__handle_stream, data_source) - adapter = SSEAdapter() - return Data(source).map(adapter.handle).use_cache(self._cache) - - def __handle_stream(self, data_source: HTTPProvider5DataSource) -> Generator[dict, None, None]: - stream = GetMessagesSSEEvents( - start_timestamp=self._start_timestamp, - end_timestamp=self._end_timestamp, - stream=self._stream, - resume_from_id=self._resume_from_id, - search_direction=self._search_direction, - result_count_limit=self._result_count_limit, - keep_open=self._keep_open, - attached_events=self._attached_events, - lookup_limit_days=self._lookup_limit_days, - filters=self._filters, - ).handle(data_source) - - for message in stream: - message = self._handle_adapters(message) - yield message diff --git a/th2_data_services/provider/v5/data_source/__init__.py b/th2_data_services/provider/v5/data_source/__init__.py deleted file mode 100644 index cddcc530..00000000 --- a/th2_data_services/provider/v5/data_source/__init__.py +++ /dev/null @@ -1,16 +0,0 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from .grpc import GRPCProvider5DataSource -from .http import HTTPProvider5DataSource diff --git a/th2_data_services/provider/v5/data_source/grpc.py b/th2_data_services/provider/v5/data_source/grpc.py deleted file mode 100644 index 96994fa6..00000000 --- a/th2_data_services/provider/v5/data_source/grpc.py +++ /dev/null @@ -1,115 +0,0 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -from __future__ import annotations -from typing import Any - -from grpc._channel import _InactiveRpcError - -from typing import TYPE_CHECKING - -from th2_data_services.provider.exceptions import CommandError -from th2_data_services.provider.interfaces import IEventStruct, IMessageStruct - -if TYPE_CHECKING: - from th2_data_services.provider.v5.interfaces.command import IGRPCProvider5Command - -from th2_data_services.provider.interfaces.data_source import IGRPCProviderDataSource - -import logging - -from th2_data_services.provider.interfaces.stub_builder import IEventStub, IMessageStub -from th2_data_services.provider.v5.provider_api import GRPCProvider5API -from th2_data_services.provider.v5.struct import ( - provider5_event_struct, - provider5_message_struct, - Provider5EventStruct, - Provider5MessageStruct, -) -from th2_data_services.provider.v5.stub_builder import ( - provider5_event_stub_builder, - provider5_message_stub_builder, -) - -logger = logging.getLogger(__name__) - - -class GRPCProvider5DataSource(IGRPCProviderDataSource): - """DataSource class which provide work with rpt-data-provider. - - Rpt-data-provider version: 5.x.y - Protocol: GRPC - """ - - def __init__( - self, - url: str, - event_struct: IEventStruct = provider5_event_struct, - message_struct: IMessageStruct = provider5_message_struct, - event_stub_builder: IEventStub = provider5_event_stub_builder, - message_stub_builder: IMessageStub = provider5_message_stub_builder, - ): - """GRPCProvider5DataSource constructor. - - Args: - url: Url of rpt-data-provider. - event_struct: Event structure that is supplied by rpt-data-provider. - message_struct: Message structure that is supplied by rpt-data-provider. - event_stub_builder: Stub builder for broken events. - message_stub_builder: Stub builder for broken messages. - """ - super().__init__( - url=url, - event_struct=event_struct, - message_struct=message_struct, - event_stub_builder=event_stub_builder, - message_stub_builder=message_stub_builder, - ) - - self.__provider_api = GRPCProvider5API(url) - - logger.info(url) - - def command(self, cmd: IGRPCProvider5Command) -> Any: - """Execute the transmitted GRPC command. - - Args: - cmd: GRPC Command. - - Returns: - Any: Command response. - - Raises: - CommandError: If the command was broken. - """ - try: - return cmd.handle(data_source=self) - except _InactiveRpcError as info: - raise CommandError( - f"The command '{cmd.__class__.__name__}' was broken. Details of error:\n{info.details()}" - ) - - @property - def source_api(self) -> GRPCProvider5API: - """Returns Provider API.""" - return self.__provider_api - - @property - def event_struct(self) -> Provider5EventStruct: - """Returns event structure class.""" - return self._event_struct - - @property - def message_struct(self) -> Provider5MessageStruct: - """Returns message structure class.""" - return self._message_struct diff --git a/th2_data_services/provider/v5/data_source/http.py b/th2_data_services/provider/v5/data_source/http.py deleted file mode 100644 index 9f719f1e..00000000 --- a/th2_data_services/provider/v5/data_source/http.py +++ /dev/null @@ -1,124 +0,0 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -from __future__ import annotations - -import logging - -from th2_data_services.decode_error_handler import UNICODE_REPLACE_HANDLER -from typing import TYPE_CHECKING - -from th2_data_services.provider.exceptions import CommandError -from th2_data_services.provider.interfaces import IEventStruct, IMessageStruct, IEventStub, IMessageStub - -if TYPE_CHECKING: - from th2_data_services.provider.v5.interfaces.command import IHTTPProvider5Command - -from th2_data_services.provider.interfaces.data_source import IHTTPProviderDataSource -from th2_data_services.provider.v5.struct import ( - provider5_event_struct, - provider5_message_struct, - Provider5EventStruct, - Provider5MessageStruct, -) -from th2_data_services.provider.v5.stub_builder import ( - provider5_event_stub_builder, - provider5_message_stub_builder, -) -from th2_data_services.provider.v5.provider_api.http import HTTPProvider5API - -logger = logging.getLogger(__name__) - - -class HTTPProvider5DataSource(IHTTPProviderDataSource): - """DataSource class which provide work with rpt-data-provider. - - Rpt-data-provider version: 5.x.y - Protocol: HTTP - """ - - def __init__( - self, - url: str, - chunk_length: int = 65536, - char_enc: str = "utf-8", - decode_error_handler: str = UNICODE_REPLACE_HANDLER, - event_struct: IEventStruct = provider5_event_struct, - message_struct: IMessageStruct = provider5_message_struct, - event_stub_builder: IEventStub = provider5_event_stub_builder, - message_stub_builder: IMessageStub = provider5_message_stub_builder, - check_connect_timeout: (int, float) = 5, - use_ssl: bool = True, - ): - """HTTPProvider5DataSource constructor. - - Args: - url: HTTP data source url. - check_connect_timeout: How many seconds to wait for the server to send data before giving up. - chunk_length: How much of the content to read in one chunk. - char_enc: Encoding for the byte stream. - decode_error_handler: Registered decode error handler. - event_struct: Struct of event from rpt-data-provider. - message_struct: Struct of message from rpt-data-provider. - event_stub_builder: Stub for event. - message_stub_builder: Stub for message. - use_ssl: Checking SSL/TSL certification. - """ - super().__init__(url, event_struct, message_struct, event_stub_builder, message_stub_builder) - - self._char_enc = char_enc - self._decode_error_handler = decode_error_handler - self.__chunk_length = chunk_length - self._use_ssl = use_ssl - self.check_connect(check_connect_timeout, use_ssl) - self._provider_api = HTTPProvider5API( - url=url, - chunk_length=chunk_length, - decode_error_handler=decode_error_handler, - char_enc=char_enc, - use_ssl=use_ssl, - ) - - logger.info(url) - - def command(self, cmd: IHTTPProvider5Command): - """HTTP Provider5 command processor. - - Args: - cmd: The command of data source to execute. - - Returns: - Data source command result. - - Raises: - CommandError: If the command was broken. - """ - try: - return cmd.handle(data_source=self) - except Exception as e: - raise CommandError(f"The command '{cmd.__class__.__name__}' was broken. Details of error:\n{e}") - - @property - def source_api(self) -> HTTPProvider5API: - """HTTP Provider5 API.""" - return self._provider_api - - @property - def event_struct(self) -> Provider5EventStruct: - """Returns event structure class.""" - return self._event_struct - - @property - def message_struct(self) -> Provider5MessageStruct: - """Returns message structure class.""" - return self._message_struct diff --git a/th2_data_services/provider/v5/events_tree/__init__.py b/th2_data_services/provider/v5/events_tree/__init__.py deleted file mode 100644 index 4f09ea38..00000000 --- a/th2_data_services/provider/v5/events_tree/__init__.py +++ /dev/null @@ -1,16 +0,0 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from .events_tree_collection import EventsTreeCollectionProvider5 -from .parent_events_tree_collection import ParentEventsTreeCollectionProvider5 diff --git a/th2_data_services/provider/v5/events_tree/events_tree_collection.py b/th2_data_services/provider/v5/events_tree/events_tree_collection.py deleted file mode 100644 index dd9954c0..00000000 --- a/th2_data_services/provider/v5/events_tree/events_tree_collection.py +++ /dev/null @@ -1,105 +0,0 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from typing import Union, Optional, Callable - -from th2_data_services import Data -from th2_data_services.interfaces.events_tree import EventsTreeCollection -from th2_data_services.events_tree.exceptions import FieldIsNotExist -from th2_data_services.provider.interfaces.struct import IEventStruct -from th2_data_services.provider.v5.data_source import HTTPProvider5DataSource, GRPCProvider5DataSource -from th2_data_services.provider.v5.struct import provider5_event_struct -from th2_data_services.provider.v5.stub_builder import provider5_event_stub_builder -from th2_data_services.provider.v5.command_resolver import resolver_get_events_by_id - - -class EventsTreeCollectionProvider5(EventsTreeCollection): - """EventsTreesCollections for data-provider v5.""" - - def __init__( - self, - data: Data, - data_source: Union[GRPCProvider5DataSource, HTTPProvider5DataSource] = None, - preserve_body: bool = False, - event_struct: IEventStruct = provider5_event_struct, - stub: bool = False, - ): - """EventsTreeCollectionProvider5 constructor. - - Args: - data: Data object. - data_source: Data Source object. - preserve_body: If True it will preserve 'body' field in the Events. - event_struct: Event struct object. - stub: If True it will create stub when event is broken. - """ - self._event_struct = event_struct # Should be placed before super! - - super().__init__( - data=data, - data_source=data_source, - preserve_body=preserve_body, - stub=stub, - ) - - def _get_events_by_id_resolver(self) -> Callable: - """Gets a function that solve which protocol command to choose.""" - return resolver_get_events_by_id - - def _get_event_id(self, event) -> str: - """Gets event id from the event. - - Returns: - Event id. - - Raises: - FieldIsNotExist: If the event doesn't have an 'event id' field. - """ - try: - return event[self._event_struct.EVENT_ID] - except KeyError: - raise FieldIsNotExist(self._event_struct.EVENT_ID) - - def _get_event_name(self, event) -> str: - """Gets event name from the event. - - Returns: - Event name. - - Raises: - FieldIsNotExist: If the event doesn't have an 'event name' field. - """ - try: - return event[self._event_struct.NAME] - except KeyError: - raise FieldIsNotExist(self._event_struct.NAME) - - def _get_parent_event_id(self, event) -> Optional[str]: - """Gets parent event id from event. - - Returns: - Parent event id. - """ - return event.get(self._event_struct.PARENT_EVENT_ID) - - def _build_stub_event(self, id_: str): - """Builds stub event. - - Args: - id_: Event Id. - - Returns: - Stub event. - """ - return provider5_event_stub_builder.build({self._event_struct.EVENT_ID: id_}) diff --git a/th2_data_services/provider/v5/events_tree/parent_events_tree_collection.py b/th2_data_services/provider/v5/events_tree/parent_events_tree_collection.py deleted file mode 100644 index 8b6fdca2..00000000 --- a/th2_data_services/provider/v5/events_tree/parent_events_tree_collection.py +++ /dev/null @@ -1,105 +0,0 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from typing import Optional, Union, Callable - -from th2_data_services import Data -from th2_data_services.interfaces.events_tree import ParentEventsTreeCollection -from th2_data_services.events_tree.exceptions import FieldIsNotExist -from th2_data_services.provider.interfaces.struct import IEventStruct -from th2_data_services.provider.v5.data_source import GRPCProvider5DataSource, HTTPProvider5DataSource -from th2_data_services.provider.v5.struct import provider5_event_struct -from th2_data_services.provider.v5.stub_builder import provider5_event_stub_builder -from th2_data_services.provider.v5.command_resolver import resolver_get_events_by_id - - -class ParentEventsTreeCollectionProvider5(ParentEventsTreeCollection): - """ParentEventsTreeCollection for data-provider v5.""" - - def __init__( - self, - data: Data, - data_source: Union[GRPCProvider5DataSource, HTTPProvider5DataSource] = None, - preserve_body: bool = False, - event_struct: IEventStruct = provider5_event_struct, - stub: bool = False, - ): - """ParentEventsTreeCollectionProvider5 constructor. - - Args: - data: Data object. - data_source: Data Source object. - preserve_body: If True it will preserve 'body' field in the Events. - event_struct: Event struct object. - stub: If True it will create stub when event is broken. - """ - self._event_struct = event_struct # Should be placed before super! - - super().__init__( - data=data, - data_source=data_source, - preserve_body=preserve_body, - stub=stub, - ) - - def _get_events_by_id_resolver(self) -> Callable: - """Gets a function that solve which protocol command to choose.""" - return resolver_get_events_by_id - - def _get_event_id(self, event) -> str: - """Gets event id from the event. - - Returns: - Event id. - - Raises: - FieldIsNotExist: If the event doesn't have an 'event id' field - """ - try: - return event[self._event_struct.EVENT_ID] - except KeyError: - raise FieldIsNotExist(self._event_struct.EVENT_ID) - - def _get_event_name(self, event) -> str: - """Gets event name from the event. - - Returns: - Event name. - - Raises: - FieldIsNotExist: If the event doesn't have an 'event name' field. - """ - try: - return event[self._event_struct.NAME] - except KeyError: - raise FieldIsNotExist(self._event_struct.NAME) - - def _get_parent_event_id(self, event) -> Optional[str]: - """Gets parent event id from the event. - - Returns: - Parent event id. - """ - return event.get(self._event_struct.PARENT_EVENT_ID) - - def _build_stub_event(self, id_: str): - """Builds stub event. - - Args: - id_: Event Id. - - Returns: - Stub event. - """ - return provider5_event_stub_builder.build({self._event_struct.EVENT_ID: id_}) diff --git a/th2_data_services/provider/v5/filters/event_filters.py b/th2_data_services/provider/v5/filters/event_filters.py deleted file mode 100644 index d2b8af09..00000000 --- a/th2_data_services/provider/v5/filters/event_filters.py +++ /dev/null @@ -1,68 +0,0 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from th2_data_services.provider.v5.filters.filter import Provider5EventFilter - - -class TypeFilter(Provider5EventFilter): - """Will match the events which type contains one of the given substrings.""" - - FILTER_NAME = "type" - - -class NameFilter(Provider5EventFilter): - """Will match the events which name contains one of the given substrings.""" - - FILTER_NAME = "name" - - -class BodyFilter(Provider5EventFilter): - """Will match the events which body contains one of the given substrings.""" - - FILTER_NAME = "body" - - -class AttachedMessageIdFilter(Provider5EventFilter): - """Filters the events that are linked to the specified message id.""" - - FILTER_NAME = "attachedMessageId" - - -class _StatusFilter(Provider5EventFilter): - FILTER_NAME = "status" - - def url(self) -> str: - """Generates the filter part of the HTTP protocol API. - - For help use this readme: - https://github.com/th2-net/th2-rpt-data-provider#filters-api. - - Returns: - str: Generated filter. - """ - return f"&filters={self.name}" + "".join([f"&{self.name}-values={val}" for val in self.values]) - - -class PassedStatusFilter(_StatusFilter): - """Will match the events which status equals passed.""" - - def __init__(self): # noqa: D107 - super().__init__("passed") - - -class FailedStatusFilter(_StatusFilter): - """Will match the events which status equals failed.""" - - def __init__(self): # noqa: D107 - super().__init__("failed") diff --git a/th2_data_services/provider/v5/filters/filter.py b/th2_data_services/provider/v5/filters/filter.py deleted file mode 100644 index 090bf36f..00000000 --- a/th2_data_services/provider/v5/filters/filter.py +++ /dev/null @@ -1,102 +0,0 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from th2_data_services.provider.interfaces.filter import IProviderFilter -from typing import Sequence, Any, Union - -from th2_grpc_data_provider.data_provider_template_pb2 import Filter as grpc_Filter, FilterName as grpc_FilterName -import google.protobuf.wrappers_pb2 - - -class Provider5Filter(IProviderFilter): - """General interface for Filters of Provider v5.""" - - def __init__( - self, - name: str, - values: Union[str, int, float, Sequence[Union[str, int, float]]], - negative: bool = False, - conjunct: bool = False, - # exact: bool = False, # Will be added in 5.4.x - ): - """Filter constructor. - - Args: - name (str): Filter name. - values (Union[str, int, float, Sequence[Union[str, int, float]]]): One string with filter value or list of filter values. - negative (bool): If true, will match events/messages that do not match those specified values. - If false, will match the events/messages by their values. Defaults to false. - conjunct (bool): If true, each of the specific filter values should be applied - If false, at least one of the specific filter values must be applied. - """ - self.name = name - - if isinstance(values, (list, tuple)): - self.values = [str(v) for v in values] - else: - self.values = [str(values)] - - self.negative = negative - self.conjunct = conjunct - # self.exact = exact # Will be added in 5.4.x - - def __repr__(self): - class_name = self.__class__.__name__ - return ( - f"{class_name}(" - f"name='{self.name}', " - f"values={self.values}, " - f"negative='{self.negative}', " - f"conjunct='{self.conjunct}')" - ) - - def url(self) -> str: - """Generates the filter part of the HTTP protocol API. - - For help use this readme: - https://github.com/th2-net/th2-rpt-data-provider#filters-api. - - Returns: - str: Generated filter. - """ - return ( - f"&filters={self.name}" - + "".join([f"&{self.name}-values={val}" for val in self.values]) - + f"&{self.name}-negative={self.negative}" - + f"&{self.name}-conjunct={self.conjunct}" - ) - - def grpc(self) -> grpc_Filter: - """Generates the grpc object of the GRPC protocol API.""" - return grpc_Filter( - name=grpc_FilterName(filter_name=self.name), - negative=google.protobuf.wrappers_pb2.BoolValue(value=self.negative), - values=self.values, - conjunct=google.protobuf.wrappers_pb2.BoolValue(value=self.conjunct), - ) - - -class _Provider5FilterBase(Provider5Filter): - FILTER_NAME = "FILTER_NAME" - - def __init__(self, values: Sequence[Any], negative: bool = False, conjunct: bool = False): - super().__init__(self.FILTER_NAME, values, negative, conjunct) - - -class Provider5EventFilter(_Provider5FilterBase): - """Base class for Event Filters of Provider v5.""" - - -class Provider5MessageFilter(_Provider5FilterBase): - """Base class for Message Filters of Provider v5.""" diff --git a/th2_data_services/provider/v5/filters/message_filters.py b/th2_data_services/provider/v5/filters/message_filters.py deleted file mode 100644 index 0e372da5..00000000 --- a/th2_data_services/provider/v5/filters/message_filters.py +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from th2_data_services.provider.v5.filters.filter import Provider5MessageFilter - - -class TypeFilter(Provider5MessageFilter): - """Will match the messages by their full type name.""" - - FILTER_NAME = "type" - - -class BodyBinaryFilter(Provider5MessageFilter): - """Will match the messages by their binary body.""" - - FILTER_NAME = "bodyBinary" - - -class BodyFilter(Provider5MessageFilter): - """Will match the messages by their parsed body.""" - - FILTER_NAME = "body" - - -class AttachedEventIdsFilter(Provider5MessageFilter): - """Filters the messages that are linked to the specified event id.""" - - FILTER_NAME = "attachedEventIds" diff --git a/th2_data_services/provider/v5/interfaces/command.py b/th2_data_services/provider/v5/interfaces/command.py deleted file mode 100644 index 85e54745..00000000 --- a/th2_data_services/provider/v5/interfaces/command.py +++ /dev/null @@ -1,43 +0,0 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from abc import abstractmethod - -from th2_data_services.provider.interfaces.command import IHTTPProviderCommand, IGRPCProviderCommand -from th2_data_services.provider.v5.data_source.grpc import GRPCProvider5DataSource -from th2_data_services.provider.v5.data_source.http import HTTPProvider5DataSource - - -class IHTTPProvider5Command(IHTTPProviderCommand): - """Interface of command for rpt-data-provider. - - Rpt-data-provider version: 5.x.y - Protocol: HTTP - """ - - @abstractmethod - def handle(self, data_source: HTTPProvider5DataSource): - pass - - -class IGRPCProvider5Command(IGRPCProviderCommand): - """Interface of command for rpt-data-provider. - - Rpt-data-provider version: 5.x.y - Protocol: GRPC - """ - - @abstractmethod - def handle(self, data_source: GRPCProvider5DataSource): - pass diff --git a/th2_data_services/provider/v5/provider_api/grpc.py b/th2_data_services/provider/v5/provider_api/grpc.py deleted file mode 100644 index ff60fe3d..00000000 --- a/th2_data_services/provider/v5/provider_api/grpc.py +++ /dev/null @@ -1,366 +0,0 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import logging -from collections import namedtuple -from typing import Iterable, List, Optional - -from google.protobuf.empty_pb2 import Empty -from google.protobuf.timestamp_pb2 import Timestamp -from google.protobuf.wrappers_pb2 import BoolValue, Int32Value, Int64Value -from th2_grpc_common.common_pb2 import MessageID, EventID, ConnectionID, Direction -from th2_grpc_data_provider.data_provider_template_pb2_grpc import DataProviderStub -from th2_grpc_data_provider.data_provider_template_pb2 import ( - EventSearchRequest, - MessageSearchRequest, - FilterName, - MatchRequest, - FilterInfo, - ListFilterName, - StreamResponse, - EventData, - StringList, - IsMatched, - MessageData, - TimeRelation, - Filter, -) -from grpc import Channel, insecure_channel -from th2_data_services.provider.interfaces.source_api import IGRPCProviderSourceAPI - -logger = logging.getLogger(__name__) - -BasicRequest = namedtuple( - "BasicRequest", - ["start_timestamp", "end_timestamp", "result_count_limit", "keep_open", "search_direction", "filters"], -) - - -class GRPCProvider5API(IGRPCProviderSourceAPI): - def __init__(self, url: str): - """GRPC Provider5 API. - - Args: - url: GRPC data source url. - """ - self._create_connection(url) - - def _create_connection(self, url: str) -> None: - """Creates gRPC channel to gRPC-server. - - Args: - url: Url of gRPC-server. - """ - channel: Channel = insecure_channel(url) - self.__stub: DataProviderStub = DataProviderStub(channel) - - def get_message_streams(self) -> StringList: - """GRPC-API `getMessageStreams` call returns a list of message stream names.""" - return self.__stub.getMessageStreams(Empty()) - - def search_events( - self, - start_timestamp: int = None, - end_timestamp: int = None, - parent_event: str = None, - search_direction: str = "NEXT", - resume_from_id: str = None, - result_count_limit: int = None, - keep_open: bool = False, - limit_for_parent: int = None, - metadata_only: bool = True, - attached_messages: bool = False, - filters: Optional[List[Filter]] = None, - ) -> Iterable[StreamResponse]: - """GRPC-API `searchEvents` call creates an event or an event metadata stream that matches the filter. - - Args: - start_timestamp: Sets the search starting point. Expected in nanoseconds. One of the 'start_timestamp' - or 'resume_from_id' must not absent. - end_timestamp: Sets the timestamp to which the search will be performed, starting with 'start_timestamp'. - Expected in nanoseconds. - parent_event: Match events to the specified parent. - search_direction: Sets the lookup direction. Can be 'NEXT' or 'PREVIOUS'. - resume_from_id: The last event id from which we start searching for events. - result_count_limit: Sets the maximum amount of events to return. - keep_open: Option if the search has reached the current moment, - it is necessary to wait further for the appearance of new data. - limit_for_parent: How many children events for each parent do we want to request. - metadata_only: Receive only metadata (true) or entire event (false) (without attachedMessageIds). - attached_messages: Option if you want to load attachedMessageIds additionally. - filters: Which filters to apply in a search. - - Returns: - Iterable object which return events as parts of streaming response. - """ - self.__search_basic_checks( - start_timestamp=start_timestamp, - end_timestamp=end_timestamp, - result_count_limit=result_count_limit, - resume_from_ids=resume_from_id, - search_direction=search_direction, - ) - - basic_request = self.__build_basic_request_object( - start_timestamp=start_timestamp, - end_timestamp=end_timestamp, - search_direction=search_direction, - result_count_limit=result_count_limit, - keep_open=keep_open, - filters=filters, - ) - parent_event = EventID(id=parent_event) if parent_event else None - resume_from_id = EventID(id=resume_from_id) if resume_from_id else None - limit_for_parent = Int64Value(value=limit_for_parent) if limit_for_parent else None - metadata_only = BoolValue(value=metadata_only) - attached_messages = BoolValue(value=attached_messages) - - event_search_request = EventSearchRequest( - start_timestamp=basic_request.start_timestamp, - end_timestamp=basic_request.end_timestamp, - parent_event=parent_event, - search_direction=basic_request.search_direction, - resume_from_id=resume_from_id, - result_count_limit=basic_request.result_count_limit, - keep_open=basic_request.keep_open, - limit_for_parent=limit_for_parent, - metadata_only=metadata_only, - attached_messages=attached_messages, - filters=basic_request.filters, - ) - return self.__stub.searchEvents(event_search_request) - - def search_messages( - self, - start_timestamp: int, - stream: List[str], - end_timestamp: int = None, - resume_from_id: str = None, - search_direction: str = "NEXT", - result_count_limit: int = None, - keep_open: bool = False, - filters: Optional[List[Filter]] = None, - message_id: Optional[List[str]] = None, - attached_events: bool = False, - ) -> Iterable[StreamResponse]: - """GRPC-API `searchMessages` call creates a message stream that matches the filter. - - Args: - start_timestamp: Sets the search starting point. Expected in nanoseconds. One of the 'start_timestamp' - or 'resume_from_id' must not absent. - stream: Sets the stream ids to search in. - end_timestamp: Sets the timestamp to which the search will be performed, starting with 'start_timestamp'. - Expected in nanoseconds. - search_direction: Sets the lookup direction. Can be 'NEXT' or 'PREVIOUS'. - resume_from_id: The last event id from which we start searching for messages. - result_count_limit: Sets the maximum amount of messages to return. - keep_open: Option if the search has reached the current moment, - it is necessary to wait further for the appearance of new data. - filters: Which filters to apply in a search. - message_id: List of message ids to restore the search. - attached_events: If true, it will additionally load attachedEventsIds. - - Returns: - Iterable object which return messages as parts of streaming response. - """ - if stream is None: - raise TypeError("Argument 'stream' is required.") - message_id = message_id or [] - self.__search_basic_checks( - start_timestamp=start_timestamp, - end_timestamp=end_timestamp, - result_count_limit=result_count_limit, - resume_from_ids=resume_from_id, - search_direction=search_direction, - ) - - basic_request = self.__build_basic_request_object( - start_timestamp=start_timestamp, - end_timestamp=end_timestamp, - result_count_limit=result_count_limit, - keep_open=keep_open, - search_direction=search_direction, - filters=filters, - ) - resume_from_id = self.__build_message_id_object(resume_from_id) if resume_from_id else None - message_id = [self.__build_message_id_object(id_) for id_ in message_id] - attached_events = BoolValue(value=attached_events) - message_search_request = MessageSearchRequest( - start_timestamp=basic_request.start_timestamp, - end_timestamp=basic_request.end_timestamp, - resume_from_id=resume_from_id, - search_direction=basic_request.search_direction, - result_count_limit=basic_request.result_count_limit, - stream=StringList(list_string=stream), - keep_open=basic_request.keep_open, - message_id=message_id, - attached_events=attached_events, - filters=basic_request.filters, - ) - return self.__stub.searchMessages(message_search_request) - - @staticmethod - def __search_basic_checks( - start_timestamp: Optional[int], - end_timestamp: Optional[int], - resume_from_ids: Optional[str], - search_direction: Optional[str], - result_count_limit: Optional[int], - ): - if start_timestamp is None and resume_from_ids is None: - raise ValueError("One of the 'startTimestamp' or 'resumeFromId(s)' must not be None.") - - if end_timestamp is None and result_count_limit is None: - raise ValueError("One of the 'end_timestamp' or 'result_count_limit' must not be None.") - - if ( - start_timestamp is not None - and len(str(start_timestamp)) != 19 - or end_timestamp is not None - and len(str(end_timestamp)) != 19 - ): - raise ValueError("Arguments 'start_timestamp' and 'end_timestamp' are expected in nanoseconds.") - - if search_direction is not None: - search_direction = search_direction.upper() - if search_direction not in ("NEXT", "PREVIOUS"): - raise ValueError("Argument 'search_direction' must be 'NEXT' or 'PREVIOUS'.") - else: - raise ValueError("Argument 'search_direction' must be 'NEXT' or 'PREVIOUS'.") - - def __build_basic_request_object( - self, - start_timestamp: int = None, - end_timestamp: int = None, - result_count_limit: int = None, - keep_open: bool = False, - search_direction: str = "NEXT", - filters: Optional[List[Filter]] = None, - ) -> BasicRequest: - """Builds a BasicRequest wrapper-object. - - Args: - start_timestamp: Start Timestamp for request. - end_timestamp: End Timestamp for request. - result_count_limit: Data count limit. - keep_open: Option for stream-request. - search_direction: Searching direction. - filters: Which filters to apply in a request. - - Returns: - BasicRequest wrapper-object. - """ - if filters is None: - filters = [] - - start_timestamp = self.__build_timestamp_object(start_timestamp) if start_timestamp else None - end_timestamp = self.__build_timestamp_object(end_timestamp) if end_timestamp else None - search_direction = TimeRelation.Value(search_direction) # getting a value from enum - result_count_limit = Int32Value(value=result_count_limit) if result_count_limit else None - keep_open = BoolValue(value=keep_open) - - basic_request = BasicRequest( - start_timestamp=start_timestamp, - end_timestamp=end_timestamp, - search_direction=search_direction, - result_count_limit=result_count_limit, - keep_open=keep_open, - filters=filters, - ) - return basic_request - - @staticmethod - def __build_timestamp_object(timestamp: int) -> Timestamp: - """Builds a Timestamp of 'protobuf' entity. - - Args: - timestamp: Timestamp in nanoseconds. - - Returns: - Timestamp object. - """ - nanos = timestamp % 10 ** 9 - seconds = timestamp // 10 ** 9 - timestamp = Timestamp(seconds=seconds, nanos=nanos) - return timestamp - - @staticmethod - def __build_message_id_object(message_id: str) -> MessageID: - """Builds a MessageID of 'protobuf' entity. - - Args: - message_id: Message id. - - Returns: - MessageID object. - """ - split_id = message_id.split(":") - split_id.reverse() # Parse the message id from the end. - - sequence, direction, alias = split_id[0], split_id[1].upper(), split_id[2:] - split_sequence = sequence.split(".") - sequence, subsequence = int(split_sequence[0]), split_sequence[1:] - subsequence = map(int, subsequence) if subsequence else subsequence - alias.reverse() - alias = ":".join(alias) - - connection_id = ConnectionID(session_alias=alias) - direction = Direction.Value(direction) # Get a value from enum. - - message_id = MessageID( - connection_id=connection_id, - direction=direction, - sequence=sequence, - subsequence=subsequence, - ) - return message_id - - def get_event(self, event_id: str) -> EventData: - """GRPC-API `getEvent` call returns a single event with the specified id.""" - event_id = EventID(id=event_id) - return self.__stub.getEvent(event_id) - - def get_message(self, message_id: str) -> MessageData: - """GRPC-API `getMessage` call returns a single message with the specified id.""" - message_id = self.__build_message_id_object(message_id) - return self.__stub.getMessage(message_id) - - def get_messages_filters(self) -> ListFilterName: - """GRPC-API `getMessagesFilters` call returns all the names of sse message filters.""" - return self.__stub.getMessagesFilters(Empty()) - - def get_events_filters(self) -> ListFilterName: - """GRPC-API `getEventsFilters` call returns all the names of sse event filters.""" - return self.__stub.getEventsFilters(Empty()) - - def get_event_filter_info(self, filter_name: str) -> FilterInfo: - """GRPC-API `getEventFilterInfo` call returns event filter info.""" - filter_name = FilterName(filter_name=filter_name) - return self.__stub.getEventFilterInfo(filter_name) - - def get_message_filter_info(self, filter_name: str) -> FilterInfo: - """GRPC-API `getMessageFilterInfo` call returns message filter info.""" - filter_name = FilterName(filter_name=filter_name) - return self.__stub.getMessageFilterInfo(filter_name) - - def match_event(self, event_id: str, filters: List[Filter]) -> IsMatched: - """GRPC-API `matchEvent` call checks that the event with the specified id is matched by the filter.""" - match_request = MatchRequest(event_id=EventID(id=event_id), filters=filters) - return self.__stub.matchEvent(match_request) - - def match_message(self, message_id: str, filters: List[Filter]) -> IsMatched: - """GRPC-API `matchMessage` call checks that the message with the specified id is matched by the filter.""" - message_id = self.__build_message_id_object(message_id) - match_request = MatchRequest(message_id=message_id, filters=filters) - return self.__stub.matchMessage(match_request) diff --git a/th2_data_services/provider/v5/provider_api/http.py b/th2_data_services/provider/v5/provider_api/http.py deleted file mode 100644 index e5d8a6c9..00000000 --- a/th2_data_services/provider/v5/provider_api/http.py +++ /dev/null @@ -1,260 +0,0 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import logging -from http import HTTPStatus -from typing import List, Generator, Optional, Union - -import requests -from requests import Response -from urllib3 import PoolManager, exceptions -from urllib.parse import quote - -from th2_data_services.provider.interfaces.source_api import IHTTPProviderSourceAPI -from th2_data_services.decode_error_handler import UNICODE_REPLACE_HANDLER - -logger = logging.getLogger("th2_data_services") -logger.setLevel(logging.DEBUG) - - -class HTTPProvider5API(IHTTPProviderSourceAPI): - def __init__( - self, - url: str, - chunk_length: int = 65536, - decode_error_handler: str = UNICODE_REPLACE_HANDLER, - char_enc: str = "utf-8", - use_ssl: bool = True, - ): - """HTTP Provider5 API. - - Args: - url: HTTP data source url. - chunk_length: How much of the content to read in one chunk. - char_enc: Encoding for the byte stream. - decode_error_handler: Registered decode error handler. - use_ssl: If False SSL/TSL certification is disable. - """ - self._url = self.__normalize_url(url) - self._char_enc = char_enc - self._chunk_length = chunk_length - self._decode_error_handler = decode_error_handler - self._use_ssl = use_ssl - - def __normalize_url(self, url): - if url is None: - return url - - pos = len(url) - 1 - while url[pos] == "/" and pos >= 0: - pos -= 1 - - return url[: pos + 1] - - def __encode_url(self, url: str) -> str: - return quote(url.encode(), "/:&?=") - - def get_url_message_streams(self) -> str: - """REST-API `messageStreams` call returns a list of message stream names.""" - return self.__encode_url(f"{self._url}/messageStreams") - - def get_url_find_event_by_id(self, event_id: str) -> str: - """REST-API `event` call returns a single event with the specified id.""" - return self.__encode_url(f"{self._url}/event/{event_id}") - - def get_url_find_events_by_id(self, *ids) -> str: - """REST-API `events` call returns a list of events with the specified ids. - - Note, at a time you can request no more eventSearchChunkSize. - - Deprecated, use `get_url_find_event_by_id` instead. - """ - query = "" - for id in ids: - query += f"ids={id}&" - return self.__encode_url(f"{self._url}/events?{query[:-1]}") - - def get_url_find_message_by_id(self, message_id: str) -> str: - """REST-API `message` call returns a single message with the specified id.""" - return self.__encode_url(f"{self._url}/message/{message_id}") - - def get_url_messages_filters(self) -> str: - """SSE-API `filters/sse-messages` call returns all names of sse message filters. - - https://github.com/th2-net/th2-rpt-data-provider#filters-api - """ - return self.__encode_url(f"{self._url}/filters/sse-messages") - - def get_url_events_filters(self) -> str: - """SSE-API `/filters/sse-events` call returns all names of sse event filters. - - https://github.com/th2-net/th2-rpt-data-provider#filters-api - """ - return self.__encode_url(f"{self._url}/filters/sse-events") - - def get_url_message_filter_info(self, filter_name: str) -> str: - """SSE-API `filters/sse-messages/{filter name}` call returns filter info. - - https://github.com/th2-net/th2-rpt-data-provider#filters-api - """ - return self.__encode_url(f"{self._url}/filters/sse-messages/{filter_name}") - - def get_url_event_filter_info(self, filter_name: str) -> str: - """SSE-API `filters/sse-events/{filter_name}` call returns filter info. - - https://github.com/th2-net/th2-rpt-data-provider#filters-api - """ - return self.__encode_url(f"{self._url}/filters/sse-events/{filter_name}") - - def get_url_match_event_by_id(self, event_id: str, filters: str = "") -> str: - """REST-API `match/event/{id}` call returns boolean value. - - Checks that event with the specified id is matched by filter. - - https://github.com/th2-net/th2-rpt-data-provider#filters-api - """ - return self.__encode_url(f"{self._url}/match/event/{event_id}{filters}") - - def get_url_match_message_by_id(self, message_id: str, filters: str = "") -> str: - """REST-API `match/message/{id}` call returns boolean value. - - Checks that message with the specified id is matched by filter. - - https://github.com/th2-net/th2-rpt-data-provider#filters-api - """ - return self.__encode_url(f"{self._url}/match/message/{message_id}{filters}") - - def get_url_search_sse_events( - self, - start_timestamp: int, - end_timestamp: Optional[int] = None, - parent_event: Optional[str] = None, - resume_from_id: Optional[str] = None, - search_direction: Optional[str] = "next", - result_count_limit: Union[int, float] = None, - keep_open: Optional[bool] = False, - limit_for_parent: Union[int, float] = None, - metadata_only: Optional[bool] = True, - attached_messages: Optional[bool] = False, - filters: Optional[str] = None, - ) -> str: - """REST-API `search/sse/events` call create a sse channel of event metadata that matches the filter. - - https://github.com/th2-net/th2-rpt-data-provider#sse-requests-api - """ - kwargs = { - "startTimestamp": start_timestamp, - "endTimestamp": end_timestamp, - "resumeFromId": resume_from_id, - "parentEvent": parent_event, - "searchDirection": search_direction, - "resultCountLimit": result_count_limit, - "limitForParent": limit_for_parent, - "keepOpen": keep_open, - "metadataOnly": metadata_only, - "attachedMessages": attached_messages, - } - - query = "" - url = f"{self._url}/search/sse/events?" - for k, v in kwargs.items(): - if v is None: - continue - else: - query += f"&{k}={v}" - url = f"{url}{query[1:]}" - if filters is not None: - url += filters - return self.__encode_url(url) - - def get_url_search_sse_messages( - self, - start_timestamp: int, - stream: List[str], - end_timestamp: Optional[int] = None, - resume_from_id: Optional[str] = None, - search_direction: Optional[str] = "next", - result_count_limit: Union[int, float] = None, - keep_open: bool = False, - message_id: Optional[List[str]] = None, - attached_events: bool = False, - lookup_limit_days: Union[int, float] = None, - filters: Optional[str] = None, - ) -> str: - """REST-API `search/sse/messages` call create a sse channel of messages that matches the filter. - - https://github.com/th2-net/th2-rpt-data-provider#sse-requests-api - """ - kwargs = { - "startTimestamp": start_timestamp, - "endTimestamp": end_timestamp, - "resumeFromId": resume_from_id, - "stream": stream, - "searchDirection": search_direction, - "resultCountLimit": result_count_limit, - "keepOpen": keep_open, - "messageId": message_id, - "attachedEvents": attached_events, - "lookupLimitDays": lookup_limit_days, - } - - query = "" - url = f"{self._url}/search/sse/messages?" - for k, v in kwargs.items(): - if v is None: - continue - if k == "stream": - for s in stream: - query += f"&{k}={s}" - else: - query += f"&{k}={v}" - url = f"{url}{query[1:]}" - if filters is not None: - url += filters - return self.__encode_url(url) - - def execute_sse_request(self, url: str) -> Generator[bytes, None, None]: - """Create stream connection. - - Args: - url: Url. - - Yields: - str: Response stream data. - """ - headers = {"Accept": "text/event-stream"} - http = PoolManager() if self._use_ssl else PoolManager(cert_reqs="CERT_NONE") - response = http.request(method="GET", url=url, headers=headers, preload_content=False) - - if response.status != HTTPStatus.OK: - for s in HTTPStatus: - if s == response.status: - raise exceptions.HTTPError(f"{s.value} {s.phrase} ({s.description})") - raise exceptions.HTTPError(f"Http returned bad status: {response.status}") - - for chunk in response.stream(self._chunk_length): - yield chunk - - response.release_conn() - - def execute_request(self, url: str) -> Response: - """Sends a GET request to provider. - - Args: - url: Url for a get request to rpt-data-provider. - - Returns: - requests.Response: Response data. - """ - return requests.get(url, verify=self._use_ssl) diff --git a/th2_data_services/provider/v5/struct.py b/th2_data_services/provider/v5/struct.py deleted file mode 100644 index fb0db374..00000000 --- a/th2_data_services/provider/v5/struct.py +++ /dev/null @@ -1,87 +0,0 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from dataclasses import dataclass - -from th2_data_services.provider.interfaces.struct import IEventStruct, IMessageStruct - - -@dataclass -class Provider5EventStruct(IEventStruct): - """Interface for Event of data-provider v5.""" - - EVENT_ID: str - PARENT_EVENT_ID: str - STATUS: str - NAME: str - TYPE: str - BATCH_ID: str - IS_BATCHED: str - EVENT_TYPE: str - END_TIMESTAMP: str - START_TIMESTAMP: str - ATTACHED_MESSAGES_IDS: str - BODY: str - - -provider5_event_struct = Provider5EventStruct( - EVENT_ID="eventId", - PARENT_EVENT_ID="parentEventId", - STATUS="successful", - NAME="eventName", - TYPE="type", - BATCH_ID="batchId", - IS_BATCHED="isBatched", - EVENT_TYPE="eventType", - END_TIMESTAMP="endTimestamp", - START_TIMESTAMP="startTimestamp", - ATTACHED_MESSAGES_IDS="attachedMessageIds", - BODY="body", -) - - -@dataclass -class Provider5MessageStruct(IMessageStruct): - """Interface for Message of data-provider v5.""" - - DIRECTION: str - SESSION_ID: str - MESSAGE_TYPE: str - CONNECTION_ID: str - SESSION_ALIAS: str - SUBSEQUENCE: str - SEQUENCE: str - TIMESTAMP: str - BODY: str - BODY_BASE64: str - TYPE: str - MESSAGE_ID: str - ATTACHED_EVENT_IDS: str - - -provider5_message_struct = Provider5MessageStruct( - DIRECTION="direction", - SESSION_ID="sessionId", - MESSAGE_TYPE="messageType", - CONNECTION_ID="connectionId", - SESSION_ALIAS="sessionAlias", - SUBSEQUENCE="subsequence", - SEQUENCE="sequence", - TIMESTAMP="timestamp", - BODY="body", - BODY_BASE64="bodyBase64", - TYPE="type", - MESSAGE_ID="messageId", - ATTACHED_EVENT_IDS="attachedEventIds", -) diff --git a/th2_data_services/provider/v5/stub_builder.py b/th2_data_services/provider/v5/stub_builder.py deleted file mode 100644 index ac86ac56..00000000 --- a/th2_data_services/provider/v5/stub_builder.py +++ /dev/null @@ -1,85 +0,0 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from th2_data_services.provider.interfaces.stub_builder import IEventStub, IMessageStub -from th2_data_services.provider.v5.struct import ( - provider5_event_struct, - provider5_message_struct, -) - - -class Provider5EventStubBuilder(IEventStub): - def __init__(self, event_struct=provider5_event_struct): - """Event stub builder for Provider v5. - - Args: - event_struct: Event struct class. - """ - self.event_fields = event_struct - super().__init__() # Requirement to define fields for the template earlier. - - @property - def template(self) -> dict: - """Event stub template. - - Returns: - (dict) Event stub template. - """ - return { - self.event_fields.ATTACHED_MESSAGES_IDS: [], - self.event_fields.BATCH_ID: "Broken_Event", - self.event_fields.END_TIMESTAMP: {"nano": 0, "epochSecond": 0}, - self.event_fields.START_TIMESTAMP: {"nano": 0, "epochSecond": 0}, - self.event_fields.TYPE: "event", - self.event_fields.EVENT_ID: self.REQUIRED_FIELD, - self.event_fields.NAME: "Broken_Event", - self.event_fields.EVENT_TYPE: "Broken_Event", - self.event_fields.PARENT_EVENT_ID: "Broken_Event", - self.event_fields.STATUS: None, - self.event_fields.IS_BATCHED: None, - } - - -class Provider5MessageStubBuilder(IMessageStub): - def __init__(self, message_struct=provider5_message_struct): - """Event stub builder for Provider v5. - - Args: - message_struct: Message struct class. - """ - self.message_fields = message_struct - super().__init__() # Requirement to define fields for the template earlier. - - @property - def template(self) -> dict: - """Message stub template. - - Returns: - (dict) Message stub template. - """ - return { - self.message_fields.DIRECTION: None, - self.message_fields.SESSION_ID: "Broken_Message", - self.message_fields.MESSAGE_TYPE: "Broken_Message", - self.message_fields.TIMESTAMP: {"nano": 0, "epochSecond": 0}, - self.message_fields.BODY: [], - self.message_fields.BODY_BASE64: [], - self.message_fields.TYPE: "message", - self.message_fields.MESSAGE_ID: self.REQUIRED_FIELD, - self.message_fields.ATTACHED_EVENT_IDS: [], - } - - -provider5_event_stub_builder = Provider5EventStubBuilder() -provider5_message_stub_builder = Provider5MessageStubBuilder() diff --git a/th2_data_services/provider/v6/adapters/__init__.py b/th2_data_services/provider/v6/adapters/__init__.py deleted file mode 100644 index 92eaf36f..00000000 --- a/th2_data_services/provider/v6/adapters/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .basic_adapters import GRPCObjectToDictAdapter -from .event_adapters import DeleteEventWrappersAdapter -from .message_adapters import CodecPipelinesAdapter, DeleteMessageWrappersAdapter diff --git a/th2_data_services/provider/v6/adapters/basic_adapters.py b/th2_data_services/provider/v6/adapters/basic_adapters.py deleted file mode 100644 index 0f8e4da3..00000000 --- a/th2_data_services/provider/v6/adapters/basic_adapters.py +++ /dev/null @@ -1,55 +0,0 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -import json -from typing import Union - -from th2_data_services.interfaces.adapter import IAdapter - -from google.protobuf.json_format import MessageToDict -from th2_grpc_data_provider.data_provider_pb2 import EventResponse, MessageGroupResponse - - -class GRPCObjectToDictAdapter(IAdapter): - """GRPC Adapter decodes a GRPC object into a Dict object.""" - - def handle(self, record: Union[MessageGroupResponse, EventResponse]) -> dict: - """Decodes MessageGroupResponse or EventResponse as GRPC object into a Dict object. - - Args: - record: MessageGroupResponse/EventResponse. - - Returns: - Dict object. - """ - new_record = MessageToDict(record, including_default_value_fields=True) - - if isinstance(record, EventResponse): - new_record["startTimestamp"] = { - "epochSecond": record.start_timestamp.seconds, - "nano": record.start_timestamp.nanos, - } - new_record["endTimestamp"] = { - "epochSecond": record.end_timestamp.seconds, - "nano": record.end_timestamp.nanos, - } - elif isinstance(record, MessageGroupResponse): - new_record["timestamp"] = {"epochSecond": record.timestamp.seconds, "nano": record.timestamp.nanos} - - try: - new_record["body"] = json.loads(record.body) - except (KeyError, AttributeError, json.JSONDecodeError): - return new_record - except Exception as e: - raise Exception(f"{e}; Current record: {record}") - return new_record diff --git a/th2_data_services/provider/v6/adapters/event_adapters.py b/th2_data_services/provider/v6/adapters/event_adapters.py deleted file mode 100644 index 1e41bf40..00000000 --- a/th2_data_services/provider/v6/adapters/event_adapters.py +++ /dev/null @@ -1,79 +0,0 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -from typing import Optional - -from th2_data_services.interfaces.adapter import IEventAdapter -from th2_data_services.provider.v6.struct import HTTPProvider6EventStruct, http_provider6_event_struct - - -class DeleteEventWrappersAdapter(IEventAdapter): - """Adapter that deletes unnecessary wrappers in events. - - It used for events to which an AdaptorGRPCObjectToDict has been applied. - """ - - def __init__(self, event_struct: HTTPProvider6EventStruct = http_provider6_event_struct): - """AdapterDeleteEventWrappers constructor. - - Args: - event_struct: Event struct. - """ - self._event_struct = event_struct - - def handle(self, event: dict) -> dict: - """Deletes unnecessary wrappers for fields eventId, parentEventId and BatchId. - - Args: - event: Event. - - Returns: - Event without wrappers. - """ - event_id_field = self._event_struct.EVENT_ID - parent_event_id_field = self._event_struct.PARENT_EVENT_ID - batch_id_field = self._event_struct.BATCH_ID - - event_id = self.__get_id_from_wrapper(event, event_id_field) - parent_event_id = self.__get_id_from_wrapper(event, parent_event_id_field) - batch_id = self.__get_id_from_wrapper(event, batch_id_field) - - if event_id: - event[event_id_field] = event_id - if parent_event_id: - event[parent_event_id_field] = parent_event_id - if batch_id: - event[batch_id_field] = batch_id - - return event - - @staticmethod - def __get_id_from_wrapper(event: dict, field: str): - """Opens the wrapper and getting the id.""" - wrapper: dict = event.get(field) - if wrapper: - return wrapper["id"] - return None - - -class DeleteSystemEvents(IEventAdapter): - """Adapter that deletes unnecessary system events.""" - - def handle(self, event: dict) -> Optional[dict]: - """Deletes unnecessary system events. - - System events have form '{'hasEnded': bool, 'hasStarted': bool, 'lastId': bool}' - """ - if event.get("hasEnded") or event.get("hasStarted") or event.get("lastId"): - return None - return event diff --git a/th2_data_services/provider/v6/adapters/message_adapters.py b/th2_data_services/provider/v6/adapters/message_adapters.py deleted file mode 100644 index 1b0789b4..00000000 --- a/th2_data_services/provider/v6/adapters/message_adapters.py +++ /dev/null @@ -1,140 +0,0 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -import pprint -from _warnings import warn -from typing import Union, List - -from th2_data_services.interfaces.adapter import IMessageAdapter -from th2_data_services.provider.v6.struct import HTTPProvider6MessageStruct, grpc_provider6_message_struct - - -class DeleteMessageWrappersAdapter(IMessageAdapter): - """Adapter that deletes unnecessary wrappers in messages. - - It used for the message to which an AdaptorGRPCObjectToDict has been applied. - """ - - def __init__(self, message_struct: HTTPProvider6MessageStruct = grpc_provider6_message_struct): - """AdapterDeleteMessageWrappers constructor. - - Args: - message_struct: Message struct. - """ - self._message_struct = message_struct - - def handle(self, message: dict) -> dict: - """Deletes unnecessary wrappers for field message_id. - - Args: - message: Message. - - Returns: - Message without wrappers. - """ - message_id_field = self._message_struct.MESSAGE_ID - - message_id = message[message_id_field] - - session = message_id[self._message_struct.CONNECTION_ID][self._message_struct.SESSION_ALIAS] - direction = message_id[self._message_struct.DIRECTION] - sequence = message_id[self._message_struct.SEQUENCE] - - message_id = f"{session}:{direction}:{sequence}" - message[message_id_field] = message_id - - return message - - -class CodecPipelinesAdapter(IMessageAdapter): - """Adapter for codec-pipeline messages from provider v6. - - Codec-pipeline messages have sub-messages in the body. - This adapter used for split codec-pipeline message to separate messages. - """ - - def __init__(self, ignore_errors=False): - """AdapterCodecPipelines constructor. - - Args: - ignore_errors: If True it will ignore errors and return message as is. - """ - self._ignore_errors = ignore_errors - - def handle(self, message: dict) -> Union[List[dict], dict]: - """Adapter handler. - - Args: - message: Th2Message dict. - - Returns: - Th2Message dict. - """ - msg_type = message.get("messageType") - if msg_type is None: - if self._ignore_errors: - warn( - "Please note, some messages don't have a messageType field. Perhaps a codec didn't decode them.", - stacklevel=3, - ) - return message - else: - raise ValueError( - "The messages doesn't have a messageType field. Message:\n" f"{pprint.pformat(message)}" - ) - - if "/" not in msg_type: - return message - - body = message["body"] - if not body: - return message - - sub_messages = [] - fields = body["fields"] - if not fields: - return message - - for sub_msg in fields: - split_msg_name = sub_msg.split("-") - if len(split_msg_name) > 1: - sub_msg_type, index = "".join(split_msg_name[:-1]), int(split_msg_name[-1]) - else: - index = msg_type.split("/").index(sub_msg) + 1 - sub_msg_type = sub_msg - - new_record = message.copy() - - metadata = new_record["body"]["metadata"].copy() - id_field = metadata["id"].copy() - id_field["subsequence"] = [index] - metadata["id"] = id_field - - body_fields = fields[sub_msg] - metadata.update(body_fields.get("metadata", {})) - - body = {"metadata": metadata} - if body_fields.get("messageValue"): - body = {**body_fields["messageValue"], **body} - elif body_fields.get("fields"): - body = {**body_fields["fields"], **body} - else: - body = {"fields": {}, **body} - - new_record["body"] = body - new_record["body"]["metadata"]["messageType"] = sub_msg_type - new_record["messageType"] = sub_msg_type - new_record["messageId"] = f"{message['messageId']}.{index}" - sub_messages.append(new_record) - - return sub_messages diff --git a/th2_data_services/provider/v6/command_resolver.py b/th2_data_services/provider/v6/command_resolver.py deleted file mode 100644 index 9cd2e410..00000000 --- a/th2_data_services/provider/v6/command_resolver.py +++ /dev/null @@ -1,63 +0,0 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from typing import Union, Type - -from th2_data_services.provider.interfaces import IProviderDataSource -from th2_data_services.provider.v6.commands.grpc import GetEventsById as GetEventsByIdFromGRPC -from th2_data_services.provider.v6.commands.http import GetEventsById as GetEventsByIdFromHTTP - -from th2_data_services.provider.v6.commands.grpc import GetEventById as GetEventByIdFromGRPC -from th2_data_services.provider.v6.commands.http import GetEventById as GetEventByIdFromHTTP - -from th2_data_services.provider.v6.data_source.grpc import GRPCProvider6DataSource -from th2_data_services.provider.v6.data_source.http import HTTPProvider6DataSource - - -def resolver_get_event_by_id( - data_source: IProviderDataSource, -) -> Union[Type[GetEventByIdFromHTTP], Type[GetEventByIdFromGRPC]]: - """Resolves what 'GetEventById' command you need to use based Data Source. - - Args: - data_source: DataSource instance. - - Returns: - GetEventById command. - """ - if isinstance(data_source, GRPCProvider6DataSource): - return GetEventByIdFromGRPC - elif isinstance(data_source, HTTPProvider6DataSource): - return GetEventByIdFromHTTP - else: - raise ValueError("Unknown DataSource Object") - - -def resolver_get_events_by_id( - data_source: IProviderDataSource, -) -> Union[Type[GetEventsByIdFromHTTP], Type[GetEventsByIdFromGRPC]]: - """Resolves what 'GetEventsById' command you need to use based Data Source. - - Args: - data_source: DataSource instance. - - Returns: - GetEventsById command. - """ - if isinstance(data_source, GRPCProvider6DataSource): - return GetEventsByIdFromGRPC - elif isinstance(data_source, HTTPProvider6DataSource): - return GetEventsByIdFromHTTP - else: - raise ValueError("Unknown DataSource Object") diff --git a/th2_data_services/provider/v6/commands/__init__.py b/th2_data_services/provider/v6/commands/__init__.py deleted file mode 100644 index c46552ee..00000000 --- a/th2_data_services/provider/v6/commands/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. diff --git a/th2_data_services/provider/v6/commands/grpc.py b/th2_data_services/provider/v6/commands/grpc.py deleted file mode 100644 index 02547f24..00000000 --- a/th2_data_services/provider/v6/commands/grpc.py +++ /dev/null @@ -1,565 +0,0 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from datetime import datetime, timezone -from functools import partial -from typing import List, Iterable, Generator, Union - -from grpc._channel import _InactiveRpcError -from th2_grpc_data_provider.data_provider_pb2 import EventResponse, MessageGroupResponse, MessageStreamPointer - -from th2_data_services import Data -from th2_data_services.provider.v6.filters.filter import Provider6Filter as Filter -from th2_data_services.provider.command import ProviderAdaptableCommand -from th2_data_services.provider.exceptions import EventNotFound, MessageNotFound -from th2_data_services.provider.v6.adapters.basic_adapters import GRPCObjectToDictAdapter -from th2_data_services.provider.v6.adapters.event_adapters import DeleteEventWrappersAdapter -from th2_data_services.provider.v6.adapters.message_adapters import DeleteMessageWrappersAdapter -from th2_data_services.provider.v6.interfaces.command import IGRPCProvider6Command - -from th2_data_services.provider.v6.data_source.grpc import GRPCProvider6DataSource -from th2_data_services.provider.v6.provider_api import GRPCProvider6API - -import logging - -from th2_data_services.provider.v6.streams import Streams - -logger = logging.getLogger(__name__) - - -class GetEventByIdGRPCObject(IGRPCProvider6Command, ProviderAdaptableCommand): - """A Class-Command for request to rpt-data-provider. - - It retrieves the event by id as GRPC object. - - Returns: - EventResponse: Th2 event. - """ - - def __init__(self, id: str): - """GetEventByIdGRPCObject constructor. - - Args: - id: Event id. - - """ - super().__init__() - self._id = id - - def handle(self, data_source: GRPCProvider6DataSource) -> EventResponse: # noqa: D102 - api: GRPCProvider6API = data_source.source_api - event = api.get_event(self._id) - - event = self._handle_adapters(event) - return event - - -class GetEventById(IGRPCProvider6Command, ProviderAdaptableCommand): - """A Class-Command for request to rpt-data-provider. - - It retrieves the event by id with `attachedMessageIds` list. - - Returns: - dict: Th2 event. - - Raises: - EventNotFound: If event by Id wasn't found. - """ - - def __init__(self, id: str, use_stub=False): - """GetEventById constructor. - - Args: - id: Event id. - use_stub: If True the command returns stub instead of exception. - - """ - super().__init__() - self._id = id - self._grpc_decoder = GRPCObjectToDictAdapter() - self._wrapper_deleter = DeleteEventWrappersAdapter() - self._stub_status = use_stub - - def handle(self, data_source: GRPCProvider6DataSource) -> dict: # noqa: D102 - try: - event = GetEventByIdGRPCObject(self._id).handle(data_source) - event = self._grpc_decoder.handle(event) - event = self._wrapper_deleter.handle(event) - except _InactiveRpcError: - if self._stub_status: - event = data_source.event_stub_builder.build({data_source.event_struct.EVENT_ID: self._id}) - else: - logger.error(f"Unable to find the event. Id: {self._id}") - raise EventNotFound(self._id) - - event = self._handle_adapters(event) - return event - - -class GetEventsById(IGRPCProvider6Command, ProviderAdaptableCommand): - """A Class-Command for request to rpt-data-provider. - - It retrieves the events by ids with `attachedMessageIds` list. - - Returns: - List[dict]: Th2 events. - - Raises: - EventNotFound: If any event by Id wasn't found. - """ - - def __init__(self, ids: List[str], use_stub=False): - """GetEventsById constructor. - - Args: - ids: Events ids. - use_stub: If True the command returns stub instead of exception. - - """ - super().__init__() - self.ids = ids - self._stub_status = use_stub - - def handle(self, data_source: GRPCProvider6DataSource) -> List[dict]: # noqa: D102 - response = [] - for event_id in self.ids: - event = GetEventById(event_id, use_stub=self._stub_status).handle(data_source=data_source) - event = self._handle_adapters(event) - response.append(event) - - return response - - -class GetEventsGRPCObjects(IGRPCProvider6Command, ProviderAdaptableCommand): - """A Class-Command for request to rpt-data-provider. - - It searches events stream as GRPC object by options. - - Returns: - Iterable[EventResponse]: Stream of Th2 events. - """ - - def __init__( - self, - start_timestamp: datetime, - end_timestamp: datetime = None, - parent_event: str = None, - search_direction: str = "NEXT", - resume_from_id: str = None, - result_count_limit: int = None, - keep_open: bool = False, - limit_for_parent: int = None, - attached_messages: bool = False, - filters: List[Filter] = None, - ): - """GetEventsGRPCObjects constructor. - - Args: - start_timestamp: Start timestamp of search. - end_timestamp: End timestamp of search. - resume_from_id: Event id from which search starts. - parent_event: Match events to the specified parent. - search_direction: Search direction. - result_count_limit: Result count limit. - keep_open: If the search has reached the current moment. - It is need to wait further for the appearance of new data. - the one closest to the specified timestamp. - limit_for_parent: How many children events for each parent do we want to request. - attached_messages: Gets messages ids which linked to events. - filters: Filters using in search for messages. - - """ - super().__init__() - self._start_timestamp = start_timestamp - self._end_timestamp = end_timestamp - self._parent_event = parent_event - self._search_direction = search_direction - self._resume_from_id = resume_from_id - self._result_count_limit = result_count_limit - self._keep_open = keep_open - self._limit_for_parent = limit_for_parent - self._metadata_only = False - self._attached_messages = attached_messages - self._filters = filters - - def handle(self, data_source: GRPCProvider6DataSource) -> Iterable[EventResponse]: # noqa: D102 - api: GRPCProvider6API = data_source.source_api - - start_timestamp = int(self._start_timestamp.replace(tzinfo=timezone.utc).timestamp() * 10 ** 9) - end_timestamp = int(self._end_timestamp.replace(tzinfo=timezone.utc).timestamp() * 10 ** 9) - - stream_response = api.search_events( - start_timestamp=start_timestamp, - end_timestamp=end_timestamp, - parent_event=self._parent_event, - search_direction=self._search_direction, - resume_from_id=self._resume_from_id, - result_count_limit=self._result_count_limit, - keep_open=self._keep_open, - limit_for_parent=self._limit_for_parent, - metadata_only=self._metadata_only, - attached_messages=self._attached_messages, - filters=self._filters, - ) - for response in stream_response: - if response.WhichOneof("data") == "event": - response = self._handle_adapters(response) - yield response.event - - -class GetEvents(IGRPCProvider6Command, ProviderAdaptableCommand): - """A Class-Command for request to rpt-data-provider. - - It searches events stream by options. - - Returns: - Iterable[dict]: Stream of Th2 events. - """ - - def __init__( - self, - start_timestamp: datetime, - end_timestamp: datetime = None, - parent_event: str = None, - search_direction: str = "NEXT", - resume_from_id: str = None, - result_count_limit: int = None, - keep_open: bool = False, - limit_for_parent: int = None, - attached_messages: bool = False, - filters: List[Filter] = None, - cache: bool = False, - ): - """GetEvents constructor. - - Args: - start_timestamp: Start timestamp of search. - end_timestamp: End timestamp of search. - resume_from_id: Event id from which search starts. - parent_event: Match events to the specified parent. - search_direction: Search direction. - result_count_limit: Result count limit. - keep_open: If the search has reached the current moment. - It is need to wait further for the appearance of new data. - the one closest to the specified timestamp. - limit_for_parent: How many children events for each parent do we want to request. - attached_messages: Gets messages ids which linked to events. - filters: Filters using in search for messages. - cache: If True, all requested data from rpt-data-provider will be saved to cache. - - """ - super().__init__() - self._start_timestamp = start_timestamp - self._end_timestamp = end_timestamp - self._parent_event = parent_event - self._search_direction = search_direction - self._resume_from_id = resume_from_id - self._result_count_limit = result_count_limit - self._keep_open = keep_open - self._limit_for_parent = limit_for_parent - self._metadata_only = False - self._attached_messages = attached_messages - self._filters = filters - self._cache = cache - - self._grpc_decoder = GRPCObjectToDictAdapter() - self._wrapper_deleter = DeleteEventWrappersAdapter() - - def handle(self, data_source: GRPCProvider6DataSource) -> Data: # noqa: D102 - source = partial(self.__handle_stream, data_source) - return Data(source, cache=self._cache) - - def __handle_stream(self, data_source: GRPCProvider6DataSource) -> Generator[dict, None, None]: - stream = GetEventsGRPCObjects( - start_timestamp=self._start_timestamp, - end_timestamp=self._end_timestamp, - parent_event=self._parent_event, - search_direction=self._search_direction, - resume_from_id=self._resume_from_id, - result_count_limit=self._result_count_limit, - keep_open=self._keep_open, - limit_for_parent=self._limit_for_parent, - attached_messages=self._attached_messages, - filters=self._filters, - ).handle(data_source) - for event in stream: - event = self._grpc_decoder.handle(event) - event = self._wrapper_deleter.handle(event) - event = self._handle_adapters(event) - yield event - - -class GetMessageByIdGRPCObject(IGRPCProvider6Command, ProviderAdaptableCommand): # noqa: D102 - """A Class-Command for request to rpt-data-provider. - - It retrieves the message by id as GRPC Object. - - Returns: - MessageGroupResponse: Th2 message. - """ - - def __init__(self, id: str): - """GetMessageByIdGRPCObject constructor. - - Args: - id: Message id. - - """ - super().__init__() - self._id = id - - def handle(self, data_source: GRPCProvider6DataSource) -> MessageGroupResponse: - api: GRPCProvider6API = data_source.source_api - response = api.get_message(self._id) - response = self._handle_adapters(response) - return response - - -class GetMessageById(IGRPCProvider6Command, ProviderAdaptableCommand): # noqa: D102 - """A Class-Command for request to rpt-data-provider. - - It retrieves the message by id. - - Please note, Provider6 doesn't return `attachedEventIds`. It will be == []. - It's expected that Provider7 will be support it. - - Returns: - dict: Th2 message. - - Raises: - MessageNotFound: If message by id wasn't found. - """ - - def __init__(self, id: str, use_stub=False): - """GetMessageById constructor. - - Args: - id: Message id. - use_stub: If True the command returns stub instead of exception. - - """ - super().__init__() - self._id = id - self._decoder = GRPCObjectToDictAdapter() - self._wrapper_deleter = DeleteMessageWrappersAdapter() - self._stub_status = use_stub - - def handle(self, data_source: GRPCProvider6DataSource) -> dict: # noqa: D102 - try: - message = GetMessageByIdGRPCObject(self._id).handle(data_source) - message = self._decoder.handle(message) - message = self._wrapper_deleter.handle(message) - except _InactiveRpcError: - if self._stub_status: - message = data_source.message_stub_builder.build({data_source.message_struct.MESSAGE_ID: self._id}) - else: - logger.error(f"Unable to find the message. Id: {self._id}") - raise MessageNotFound(self._id) - message = self._handle_adapters(message) - return message - - -class GetMessagesById(IGRPCProvider6Command, ProviderAdaptableCommand): - """A Class-Command for request to rpt-data-provider. - - It retrieves the messages by id. - - Please note, Provider6 doesn't return `attachedEventIds`. It will be == []. - It's expected that Provider7 will be support it. - - Returns: - List[dict]: Th2 messages. - - Raises: - MessageNotFound: If any message by id wasn't found. - """ - - def __init__(self, ids: List[str], use_stub=False): - """GetMessagesById constructor. - - Args: - ids: Messages id. - use_stub: If True the command returns stub instead of exception. - - """ - super().__init__() - self._ids = ids - self._stub_status = use_stub - - def handle(self, data_source: GRPCProvider6DataSource) -> List[dict]: # noqa: D102 - response = [] - for id_ in self._ids: - message = GetMessageById(id_, use_stub=self._stub_status).handle(data_source) - message = self._handle_adapters(message) - response.append(message) - - return response - - -class GetMessagesGRPCObject(IGRPCProvider6Command, ProviderAdaptableCommand): - """A Class-Command for request to rpt-data-provider. - - It searches messages stream as GRPC object by options. - - Returns: - Iterable[MessageGroupResponse]: Stream of Th2 messages. - """ - - def __init__( - self, - start_timestamp: datetime, - stream: List[Union[str, Streams]], - end_timestamp: datetime = None, - search_direction: str = "NEXT", - result_count_limit: int = None, - keep_open: bool = False, - message_id: List[str] = None, - attached_events: bool = False, - stream_pointers: List[MessageStreamPointer] = None, - filters: List[Filter] = None, - ): - """GetMessagesGRPCObject constructor. - - Args: - start_timestamp: Start timestamp of search. - end_timestamp: End timestamp of search. - stream: Alias of messages. - search_direction: Search direction. - result_count_limit: Result count limit. - keep_open: If the search has reached the current moment. - It is need to wait further for the appearance of new data. - message_id: List of message ids to restore the search - attached_events: If true, it will additionally load attachedEventsIds. - stream_pointers: List of stream pointers to restore the search from. - start_timestamp will be ignored if this parameter is specified. This parameter is only received - from the provider. - filters: Filters using in search for messages. - """ - super().__init__() - self._start_timestamp = start_timestamp - self._end_timestamp = end_timestamp - self._stream = stream - self._search_direction = search_direction - self._result_count_limit = result_count_limit - self._keep_open = keep_open - self._filters = filters - self._message_id = message_id - self._attached_events = attached_events - self._stream_pointers = stream_pointers - - def handle(self, data_source: GRPCProvider6DataSource) -> List[MessageGroupResponse]: - api = data_source.source_api - - start_timestamp = int(self._start_timestamp.replace(tzinfo=timezone.utc).timestamp() * 10 ** 9) - end_timestamp = int(self._end_timestamp.replace(tzinfo=timezone.utc).timestamp() * 10 ** 9) - - stream_response = api.search_messages( - start_timestamp=start_timestamp, - end_timestamp=end_timestamp, - stream=self._stream, - search_direction=self._search_direction, - result_count_limit=self._result_count_limit, - keep_open=self._keep_open, - filters=self._filters, - stream_pointer=self._stream_pointers, - attached_events=self._attached_events, - ) - for response in stream_response: - if response.WhichOneof("data") == "message": - response = self._handle_adapters(response) - yield response.message - - -class GetMessages(IGRPCProvider6Command, ProviderAdaptableCommand): - """A Class-Command for request to rpt-data-provider. - - It searches messages stream by options. - - Returns: - Iterable[dict]: Stream of Th2 messages. - """ - - def __init__( - self, - start_timestamp: datetime, - stream: List[Union[str, Streams]], - end_timestamp: datetime = None, - resume_from_id: str = None, - search_direction: str = "NEXT", - result_count_limit: int = None, - keep_open: bool = False, - filters: List[Filter] = None, - message_id: List[str] = None, - attached_events: bool = False, - stream_pointers: List[MessageStreamPointer] = None, - cache: bool = False, - ): - """GetMessages constructor. - - Args: - start_timestamp: Start timestamp of search. - end_timestamp: End timestamp of search. - stream: Alias of messages. - resume_from_id: Message id from which search starts. - search_direction: Search direction. - result_count_limit: Result count limit. - keep_open: If the search has reached the current moment. - It is need to wait further for the appearance of new data. - filters: Filters using in search for messages. - message_id: List of message ids to restore the search - attached_events: If true, it will additionally load attachedEventsIds. - stream_pointers: List of stream pointers to restore the search from. - start_timestamp will be ignored if this parameter is specified. This parameter is only received - from the provider. - cache: If True, all requested data from rpt-data-provider will be saved to cache. - """ - super().__init__() - self._start_timestamp = start_timestamp - self._end_timestamp = end_timestamp - self._stream = stream - self._resume_from_id = resume_from_id - self._search_direction = search_direction - self._result_count_limit = result_count_limit - self._keep_open = keep_open - self._filters = filters - self._message_id = message_id - self._attached_events = attached_events - self._stream_pointers = stream_pointers - self._cache = cache - - self._decoder = GRPCObjectToDictAdapter() - self._wrapper_deleter = DeleteMessageWrappersAdapter() - - def handle(self, data_source: GRPCProvider6DataSource) -> Data: - source = partial(self.__handle_stream, data_source) - return Data(source, cache=self._cache) - - def __handle_stream(self, data_source: GRPCProvider6DataSource) -> Iterable[dict]: - stream = GetMessagesGRPCObject( - start_timestamp=self._start_timestamp, - end_timestamp=self._end_timestamp, - stream=self._stream, - search_direction=self._search_direction, - result_count_limit=self._result_count_limit, - keep_open=self._keep_open, - message_id=self._message_id, - attached_events=self._attached_events, - stream_pointers=self._stream_pointers, - filters=self._filters, - ).handle(data_source) - for message in stream: - message = self._decoder.handle(message) - message = self._wrapper_deleter.handle(message) - message = self._handle_adapters(message) - yield message diff --git a/th2_data_services/provider/v6/commands/http.py b/th2_data_services/provider/v6/commands/http.py deleted file mode 100644 index e10b9656..00000000 --- a/th2_data_services/provider/v6/commands/http.py +++ /dev/null @@ -1,710 +0,0 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from typing import Generator, List, Union -from datetime import datetime, timezone -from functools import partial - -from th2_data_services import Data -from th2_data_services.provider.v6.adapters.event_adapters import DeleteSystemEvents -from th2_data_services.provider.v6.filters.filter import Provider6Filter as Filter -from th2_data_services.provider.exceptions import EventNotFound, MessageNotFound -from th2_data_services.provider.v6.interfaces.command import IHTTPProvider6Command -from th2_data_services.provider.v6.data_source.http import HTTPProvider6DataSource -from th2_data_services.provider.v6.provider_api import HTTPProvider6API -from th2_data_services.provider.command import ProviderAdaptableCommand -from th2_data_services.provider.v6.streams import Streams -from th2_data_services.sse_client import SSEClient -from th2_data_services.provider.adapters.adapter_sse import SSEAdapter -from th2_data_services.decode_error_handler import UNICODE_REPLACE_HANDLER - -import logging - -logger = logging.getLogger(__name__) - - -class GetEventById(IHTTPProvider6Command, ProviderAdaptableCommand): - """A Class-Command for request to rpt-data-provider. - - It retrieves the event by id with `attachedMessageIds` list. - - Returns: - dict: Th2 event. - - Raises: - EventNotFound: If event by Id wasn't found. - """ - - def __init__(self, id: str, use_stub=False): - """GetEventById constructor. - - Args: - id: Event id. - use_stub: If True the command returns stub instead of exception. - - """ - super().__init__() - self._id = id - self._stub_status = use_stub - - def handle(self, data_source: HTTPProvider6DataSource) -> dict: # noqa: D102 - api: HTTPProvider6API = data_source.source_api - url = api.get_url_find_event_by_id(self._id) - - logger.info(url) - - response = api.execute_request(url) - - if response.status_code == 404 and self._stub_status: - return data_source.event_stub_builder.build({data_source.event_struct.EVENT_ID: self._id}) - elif response.status_code == 404: - logger.error(f"Unable to find the message. Id: {self._id}") - raise EventNotFound(self._id) - else: - return self._handle_adapters(response.json()) - - -class GetEventsById(IHTTPProvider6Command, ProviderAdaptableCommand): - """A Class-Command for request to rpt-data-provider. - - It retrieves the events by ids with `attachedMessageIds` list. - - Returns: - List[dict]: Th2 events. - - Raises: - EventNotFound: If any event by Id wasn't found. - """ - - def __init__(self, ids: List[str], use_stub=False): - """GetEventsById constructor. - - Args: - ids: Event id list. - use_stub: If True the command returns stub instead of exception. - - """ - super().__init__() - self._ids: ids = ids - self._stub_status = use_stub - - def handle(self, data_source: HTTPProvider6DataSource): # noqa: D102 - result = [] - for event_id in self._ids: - event = GetEventById(event_id, use_stub=self._stub_status).handle(data_source) - result.append(self._handle_adapters(event)) - - return result - - -class GetEventsSSEBytes(IHTTPProvider6Command, ProviderAdaptableCommand): - """A Class-Command for request to rpt-data-provider. - - It searches events stream by options. - - Returns: - Iterable[dict]: Stream of Th2 events. - """ - - def __init__( - self, - start_timestamp: datetime, - end_timestamp: datetime = None, - parent_event: str = None, - search_direction: str = "next", - resume_from_id: str = None, - result_count_limit: int = None, - keep_open: bool = False, - limit_for_parent: int = None, - attached_messages: bool = False, - filters: (Filter, List[Filter]) = None, - ): - """GetEventsSSEBytes constructor. - - Args: - start_timestamp: Start timestamp of search. - end_timestamp: End timestamp of search. - parent_event: Match events to the specified parent. - search_direction: Search direction. - resume_from_id: Event id from which search starts. - result_count_limit: Result count limit. - keep_open: If the search has reached the current moment. - It is need to wait further for the appearance of new data. - the one closest to the specified timestamp. - limit_for_parent: How many children events for each parent do we want to request. - attached_messages: Gets messages ids which linked to events. - filters: Filters using in search for messages. - - """ - super().__init__() - self._start_timestamp = start_timestamp.replace(tzinfo=timezone.utc).strftime("%Y-%m-%dT%H:%M:%S.%fZ") - self._end_timestamp = end_timestamp.replace(tzinfo=timezone.utc).strftime("%Y-%m-%dT%H:%M:%S.%fZ") - self._parent_event = parent_event - self._search_direction = search_direction - self._resume_from_id = resume_from_id - self._result_count_limit = result_count_limit - self._keep_open = keep_open - self._limit_for_parent = limit_for_parent - self._metadata_only = False - self._attached_messages = attached_messages - self._filters = filters - if isinstance(filters, Filter): - self._filters = filters.url() - elif isinstance(filters, (tuple, list)): - self._filters = "".join([filter_.url() for filter_ in filters]) - - def handle(self, data_source: HTTPProvider6DataSource): # noqa: D102 - api: HTTPProvider6API = data_source.source_api - url = api.get_url_search_sse_events( - start_timestamp=self._start_timestamp, - end_timestamp=self._end_timestamp, - parent_event=self._parent_event, - search_direction=self._search_direction, - resume_from_id=self._resume_from_id, - result_count_limit=self._result_count_limit, - keep_open=self._keep_open, - limit_for_parent=self._limit_for_parent, - metadata_only=self._metadata_only, - attached_messages=self._attached_messages, - filters=self._filters, - ) - - logger.info(url) - - for response in api.execute_sse_request(url): - response = self._handle_adapters(response) - if response is not None: - yield response - - -class GetEventsSSEEvents(IHTTPProvider6Command, ProviderAdaptableCommand): - """A Class-Command for request to rpt-data-provider. - - It searches events stream by options. - - Returns: - Iterable[dict]: Stream of Th2 events. - """ - - def __init__( - self, - start_timestamp: datetime, - end_timestamp: datetime = None, - parent_event: str = None, - search_direction: str = "next", - resume_from_id: str = None, - result_count_limit: int = None, - keep_open: bool = False, - limit_for_parent: int = None, - attached_messages: bool = False, - filters: (Filter, List[Filter]) = None, - char_enc: str = "utf-8", - decode_error_handler: str = UNICODE_REPLACE_HANDLER, - ): - """GetEventsSSEEvents constructor. - - Args: - start_timestamp: Start timestamp of search. - end_timestamp: End timestamp of search. - parent_event: Match events to the specified parent. - search_direction: Search direction. - resume_from_id: Event id from which search starts. - result_count_limit: Result count limit. - keep_open: If the search has reached the current moment. - It is need to wait further for the appearance of new data. - the one closest to the specified timestamp. - limit_for_parent: How many children events for each parent do we want to request. - attached_messages: Gets messages ids which linked to events. - filters: Filters using in search for messages. - char_enc: Encoding for the byte stream. - decode_error_handler: Registered decode error handler. - - """ - super().__init__() - self._start_timestamp = start_timestamp - self._end_timestamp = end_timestamp - self._parent_event = parent_event - self._search_direction = search_direction - self._resume_from_id = resume_from_id - self._result_count_limit = result_count_limit - self._keep_open = keep_open - self._limit_for_parent = limit_for_parent - self._attached_messages = attached_messages - self._filters = filters - self._char_enc = char_enc - self._decode_error_handler = decode_error_handler - - def handle(self, data_source: HTTPProvider6DataSource): # noqa: D102 - response = GetEventsSSEBytes( - start_timestamp=self._start_timestamp, - end_timestamp=self._end_timestamp, - parent_event=self._parent_event, - search_direction=self._search_direction, - resume_from_id=self._resume_from_id, - result_count_limit=self._result_count_limit, - keep_open=self._keep_open, - limit_for_parent=self._limit_for_parent, - attached_messages=self._attached_messages, - filters=self._filters, - ).handle(data_source) - client = SSEClient(response, char_enc=self._char_enc, decode_errors_handler=self._decode_error_handler) - for record in client.events(): - record = self._handle_adapters(record) - if record is not None: - yield record - - -class GetEvents(IHTTPProvider6Command, ProviderAdaptableCommand): - """A Class-Command for request to rpt-data-provider. - - It searches events stream by options. - - Returns: - Iterable[dict]: Stream of Th2 events. - """ - - def __init__( - self, - start_timestamp: datetime, - end_timestamp: datetime = None, - parent_event: str = None, - search_direction: str = "next", - resume_from_id: str = None, - result_count_limit: int = None, - keep_open: bool = False, - limit_for_parent: int = None, - attached_messages: bool = False, - filters: (Filter, List[Filter]) = None, - cache: bool = False, - ): - """GetEvents constructor. - - Args: - start_timestamp: Start timestamp of search. - end_timestamp: End timestamp of search. - parent_event: Match events to the specified parent. - search_direction: Search direction. - resume_from_id: Event id from which search starts. - result_count_limit: Result count limit. - keep_open: If the search has reached the current moment. - It is need to wait further for the appearance of new data. - the one closest to the specified timestamp. - limit_for_parent: How many children events for each parent do we want to request. - attached_messages: Gets messages ids which linked to events. - filters: Filters using in search for messages. - cache: If True, all requested data from rpt-data-provider will be saved to cache. - - """ - super().__init__() - self._start_timestamp = start_timestamp - self._end_timestamp = end_timestamp - self._parent_event = parent_event - self._search_direction = search_direction - self._resume_from_id = resume_from_id - self._result_count_limit = result_count_limit - self._keep_open = keep_open - self._limit_for_parent = limit_for_parent - self._attached_messages = attached_messages - self._filters = filters - self._cache = cache - - self._sse_adapter = SSEAdapter() - self._event_system_adapter = DeleteSystemEvents() - - def handle(self, data_source: HTTPProvider6DataSource) -> Data: # noqa: D102 - source = partial(self.__handle_stream, data_source) - return Data(source).use_cache(self._cache) - - def __handle_stream(self, data_source: HTTPProvider6DataSource) -> Generator[dict, None, None]: - stream = GetEventsSSEEvents( - start_timestamp=self._start_timestamp, - end_timestamp=self._end_timestamp, - parent_event=self._parent_event, - search_direction=self._search_direction, - resume_from_id=self._resume_from_id, - result_count_limit=self._result_count_limit, - keep_open=self._keep_open, - limit_for_parent=self._limit_for_parent, - attached_messages=self._attached_messages, - filters=self._filters, - ).handle(data_source) - - for event in stream: - event = self._sse_adapter.handle(event) - if event is None: - continue - - event = self._event_system_adapter.handle(event) - if event is None: - continue - - event = self._handle_adapters(event) - yield event - - -class GetMessageById(IHTTPProvider6Command, ProviderAdaptableCommand): - """A Class-Command for request to rpt-data-provider. - - It retrieves the message by id. - - Please note, Provider6 doesn't return `attachedEventIds`. It will be == []. - It's expected that Provider7 will be support it. - - Returns: - dict: Th2 message. - - Raises: - MessageNotFound: If message by id wasn't found. - """ - - def __init__(self, id: str, use_stub=False): - """GetMessageById constructor. - - Args: - id: Message id. - use_stub: If True the command returns stub instead of exception. - - """ - super().__init__() - self._id = id - self._stub_status = use_stub - - def handle(self, data_source: HTTPProvider6DataSource) -> dict: # noqa: D102 - api: HTTPProvider6API = data_source.source_api - url = api.get_url_find_message_by_id(self._id) - - logger.info(url) - - response = api.execute_request(url) - - if response.status_code == 404 and self._stub_status: - return data_source.message_stub_builder.build({data_source.message_struct.MESSAGE_ID: self._id}) - elif response.status_code == 404: - logger.error(f"Unable to find the message. Id: {self._id}") - raise MessageNotFound(self._id) - else: - return self._handle_adapters(response.json()) - - -class GetMessagesById(IHTTPProvider6Command, ProviderAdaptableCommand): - """A Class-Command for request to rpt-data-provider. - - It retrieves the messages by ids. - - Please note, Provider6 doesn't return `attachedEventIds`. It will be == []. - It's expected that Provider7 will be support it. - - Returns: - List[dict]: Th2 messages. - - Raises: - MessageNotFound: If any message by id wasn't found. - """ - - def __init__(self, ids: List[str], use_stub=False): - """GetMessagesById constructor. - - Args: - ids: Message id list. - use_stub: If True the command returns stub instead of exception. - - """ - super().__init__() - self._ids: ids = ids - self._stub_status = use_stub - - def handle(self, data_source: HTTPProvider6DataSource) -> List[dict]: # noqa: D102 - result = [] - for message_id in self._ids: - message = GetMessageById(message_id, use_stub=self._stub_status).handle(data_source) - result.append(self._handle_adapters(message)) - - return result - - -class GetMessagesSSEBytes(IHTTPProvider6Command, ProviderAdaptableCommand): - """A Class-Command for request to rpt-data-provider. - - It searches messages stream by options. - - Returns: - Iterable[dict]: Stream of Th2 messages. - """ - - def __init__( - self, - start_timestamp: datetime, - stream: List[Union[str, Streams]], - end_timestamp: datetime = None, - resume_from_id: str = None, - search_direction: str = "next", - result_count_limit: int = None, - keep_open: bool = False, - message_id: List[str] = None, - attached_events: bool = False, - lookup_limit_days: int = None, - filters: (Filter, List[Filter]) = None, - ): - """GetMessagesSSEBytes constructor. - - Args: - start_timestamp: Start timestamp of search. - end_timestamp: End timestamp of search. - stream: Alias of messages. - resume_from_id: Message id from which search starts. - search_direction: Search direction. - result_count_limit: Result count limit. - keep_open: If the search has reached the current moment. - It is need to wait further for the appearance of new data. - message_id: List of message IDs to restore search. If given, it has - the highest priority and ignores stream (uses streams from ids), startTimestamp and resumeFromId. - attached_events: If true, additionally load attached_event_ids - lookup_limit_days: The number of days that will be viewed on - the first request to get the one closest to the specified timestamp. - filters: Filters using in search for messages. - """ - super().__init__() - self._start_timestamp = start_timestamp.replace(tzinfo=timezone.utc).strftime("%Y-%m-%dT%H:%M:%S.%fZ") - self._end_timestamp = ( - end_timestamp - if end_timestamp is None - else end_timestamp.replace(tzinfo=timezone.utc).strftime("%Y-%m-%dT%H:%M:%S.%fZ") - ) - self._stream = stream - self._resume_from_id = resume_from_id - self._search_direction = search_direction - self._result_count_limit = result_count_limit - self._keep_open = keep_open - self._message_id = message_id - self._attached_events = attached_events - self._lookup_limit_days = lookup_limit_days - self._filters = filters - if isinstance(filters, Filter): - self._filters = filters.url() - elif isinstance(filters, (tuple, list)): - self._filters = "".join([filter_.url() for filter_ in filters]) - - def handle(self, data_source: HTTPProvider6DataSource) -> Generator[dict, None, None]: # noqa: D102 - api: HTTPProvider6API = data_source.source_api - url = api.get_url_search_sse_messages( - start_timestamp=self._start_timestamp, - end_timestamp=self._end_timestamp, - stream=[""], - resume_from_id=self._resume_from_id, - search_direction=self._search_direction, - result_count_limit=self._result_count_limit, - keep_open=self._keep_open, - attached_events=self._attached_events, - lookup_limit_days=self._lookup_limit_days, - filters=self._filters, - ).replace("&stream=", "") - - fixed_part_len = len(url) - current_url, resulting_urls = "", [] - for stream in self._stream: - if isinstance(stream, Streams): - stream = f"&{stream.url()}" - else: - splitted_stream = stream.split(":") - if len(splitted_stream) > 1: - name, search_direction = ":".join(splitted_stream[0:-1]), splitted_stream[-1].upper() - if search_direction in ("FIRST", "SECOND"): - stream = f"&stream={name}:{search_direction}" - else: - stream = f"&stream={stream}:FIRST&stream={stream}:SECOND" - else: - stream = f"&stream={stream}:FIRST&stream={stream}:SECOND" - - if fixed_part_len + len(current_url) + len(stream) >= 2048: - resulting_urls.append(url + current_url) - current_url = "" - current_url += stream - if current_url: - resulting_urls.append(url + current_url) - - for url in resulting_urls: - logger.info(url) - for response in api.execute_sse_request(url): - response = self._handle_adapters(response) - if response is not None: - yield response - - -class GetMessagesSSEEvents(IHTTPProvider6Command, ProviderAdaptableCommand): - """A Class-Command for request to rpt-data-provider. - - It searches messages stream by options. - - Returns: - Iterable[dict]: Stream of Th2 messages. - """ - - def __init__( - self, - start_timestamp: datetime, - stream: List[Union[str, Streams]], - end_timestamp: datetime = None, - resume_from_id: str = None, - search_direction: str = "next", - result_count_limit: int = None, - keep_open: bool = False, - message_id: List[str] = None, - attached_events: bool = False, - lookup_limit_days: int = None, - filters: (Filter, List[Filter]) = None, - char_enc: str = "utf-8", - decode_error_handler: str = UNICODE_REPLACE_HANDLER, - ): - """GetMessagesSSEEvents constructor. - - Args: - start_timestamp: Start timestamp of search. - end_timestamp: End timestamp of search. - stream: Alias of messages. - resume_from_id: Message id from which search starts. - search_direction: Search direction. - result_count_limit: Result count limit. - keep_open: If the search has reached the current moment. - It is need to wait further for the appearance of new data. - message_id: List of message IDs to restore search. If given, it has - the highest priority and ignores stream (uses streams from ids), startTimestamp and resumeFromId. - attached_events: If true, additionally load attached_event_ids - lookup_limit_days: The number of days that will be viewed on - the first request to get the one closest to the specified timestamp. - filters: Filters using in search for messages. - char_enc: Character encode that will use SSEClient. - decode_error_handler: Decode error handler. - """ - super().__init__() - self._start_timestamp = start_timestamp - self._end_timestamp = end_timestamp - self._stream = stream - self._resume_from_id = resume_from_id - self._search_direction = search_direction - self._result_count_limit = result_count_limit - self._keep_open = keep_open - self._message_id = message_id - self._attached_events = attached_events - self._lookup_limit_days = lookup_limit_days - self._filters = filters - self._char_enc = char_enc - self._decode_error_handler = decode_error_handler - - def handle(self, data_source: HTTPProvider6DataSource) -> Generator[dict, None, None]: # noqa: D102 - response = GetMessagesSSEBytes( - start_timestamp=self._start_timestamp, - end_timestamp=self._end_timestamp, - stream=self._stream, - resume_from_id=self._resume_from_id, - search_direction=self._search_direction, - result_count_limit=self._result_count_limit, - keep_open=self._keep_open, - attached_events=self._attached_events, - lookup_limit_days=self._lookup_limit_days, - filters=self._filters, - ).handle(data_source) - - client = SSEClient(response, char_enc=self._char_enc, decode_errors_handler=self._decode_error_handler) - - for record in client.events(): - record = self._handle_adapters(record) - if record is not None: - yield record - - -class GetMessages(IHTTPProvider6Command, ProviderAdaptableCommand): - """A Class-Command for request to rpt-data-provider. - - It searches messages stream by options. - - Returns: - Iterable[dict]: Stream of Th2 messages. - """ - - def __init__( - self, - start_timestamp: datetime, - stream: List[Union[str, Streams]], - end_timestamp: datetime = None, - resume_from_id: str = None, - search_direction: str = "next", - result_count_limit: int = None, - keep_open: bool = False, - message_id: List[str] = None, - attached_events: bool = False, - lookup_limit_days: int = None, - filters: (Filter, List[Filter]) = None, - char_enc: str = "utf-8", - decode_error_handler: str = UNICODE_REPLACE_HANDLER, - cache: bool = False, - ): - """GetMessages constructor. - - Args: - start_timestamp: Start timestamp of search. - end_timestamp: End timestamp of search. - stream: Alias of messages. - resume_from_id: Message id from which search starts. - search_direction: Search direction. - result_count_limit: Result count limit. - keep_open: If the search has reached the current moment. - It is need to wait further for the appearance of new data. - message_id: List of message IDs to restore search. If given, it has - the highest priority and ignores stream (uses streams from ids), startTimestamp and resumeFromId. - attached_events: If true, additionally load attached_event_ids - lookup_limit_days: The number of days that will be viewed on - the first request to get the one closest to the specified timestamp. - filters: Filters using in search for messages. - char_enc: Encoding for the byte stream. - decode_error_handler: Registered decode error handler. - cache: If True, all requested data from rpt-data-provider will be saved to cache. - """ - super().__init__() - self._start_timestamp = start_timestamp - self._end_timestamp = end_timestamp - self._stream = stream - self._resume_from_id = resume_from_id - self._search_direction = search_direction - self._result_count_limit = result_count_limit - self._keep_open = keep_open - self._message_id = message_id - self._attached_events = attached_events - self._lookup_limit_days = lookup_limit_days - self._filters = filters - self._char_enc = char_enc - self._decode_error_handler = decode_error_handler - self._cache = cache - - def handle(self, data_source: HTTPProvider6DataSource) -> Data: # noqa: D102 - source = partial(self.__handle_stream, data_source) - adapter = SSEAdapter() - return Data(source).map(adapter.handle).use_cache(self._cache) - - def __handle_stream(self, data_source: HTTPProvider6DataSource) -> Generator[dict, None, None]: - stream = GetMessagesSSEEvents( - start_timestamp=self._start_timestamp, - end_timestamp=self._end_timestamp, - stream=self._stream, - resume_from_id=self._resume_from_id, - search_direction=self._search_direction, - result_count_limit=self._result_count_limit, - keep_open=self._keep_open, - attached_events=self._attached_events, - lookup_limit_days=self._lookup_limit_days, - filters=self._filters, - ).handle(data_source) - - for message in stream: - message = self._handle_adapters(message) - yield message diff --git a/th2_data_services/provider/v6/data_source/__init__.py b/th2_data_services/provider/v6/data_source/__init__.py deleted file mode 100644 index e6b6b23c..00000000 --- a/th2_data_services/provider/v6/data_source/__init__.py +++ /dev/null @@ -1,16 +0,0 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from .grpc import GRPCProvider6DataSource -from .http import HTTPProvider6DataSource diff --git a/th2_data_services/provider/v6/data_source/grpc.py b/th2_data_services/provider/v6/data_source/grpc.py deleted file mode 100644 index c9a2ccef..00000000 --- a/th2_data_services/provider/v6/data_source/grpc.py +++ /dev/null @@ -1,115 +0,0 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -from __future__ import annotations -from typing import Any - -from grpc._channel import _InactiveRpcError - -from typing import TYPE_CHECKING - -from th2_data_services.provider.exceptions import CommandError -from th2_data_services.provider.interfaces import IEventStruct, IMessageStruct - -if TYPE_CHECKING: - from th2_data_services.provider.v6.interfaces.command import IGRPCProvider6Command - -from th2_data_services.provider.interfaces.data_source import IGRPCProviderDataSource - -import logging - -from th2_data_services.provider.interfaces.stub_builder import IEventStub, IMessageStub -from th2_data_services.provider.v6.provider_api import GRPCProvider6API -from th2_data_services.provider.v6.struct import ( - HTTPProvider6EventStruct, - HTTPProvider6MessageStruct, - grpc_provider6_message_struct, - grpc_provider6_event_struct, -) -from th2_data_services.provider.v6.stub_builder import ( - provider6_event_stub_builder, - provider6_message_stub_builder, -) - -logger = logging.getLogger(__name__) - - -class GRPCProvider6DataSource(IGRPCProviderDataSource): - """DataSource class which provide work with rpt-data-provider. - - Rpt-data-provider version: 6.x.y - Protocol: GRPC - """ - - def __init__( - self, - url: str, - event_struct: IEventStruct = grpc_provider6_event_struct, - message_struct: IMessageStruct = grpc_provider6_message_struct, - event_stub_builder: IEventStub = provider6_event_stub_builder, - message_stub_builder: IMessageStub = provider6_message_stub_builder, - ): - """GRPCProvider6DataSource constructor. - - Args: - url: Url of rpt-data-provider. - event_struct: Event structure that is supplied by rpt-data-provider. - message_struct: Message structure that is supplied by rpt-data-provider. - event_stub_builder: Stub builder for broken events. - message_stub_builder: Stub builder for broken messages. - """ - super().__init__( - url=url, - event_struct=event_struct, - message_struct=message_struct, - event_stub_builder=event_stub_builder, - message_stub_builder=message_stub_builder, - ) - - self.__provider_api = GRPCProvider6API(url) - - logger.info(url) - - def command(self, cmd: IGRPCProvider6Command) -> Any: - """Execute the transmitted GRPC command. - - Args: - cmd: GRPC Command. - - Returns: - Any: Command response. - - Raises: - CommandError: If the command was broken. - """ - try: - return cmd.handle(data_source=self) - except _InactiveRpcError as info: - raise CommandError( - f"The command '{cmd.__class__.__name__}' was broken. Details of error:\n{info.details()}" - ) - - @property - def source_api(self) -> GRPCProvider6API: - """Returns Provider API.""" - return self.__provider_api - - @property - def event_struct(self) -> HTTPProvider6EventStruct: - """Returns event structure class.""" - return self._event_struct - - @property - def message_struct(self) -> HTTPProvider6MessageStruct: - """Returns message structure class.""" - return self._message_struct diff --git a/th2_data_services/provider/v6/data_source/http.py b/th2_data_services/provider/v6/data_source/http.py deleted file mode 100644 index 6f293c1d..00000000 --- a/th2_data_services/provider/v6/data_source/http.py +++ /dev/null @@ -1,115 +0,0 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -from __future__ import annotations - -import logging - -from th2_data_services.decode_error_handler import UNICODE_REPLACE_HANDLER -from typing import TYPE_CHECKING - -from th2_data_services.provider.exceptions import CommandError -from th2_data_services.provider.interfaces import IEventStruct, IMessageStruct, IEventStub, IMessageStub - -if TYPE_CHECKING: - from th2_data_services.provider.v6.interfaces.command import IHTTPProvider6Command - -from th2_data_services.provider.interfaces.data_source import IHTTPProviderDataSource -from th2_data_services.provider.v6.struct import ( - http_provider6_event_struct, - http_provider6_message_struct, - HTTPProvider6EventStruct, - HTTPProvider6MessageStruct, -) -from th2_data_services.provider.v6.stub_builder import ( - provider6_event_stub_builder, - provider6_message_stub_builder, -) -from th2_data_services.provider.v6.provider_api.http import HTTPProvider6API - -logger = logging.getLogger(__name__) - - -class HTTPProvider6DataSource(IHTTPProviderDataSource): - """DataSource class which provide work with rpt-data-provider. - - Rpt-data-provider version: 5.x.y - Protocol: HTTP - """ - - def __init__( - self, - url: str, - chunk_length: int = 65536, - char_enc: str = "utf-8", - decode_error_handler: str = UNICODE_REPLACE_HANDLER, - event_struct: IEventStruct = http_provider6_event_struct, - message_struct: IMessageStruct = http_provider6_message_struct, - event_stub_builder: IEventStub = provider6_event_stub_builder, - message_stub_builder: IMessageStub = provider6_message_stub_builder, - check_connect_timeout: (int, float) = 5, - ): - """HTTPProvider6DataSource constructor. - - Args: - url: HTTP data source url. - check_connect_timeout: How many seconds to wait for the server to send data before giving up. - chunk_length: How much of the content to read in one chunk. - char_enc: Encoding for the byte stream. - decode_error_handler: Registered decode error handler. - event_struct: Struct of event from rpt-data-provider. - message_struct: Struct of message from rpt-data-provider. - event_stub_builder: Stub for event. - message_stub_builder: Stub for message. - """ - super().__init__(url, event_struct, message_struct, event_stub_builder, message_stub_builder) - - self._char_enc = char_enc - self._decode_error_handler = decode_error_handler - self.__chunk_length = chunk_length - self.check_connect(check_connect_timeout) - self._provider_api = HTTPProvider6API(url, chunk_length, decode_error_handler, char_enc) - - logger.info(url) - - def command(self, cmd: IHTTPProvider6Command): - """HTTP Provider6 command processor. - - Args: - cmd: The command of data source to execute. - - Returns: - Data source command result. - - Raises: - CommandError: If the command was broken. - """ - try: - return cmd.handle(data_source=self) - except Exception as e: - raise CommandError(f"The command '{cmd.__class__.__name__}' was broken. Details of error:\n{e}") - - @property - def source_api(self) -> HTTPProvider6API: - """HTTP Provider6 API.""" - return self._provider_api - - @property - def event_struct(self) -> HTTPProvider6EventStruct: - """Returns event structure class.""" - return self._event_struct - - @property - def message_struct(self) -> HTTPProvider6MessageStruct: - """Returns message structure class.""" - return self._message_struct diff --git a/th2_data_services/provider/v6/events_tree/__init__.py b/th2_data_services/provider/v6/events_tree/__init__.py deleted file mode 100644 index 4064588c..00000000 --- a/th2_data_services/provider/v6/events_tree/__init__.py +++ /dev/null @@ -1,16 +0,0 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from .events_tree_collection import EventsTreeCollectionProvider6 -from .parent_events_tree_collection import ParentEventsTreeCollectionProvider6 diff --git a/th2_data_services/provider/v6/events_tree/events_tree_collection.py b/th2_data_services/provider/v6/events_tree/events_tree_collection.py deleted file mode 100644 index f110f84e..00000000 --- a/th2_data_services/provider/v6/events_tree/events_tree_collection.py +++ /dev/null @@ -1,100 +0,0 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from typing import Union, Optional, Callable - -from th2_data_services import Data -from th2_data_services.interfaces.events_tree import EventsTreeCollection -from th2_data_services.events_tree.exceptions import FieldIsNotExist -from th2_data_services.provider.interfaces.struct import IEventStruct -from th2_data_services.provider.v6.data_source import HTTPProvider6DataSource, GRPCProvider6DataSource -from th2_data_services.provider.v6.struct import http_provider6_event_struct -from th2_data_services.provider.v6.stub_builder import provider6_event_stub_builder -from th2_data_services.provider.v6.command_resolver import resolver_get_events_by_id - - -class EventsTreeCollectionProvider6(EventsTreeCollection): - """EventsTreesCollections for data-provider v6.""" - - def __init__( - self, - data: Data, - data_source: Union[GRPCProvider6DataSource, HTTPProvider6DataSource] = None, - preserve_body: bool = False, - event_struct: IEventStruct = http_provider6_event_struct, - stub: bool = False, - ): - """EventsTreeCollectionProvider6 constructor. - - Args: - data: Data object. - data_source: Data Source object. - preserve_body: If True it will preserve 'body' field in the Events. - event_struct: Event struct object. - stub: If True it will create stub when event is broken. - """ - self._event_struct = event_struct # Should be placed before super! - - super().__init__(data=data, data_source=data_source, preserve_body=preserve_body, stub=stub) - - def _get_events_by_id_resolver(self) -> Callable: - """Gets a function that solve which protocol command to choose.""" - return resolver_get_events_by_id - - def _get_event_id(self, event) -> str: - """Gets event id from the event. - - Returns: - Event id. - - Raises: - FieldIsNotExist: If the event doesn't have an 'event id' field. - """ - try: - return event[self._event_struct.EVENT_ID] - except KeyError: - raise FieldIsNotExist(self._event_struct.EVENT_ID) - - def _get_event_name(self, event) -> str: - """Gets event name from the event. - - Returns: - Event name. - - Raises: - FieldIsNotExist: If the event doesn't have an 'event name' field. - """ - try: - return event[self._event_struct.NAME] - except KeyError: - raise FieldIsNotExist(self._event_struct.NAME) - - def _get_parent_event_id(self, event) -> Optional[str]: - """Gets parent event id from event. - - Returns: - Parent event id. - """ - return event.get(self._event_struct.PARENT_EVENT_ID) - - def _build_stub_event(self, id_: str): - """Builds stub event. - - Args: - id_: Event Id. - - Returns: - Stub event. - """ - return provider6_event_stub_builder.build({self._event_struct.EVENT_ID: id_}) diff --git a/th2_data_services/provider/v6/events_tree/parent_events_tree_collection.py b/th2_data_services/provider/v6/events_tree/parent_events_tree_collection.py deleted file mode 100644 index 8bd7bc6d..00000000 --- a/th2_data_services/provider/v6/events_tree/parent_events_tree_collection.py +++ /dev/null @@ -1,105 +0,0 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from typing import Union, Optional, Callable - -from th2_data_services import Data -from th2_data_services.interfaces.events_tree import ParentEventsTreeCollection -from th2_data_services.events_tree.exceptions import FieldIsNotExist -from th2_data_services.provider.interfaces.struct import IEventStruct -from th2_data_services.provider.v6.command_resolver import resolver_get_events_by_id -from th2_data_services.provider.v6.data_source import GRPCProvider6DataSource, HTTPProvider6DataSource -from th2_data_services.provider.v6.struct import http_provider6_event_struct -from th2_data_services.provider.v6.stub_builder import provider6_event_stub_builder - - -class ParentEventsTreeCollectionProvider6(ParentEventsTreeCollection): - """ParentEventsTreeCollection for data-provider v6.""" - - def __init__( - self, - data: Data, - data_source: Union[GRPCProvider6DataSource, HTTPProvider6DataSource] = None, - preserve_body: bool = False, - event_struct: IEventStruct = http_provider6_event_struct, - stub: bool = False, - ): - """ParentEventsTreeCollectionProvider6 constructor. - - Args: - data: Data object. - data_source: Data Source object. - preserve_body: If True it will preserve 'body' field in the Events. - event_struct: Event struct object. - stub: If True it will create stub when event is broken. - """ - self._event_struct = event_struct # Should be placed before super! - - super().__init__( - data=data, - data_source=data_source, - preserve_body=preserve_body, - stub=stub, - ) - - def _get_events_by_id_resolver(self) -> Callable: - """Gets a function that solve which protocol command to choose.""" - return resolver_get_events_by_id - - def _get_event_id(self, event) -> str: - """Gets event id from the event. - - Returns: - Event id. - - Raises: - FieldIsNotExist: If the event doesn't have an 'event id' field - """ - try: - return event[self._event_struct.EVENT_ID] - except KeyError: - raise FieldIsNotExist(self._event_struct.EVENT_ID) - - def _get_event_name(self, event) -> str: - """Gets event name from the event. - - Returns: - Event name. - - Raises: - FieldIsNotExist: If the event doesn't have an 'event name' field. - """ - try: - return event[self._event_struct.NAME] - except KeyError: - raise FieldIsNotExist(self._event_struct.NAME) - - def _get_parent_event_id(self, event) -> Optional[str]: - """Gets parent event id from the event. - - Returns: - Parent event id. - """ - return event.get(self._event_struct.PARENT_EVENT_ID) - - def _build_stub_event(self, id_: str): - """Builds stub event. - - Args: - id_: Event Id. - - Returns: - Stub event. - """ - return provider6_event_stub_builder.build({self._event_struct.EVENT_ID: id_}) diff --git a/th2_data_services/provider/v6/filters/__init__.py b/th2_data_services/provider/v6/filters/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/th2_data_services/provider/v6/filters/event_filters.py b/th2_data_services/provider/v6/filters/event_filters.py deleted file mode 100644 index 7ffc5082..00000000 --- a/th2_data_services/provider/v6/filters/event_filters.py +++ /dev/null @@ -1,68 +0,0 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from th2_data_services.provider.v6.filters.filter import Provider6EventFilter - - -class TypeFilter(Provider6EventFilter): - """Will match the events which type contains one of the given substrings.""" - - FILTER_NAME = "type" - - -class NameFilter(Provider6EventFilter): - """Will match the events which name contains one of the given substrings.""" - - FILTER_NAME = "name" - - -class BodyFilter(Provider6EventFilter): - """Will match the events which body contains one of the given substrings.""" - - FILTER_NAME = "body" - - -class AttachedMessageIdFilter(Provider6EventFilter): - """Filters the events that are linked to the specified message id.""" - - FILTER_NAME = "attachedMessageId" - - -class _StatusFilter(Provider6EventFilter): - FILTER_NAME = "status" - - def url(self) -> str: - """Generates the filter part of the HTTP protocol API. - - For help use this readme: - https://github.com/th2-net/th2-rpt-data-provider#filters-api. - - Returns: - str: Generated filter. - """ - return f"&filters={self.name}" + "".join([f"&{self.name}-values={val}" for val in self.values]) - - -class PassedStatusFilter(_StatusFilter): - """Will match the events which status equals passed.""" - - def __init__(self): # noqa: D107 - super().__init__("passed") - - -class FailedStatusFilter(_StatusFilter): - """Will match the events which status equals failed.""" - - def __init__(self): # noqa: D107 - super().__init__("failed") diff --git a/th2_data_services/provider/v6/filters/filter.py b/th2_data_services/provider/v6/filters/filter.py deleted file mode 100644 index bed0a47f..00000000 --- a/th2_data_services/provider/v6/filters/filter.py +++ /dev/null @@ -1,100 +0,0 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from th2_data_services.provider.interfaces.filter import IProviderFilter -from typing import Sequence, Any, Union - -from th2_grpc_data_provider.data_provider_pb2 import Filter as grpc_Filter, FilterName as grpc_FilterName -import google.protobuf.wrappers_pb2 - - -class Provider6Filter(IProviderFilter): - """General interface for Filters of Provider v6.""" - - def __init__( - self, - name: str, - values: Union[str, int, float, Sequence[Union[str, int, float]]], - negative: bool = False, - conjunct: bool = False, - ): - """Filter constructor. - - Args: - name (str): Filter name. - values (Union[str, int, float, Sequence[Union[str, int, float]]]): One string with filter value or list of filter values. - negative (bool): If true, will match events/messages that do not match those specified values. - If false, will match the events/messages by their values. Defaults to false. - conjunct (bool): If true, each of the specific filter values should be applied - If false, at least one of the specific filter values must be applied. - """ - self.name = name - - if isinstance(values, (list, tuple)): - self.values = [str(v) for v in values] - else: - self.values = [str(values)] - - self.negative = negative - self.conjunct = conjunct - - def __repr__(self): - class_name = self.__class__.__name__ - return ( - f"{class_name}(" - f"name='{self.name}', " - f"values={self.values}, " - f"negative='{self.negative}', " - f"conjunct='{self.conjunct}')" - ) - - def url(self) -> str: - """Generates the filter part of the HTTP protocol API. - - For help use this readme: - https://github.com/th2-net/th2-rpt-data-provider#filters-api. - - Returns: - str: Generated filter. - """ - return ( - f"&filters={self.name}" - + "".join([f"&{self.name}-values={val}" for val in self.values]) - + f"&{self.name}-negative={self.negative}" - + f"&{self.name}-conjunct={self.conjunct}" - ) - - def grpc(self) -> grpc_Filter: - """Generates the grpc object of the GRPC protocol API.""" - return grpc_Filter( - name=grpc_FilterName(name=self.name), - negative=google.protobuf.wrappers_pb2.BoolValue(value=self.negative), - value=self.values, - conjunct=google.protobuf.wrappers_pb2.BoolValue(value=self.conjunct), - ) - - -class _Provider6FilterBase(Provider6Filter): - FILTER_NAME = "FILTER_NAME" - - def __init__(self, values: Sequence[Any], negative: bool = False, conjunct: bool = False): - super().__init__(self.FILTER_NAME, values, negative, conjunct) - - -class Provider6EventFilter(_Provider6FilterBase): - """Base class for Event Filters of Provider v5.""" - - -class Provider6MessageFilter(_Provider6FilterBase): - """Base class for Message Filters of Provider v5.""" diff --git a/th2_data_services/provider/v6/filters/message_filters.py b/th2_data_services/provider/v6/filters/message_filters.py deleted file mode 100644 index d5693414..00000000 --- a/th2_data_services/provider/v6/filters/message_filters.py +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from th2_data_services.provider.v6.filters.filter import Provider6MessageFilter - - -class TypeFilter(Provider6MessageFilter): - """Will match the messages by their full type name.""" - - FILTER_NAME = "type" - - -class BodyBinaryFilter(Provider6MessageFilter): - """Will match the messages by their binary body.""" - - FILTER_NAME = "bodyBinary" - - -class BodyFilter(Provider6MessageFilter): - """Will match the messages by their parsed body.""" - - FILTER_NAME = "body" - - -class AttachedEventIdsFilter(Provider6MessageFilter): - """Filters the messages that are linked to the specified event id.""" - - FILTER_NAME = "attachedEventIds" diff --git a/th2_data_services/provider/v6/interfaces/command.py b/th2_data_services/provider/v6/interfaces/command.py deleted file mode 100644 index 4eb2e1dc..00000000 --- a/th2_data_services/provider/v6/interfaces/command.py +++ /dev/null @@ -1,43 +0,0 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from abc import abstractmethod - -from th2_data_services.provider.interfaces.command import IHTTPProviderCommand, IGRPCProviderCommand -from th2_data_services.provider.v6.data_source.grpc import GRPCProvider6DataSource -from th2_data_services.provider.v6.data_source.http import HTTPProvider6DataSource - - -class IHTTPProvider6Command(IHTTPProviderCommand): - """Interface of command for rpt-data-provider. - - Rpt-data-provider version: 5.x.y - Protocol: HTTP - """ - - @abstractmethod - def handle(self, data_source: HTTPProvider6DataSource): - pass - - -class IGRPCProvider6Command(IGRPCProviderCommand): - """Interface of command for rpt-data-provider. - - Rpt-data-provider version: 5.x.y - Protocol: GRPC - """ - - @abstractmethod - def handle(self, data_source: GRPCProvider6DataSource): - pass diff --git a/th2_data_services/provider/v6/provider_api/__init__.py b/th2_data_services/provider/v6/provider_api/__init__.py deleted file mode 100644 index c84a3acc..00000000 --- a/th2_data_services/provider/v6/provider_api/__init__.py +++ /dev/null @@ -1,16 +0,0 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from .grpc import GRPCProvider6API -from .http import HTTPProvider6API diff --git a/th2_data_services/provider/v6/provider_api/grpc.py b/th2_data_services/provider/v6/provider_api/grpc.py deleted file mode 100644 index a40558ab..00000000 --- a/th2_data_services/provider/v6/provider_api/grpc.py +++ /dev/null @@ -1,413 +0,0 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import logging -from collections import namedtuple -from typing import Iterable, List, Optional, Union - -from google.protobuf.empty_pb2 import Empty -from google.protobuf.timestamp_pb2 import Timestamp -from google.protobuf.wrappers_pb2 import BoolValue, Int32Value, Int64Value -from th2_grpc_common.common_pb2 import MessageID, EventID, ConnectionID, Direction -from th2_grpc_data_provider.data_provider_pb2_grpc import DataProviderStub -from th2_grpc_data_provider.data_provider_pb2 import ( - EventResponse, - MessageGroupResponse, - MessageStreamsResponse, - MessageSearchResponse, - Filter, - EventSearchResponse, - FilterNamesResponse, - FilterInfoResponse, - FilterName, - MatchResponse, - EventMatchRequest, - MessageMatchRequest, - EventSearchRequest, - MessageSearchRequest, - TimeRelation, - MessageStream, - MessageStreamPointer, -) -from grpc import Channel, insecure_channel -from th2_data_services.provider.interfaces.source_api import IGRPCProviderSourceAPI -from th2_data_services.provider.v6.streams import Streams - -logger = logging.getLogger(__name__) - -BasicRequest = namedtuple( - "BasicRequest", - ["start_timestamp", "end_timestamp", "result_count_limit", "keep_open", "search_direction", "filters"], -) - - -class GRPCProvider6API(IGRPCProviderSourceAPI): - def __init__(self, url: str): - """GRPC Provider6 API. - - Args: - url: GRPC data source url. - """ - self._create_connection(url) - - def _create_connection(self, url: str) -> None: - """Creates gRPC channel to gRPC-server. - - Args: - url: Url of gRPC-server. - """ - channel: Channel = insecure_channel(url) - self.__stub: DataProviderStub = DataProviderStub(channel) - - def get_message_streams(self) -> MessageStreamsResponse: - """GRPC-API `getMessageStreams` call returns a list of message stream names.""" - return self.__stub.getMessageStreams(Empty()) - - def search_events( - self, - start_timestamp: int = None, - end_timestamp: int = None, - parent_event: str = None, - search_direction: str = "NEXT", - resume_from_id: str = None, - result_count_limit: int = None, - keep_open: bool = False, - limit_for_parent: int = None, - metadata_only: bool = True, - attached_messages: bool = False, - filters: Optional[List[Filter]] = None, - ) -> Iterable[EventSearchResponse]: - """GRPC-API `searchEvents` call creates an event or an event metadata stream that matches the filter. - - Args: - start_timestamp: Sets the search starting point. Expected in nanoseconds. One of the 'start_timestamp' - or 'resume_from_id' must not absent. - end_timestamp: Sets the timestamp to which the search will be performed, starting with 'start_timestamp'. - Expected in nanoseconds. - parent_event: Match events to the specified parent. - search_direction: Sets the lookup direction. Can be 'NEXT' or 'PREVIOUS'. - resume_from_id: The last event id from which we start searching for events. - result_count_limit: Sets the maximum amount of events to return. - keep_open: Option if the search has reached the current moment, - it is necessary to wait further for the appearance of new data. - limit_for_parent: How many children events for each parent do we want to request. - metadata_only: Receive only metadata (true) or entire event (false) (without attachedMessageIds). - attached_messages: Option if you want to load attachedMessageIds additionally. - filters: Which filters to apply in a search. - - Returns: - Iterable object which return events as parts of streaming response. - """ - self.__search_basic_checks( - start_timestamp=start_timestamp, - end_timestamp=end_timestamp, - result_count_limit=result_count_limit, - search_direction=search_direction, - ) - - basic_request = self.__build_basic_request_object( - start_timestamp=start_timestamp, - end_timestamp=end_timestamp, - search_direction=search_direction, - result_count_limit=result_count_limit, - keep_open=keep_open, - filters=filters, - ) - parent_event = EventID(id=parent_event) if parent_event else None - resume_from_id = EventID(id=resume_from_id) if resume_from_id else None - limit_for_parent = Int64Value(value=limit_for_parent) if limit_for_parent else None - metadata_only = BoolValue(value=metadata_only) - attached_messages = BoolValue(value=attached_messages) - - event_search_request = EventSearchRequest( - start_timestamp=basic_request.start_timestamp, - end_timestamp=basic_request.end_timestamp, - parent_event=parent_event, - search_direction=basic_request.search_direction, - resume_from_id=resume_from_id, - result_count_limit=basic_request.result_count_limit, - keep_open=basic_request.keep_open, - limit_for_parent=limit_for_parent, - metadata_only=metadata_only, - attached_messages=attached_messages, - filter=basic_request.filters, - ) - return self.__stub.searchEvents(event_search_request) - - def search_messages( - self, - start_timestamp: int, - end_timestamp: int = None, - search_direction: str = "NEXT", - result_count_limit: int = None, - stream: List[str] = None, - keep_open: bool = False, - stream_pointer: List[MessageStreamPointer] = None, - filters: Optional[List[Filter]] = None, - attached_events: bool = False, - ) -> Iterable[MessageSearchResponse]: - """GRPC-API `searchMessages` call creates a message stream that matches the filter. - - Args: - start_timestamp: Sets the search starting point. Expected in nanoseconds. One of the 'start_timestamp' - or 'resume_from_id' must not absent. - stream: Sets the stream ids to search in. - end_timestamp: Sets the timestamp to which the search will be performed, starting with 'start_timestamp'. - Expected in nanoseconds. - search_direction: Sets the lookup direction. Can be 'NEXT' or 'PREVIOUS'. - result_count_limit: Sets the maximum amount of messages to return. - keep_open: Option if the search has reached the current moment, - it is necessary to wait further for the appearance of new data. - stream_pointer: List of stream pointers to restore the search from. - start_timestamp will be ignored if this parameter is specified. This parameter is only received - from the provider. - filters: Which filters to apply in a search. - attached_events: If true, it will additionally load attachedEventsIds. - - Returns: - Iterable object which return messages as parts of streaming response or message stream pointers. - """ - if stream is None: - raise TypeError("Argument 'stream' is required.") - self.__search_basic_checks( - start_timestamp=start_timestamp, - end_timestamp=end_timestamp, - result_count_limit=result_count_limit, - search_direction=search_direction, - ) - - basic_request = self.__build_basic_request_object( - start_timestamp=start_timestamp, - end_timestamp=end_timestamp, - result_count_limit=result_count_limit, - keep_open=keep_open, - search_direction=search_direction, - filters=filters, - ) - - stream = self.__transform_streams(stream) - attached_events = BoolValue(value=attached_events) - message_search_request = MessageSearchRequest( - start_timestamp=basic_request.start_timestamp, - end_timestamp=basic_request.end_timestamp, - search_direction=basic_request.search_direction, - result_count_limit=basic_request.result_count_limit, - keep_open=basic_request.keep_open, - filter=basic_request.filters, - attached_events=attached_events, - stream=stream, - stream_pointer=stream_pointer, - ) - - return self.__stub.searchMessages(message_search_request) - - @staticmethod - def __search_basic_checks( - start_timestamp: Optional[int], - end_timestamp: Optional[int], - search_direction: Optional[str], - result_count_limit: Optional[int], - ): - if start_timestamp is None: - raise ValueError("One of the 'startTimestamp' or 'resumeFromId(s)' must not be None.") - - if end_timestamp is None and result_count_limit is None: - raise ValueError("One of the 'end_timestamp' or 'result_count_limit' must not be None.") - - if ( - start_timestamp is not None - and len(str(start_timestamp)) != 19 - or end_timestamp is not None - and len(str(end_timestamp)) != 19 - ): - raise ValueError("Arguments 'start_timestamp' and 'end_timestamp' are expected in nanoseconds.") - - if search_direction is not None: - search_direction = search_direction.upper() - if search_direction not in ("NEXT", "PREVIOUS"): - raise ValueError("Argument 'search_direction' must be 'NEXT' or 'PREVIOUS'.") - else: - raise ValueError("Argument 'search_direction' must be 'NEXT' or 'PREVIOUS'.") - - def __transform_streams(self, streams: List[str]) -> List[MessageStream]: - """Transforms streams to MessagesStream of 'protobuf' entity. - - Args: - streams: Streams. - - Returns: - List of MessageStream. - """ - new_streams = [] - for raw_stream in streams: - if isinstance(raw_stream, Streams): - msg_stream = raw_stream.grpc() - else: - msg_stream = self.__build_message_stream(raw_stream) - if isinstance(msg_stream, list): - new_streams.extend(msg_stream) - else: - new_streams.append(msg_stream) - return new_streams - - @staticmethod - def __build_message_stream(raw_stream: str) -> Union[MessageStream, List[MessageStream]]: - """Builds MessageStream of 'protobuf' entity. - - Note that if raw_stream doesn't have direction, the function returns both directions. - - Args: - raw_stream: Stream string as 'alias:direction' - - Returns: - MessageStream. - """ - splitted_stream = raw_stream.split(":") - name = splitted_stream[0] - if len(splitted_stream) > 1: - name, search_direction = ":".join(splitted_stream[0:-1]), splitted_stream[-1].upper() - if search_direction in ("FIRST", "SECOND"): - return MessageStream(name=name, direction=Direction.Value(search_direction)) - else: - name = ":".join(splitted_stream) - return [ - MessageStream(name=name, direction=Direction.Value("FIRST")), - MessageStream(name=name, direction=Direction.Value("SECOND")), - ] - - def __build_basic_request_object( - self, - start_timestamp: int = None, - end_timestamp: int = None, - result_count_limit: int = None, - keep_open: bool = False, - search_direction: str = "NEXT", - filters: Optional[List[Filter]] = None, - ) -> BasicRequest: - """Builds a BasicRequest wrapper-object. - - Args: - start_timestamp: Start Timestamp for request. - end_timestamp: End Timestamp for request. - result_count_limit: Data count limit. - keep_open: Option for stream-request. - search_direction: Searching direction. - filters: Which filters to apply in a request. - - Returns: - BasicRequest wrapper-object. - """ - if filters is None: - filters = [] - - start_timestamp = self.__build_timestamp_object(start_timestamp) if start_timestamp else None - end_timestamp = self.__build_timestamp_object(end_timestamp) if end_timestamp else None - search_direction = TimeRelation.Value(search_direction) # getting a value from enum - result_count_limit = Int32Value(value=result_count_limit) if result_count_limit else None - keep_open = BoolValue(value=keep_open) - - basic_request = BasicRequest( - start_timestamp=start_timestamp, - end_timestamp=end_timestamp, - search_direction=search_direction, - result_count_limit=result_count_limit, - keep_open=keep_open, - filters=filters, - ) - return basic_request - - @staticmethod - def __build_timestamp_object(timestamp: int) -> Timestamp: - """Builds a Timestamp of 'protobuf' entity. - - Args: - timestamp: Timestamp in nanoseconds. - - Returns: - Timestamp object. - """ - nanos = timestamp % 10 ** 9 - seconds = timestamp // 10 ** 9 - timestamp = Timestamp(seconds=seconds, nanos=nanos) - return timestamp - - @staticmethod - def __build_message_id_object(message_id: str) -> MessageID: - """Builds a MessageID of 'protobuf' entity. - - Args: - message_id: Message id. - - Returns: - MessageID object. - """ - split_id = message_id.split(":") - split_id.reverse() # Parse the message id from the end. - - sequence, direction, alias = split_id[0], split_id[1].upper(), split_id[2:] - split_sequence = sequence.split(".") - sequence, subsequence = int(split_sequence[0]), split_sequence[1:] - subsequence = map(int, subsequence) if subsequence else subsequence - alias.reverse() - alias = ":".join(alias) - - connection_id = ConnectionID(session_alias=alias) - direction = Direction.Value(direction) # Get a value from enum. - - message_id = MessageID( - connection_id=connection_id, - direction=direction, - sequence=sequence, - subsequence=subsequence, - ) - return message_id - - def get_event(self, event_id: str) -> EventResponse: - """GRPC-API `getEvent` call returns a single event with the specified id.""" - event_id = EventID(id=event_id) - return self.__stub.getEvent(event_id) - - def get_message(self, message_id: str) -> MessageGroupResponse: - """GRPC-API `getMessage` call returns a single message with the specified id.""" - message_id = self.__build_message_id_object(message_id) - return self.__stub.getMessage(message_id) - - def get_messages_filters(self) -> FilterNamesResponse: - """GRPC-API `getMessagesFilters` call returns all the names of sse message filters.""" - return self.__stub.getMessagesFilters(Empty()) - - def get_events_filters(self) -> FilterNamesResponse: - """GRPC-API `getEventsFilters` call returns all the names of sse event filters.""" - return self.__stub.getEventsFilters(Empty()) - - def get_event_filter_info(self, filter_name: str) -> FilterInfoResponse: - """GRPC-API `getEventFilterInfo` call returns event filter info.""" - filter_name = FilterName(name=filter_name) - return self.__stub.getEventFilterInfo(filter_name) - - def get_message_filter_info(self, filter_name: str) -> FilterInfoResponse: - """GRPC-API `getMessageFilterInfo` call returns message filter info.""" - filter_name = FilterName(name=filter_name) - return self.__stub.getMessageFilterInfo(filter_name) - - def match_event(self, event_id: str, filters: List[Filter]) -> MatchResponse: - """GRPC-API `matchEvent` call checks that the event with the specified id is matched by the filter.""" - match_request = EventMatchRequest(event_id=EventID(id=event_id), filter=filters) - return self.__stub.matchEvent(match_request) - - def match_message(self, message_id: str, filters: List[Filter]) -> MatchResponse: - """GRPC-API `matchMessage` call checks that the message with the specified id is matched by the filter.""" - message_id = self.__build_message_id_object(message_id) - match_request = MessageMatchRequest(message_id=message_id, filter=filters) - return self.__stub.matchMessage(match_request) diff --git a/th2_data_services/provider/v6/provider_api/http.py b/th2_data_services/provider/v6/provider_api/http.py deleted file mode 100644 index 7600ada2..00000000 --- a/th2_data_services/provider/v6/provider_api/http.py +++ /dev/null @@ -1,257 +0,0 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import logging -from http import HTTPStatus -from typing import List, Generator, Optional, Union - -import requests -from requests import Response -from urllib3 import PoolManager, exceptions -from urllib.parse import quote - -from th2_data_services.provider.interfaces.source_api import IHTTPProviderSourceAPI -from th2_data_services.decode_error_handler import UNICODE_REPLACE_HANDLER - -logger = logging.getLogger("th2_data_services") -logger.setLevel(logging.DEBUG) - - -class HTTPProvider6API(IHTTPProviderSourceAPI): - def __init__( - self, - url: str, - chunk_length: int = 65536, - decode_error_handler: str = UNICODE_REPLACE_HANDLER, - char_enc: str = "utf-8", - ): - """HTTP Provider6 API. - - Args: - url: HTTP data source url. - chunk_length: How much of the content to read in one chunk. - char_enc: Encoding for the byte stream. - decode_error_handler: Registered decode error handler. - """ - self._url = self.__normalize_url(url) - self._char_enc = char_enc - self._chunk_length = chunk_length - self._decode_error_handler = decode_error_handler - - def __normalize_url(self, url): - if url is None: - return url - - pos = len(url) - 1 - while url[pos] == '/' and pos >= 0: - pos -= 1 - - return url[:pos + 1] - - def __encode_url(self, url: str) -> str: - return quote(url.encode(), "/:&?=") - - def get_url_message_streams(self) -> str: - """REST-API `messageStreams` call returns a list of message stream names.""" - return self.__encode_url(f"{self._url}/messageStreams") - - def get_url_find_event_by_id(self, event_id: str) -> str: - """REST-API `event` call returns a single event with the specified id.""" - return self.__encode_url(f"{self._url}/event/{event_id}") - - def get_url_find_events_by_id(self, *ids) -> str: - """REST-API `events` call returns a list of events with the specified ids. - - Note, at a time you can request no more eventSearchChunkSize. - - Deprecated, use `get_url_find_event_by_id` instead. - """ - query = "" - for id in ids: - query += f"ids={id}&" - return self.__encode_url(f"{self._url}/events?{query[:-1]}") - - def get_url_find_message_by_id(self, message_id: str) -> str: - """REST-API `message` call returns a single message with the specified id.""" - return self.__encode_url(f"{self._url}/message/{message_id}") - - def get_url_messages_filters(self) -> str: - """SSE-API `filters/sse-messages` call returns all names of sse message filters. - - https://github.com/th2-net/th2-rpt-data-provider#filters-api - """ - return self.__encode_url(f"{self._url}/filters/sse-messages") - - def get_url_events_filters(self) -> str: - """SSE-API `/filters/sse-events` call returns all names of sse event filters. - - https://github.com/th2-net/th2-rpt-data-provider#filters-api - """ - return self.__encode_url(f"{self._url}/filters/sse-events") - - def get_url_message_filter_info(self, filter_name: str) -> str: - """SSE-API `filters/sse-messages/{filter name}` call returns filter info. - - https://github.com/th2-net/th2-rpt-data-provider#filters-api - """ - return self.__encode_url(f"{self._url}/filters/sse-messages/{filter_name}") - - def get_url_event_filter_info(self, filter_name: str) -> str: - """SSE-API `filters/sse-events/{filter_name}` call returns filter info. - - https://github.com/th2-net/th2-rpt-data-provider#filters-api - """ - return self.__encode_url(f"{self._url}/filters/sse-events/{filter_name}") - - def get_url_match_event_by_id(self, event_id: str, filters: str = "") -> str: - """REST-API `match/event/{id}` call returns boolean value. - - Checks that event with the specified id is matched by filter. - - https://github.com/th2-net/th2-rpt-data-provider#filters-api - """ - return self.__encode_url(f"{self._url}/match/event/{event_id}{filters}") - - def get_url_match_message_by_id(self, message_id: str, filters: str = "") -> str: - """REST-API `match/message/{id}` call returns boolean value. - - Checks that message with the specified id is matched by filter. - - https://github.com/th2-net/th2-rpt-data-provider#filters-api - """ - return self.__encode_url(f"{self._url}/match/message/{message_id}{filters}") - - def get_url_search_sse_events( - self, - start_timestamp: int, - end_timestamp: Optional[int] = None, - parent_event: Optional[str] = None, - resume_from_id: Optional[str] = None, - search_direction: Optional[str] = "next", - result_count_limit: Union[int, float] = None, - keep_open: Optional[bool] = False, - limit_for_parent: Union[int, float] = None, - metadata_only: Optional[bool] = True, - attached_messages: Optional[bool] = False, - filters: Optional[str] = None, - ) -> str: - """REST-API `search/sse/events` call create a sse channel of event metadata that matches the filter. - - https://github.com/th2-net/th2-rpt-data-provider#sse-requests-api - """ - kwargs = { - "startTimestamp": start_timestamp, - "endTimestamp": end_timestamp, - "resumeFromId": resume_from_id, - "parentEvent": parent_event, - "searchDirection": search_direction, - "resultCountLimit": result_count_limit, - "limitForParent": limit_for_parent, - "keepOpen": keep_open, - "metadataOnly": metadata_only, - "attachedMessages": attached_messages, - } - - query = "" - url = f"{self._url}/search/sse/events?" - for k, v in kwargs.items(): - if v is None: - continue - else: - query += f"&{k}={v}" - url = f"{url}{query[1:]}" - if filters is not None: - url += filters - return self.__encode_url(url) - - def get_url_search_sse_messages( - self, - start_timestamp: int, - stream: List[str], - end_timestamp: Optional[int] = None, - resume_from_id: Optional[str] = None, - search_direction: Optional[str] = "next", - result_count_limit: Union[int, float] = None, - keep_open: bool = False, - message_id: Optional[List[str]] = None, - attached_events: bool = False, - lookup_limit_days: Union[int, float] = None, - filters: Optional[str] = None, - ) -> str: - """REST-API `search/sse/messages` call create a sse channel of messages that matches the filter. - - https://github.com/th2-net/th2-rpt-data-provider#sse-requests-api - """ - kwargs = { - "startTimestamp": start_timestamp, - "endTimestamp": end_timestamp, - "resumeFromId": resume_from_id, - "stream": stream, - "searchDirection": search_direction, - "resultCountLimit": result_count_limit, - "keepOpen": keep_open, - "messageId": message_id, - "attachedEvents": attached_events, - "lookupLimitDays": lookup_limit_days, - } - - query = "" - url = f"{self._url}/search/sse/messages?" - for k, v in kwargs.items(): - if v is None: - continue - if k == "stream": - for s in stream: - query += f"&{k}={s}" - else: - query += f"&{k}={v}" - url = f"{url}{query[1:]}" - if filters is not None: - url += filters - return self.__encode_url(url) - - def execute_sse_request(self, url: str) -> Generator[bytes, None, None]: - """Create stream connection. - - Args: - url: Url. - - Yields: - str: Response stream data. - """ - headers = {"Accept": "text/event-stream"} - http = PoolManager() - response = http.request(method="GET", url=url, headers=headers, preload_content=False) - - if response.status != HTTPStatus.OK: - for s in HTTPStatus: - if s == response.status: - raise exceptions.HTTPError(f"{s.value} {s.phrase} ({s.description})") - raise exceptions.HTTPError(f"Http returned bad status: {response.status}") - - for chunk in response.stream(self._chunk_length): - yield chunk - - response.release_conn() - - def execute_request(self, url: str) -> Response: - """Sends a GET request to provider. - - Args: - url: Url for a get request to rpt-data-provider. - - Returns: - requests.Response: Response data. - """ - return requests.get(url) diff --git a/th2_data_services/provider/v6/streams.py b/th2_data_services/provider/v6/streams.py deleted file mode 100644 index ed8fe7ae..00000000 --- a/th2_data_services/provider/v6/streams.py +++ /dev/null @@ -1,55 +0,0 @@ -from typing import List - -from th2_grpc_common.common_pb2 import Direction -from th2_grpc_data_provider.data_provider_pb2 import MessageStream - - -class Streams: - """General interface for composite streams of Provider v6. - - The class gives the opportunity to make list of streams with direction for each. - """ - - def __init__(self, streams: List[str], direction: str = None): - """Streams constructor. - - Args: - streams: List of Streams. - direction: Direction of Streams (Only FIRST or SECOND). If None then is both directions. - """ - self._streams = streams - if direction is not None: - direction = direction.upper() - if direction not in ("FIRST", "SECOND"): - raise ValueError("The direction must be 'FIRST' or 'SECOND'.") - self._direction = direction - - def __repr__(self): - class_name = self.__class__.__name__ - return f"{class_name}(" f"streams={self._streams}, " f"direction={self._direction})" - - def url(self) -> str: - """Generates the stream part of the HTTP protocol API. - - Returns: - str: Generated streams. - """ - if self._direction is None: - return "&".join([f"stream={stream}:FIRST&stream={stream}:SECOND" for stream in self._streams]) - return "&".join([f"stream={stream}:{self._direction}" for stream in self._streams]) - - def grpc(self) -> List[MessageStream]: - """Generates the grpc objects of the GRPC protocol API. - - Returns: - List[MessageStream]: List of Stream with specified direction. - """ - if self._direction is None: - result = [] - for stream in self._streams: - result += [ - MessageStream(name=stream, direction=Direction.Value("FIRST")), - MessageStream(name=stream, direction=Direction.Value("SECOND")), - ] - return result - return [MessageStream(name=stream, direction=Direction.Value(self._direction)) for stream in self._streams] diff --git a/th2_data_services/provider/v6/struct.py b/th2_data_services/provider/v6/struct.py deleted file mode 100644 index 2430e4ec..00000000 --- a/th2_data_services/provider/v6/struct.py +++ /dev/null @@ -1,157 +0,0 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from dataclasses import dataclass - -from th2_data_services.provider.interfaces.struct import IEventStruct, IMessageStruct - - -@dataclass -class HTTPProvider6EventStruct(IEventStruct): - """Interface for Event of data-provider v6.""" - - EVENT_ID: str - PARENT_EVENT_ID: str - STATUS: str - NAME: str - TYPE: str - BATCH_ID: str - IS_BATCHED: str - EVENT_TYPE: str - END_TIMESTAMP: str - START_TIMESTAMP: str - ATTACHED_MESSAGES_IDS: str - BODY: str - - -http_provider6_event_struct = HTTPProvider6EventStruct( - EVENT_ID="eventId", - PARENT_EVENT_ID="parentEventId", - STATUS="successful", - NAME="eventName", - TYPE="type", - BATCH_ID="batchId", - IS_BATCHED="isBatched", - EVENT_TYPE="eventType", - END_TIMESTAMP="endTimestamp", - START_TIMESTAMP="startTimestamp", - ATTACHED_MESSAGES_IDS="attachedMessageIds", - BODY="body", -) - - -@dataclass -class HTTPProvider6MessageStruct(IMessageStruct): - """Interface for Message of data-provider v6.""" - - DIRECTION: str - SESSION_ID: str - MESSAGE_TYPE: str - CONNECTION_ID: str - SESSION_ALIAS: str - SUBSEQUENCE: str - SEQUENCE: str - TIMESTAMP: str - BODY: str - BODY_BASE64: str - TYPE: str - MESSAGE_ID: str - ATTACHED_EVENT_IDS: str - - -http_provider6_message_struct = HTTPProvider6MessageStruct( - DIRECTION="direction", - SESSION_ID="sessionId", - MESSAGE_TYPE="messageType", - CONNECTION_ID="connectionId", - SESSION_ALIAS="sessionAlias", - SUBSEQUENCE="subsequence", - SEQUENCE="sequence", - TIMESTAMP="timestamp", - BODY="parsedMessages", - BODY_BASE64="rawMessageBase64", - TYPE="type", - MESSAGE_ID="id", - ATTACHED_EVENT_IDS="attachedEventIds", -) - - -@dataclass -class GRPCProvider6EventStruct(IEventStruct): - """Interface for Event of data-provider v6.""" - - EVENT_ID: str - PARENT_EVENT_ID: str - STATUS: str - NAME: str - TYPE: str - BATCH_ID: str - IS_BATCHED: str - EVENT_TYPE: str - END_TIMESTAMP: str - START_TIMESTAMP: str - ATTACHED_MESSAGES_IDS: str - BODY: str - - -grpc_provider6_event_struct = GRPCProvider6EventStruct( - EVENT_ID="eventId", - PARENT_EVENT_ID="parentEventId", - STATUS="successful", - NAME="eventName", - TYPE="type", - BATCH_ID="batchId", - IS_BATCHED="isBatched", - EVENT_TYPE="eventType", - END_TIMESTAMP="endTimestamp", - START_TIMESTAMP="startTimestamp", - ATTACHED_MESSAGES_IDS="attachedMessageIds", - BODY="body", -) - - -@dataclass -class GRPCProvider6MessageStruct(IMessageStruct): - """Interface for Message of data-provider v6.""" - - DIRECTION: str - SESSION_ID: str - MESSAGE_TYPE: str - CONNECTION_ID: str - SESSION_ALIAS: str - SUBSEQUENCE: str - SEQUENCE: str - TIMESTAMP: str - BODY: str - BODY_BASE64: str - TYPE: str - MESSAGE_ID: str - ATTACHED_EVENT_IDS: str - - -grpc_provider6_message_struct = GRPCProvider6MessageStruct( - DIRECTION="direction", - SESSION_ID="sessionId", - MESSAGE_TYPE="messageType", - CONNECTION_ID="connectionId", - SESSION_ALIAS="sessionAlias", - SUBSEQUENCE="subsequence", - SEQUENCE="sequence", - TIMESTAMP="timestamp", - BODY="body", - BODY_BASE64="bodyBase64", - TYPE="type", - MESSAGE_ID="messageId", - ATTACHED_EVENT_IDS="attachedEventIds", -) diff --git a/th2_data_services/provider/v6/stub_builder.py b/th2_data_services/provider/v6/stub_builder.py deleted file mode 100644 index 268330de..00000000 --- a/th2_data_services/provider/v6/stub_builder.py +++ /dev/null @@ -1,85 +0,0 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from th2_data_services.provider.interfaces.stub_builder import IEventStub, IMessageStub -from th2_data_services.provider.v6.struct import ( - http_provider6_event_struct, - http_provider6_message_struct, -) - - -class Provider6EventStubBuilder(IEventStub): - def __init__(self, event_struct=http_provider6_event_struct): - """Event stub builder for Provider v6. - - Args: - event_struct: Event struct class. - """ - self.event_fields = event_struct - super().__init__() # Requirement to define fields for the template earlier. - - @property - def template(self) -> dict: - """Event stub template. - - Returns: - (dict) Event stub template. - """ - return { - self.event_fields.ATTACHED_MESSAGES_IDS: [], - self.event_fields.BATCH_ID: "Broken_Event", - self.event_fields.END_TIMESTAMP: {"nano": 0, "epochSecond": 0}, - self.event_fields.START_TIMESTAMP: {"nano": 0, "epochSecond": 0}, - self.event_fields.TYPE: "event", - self.event_fields.EVENT_ID: self.REQUIRED_FIELD, - self.event_fields.NAME: "Broken_Event", - self.event_fields.EVENT_TYPE: "Broken_Event", - self.event_fields.PARENT_EVENT_ID: "Broken_Event", - self.event_fields.STATUS: None, - self.event_fields.IS_BATCHED: None, - } - - -class Provider6MessageStubBuilder(IMessageStub): - def __init__(self, message_struct=http_provider6_message_struct): - """Event stub builder for Provider 6. - - Args: - message_struct: Message struct class. - """ - self.message_fields = message_struct - super().__init__() # Requirement to define fields for the template earlier. - - @property - def template(self) -> dict: - """Message stub template. - - Returns: - (dict) Message stub template. - """ - return { - self.message_fields.DIRECTION: None, - self.message_fields.SESSION_ID: "Broken_Message", - self.message_fields.MESSAGE_TYPE: "Broken_Message", - self.message_fields.TIMESTAMP: {"nano": 0, "epochSecond": 0}, - self.message_fields.BODY: [], - self.message_fields.BODY_BASE64: [], - self.message_fields.TYPE: "message", - self.message_fields.MESSAGE_ID: self.REQUIRED_FIELD, - self.message_fields.ATTACHED_EVENT_IDS: [], - } - - -provider6_event_stub_builder = Provider6EventStubBuilder() -provider6_message_stub_builder = Provider6MessageStubBuilder() diff --git a/th2_data_services/th2_gui_report.py b/th2_data_services/th2_gui_report.py deleted file mode 100644 index 6f290b49..00000000 --- a/th2_data_services/th2_gui_report.py +++ /dev/null @@ -1,53 +0,0 @@ -class Th2GUIReport: - """Class for creating gui link by event ID or message ID.""" - - def __init__(self, provider_link: str): - """Th2GUIReport constructor. - - Args: - provider_link (str): link to provider. - """ - self._provider_link = self.__normalize_link(provider_link) - - def __normalize_link(self, link: str) -> str: - """Bringing links to a single form. - - Add 'http://' to the beginning of the link. - Add slash to the ending of link. - - Args: - link (str): link for editing. - - Returns: - Normalize link. - """ - find_http = link.startswith("http", 0) - if find_http is False: - link = "http://" + link - - if link[-1] != "/": - link = link + "/" - - return link - - def get_event_link(self, event_id: str) -> str: - """Creates the link with event id. - - Args: - event_id (str): id for adding in link. - - Returns: - GUI link to event. - """ - return f"{self._provider_link}?eventId={event_id}" - - def get_message_link(self, message_id: str) -> str: - """Creates the link with message id. - - Args: - message_id (str): id for adding in link. - - Returns: - GUI link to message. - """ - return f"{self._provider_link}?messageId={message_id}" diff --git a/th2_data_services/utils/__init__.py b/th2_data_services/utils/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/th2_data_services/utils/_is_sorted_result.py b/th2_data_services/utils/_is_sorted_result.py new file mode 100644 index 00000000..48dde6f7 --- /dev/null +++ b/th2_data_services/utils/_is_sorted_result.py @@ -0,0 +1,35 @@ +# Copyright 2024-2025 Exactpro (Exactpro Systems Limited) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from typing import Optional + + +class IsSortedResult: + """IsSortedResult is used by util methods that check whether a sequence of elements is sorted. + + The class provides some attributes that tells its user additional information about the sequence provided, + for example: index of the first unsorted element. + """ + + def __init__(self, status: bool = True): + """IsSortedResult constructor. + + Args: + status: Whether the sequence is sorted. + """ + self.status: bool = status + self.first_unsorted: Optional[int] = None + + def __bool__(self): + return self.status diff --git a/th2_data_services/utils/_json.py b/th2_data_services/utils/_json.py new file mode 100644 index 00000000..dd55f795 --- /dev/null +++ b/th2_data_services/utils/_json.py @@ -0,0 +1,188 @@ +# Copyright 2023-2025 Exactpro (Exactpro Systems Limited) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +from typing import Generator +import gzip + +import orjson as json +from orjson import JSONDecodeError + +from th2_data_services.utils.decode_error_handler import UNICODE_REPLACE_HANDLER + +# FIXME +# why do we have separate the same funcitons? +def iter_json_file(filename, buffer_limit=250): + """Returns the function that returns generators.""" + + def iter_json_file_logic(): + """Generator that reads and yields decoded JSON objects from a file.""" + json_processor = BufferedJSONProcessor(buffer_limit) + + with open(filename, "r") as data: + while True: + try: + # We don't need to decode here because readline for + # non-binary returns strings, not bytes. + v = data.readline() + if not v: + break + + yield from json_processor.decode(v) + except ValueError: + print("Json Decode error") + print(f"Current buffer len: {len(json_processor.buffer)}") + print(f"Error string: {v}") + raise + yield from json_processor.fin() + + def iter_json_file_wrapper(*args, **kwargs): + """Wrapper function that allows passing arguments to the generator.""" + return iter_json_file_logic(*args, **kwargs) + + return iter_json_file_wrapper + + +def iter_json_gzip_file(filename, buffer_limit=250): + """Returns the function that returns generators.""" + + def iter_json_gzip_file_logic(): + """Generator that reads and yields decoded JSON objects from a file.""" + json_processor = BufferedJSONProcessor(buffer_limit) + + if buffer_limit != 0: + finished = False + with gzip.open(filename, "r") as data: + while True: + try: + for _ in range(buffer_limit): + # TODO + # probably we don't need to decode here + # and we can just take bytes as is. + v = data.readline().decode("utf-8", UNICODE_REPLACE_HANDLER) + if not v: + finished = True + break + json_processor.buffer.append(v) + + yield from json_processor.from_buffer() + + if finished: + break + + except ValueError: + print("Json Decode error") + print(f"Current buffer len: {len(json_processor.buffer)}") + print(f"Error string: {v}") + print(f"data.readline(): {data.readline()}") + raise + + yield from json_processor.fin() + else: + with gzip.open(filename, "r") as data: + while True: + try: + # We have to decode bytes first. + v = data.readline().decode("utf-8", UNICODE_REPLACE_HANDLER) + if not v: + break + + # v = v.decode("utf-8", UNICODE_REPLACE_HANDLER) + yield from json_processor.decode(v) + + except ValueError: + print("Json Decode error") + print(f"Current buffer len: {len(json_processor.buffer)}") + print(f"Error string: {v}") + print(f"data.readline(): {data.readline()}") + raise + + def iter_json_gzip_file_wrapper(*args, **kwargs): + """Wrapper function that allows to rerun generator one more time.""" + return iter_json_gzip_file_logic(*args, **kwargs) + + return iter_json_gzip_file_wrapper + + +class BufferedJSONProcessor: + def __init__(self, buffer_limit: int = 250): + """BufferedJSONProcessor constructor. + + Args: + buffer_limit: By default 250. If limit is 0 buffer will not be used. + """ + self.buffer = [] + self.buffer_limit = buffer_limit + if buffer_limit == 0: + self.decode = self._decode_without_buffer + else: + self.decode = self._decode_with_buffer + + def from_buffer(self) -> Generator: + """Transforms JSON objects to dict objects. + + Returns: + Generator[dict] + """ + try: + for i in json.loads("[" + ",".join(self.buffer) + "]"): + yield i + except JSONDecodeError as e: + raise ValueError( + f"json.decoder.JSONDecodeError: Invalid json received.\n" f"{e}\n" f"{self.buffer}" + ) + finally: + # Prevents StopIteration issues + self.buffer = [] + + def _decode_without_buffer(self, x: str) -> Generator: + """Decode JSON without buffer. + + Args: + x: JSON Object + + Returns: + dict + """ + yield json.loads(x) + + def _decode_with_buffer(self, x: str) -> Generator: + """Decode JSON with buffer. + + Args: + x: JSON Object + + Returns: + dict + """ + # for i in range(self.buffer_limit): + + # # FIXME -- we check len every message. It can take a lot of time + # if len(self.buffer) < self.buffer_limit: + # self.buffer.append(x) + # else: + # yield from self.from_buffer() + # self.buffer = [x] + + yield from self.from_buffer() + self.buffer = [x] + + def fin(self) -> Generator: + """If buffer exists, returns dicts from buffer. + + Returns: + Generator[dict] + """ + if self.buffer: + yield from self.from_buffer() diff --git a/th2_data_services/provider/v5/interfaces/__init__.py b/th2_data_services/utils/_types.py similarity index 85% rename from th2_data_services/provider/v5/interfaces/__init__.py rename to th2_data_services/utils/_types.py index 0c0563dc..211cf8e2 100644 --- a/th2_data_services/provider/v5/interfaces/__init__.py +++ b/th2_data_services/utils/_types.py @@ -1,4 +1,4 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) +# Copyright 2023-2025 Exactpro (Exactpro Systems Limited) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -12,4 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -from .command import * + +Th2Event = dict +Th2Message = dict diff --git a/th2_data_services/utils/aggregation_classes.py b/th2_data_services/utils/aggregation_classes.py new file mode 100644 index 00000000..7e26812a --- /dev/null +++ b/th2_data_services/utils/aggregation_classes.py @@ -0,0 +1,409 @@ +# Copyright 2023-2025 Exactpro (Exactpro Systems Limited) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +from abc import ABC, abstractmethod +from typing import List, Dict + +from tabulate import tabulate + +from th2_data_services.utils.perfect_table import PerfectTable + + +class AggrClassBase(ABC): + @abstractmethod + def _repr_html_(self): + pass + + def __html__(self): + self._repr_html_() + + def html_format(self): + return self._repr_html_() + + +# TODO - if categorizer returns non-str but tuple or list or dict, we can provide more opportunities! +class EventStatTotalValue: + def __init__( + self, + value, + ): # noqa + self.value = value + + +# TODO - this is deprecated and should be removed. Use TotalCategoryTable instead +# TODO - Values of Categories should be objects with metainfo +# So not only value = Cnt +# But also status, and everything else +# If we can such values, we can sort, and analyse them! +class CategoryTotal(Dict[str, int], AggrClassBase): + # service fields + # TODO - configure fields order? + + # TODO + # 1. now it sorts by count. What about status or category name? + def __init__(self, val: Dict[str, int]): + """TODO - add. + + Args: + val: add + """ + super().__init__(val) + + self._table = [] + header = ["category", "count"] + self._table.append(header) + + total = 0 + result = [] + for category_name, category_value in self.items(): + result.append([category_name, str(category_value)]) + total += category_value + + # if sort_values: + # result.sort(key=lambda item: int(item[1]), reverse=True) + + self._table.extend(result) + self.categories_cnt = len(self.keys()) # Without total. + self.total = total + + self._table.append(["CATEGORIES", str(self.categories_cnt)]) + self._table.append(["TOTAL", str(total)]) + + def __repr__(self): + return tabulate(self._table, headers="firstrow", tablefmt="grid") + + def _repr_html_(self): + # TODO - non zero and non None values we can highlight + # FOR Jupyter + return tabulate(self._table, headers="firstrow", tablefmt="html") + + def get_categories(self) -> List[str]: + """Returns categories.""" + return list(self.keys()) + + # def sort_by(self, categories: List[str]): + # """Sort (update the object) and returns self.""" + # return self + + # def show_format(self, **kwargs): + # return tabulate(self, **kwargs) + + +# TODO - this is deprecated and should be removed. Use FrequencyCategoryTable +class CategoryFrequencies(list, AggrClassBase): + def __repr__(self): + return tabulate(self, headers="firstrow", tablefmt="grid") + + def _repr_html_(self): + # TODO - non zero and non None values we can highlight + # FOR Jupyter + return tabulate(self, headers="firstrow", tablefmt="html") + + def show_format(self, **kwargs): + return tabulate(self, **kwargs) + + def get_header(self) -> List[str]: + """Returns header. + + First value is always timestamp. + """ + return self[0] + + def get_categories(self) -> List[str]: + """Returns categories.""" + return self.get_header()[1:] # Skip timestamp. + + def by_category(self, name, exclude_zero_values=True): + """Returns CategoryFrequencies for requested column.""" + header_lst = self.get_header() + col_name_idx = header_lst.index(name) + res = CategoryFrequencies() + timestamp_col_name = header_lst[0] + res.append([timestamp_col_name, name]) + for row in self[1:]: + val = row[col_name_idx] + if exclude_zero_values: + if val != 0: + res.append([row[0], val]) + else: + res.append([row[0], val]) + + return res + + +# TODO -- new tables +# They will change deprecated above + + +class CategoryTable(ABC, PerfectTable): + def __init__(self, header: List[str]): # noqa + super().__init__(header) + self._service_columns = {} # {'col_name': 'idx'} + self._service_rows = [] # [idx] + + def _totals_line(self): + totals = [] + for col_name in self.header: + col_tuple = self[col_name] + + try: + # If all Bool. + if all([isinstance(x, bool) for x in col_tuple]): + pos = sum(col_tuple) + neg = len(col_tuple) - pos + totals.append(f"{pos}/{neg}") + else: + totals.append(sum(col_tuple)) + except: + totals.append("") + + return totals + + +class FrequencyCategoryTable(CategoryTable): + def __init__(self, header: List[str], rows=None): # noqa + super().__init__(header) + self.service_columns = { + "timestamp": 0, + } # {'col_name': 'idx'} + if rows is not None: + self.add_rows(rows) + + def get_categories(self) -> List[str]: + """Returns categories.""" + return self.header[1:] # Skip timestamp. + + def by_category(self, name, exclude_zero_values=True) -> "FrequencyCategoryTable": + """Returns CategoryFrequencies for requested column.""" + header_lst = self.header + if name not in self.get_categories(): + raise ValueError(f"'{name}' is not categories: {self.get_categories()}") + col_name_idx = header_lst.index(name) + timestamp_col_name = header_lst[0] + fct = FrequencyCategoryTable(header=[timestamp_col_name, name]) + + for row in self.rows: + val = row[col_name_idx] + if exclude_zero_values: + if val != 0: + fct.add_row([row[self.service_columns["timestamp"]], val]) + else: + fct.add_row([row[self.service_columns["timestamp"]], val]) + + return fct + + def by_categories(self, names: List[str], exclude_zero_values=True) -> "FrequencyCategoryTable": + """Returns CategoryFrequencies for requested column.""" + header_lst = self.header + for name in names: + if name not in self.get_categories(): + raise ValueError(f"'{name}' is not categories: {self.get_categories()}") + + col_name_idxs = [] + for name in names: + col_name_idxs.append(header_lst.index(name)) + + timestamp_col_name = header_lst[0] + fct = FrequencyCategoryTable(header=[timestamp_col_name, *names]) + + for row in self.rows: + vals = [row[idx] for idx in col_name_idxs] + if exclude_zero_values: + if any(vals) != 0: + fct.add_row([row[self.service_columns["timestamp"]], *vals]) + else: + fct.add_row([row[self.service_columns["timestamp"]], *vals]) + + return fct + + def get_list_repr(self): + additional_rows = [ + ["count"] + ["" for _ in range(len(self.header) - 1)] + [len(self.rows)], + ["totals"] + self._totals_line(), + ] + return [ + [" "] + list(self.header), + *[[" "] + list(row) for row in self.rows], + *additional_rows, + ] + + +class TotalCategoryTable(CategoryTable): + # This class allows to create tables with multiple categories. e.g type | status | count + def __init__(self, header, rows=None): # noqa + super().__init__(header) + self.service_columns = { + "timestamp": 0, + } # {'col_name': 'idx'} + if rows is not None: + self.add_rows(rows) + + self._transposed = False + self.count_field_name = "count" + + @property + def total(self): + return sum(self[self.count_field_name]) + + def add_rows_from_dict(self, d: dict): + result = [] + for category_name, category_value in d.items(): + result.append([category_name, str(category_value)]) + # total += category_value + + # if sort_values: + # result.sort(key=lambda item: int(item[1]), reverse=True) + + self.add_rows(result) + + # TODO - I'm not sure that it's categories! + def get_categories(self) -> List: + return [row[:-1] for row in self.rows] + + def get_list_repr(self): + additional_rows = [ + # ['' for i in range(len(self.header) - 1)] + [self.total], + ["count"] + ["" for _ in range(len(self.header) - 1)] + [len(self.rows)], + ["totals"] + self._totals_line(), + ] + return [ + [" "] + list(self.header), + *[[" "] + list(row) for row in self.rows], + *additional_rows, + ] + + def transpose_column(self, column_name) -> "TotalCategoryTable": + """Returns a new table with transposed column. + + Look at the example below. + + Example: + +--------+-------------+----------------+-----------+---------+ + | | direction | messageType | session | count | + +========+=============+================+===========+=========+ + | | OUT | NewOrderSingle | s1 | 54 | + +--------+-------------+----------------+-----------+---------+ + | | OUT | Cancel | s3 | 54 | + +--------+-------------+----------------+-----------+---------+ + | | IN | Amend | s1 | 51 | + +--------+-------------+----------------+-----------+---------+ + | | IN | NewOrderSingle | s3 | 50 | + +--------+-------------+----------------+-----------+---------+ + | | OUT | NewOrderSingle | s4 | 50 | + +--------+-------------+----------------+-----------+---------+ + | | OUT | Cancel | s2 | 49 | + +--------+-------------+----------------+-----------+---------+ + | | OUT | Amend | s2 | 48 | + +--------+-------------+----------------+-----------+---------+ + | | IN | NewOrderSingle | s1 | 47 | + +--------+-------------+----------------+-----------+---------+ + | | OUT | Cancel | s4 | 44 | + +--------+-------------+----------------+-----------+---------+ + | | OUT | NewOrderSingle | s2 | 43 | + +--------+-------------+----------------+-----------+---------+ + | | IN | Cancel | s1 | 43 | + +--------+-------------+----------------+-----------+---------+ + | | IN | Amend | s4 | 42 | + +--------+-------------+----------------+-----------+---------+ + | | OUT | Amend | s3 | 41 | + +--------+-------------+----------------+-----------+---------+ + | | IN | Cancel | s2 | 40 | + +--------+-------------+----------------+-----------+---------+ + | | IN | Amend | s2 | 39 | + +--------+-------------+----------------+-----------+---------+ + | | OUT | Amend | s4 | 38 | + +--------+-------------+----------------+-----------+---------+ + | | IN | Cancel | s4 | 37 | + +--------+-------------+----------------+-----------+---------+ + | | IN | Cancel | s3 | 36 | + +--------+-------------+----------------+-----------+---------+ + | | OUT | NewOrderSingle | s3 | 34 | + +--------+-------------+----------------+-----------+---------+ + | | OUT | Cancel | s1 | 34 | + +--------+-------------+----------------+-----------+---------+ + | | IN | Amend | s3 | 34 | + +--------+-------------+----------------+-----------+---------+ + | | IN | NewOrderSingle | s2 | 33 | + +--------+-------------+----------------+-----------+---------+ + | | IN | NewOrderSingle | s4 | 30 | + +--------+-------------+----------------+-----------+---------+ + | | OUT | Amend | s1 | 29 | + +--------+-------------+----------------+-----------+---------+ + | count | | | | 24 | + +--------+-------------+----------------+-----------+---------+ + | totals | | | | 1000 | + +--------+-------------+----------------+-----------+---------+ + + to + + +--------+-------------+----------------+------+------+------+------+ + | | direction | messageType | s4 | s2 | s1 | s3 | + +========+=============+================+======+======+======+======+ + | | OUT | NewOrderSingle | 50 | 43 | 54 | 34 | + +--------+-------------+----------------+------+------+------+------+ + | | OUT | Cancel | 44 | 49 | 34 | 54 | + +--------+-------------+----------------+------+------+------+------+ + | | IN | Amend | 42 | 39 | 51 | 34 | + +--------+-------------+----------------+------+------+------+------+ + | | IN | NewOrderSingle | 30 | 33 | 47 | 50 | + +--------+-------------+----------------+------+------+------+------+ + | | OUT | Amend | 38 | 48 | 29 | 41 | + +--------+-------------+----------------+------+------+------+------+ + | | IN | Cancel | 37 | 40 | 43 | 36 | + +--------+-------------+----------------+------+------+------+------+ + | count | | | | | | 6 | + +--------+-------------+----------------+------+------+------+------+ + | totals | | | 241 | 252 | 258 | 249 | + +--------+-------------+----------------+------+------+------+------+ + + + """ + static_col_names = [] + dynamic_col_names = set() + for h in self.header: + if h == column_name or h == self.count_field_name: + pass + else: + static_col_names.append(h) + + new_tbl_dict = {} # {(static_columns): {dynamic_col: val} } + + for row in self.rows: + new_row = [] + for h in static_col_names: + new_row.append(row[h]) + + new_tbl_dict.setdefault(tuple(new_row), {})[row[column_name]] = row[ + self.count_field_name + ] + dynamic_col_names.add(row[column_name]) + + dynamic_col_names_lst = sorted(list(dynamic_col_names)) + new_header = static_col_names + dynamic_col_names_lst + new_tbl = TotalCategoryTable(header=new_header) + """ + {('OUT', 'NewOrderSingle'): {'s3': 34}, + ('OUT', 'Cancel'): {'s1': 34}, + ('IN', 'Amend'): {'s3': 34}, + """ + + for static_part, dict_with_dynamic_values in new_tbl_dict.items(): + values_line = [] + for col_name in dynamic_col_names_lst: + values_line.append(dict_with_dynamic_values.get(col_name, 0)) + new_tbl._append_row(list(static_part) + values_line) + + self._transposed = True + return new_tbl diff --git a/th2_data_services/utils/az_tree.py b/th2_data_services/utils/az_tree.py new file mode 100644 index 00000000..6ada618c --- /dev/null +++ b/th2_data_services/utils/az_tree.py @@ -0,0 +1,27 @@ +# Copyright 2023-2025 Exactpro (Exactpro Systems Limited) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +from warnings import warn +from th2_data_services.utils.json_tree import * + +# Just to autoflake don't remove import * +json + +warn( + "'az_tree' module was deprecated and will be removed since 2.0.0 release.\n" + "Use 'json_tree' module instead", + RuntimeWarning, + stacklevel=2, +) diff --git a/th2_data_services/interfaces/events_tree/__init__.py b/th2_data_services/utils/categorizers.py similarity index 74% rename from th2_data_services/interfaces/events_tree/__init__.py rename to th2_data_services/utils/categorizers.py index 6166fa4a..8a6658ff 100644 --- a/th2_data_services/interfaces/events_tree/__init__.py +++ b/th2_data_services/utils/categorizers.py @@ -1,4 +1,4 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) +# Copyright 2023-2025 Exactpro (Exactpro Systems Limited) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -12,5 +12,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -from .events_tree_collection import EventsTreeCollection -from .parent_events_tree_collection import ParentEventsTreeCollection + +class EventCategorizer: + @classmethod + def type(cls, event): + return event["eventType"] + + +class GetFrequences: + pass diff --git a/th2_data_services/utils/category.py b/th2_data_services/utils/category.py new file mode 100644 index 00000000..bdf82e98 --- /dev/null +++ b/th2_data_services/utils/category.py @@ -0,0 +1,28 @@ +# Copyright 2023-2025 Exactpro (Exactpro Systems Limited) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +class Category: + def __init__(self, name: str, get_func): + """Category is category name + categorizer function. + + Args: + name: Name that you will see as category name. Often it's a column name. + get_func: A function to get a value for this category from every data value. + """ + self.name: str = name + self.get_func = get_func + + def __repr__(self): + return f"Category<{self.name}>" diff --git a/th2_data_services/utils/converters.py b/th2_data_services/utils/converters.py index 5ea47fc8..ebfcb1bf 100644 --- a/th2_data_services/utils/converters.py +++ b/th2_data_services/utils/converters.py @@ -1,30 +1,329 @@ -from collections import namedtuple +# Copyright 2022-2025 Exactpro (Exactpro Systems Limited) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +import base64 from datetime import datetime, timezone +import shutil +import gzip +import ciso8601 -from th2_data_services.interfaces.utils.converter import ITimestampConverter +import flatdict as _flatdict -_DatetimeTuple = namedtuple("DatetimeTuple", "datetime mantissa") +from th2_data_services.interfaces.utils.converter import ITimestampConverter, TimestampType class DatetimeStringConverter(ITimestampConverter[str]): """Converts datetime strings. - If you request microseconds but your timestamp has nanoseconds, they will be just cut (not rounding). + Works with ISO_8601 datetime strings. - Expected timestamp format "yyyy-MM-ddTHH:mm:ss[.SSSSSSSSS]Z". + If you request microseconds but your timestamp has nanoseconds, + they will be just cut (not rounding). + + Expected timestamp format "yyyy-MM-ddTHH:mm:ss[.SSSSSSSSS][Z]". + 'Z' in the end is optional. """ @classmethod def parse_timestamp(cls, datetime_string: str) -> (str, str): + # Note: + # we have similar code here (not the separate function) + # to improve performance. try: - dt_tuple = _DatetimeTuple("", "") # ('2022-03-05T23:56:44', '0Z') - timestamp = datetime.strptime(datetime_string, "%Y-%m-%dT%H:%M:%SZ").replace(tzinfo=timezone.utc) - except ValueError: - dt_tuple = _DatetimeTuple(*datetime_string.rsplit(".")) - timestamp = datetime.strptime(dt_tuple.datetime, "%Y-%m-%dT%H:%M:%S").replace(tzinfo=timezone.utc) + if datetime_string[19] == ".": + datetime_part, mantissa = datetime_string.rsplit(".") + if mantissa[-1] == "Z": + mantissa = mantissa[:-1] + else: + datetime_part, mantissa = datetime_string, "" + except: + datetime_part, mantissa = datetime_string, "" + + dt = ciso8601.parse_datetime(datetime_part).replace(tzinfo=timezone.utc) + + nanoseconds = f"{mantissa:0<9}" # Add zeros on right. + seconds = str(int(dt.timestamp())) + + return seconds, nanoseconds + + @classmethod + def parse_timestamp_int(cls, datetime_string: str) -> (int, int): + # Note: + # we have similar code here (not the separate function) + # to improve performance. + try: + if datetime_string[19] == ".": + datetime_part, mantissa = datetime_string.rsplit(".") + if mantissa[-1] == "Z": + mantissa = mantissa[:-1] + else: + datetime_part, mantissa = datetime_string, "" + except: + datetime_part, mantissa = datetime_string, "" + + dt = ciso8601.parse_datetime_as_naive(datetime_part).replace(tzinfo=timezone.utc) + + return int(dt.timestamp()), int(f"{mantissa:0<9}") + + @classmethod + def to_datetime(cls, datetime_string: str) -> datetime: + return ciso8601.parse_datetime_as_naive(datetime_string) + + +class UniversalDatetimeStringConverter(ITimestampConverter[str]): + """Converts datetime strings. + + If you request microseconds but your timestamp has nanoseconds, + they will be just cut (not rounding). + + Expected timestamp format "yyyy-MM-ddTHH:mm:ss[.SSSSSSSSS]Z" or without Z or T as separators. + """ + + @classmethod + def parse_timestamp(cls, datetime_string: str) -> (str, str): + try: + datetime_string = datetime_string.replace("T", " ") + if datetime_string[19] == ".": + datetime_part, mantissa = datetime_string.rsplit(".") + if mantissa[-1] == "Z": + mantissa = mantissa[:-1] + else: + datetime_part, mantissa = datetime_string, "" + except: + datetime_part, mantissa = datetime_string, "" + + dt = ciso8601.parse_datetime(datetime_part).replace(tzinfo=timezone.utc) - mantissa_wo_z = dt_tuple.mantissa[:-1] - nanoseconds = f"{mantissa_wo_z:0<9}" - seconds = int(timestamp.timestamp()) + nanoseconds = f"{mantissa:0<9}" # Add zeros on right. + seconds = str(int(dt.timestamp())) return seconds, nanoseconds + + @classmethod + def parse_timestamp_int(cls, datetime_string: str) -> (int, int): + # Note: + # we have similar code here (not the separate function) + # to improve performance. + try: + datetime_string = datetime_string.replace("T", " ") + if datetime_string[19] == ".": + datetime_part, mantissa = datetime_string.rsplit(".") + if mantissa[-1] == "Z": + mantissa = mantissa[:-1] + else: + datetime_part, mantissa = datetime_string, "" + except: + datetime_part, mantissa = datetime_string, "" + + dt = ciso8601.parse_datetime(datetime_part).replace(tzinfo=timezone.utc) + + return int(dt.timestamp()), int(f"{mantissa:0<9}") + + @classmethod + def to_datetime(cls, datetime_string: str) -> datetime: + return ciso8601.parse_datetime_as_naive(datetime_string) + + +class DatetimeConverter(ITimestampConverter[datetime]): + """Converts datetime objects to timestamp. + + If you request milliseconds but your timestamp has microseconds, they will + be just cut (not rounding). + If you request nanoseconds, last 3 number will be zeros, because datatime + object doesn't have nanoseconds. + + Expected timestamp format "datetime.datetime object". + Expected that you provide UTC time in your data object. + """ + + @classmethod + def parse_timestamp(cls, datetime_obj: datetime) -> (str, str): + sec_and_mantissa = str(datetime_obj.replace(tzinfo=timezone.utc).timestamp()).split(".") + seconds = sec_and_mantissa[0] + nanoseconds = f"{sec_and_mantissa[1]:0<9}" # Add zeros on right. + return seconds, nanoseconds + + @classmethod + def parse_timestamp_int(cls, datetime_obj: datetime) -> (int, int): + # TODO - there should be better solution + seconds, nanoseconds = cls.parse_timestamp(datetime_obj) + return int(seconds), int(nanoseconds) + + +class UnixTimestampConverter(ITimestampConverter[int]): + """Converts unix timestamp integers to timestamp. + + If you request microseconds but your timestamp has nanoseconds, + they will be just cut (not rounding). + + Expected timestamp format 1705581844 (seconds), 1705581844123 (milliseconds), 17055818441123456 (microseconds), 17055818441123456789 (nanoseconds). + Timestamp should be given as integer. + """ + + @classmethod + def parse_timestamp(cls, unix_timestamp: int) -> (str, str): + if unix_timestamp < 99999999999: + return str(unix_timestamp), "000000000" + elif unix_timestamp < 99999999999999: + return str(unix_timestamp)[:-3], f"{str(unix_timestamp)[-3:]}000000" + elif unix_timestamp < 99999999999999999: + return str(unix_timestamp)[:-6], f"{str(unix_timestamp)[-6:]}000" + else: + return str(unix_timestamp)[:-9], str(unix_timestamp)[-9:] + + @classmethod + def parse_timestamp_int(cls, unix_timestamp: int) -> (int, int): + seconds, nanoseconds = cls.parse_timestamp(unix_timestamp) + return int(seconds), int(nanoseconds) + + +class ProtobufTimestampConverter(ITimestampConverter[dict]): + """Converts Th2 timestamps. + + If you request microseconds but your timestamp has nanoseconds, + they will be just cut (not rounding). + + Expected timestamp format {'epochSecond': 123, 'nano': 500}. + Values are Int. + """ + + @classmethod + def parse_timestamp(cls, timestamp: dict) -> (str, str): + seconds, nanoseconds = timestamp["epochSecond"], timestamp["nano"] + return str(seconds), str(nanoseconds).zfill(9) # Add zeros on left. + + @classmethod + def parse_timestamp_int(cls, timestamp: dict) -> (int, int): + seconds, nanoseconds = timestamp["epochSecond"], timestamp["nano"] + return seconds, nanoseconds + + @classmethod + def to_seconds(cls, timestamp: TimestampType): + """Converts timestamp to seconds. + + If your timestamp has nanoseconds, they will be just cut (not rounding). + + Args: + timestamp: TimestampType object to convert. + + Returns: + int: Timestamp in seconds format. + """ + return timestamp["epochSecond"] + + @classmethod + def to_microseconds(cls, timestamp: TimestampType) -> int: + """Converts timestamp to microseconds. + + If your timestamp has nanoseconds, they will be just cut (not rounding). + + Args: + timestamp: TimestampType object to convert. + + Returns: + int: Timestamp in microseconds format. + """ + seconds, nanoseconds = timestamp["epochSecond"], timestamp["nano"] + return 1_000_000 * seconds + nanoseconds // 1_000 + + @classmethod + def to_milliseconds(cls, timestamp: TimestampType) -> int: + """Converts timestamp to milliseconds. + + If your timestamp has nanoseconds, they will be just cut (not rounding). + + Args: + timestamp: TimestampType object to convert. + + Returns: + int: Timestamp in microseconds format. + """ + seconds, nanoseconds = timestamp["epochSecond"], timestamp["nano"] + return 1_000 * seconds + nanoseconds // 1_000_000 + + @classmethod + def to_nanoseconds(cls, timestamp: TimestampType) -> int: + """Converts timestamp to nanoseconds. + + Args: + timestamp: TimestampType object to convert. + + Returns: + int: Timestamp in nanoseconds format. + """ + seconds, nanoseconds = timestamp["epochSecond"], timestamp["nano"] + return 1_000_000_000 * seconds + nanoseconds + + +Th2TimestampConverter = ProtobufTimestampConverter + + +def decompress_gzip_file(input_filename: str, output_filename: str) -> None: + """Unzip gzip file. + + The original file won't be removed. + + Args: + input_filename: gzip file path. + output_filename: out file path. + """ + with gzip.open(input_filename, "rb") as f_in: + with open(output_filename, "wb") as f_out: + shutil.copyfileobj(f_in, f_out) + + +def flatten_dict(dictionary: dict, separator: str = ".") -> dict: + """Returns flatten dict. + + Examples: + >>> rv = flatten_dict({ + 'd': [ + {'a': 1, + 'c': {'z': 2, + 'b': [{'x': 5, 'y': 10}, 'str-in-lst'] + } + }, + 'str', + 3 + ] + } + ) + + assert rv == { + 'd.0.a': 1, + 'd.0.c.z': 2, + 'd.0.c.b.0.x': 5, + 'd.0.c.b.0.y': 10, + 'd.0.c.b.1': 'str-in-lst', + 'd.1': 'str', + 'd.2': 3 + } + + Args: + dictionary: dict object. + parent_key: used for internal function purposes. + separator: the separator between words. + + Returns: + Flatten dict. + + """ + rv = _flatdict.FlatterDict(dictionary, delimiter=separator) + return dict(rv) + + +def decode_base64(coded_string: str) -> bytes: + """Returns decoded bytes.""" + return base64.b64decode(coded_string) diff --git a/th2_data_services/utils/data_utils.py b/th2_data_services/utils/data_utils.py new file mode 100644 index 00000000..5b667f70 --- /dev/null +++ b/th2_data_services/utils/data_utils.py @@ -0,0 +1,51 @@ +# Copyright 2024-2025 Exactpro (Exactpro Systems Limited) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +import os +from pathlib import Path +from typing import List, Union + +from th2_data_services.data import Data + + +def read_all_pickle_files_from_the_folder( + path: Union[str, Path], return_list=False +) -> Union[Data, List[Data]]: + """Reads all Pickle files from the folder. + + Args: + path: Directory path. + return_list: Returns list of Data objects if True. + + Returns: + Single data object or a list of Data objects. + """ + datas = [] + for (dirpath, dirnames, filenames) in os.walk(path): + for filename in filenames: + if not filename.endswith(".pickle"): + continue + file_path = os.path.join(dirpath, filename) + datas.append(Data.from_cache_file(file_path)) + + if return_list: + return datas + + if len(datas) == 1: + return datas[0] + else: + d = Data(datas) + d.update_metadata({"source_file": [dx.metadata.get("source_file") for dx in datas]}) + return d diff --git a/th2_data_services/decode_error_handler.py b/th2_data_services/utils/decode_error_handler.py similarity index 84% rename from th2_data_services/decode_error_handler.py rename to th2_data_services/utils/decode_error_handler.py index 120a42ea..c9a03a98 100644 --- a/th2_data_services/decode_error_handler.py +++ b/th2_data_services/utils/decode_error_handler.py @@ -1,4 +1,4 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) +# Copyright 2022-2025 Exactpro (Exactpro Systems Limited) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -12,10 +12,12 @@ # See the License for the specific language governing permissions and # limitations under the License. + +from __future__ import annotations from codecs import register_error -def handler(err: UnicodeDecodeError): +def handler(err: UnicodeDecodeError) -> tuple[str, int]: """Decode error handler that tries change utf-8 character to Unicode.""" return chr(err.object[err.start]), err.end diff --git a/th2_data_services/utils/display.py b/th2_data_services/utils/display.py new file mode 100644 index 00000000..b15b0153 --- /dev/null +++ b/th2_data_services/utils/display.py @@ -0,0 +1,85 @@ +# Copyright 2023-2025 Exactpro (Exactpro Systems Limited) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +from typing import Dict, Union + +from tabulate import tabulate + + +def calculate_stats_dict(data: Dict, sort_values: bool = False): # noqa + table = [["category", "count"]] # Header + total = 0 + result = [] + for item in data.items(): + result.append([item[0], str(item[1])]) + total += item[1] + + if sort_values: + result.sort(key=lambda item: int(item[1]), reverse=True) + + table.extend(result) + table.append(["CATEGORIES", str(len(data))]) + table.append(["TOTAL", str(total)]) + return table + + +def print_stats_dict( + data: Dict, return_html: bool = False, sort_values: bool = False, tabulate_style: str = "grid" +) -> Union[None, str]: + """Prints Statistics. + + Args: + data: Dictionary of data + return_html: Return HTML format, defaults to False + sort_values: Sort result, defaults to False + tabulate_style: Table format style, defaults to "grid" + + Returns: + None if return_html is False else str + """ + table = calculate_stats_dict(data, sort_values) + + if return_html: + return tabulate(table, headers="firstrow", tablefmt="html") + else: + print(tabulate(table, headers="firstrow", tablefmt=tabulate_style)) + return None + + +def print_measurement_dict(data: Dict, return_html: bool = False): + """Prints Measurements. + + Args: + data: Dictionary of data + return_html: Return HTML format, defaults to False + + Returns: + None if return_html is False else str + """ + header = list(set(key for value in data.values() for key in value if key != "distr")) + header.sort() + table = [["category", *header]] + + for key, value in data.items(): + row = [key] + for header_name in header: + row.append(str(value[header_name])) + table.append(row) + + if return_html: + return tabulate(table, headers="firstrow", tablefmt="html") + else: + print(tabulate(table, headers="firstrow", tablefmt="grid")) + return None diff --git a/th2_data_services/provider/v5/__init__.py b/th2_data_services/utils/event_utils/__init__.py similarity index 76% rename from th2_data_services/provider/v5/__init__.py rename to th2_data_services/utils/event_utils/__init__.py index ad81fdcd..f5a7795d 100644 --- a/th2_data_services/provider/v5/__init__.py +++ b/th2_data_services/utils/event_utils/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) +# Copyright 2023-2025 Exactpro (Exactpro Systems Limited) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -12,6 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -from th2_data_services.provider.utils.version_checker import verify_grpc_version -verify_grpc_version(["0.1.6"]) +from . import display +from . import event_utils +from . import frequencies +from . import select +from . import totals diff --git a/th2_data_services/utils/event_utils/display.py b/th2_data_services/utils/event_utils/display.py new file mode 100644 index 00000000..638a02fa --- /dev/null +++ b/th2_data_services/utils/event_utils/display.py @@ -0,0 +1,322 @@ +# Copyright 2023-2025 Exactpro (Exactpro Systems Limited) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +from typing import Iterable, Union +from datetime import datetime +from tabulate import tabulate +from typing import Callable + +from th2_data_services.utils.event_utils.event_utils import extract_start_timestamp, get_some +from th2_data_services.utils.event_utils.select import ( + get_children_from_parents, + get_events_by_category, + get_roots, + get_children_from_parent_id, +) +from th2_data_services.utils._types import Th2Event + +from th2_data_services.config import options + + +# TODO +# COMMENTED - because we don't need it more. We will return classes that have good representation! +# def print_attached_messages_totals(events: Iterable[Th2Event], return_html: bool = False) -> Union[None, str]: +# """Prints Dictionary quantities of messages attached to events for each stream + direction. +# +# Args: +# events (Iterable[Th2Event]): TH2-Events +# return_html (bool): Return HTML Format +# +# """ +# data = get_attached_messages_totals(events) +# return misc_utils.print_stats_dict(data, return_html) + + +# TODO +# COMMENTED - because we don't need it more. We will return classes that have good representation! +# def print_category_totals( +# events: Iterable[Th2Event], categorizer: Callable, return_html: bool = False, ignore_status: bool = False +# ) -> Union[None, str]: +# """Prints dictionary quantities of events for different categories. +# +# Args: +# events (Iterable[Th2Event]): TH2-Events +# categorizer (Callable): Categorizer Method +# return_html (bool): Return HTML Format, defaults to False +# ignore_status (bool): Get status of events, defaults to False +# +# Returns: +# Union[None, str] +# """ +# data = get_category_totals(events, categorizer, ignore_status=ignore_status) +# return misc_utils.print_stats_dict(data, return_html) + + +# STREAMING +def print_event(event: Th2Event) -> None: + """Prints event in human-readable format. + + Args: + event (Th2Event): TH2-Event + + """ + print( + f"{extract_start_timestamp(event)} > [{'ok' if options.EVENT_FIELDS_RESOLVER.get_status(event) else 'fail'}] " + f"Type: {options.EVENT_FIELDS_RESOLVER.get_type(event)} " + f"Name: {options.EVENT_FIELDS_RESOLVER.get_name(event)} " + f"ID: {options.EVENT_FIELDS_RESOLVER.get_id(event)} " + f"Parent:{options.EVENT_FIELDS_RESOLVER.get_parent_id(event)} " + f"Body:{options.EVENT_FIELDS_RESOLVER.get_body(event)}" + ) + + +# NOT STREAMING +# PREV name print_some_raw +def print_events_raw( + events: Iterable[Th2Event], event_type: str, count: int, start: int = 0, failed: bool = False +) -> None: + """Prints limited list of events of specific eventType in dictionary format. + + Args: + events (Iterable[Th2Event]): TH2-Events + event_type (set): Event Type To Extract + count (int): Maximum number of events to extract + start (int, optional): Start Iteration Index. Defaults to 0. + failed (bool, optional): Extract Only Failed Events. Defaults to False. + + """ + records = get_some(events, event_type, count, start, failed) + for r in records: + print(r) + + +# NOT STREAMING +def print_some( + events: Iterable[Th2Event], event_type: str, count: int, start: int = 0, failed: bool = False +) -> None: + """Prints limited list of events of specific eventType in human-readable format. + + Args: + events (Iterable[Th2Event]): TH2-Events + event_type (set): Event Type To Extract + count (int): Maximum number of events to extract + start (int, optional): Start Iteration Index. Defaults to 0. + failed (bool, optional): Extract Only Failed Events. Defaults to False. + + """ + records = get_some(events, event_type, count, start, failed) + for r in records: + print_event(r) + + +# NOT STREAMING +def print_some_by_category( + events: Iterable[Th2Event], + category: str, + count: int, + categorizer: Callable, + start: int = 0, + failed: bool = False, +) -> None: + """Print limited events by category. + + Args: + events (Iterable[Th2Event]): TH2-Events + category (str): Event category to extract + count (int): Maximum number of events to extract + categorizer (Callable): Categorizer function + start (int, optional): Start iteration index, defaults to 0. + failed (bool, optional): Extract only failed events, defaults to False. + + """ + records = get_events_by_category(events, category, count, categorizer, start, failed) + for r in records: + print_event(r) + + +# STREAMING +def print_roots(events: Iterable[Th2Event], count: int, start: int = 0) -> None: + """Prints limited list of root events (events without parents). + + Args: + events (Iterable[Th2Event]): TH2-Events + count (int): Maximum number of events to extract + start (int, optional): Start Iteration Index. Defaults to 0. + + """ + records = get_roots(events, count, start) + for r in records: + print_event(r) + + +# STREAMING +def print_children(events: Iterable[Th2Event], parent_id: str, count: int, verbose: bool = True): + """Prints limited list of direct children events. + + Args: + events (Iterable[Th2Event]): TH2-Events + parent_id (str): Parent ID + count (int): Maximum number of events to extract + verbose (bool): Verbose output, defaults to True. + + """ + records, _ = get_children_from_parent_id(events, parent_id, count) + fprint = print_event if verbose is True else print + for r in records: + fprint(r) + + +# NOT STREAMING +def print_children_from_parents( + events: Iterable[Th2Event], parents: Iterable[Th2Event], max_events: int = 10_000 +) -> None: + """Prints limited list of direct children events for each event in parents_list. + + Args: + events (Iterable[Th2Event]): TH2-Events + parents (Iterable[Th2Event]): Parent TH2-Events + max_events (int): Maximum number of events to extract from each parent, default to 10'000 + + """ + tree, count = get_children_from_parents(events, parents, max_events) + print(f"####### Retrieved Children: {count}") + for parent in parents: + print(parent) + print(f">>>>>>> Children: {len(tree[options.EVENT_FIELDS_RESOLVER.get_id(parent)])}") + for child in tree[options.EVENT_FIELDS_RESOLVER.get_id(parent)]: + print_event(child) + print(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>") + + +# NOT STREAMING +def print_children_stats_from_parents( + events: Iterable[Th2Event], + parents: Iterable[Th2Event], + max_events: int = 10_000, + return_html: bool = False, +) -> Union[None, str]: + """Prints statistics with number of children and their duration for each event in parents_list. + + Args: + events (Iterable[Th2Event]): TH2-Events + parents (Iterable[Th2Event]): Parent TH2-Events + max_events (int): Maximum number of events to extract, default to 10'000 + return_html (bool): Return HTML format, defaults to False + + """ + tree, _ = get_children_from_parents(events, parents, max_events) + table = [ + ["eventName", "status", "eventId", "child_pass", "child_fail", "start", "end"] + ] # Header + for parent in parents: + start_timestamp, end_timestamp = 0, 0 + events_passed, events_failed = 0, 0 + for child in tree[options.EVENT_FIELDS_RESOLVER.get_id(parent)]: + child_start_time_epoch = options.EVENT_FIELDS_RESOLVER.get_start_timestamp(child)[ + "epochSecond" + ] + if child_start_time_epoch > end_timestamp: + end_timestamp = child_start_time_epoch + if start_timestamp == 0 or child_start_time_epoch < start_timestamp: + start_timestamp = child_start_time_epoch + + if options.EVENT_FIELDS_RESOLVER.get_status(child): + events_passed += 1 + else: + events_failed += 1 + + table.append( + [ + options.EVENT_FIELDS_RESOLVER.get_name(parent), + "[ok]" if options.EVENT_FIELDS_RESOLVER.get_status(parent) else "[fail]", + events_passed, + events_failed, + datetime.fromtimestamp(start_timestamp).isoformat(), + datetime.fromtimestamp(end_timestamp).isoformat(), + datetime.fromtimestamp(end_timestamp).isoformat(), + ] + ) + + if return_html: + return tabulate(table, headers="firstrow", tablefmt="html") + else: + print(tabulate(table, headers="firstrow", tablefmt="grid")) + + +# TODO +# COMMENTED - because we don't need it more. We will return classes that have good representation! +# STREAMING +# TODO - bad function, that not only prints but also gets +# If we want to have pretty look, we can implement __repr__ functions +# def print_type_frequencies( +# events: Iterable[Th2Event], event_types: List[str], aggregation_level: str = "seconds", return_html=False +# ) -> Union[None, str]: +# """Prints table of events per seconds or each second when there were events within events stream. +# +# Args: +# events: TH2-Events +# event_types: List of event types to analyze +# aggregation_level: Aggregation level +# return_html: Return HTML format, defaults to False +# +# """ +# table = get_type_frequencies(events, event_types, aggregation_level) +# if return_html: +# return tabulate(table, headers="firstrow", tablefmt="html") +# else: +# print(tabulate(table, headers="firstrow", tablefmt="grid")) + +# +# +# # STREAMING +# # TODO - takes event_types - but it should be categiries +# +# def print_category_frequencies( +# events: List[Dict], +# event_types: List[str], +# categorizer: Callable, +# aggregation_level: str = "seconds", +# return_html: bool = False, +# ) -> Union[None, str]: +# """Prints table of events per seconds or each second when there were events within events stream. +# +# Args: +# events (List[Dict]): TH2-Events +# event_types (List[str]): Event Types To Extract +# categorizer (Callable): Categorizer function +# aggregation_level (str): Aggregation Level +# return_html: Return HTML Format +# +# Returns: +# Union[None, str] +# """ +# data = get_category_frequencies(events, event_types, categorizer, aggregation_level) +# if return_html: +# return tabulate(data, headers="firstrow", tablefmt="html") +# else: +# print(tabulate(data, headers="firstrow", tablefmt="grid")) +# return None +# def print_type_totals(events: List[Dict], return_html: bool = False) -> Union[None, str]: +# """Prints dictionary quantities of events for different event types. +# +# Args: +# events (List[Dict]): TH2-Events +# return_html (bool): HTML format, defaults to False +# +# Returns: +# Union[None, str] +# """ +# event_types = get_type_totals(events) +# return misc_utils.print_stats_dict(event_types, return_html=return_html) diff --git a/th2_data_services/utils/event_utils/event_utils.py b/th2_data_services/utils/event_utils/event_utils.py new file mode 100644 index 00000000..f8bdbcc2 --- /dev/null +++ b/th2_data_services/utils/event_utils/event_utils.py @@ -0,0 +1,258 @@ +# Copyright 2023-2025 Exactpro (Exactpro Systems Limited) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +import json + +from th2_data_services.utils._types import Th2Event +import th2_data_services.utils.time +from typing import Callable, Dict, Iterable, Optional +from datetime import datetime + +from th2_data_services.config import options + +# TODO - +# 1. events: List[Dict] -- should be Iterable[Th2Event], where Th2Event = Dict. It can be changed in the future +# 2. IDEA - it's difficult to understand what you will get when read some functions. I think add examples +# 3. I want to return special classes - not just dicts because dicts +# usually difficult to understand and customize + +from th2_data_services.utils.event_utils.select import ( + get_roots, + get_children_from_parents_as_list, + sublist, +) +from th2_data_services.utils._is_sorted_result import IsSortedResult + + +# NOT STREAMING +# TODO - Can we have single function for events and messages? +# +# Will return list! Perhaps it's better to return Data? +def get_some( + events: Iterable[Th2Event], + event_type: Optional[str], + max_count: int, # TODO -- Slava - I think we need to add Optional = None, for unlimited. + start: int = 0, + failed: bool = False, # ?? +) -> Iterable[Th2Event]: + """Returns limited list of events of specific eventType. + + Args: + events (Iterable[Th2Event]): TH2-Events + event_type (str): Event Type To Extract + max_count (int): Maximum number of events to extract + start (int, optional): Start Iteration Index. Defaults to 0. + failed (bool, optional): Extract Only Failed Events. Defaults to False. + + Returns: + Iterable[Th2Event] + + Example: + >>> get_some(events=events, + event_type="ModelCase", + count=100, + start=0 + failed=False) + [ + {**TH2-Event}, + ... + ] + + """ + result = [] + counter = 0 + limit = start + max_count + + for event in events: + if event_type is None or options.EVENT_FIELDS_RESOLVER.get_type(event) == event_type: + if failed and options.EVENT_FIELDS_RESOLVER.get_status(event): + continue + if counter >= start: + result.append(event) + counter += 1 + if counter == limit: + break + + return result + + +# NOT STREAMING +# TODO: Change name +def build_roots_cache(events: Iterable[Th2Event], depth: int, max_level: int) -> Dict: + """Returns event path for each event. + + Notes: + Event path from root to event, it's a string of event names separated by `/` + + Args: + events: TH2-Events + depth: Max depth to search + max_level: Max events from leaf + + Returns: + Dict[str, Dict[str, str]] + + Example: + >>> build_roots_cache(events=events, + depth=10, + max_level=10) + { + eventId: { + eventName: "example event name", + eventPath: "rootName/.../currentEventName" + }, + ... + } + """ + result = {} + level = 1 + prev_levels = get_roots(events, max_level) + print(f"Level {level}: {len(prev_levels)} events") + for prev_level in prev_levels: + result[options.EVENT_FIELDS_RESOLVER.get_id(prev_level)] = { + "eventName": options.EVENT_FIELDS_RESOLVER.get_name(prev_level), + "eventPath": options.EVENT_FIELDS_RESOLVER.get_name(prev_level), + } + while level < depth: + next_levels = get_children_from_parents_as_list(events, prev_levels, max_level) + next_levels_count = len(next_levels) + if next_levels_count == 0: + break + level += 1 + print(f"Level {level}: {next_levels_count} events") + for next_level in next_levels: + event_id = options.EVENT_FIELDS_RESOLVER.get_id(next_level) + parent_id = options.EVENT_FIELDS_RESOLVER.get_parent_id(next_level) + result[event_id] = { + "eventName": options.EVENT_FIELDS_RESOLVER.get_name(next_level), + "eventPath": result[parent_id]["eventPath"] + + "/" + + options.EVENT_FIELDS_RESOLVER.get_name(next_level), + } + prev_levels = next_levels + + return result + + +# STREAMING +# TODO - perhaps we can move it to resolver. +def extract_start_timestamp(event: Dict) -> str: + """Returns string representation of events timestamp. + + Args: + event: TH2-Event + + Returns: + str + """ + return th2_data_services.utils.time.extract_timestamp( + options.EVENT_FIELDS_RESOLVER.get_start_timestamp(event) + ) + + +# NOT STREAMING +def extract_parent_as_json( + events: Iterable[Th2Event], + parent_id: str, + json_file_path: str, + interval_start: str, + interval_end: str, + body_to_simple_processors: Callable = None, +): + """Parse parent into JSON format. + + Args: + events (Dict): TH2-Events + parent_id (str): Parent ID + json_file_path (str): file JSON output path + interval_start (str): Use events from this timestamp + interval_end (str): Use events till this timestamp + body_to_simple_processors (Callable, optional): Body categorizer function, defaults to None. + + Example: + >>> extract_parent_as_json( + events=data, + parent_id="demo_parent_id", + json_file_path="path/to/output.json", + interval_start="2022-03-16T08:40:16", + interval_end="2022-03-16T14:40:16" + ) + + JSON structure: + { + "info": { + "stats": EventType+Status (Frequency Table), + parent_event_details... + } + "child_id": { + "info": { event_details...} + "child_id": { + "info": { event_details...} + "body" { ... } # If event has body + "childId": { ... } + } + } + "child_id2": { ... } + } + """ + from th2_data_services.utils.az_tree import get_event_tree_from_parent_id + + sub_events = sublist( + events, datetime.fromisoformat(interval_start), datetime.fromisoformat(interval_end) + ) + print(f"Sublist length = {len(sub_events)}") + tree = get_event_tree_from_parent_id( + sub_events, parent_id, 10, 10000, body_to_simple_processors + ) + if not tree: + return + types_set = set( + (type_[: type_.index(" [")] for type_ in tree["info"]["stats"] if type_ != "TOTAL") + ) + tree["info"]["types_list"] = list(types_set) + + with open(json_file_path, "w") as file: + json.dump(tree, file, indent=3) + + +def is_sorted(events: Iterable[Th2Event]) -> IsSortedResult: + """Checks whether events are sorted. + + Args: + events (Dict): Th2-Events + + Returns: + IsSortedResult: Whether events are sorted and additional info (e.g. index of the first unsorted element). + """ + is_sorted_result = IsSortedResult() + flag = True + previous_timestamp = None + i = 0 + for event in events: + if flag: + previous_timestamp = options.EVENT_FIELDS_RESOLVER.get_start_timestamp(event) + flag = False + current_timestamp = options.EVENT_FIELDS_RESOLVER.get_start_timestamp(event) + if previous_timestamp["epochSecond"] > current_timestamp["epochSecond"] or ( + previous_timestamp["epochSecond"] == current_timestamp["epochSecond"] + and previous_timestamp["nano"] > current_timestamp["nano"] + ): + is_sorted_result.status = False + is_sorted_result.first_unsorted = i + break + previous_timestamp = current_timestamp + i += 1 + + return is_sorted_result diff --git a/th2_data_services/utils/event_utils/frequencies.py b/th2_data_services/utils/event_utils/frequencies.py new file mode 100644 index 00000000..e80c1aab --- /dev/null +++ b/th2_data_services/utils/event_utils/frequencies.py @@ -0,0 +1,204 @@ +# Copyright 2023-2025 Exactpro (Exactpro Systems Limited) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +from deprecated.classic import deprecated + +from th2_data_services.utils import misc_utils +from typing import Callable, Iterable, List, Literal, Optional + +from th2_data_services.utils._types import Th2Event +from th2_data_services.utils.aggregation_classes import FrequencyCategoryTable +from th2_data_services.config import options +from th2_data_services.utils.category import Category + + +# STREAMING +@deprecated( + reason='Use "get_category_frequencies2" instead. \n' + "We want to have unification in functions.\n" + "Tell DS team if you dont agree or have some ideas." +) +def get_category_frequencies( + events: Iterable[Th2Event], + categories: List[str], + categorizer: Callable, + aggregation_level: str = "seconds", + object_expander=None, +) -> FrequencyCategoryTable: + """Returns event frequencies based on event category. + + Args: + events (Iterable[Th2Event]): TH2-Events + categories (List[str]): Event Categories + categorizer (Callable): Categorizer Method + aggregation_level (Optional, str): Aggregation Level + + Returns: + List[List[str]] + + Example: + >>> get_category_frequencies(events=events, + categories=["Info", "ModelMatrix"], + categorizer=lambda e: e["eventType"], + aggregation_level="seconds" # Optional + ) + [ + ['timestamp', 'Info', 'ModelMatrix'], + ['2022-03-16T02:00:00', 4, 0], + ['2022-03-16T02:00:31', 1, 0], + ['2022-03-16T02:00:32', 4, 0], + ... + ] + + """ + return misc_utils.get_objects_frequencies2( + events, + categories, + categorizer, + # TODO -- we shouldn't know internal structure!!! - epochSeconds + lambda e: options.EVENT_FIELDS_RESOLVER.get_start_timestamp(e)["epochSecond"], + aggregation_level=aggregation_level, + object_expander=object_expander, + ) + + +# Doesn't use category name now. Category values are table header. +def get_category_frequencies2( + events: Iterable[Th2Event], + category: Category, + aggregation_level: str = "seconds", + filter_: Optional[Callable] = None, + gap_mode: Literal[1, 2, 3] = 1, + zero_anchor: bool = False, + include_total: bool = True, +) -> FrequencyCategoryTable: + """Returns event frequencies based on event category. + + For more info please see: https://github.com/th2-net/th2-data-services/blob/dev_2.0.0/documentation/frequencies.md + + Args: + events (Iterable[Th2Event]): TH2-Events + category: The name of the category doesn't make sence. + Used just for unification to use general Category class. + aggregation_level (Optional, str): Aggregation Level + filter_: Event filter function + gap_mode: + 1 - Every range starts with actual event timestamp, + 2 - Ranges are split equally, + 3 - Same as 2, but filled with empty ranges in between + zero_anchor: If False anchor used is first timestamp from event, if True anchor is 0 + include_total: Will add Total column if True. + + Returns: + List[List[str]] + + Example: + >>> get_category_frequencies(events=events, + categories=["Info", "ModelMatrix"], + categorizer=lambda e: e["eventType"], + aggregation_level="seconds" # Optional + ) + [ + ['timestamp', 'Info', 'ModelMatrix'], + ['2022-03-16T02:00:00', 4, 0], + ['2022-03-16T02:00:31', 1, 0], + ['2022-03-16T02:00:32', 4, 0], + ... + ] + + Examples: + It'll return the table like this. + +--------+-------------------+-----------------+-------------------+------------+---------------+---------+ + | | timestamp_start | timestamp_end | ExecutionReport | NewOrder | OrderCancel | Total | + +========+===================+=================+===================+============+===============+=========+ + | | 2023-08-13 | 2023-08-14 | 1 | 1 | 2 | 4 | + +--------+-------------------+-----------------+-------------------+------------+---------------+---------+ + | | 2023-08-14 | 2023-08-15 | 1 | 1 | 2 | 4 | + +--------+-------------------+-----------------+-------------------+------------+---------------+---------+ + | | 2023-08-16 | 2023-08-17 | 0 | 2 | 3 | 5 | + +--------+-------------------+-----------------+-------------------+------------+---------------+---------+ + | | 2023-08-17 | 2023-08-18 | 1 | 0 | 1 | 2 | + +--------+-------------------+-----------------+-------------------+------------+---------------+---------+ + | | 2023-08-19 | 2023-08-20 | 1 | 1 | 0 | 2 | + +--------+-------------------+-----------------+-------------------+------------+---------------+---------+ + | | 2023-08-20 | 2023-08-21 | 0 | 0 | 2 | 2 | + +--------+-------------------+-----------------+-------------------+------------+---------------+---------+ + | | 2023-08-21 | 2023-08-22 | 1 | 3 | 0 | 4 | + +--------+-------------------+-----------------+-------------------+------------+---------------+---------+ + | | 2023-08-22 | 2023-08-23 | 1 | 0 | 0 | 1 | + +--------+-------------------+-----------------+-------------------+------------+---------------+---------+ + | | 2023-08-23 | 2023-08-24 | 0 | 3 | 0 | 3 | + +--------+-------------------+-----------------+-------------------+------------+---------------+---------+ + | | 2023-08-24 | 2023-08-25 | 0 | 2 | 1 | 3 | + +--------+-------------------+-----------------+-------------------+------------+---------------+---------+ + | count | | | | | | 10 | + +--------+-------------------+-----------------+-------------------+------------+---------------+---------+ + | totals | | | 6 | 13 | 11 | 30 | + +--------+-------------------+-----------------+-------------------+------------+---------------+---------+ + + """ + return misc_utils.get_objects_frequencies2( + events, + categories=[], + categorizer=category.get_func, + # TODO -- we shouldn't know internal structure!!! - epochSeconds + timestamp_function=lambda e: options.EVENT_FIELDS_RESOLVER.get_start_timestamp(e)[ + "epochSecond" + ], + aggregation_level=aggregation_level, + objects_filter=filter_, + gap_mode=gap_mode, + zero_anchor=zero_anchor, + include_total=include_total, + ) + + +# STREAMING +# TODO - slava +# Do we really need it? Why user cannot just use this one line? +# Maybe better to have prepared list of categorizers? e.g. in form of Adapters. +# get_category_frequencies(events, types_list, EventCategorizer.type) +# or idea to creat class TypeFrequences +# GetFrequences.by_type_category +# GetFrequences.by_name_category +# GetFrequences.by_category +# OR maybe better to separate them to modules +# utils.frequencies. +def get_type_frequencies( + events: Iterable[Th2Event], types: List[str], aggregation_level="seconds" +) -> FrequencyCategoryTable: + """Returns event frequencies based on event type. + + Args: + events (Iterable[Th2Event]): TH2-Events + types (List[str]): Event Types + aggregation_level (Optional, str): Aggregation Level + + Returns: + List[List[str]]: List Of Frequency Lists + + Example: + >>> get_type_frequencies(events=events, types=["Info", "ModelMatrix"]) + [ + ['timestamp', 'Info', 'ModelMatrix'], + ['2022-03-16T02:00:00', 4, 0], + ['2022-03-16T02:00:31', 1, 0], + ['2022-03-16T02:00:32', 4, 0], + ... + ] + """ + return get_category_frequencies( + events, types, lambda e: options.EVENT_FIELDS_RESOLVER.get_type(e), aggregation_level + ) diff --git a/th2_data_services/utils/event_utils/select.py b/th2_data_services/utils/event_utils/select.py new file mode 100644 index 00000000..25affac8 --- /dev/null +++ b/th2_data_services/utils/event_utils/select.py @@ -0,0 +1,406 @@ +# Copyright 2023-2025 Exactpro (Exactpro Systems Limited) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +# The module for selecting events by some rules +from collections import defaultdict +from datetime import datetime +from typing import Callable, Dict, Iterable, Set, Tuple + +from deprecated.classic import deprecated + +from th2_data_services.utils._types import Th2Event +from th2_data_services.config import options + + +# TODO - THEY ALL ARE NOT STREAMING!! +# 1. what about iter functions or return Data obj? The second one sounds better + + +def get_related_events( + events: Iterable[Th2Event], messages: Iterable[Th2Event], count: int +) -> Iterable[Th2Event]: + """Returns limited list of events of linked to any message within specified messages objects collection. + + Args: + events: TH2-Events + messages: TH2-Messages + count: Maximum number of events to extract + + Returns: + List[Dict] + + Example: + >>> get_related_events(events=events, + messages=messages, + count=10) + [ + {**TH2-Event}, + ... + ] + """ + result = [] + msg_ids = set(options.MESSAGE_FIELDS_RESOLVER.get_id(message) for message in messages) + + for event in events: + for msg_id in options.EVENT_FIELDS_RESOLVER.get_attached_messages_ids(event): + if msg_id in msg_ids: + result.append(event) + if len(result) == count: + return result + + return result + + +# TODO - duplicates get_some (get_events) +def get_events_by_category( + events: Iterable[Th2Event], + category: str, + count: int, + categorizer: Callable, + start=0, + failed=False, +) -> Iterable[Th2Event]: + """Returns limited list of events of specific category produced by custom categorizer. + + Args: + events (List[Dict]): TH2-Events + category (str): Event category to extract + count (int): Maximum number of events to extract + categorizer (Callable): Categorizer function + start (int, optional): Start iteration index, defaults to 0. + failed (bool, optional): Extract only failed events, defaults to False. + + Returns: + List[Dict] + + >>> # TODO: example! + [ + {**TH2-Event}, + ... + ] + """ + result = [] + limit = start + count + counter = 0 + for event in events: + if categorizer(event) == category: + if failed and options.EVENT_FIELDS_RESOLVER.get_status(event): + continue + if counter >= start: + result.append(event) + counter += 1 + if counter == limit: + break + + return result + + +def get_roots(events: Iterable[Th2Event], count: int, start: int = 0) -> Iterable[Th2Event]: + """Returns limited list of root events (events without parents). + + Args: + events (List[Dict]): TH2-Events + count (int): Maximum number of events to extract + start (int, optional): Iteration Start Index, Defaults to 0. + + Returns: + List[Dict]: List Of Root Events. + """ + result = [] + limit = start + count + counter = 0 + for event in events: + if options.EVENT_FIELDS_RESOLVER.get_parent_id(event) is None: + if counter >= start: + result.append(event) + counter += 1 + if counter == limit: + break + + return result + + +def get_parents(events: Iterable[Th2Event], children: Iterable[Th2Event]) -> Iterable[Th2Event]: + """Returns all parent events of linked to any event within specified events objects collection. + + Args: + events (List[Dict]): TH2-Events + children (List[Dict]): Extract Parents By Child Events + + Returns: + List[Dict] + + Example: + >>> get_parents(events=events, children=subevents) + [ + {**TH2-Event} # Parent + ... + ] + """ + parent_ids = set(options.EVENT_FIELDS_RESOLVER.get_parent_id(child) for child in children) + return [event for event in events if options.EVENT_FIELDS_RESOLVER.get_id(event) in parent_ids] + + +def get_children_from_parent_id( + events: Iterable[Th2Event], parent_id: str, max_events: int +) -> Tuple[Iterable[Th2Event], Th2Event]: + """Returns limited list of direct children events. + + Args: + events (List[Dict]): TH2-Events + parent_id (str): Parent ID + max_events (int): Maximum number of events to extract + + Returns: + Tuple[List[Dict], Dict]: Children Events, Parent Event + + Example: + >>> get_children_from_parent_id(events=events, + parent_id="demo_parent_id", + max_events=10) + ( + [{**TH2-Event}, ...], # Child Events + {**TH2-Event} # Parent Event + ) + """ + children = [] + resolved_parent = {} + counter = 0 + for event in events: + if options.EVENT_FIELDS_RESOLVER.get_id(event) == parent_id: + resolved_parent = event + if options.EVENT_FIELDS_RESOLVER.get_parent_id(event) == parent_id: + children.append(event) + counter += 1 + if counter == max_events: + break + + return children, resolved_parent + + +def get_children_from_parents( + events: Iterable[Th2Event], parents: Iterable[Th2Event], max_events: int +) -> Tuple[Dict[str, list], int]: + """Returns limited list of direct children events for each event in parents. + + Args: + events (List[Dict]): TH2-Events + parents (List[str]): TH2-Events + max_events (int): Maximum number of events to extract from parent + + Returns: + Tuple(Dict[str, list], int): Parent-Children, Events Count + + Example: + >>> get_children_from_parents(events=events, + parents=parent_events, + max_events=2) + ( + { + "parentEvent_1": [{**TH2-ChildEvent1, **TH2-ChildEvent2}] + "parentEvent_2": [{**TH2-ChildEvent1, **TH2-ChildEvent2}], + ... + }, + child_events_count + ) + """ + result = {options.EVENT_FIELDS_RESOLVER.get_id(parent): [] for parent in parents} + events_count = 0 + for event in events: + parent_id = options.EVENT_FIELDS_RESOLVER.get_parent_id(event) + if parent_id not in result: + continue + if len(result[parent_id]) < max_events: + events_count += 1 + result[parent_id].append(event) + + return result, events_count + + +@deprecated("Use `get_children_from_parents` instead") +def get_children_for_events_list(evnts, parents_list, max_events): # noqa + return get_children_from_parents(evnts, parents_list, max_events) + + +def get_children_from_parents_as_list( + events: Iterable[Th2Event], parents: Iterable[Th2Event], max_events: int +) -> Iterable[Th2Event]: + """Returns limited list of direct children events for each event in parents. + + Args: + events (Iterable[Th2Event]): TH2-Events + parents (Iterable[Th2Event]): TH2-Events + max_events(int): Maximum number of events to extract + + Returns: + Dict[str, list]: Children Events + + Example: + >>> get_children_from_parents_as_list(events=events, + parents=parent_events, + max_events=2) + [ + {**TH2-Parent1_Child1}, {**TH2-Parent1_Child2}, + {**TH2-Parent2_Child2}, {**TH2-Parent2_Child2}, + ... + ] + + """ + parent_ids = set(options.EVENT_FIELDS_RESOLVER.get_id(parent) for parent in parents) + result = [] + parents_counts = defaultdict(int) + for event in events: + parent_id = options.EVENT_FIELDS_RESOLVER.get_parent_id(event) + if parent_id not in parent_ids: + continue + if parents_counts[parent_id] < max_events: + result.append(event) + parents_counts[parent_id] += 1 + + return result + + +def sublist( + events: Iterable[Th2Event], start_time: datetime, end_time: datetime +) -> Iterable[Th2Event]: + """Filter Events Based On Timeframe. + + Args: + events (Iterable[Th2Event]): TH2-Events + start_time (datetime): Start time + end_time (datetime): End time + + Returns: + Iterable[Th2Event]: Filtered Events. + + Example: + >>> sublist(events=events, + start_time=datetime.fromisoformat("2022-03-16T10:50:16"), + end_time=datetime.fromisoformat("2022-03-16T10:53:16")) + [ + {**TH2-Event}, + ... + ] + """ + result = [] + start_time = datetime.timestamp(start_time) + end_time = datetime.timestamp(end_time) + for event in events: + event_time = options.EVENT_FIELDS_RESOLVER.get_start_timestamp(event)["epochSecond"] + if start_time <= event_time <= end_time: + result.append(event) + + return result + + +# USEFUL +# NOT STREAMING +# TODO - NOT-READY -- event["attachedMessageIds"] should be updated by resolver +def get_attached_message_ids(events: Iterable[Th2Event]) -> Set[str]: + """Returns the set of unique message IDs linked to all events. + + Args: + events (Iterable[Th2Event]): TH2-Events + + Returns: + Set[str] + + Example: + >>> get_attached_message_ids(events=events) + { + 'demo_fix5:first:1646738629665873718', + 'demo_fixg2:second:1646736618848913837', + ... + } + """ + return set( + message_id + for event in events + for message_id in options.EVENT_FIELDS_RESOLVER.get_attached_messages_ids(event) + ) + + +# USEFUL +# NOT STREAMING +# TODO - NOT-READY -- event["parentEventId, eventId"] should be updated by resolver +# TODO - It returns only parent events that not present in the events. +# Perhaps we need to find better name +# we use something similar in our EventTree +def get_prior_parent_ids(events: Iterable[Th2Event]) -> Set[str]: + """Returns only parent events that are not present in the events. + + Args: + events (Iterable[Th2Event]): TH2-Events + + Returns: + Set[str] + + Example: + >>> get_prior_parent_ids(events=events) + { + '009b3122-9ec1-ec11-91bd-ed37395ac9af', + '014ac1d8-9ed2-ec11-ba0d-13099b4139e8', + ... + } + """ + all_event_ids = set() + parent_ids = set() + for event in events: + parent_id = options.EVENT_FIELDS_RESOLVER.get_parent_id(event) + event_id = options.EVENT_FIELDS_RESOLVER.get_id(event) + if parent_id is not None and parent_id not in all_event_ids: + parent_ids.add(parent_id) + if event_id in parent_ids: + parent_ids.remove(event_id) + all_event_ids.add(event_id) + + return parent_ids + + +# USEFUL +# NOT STREAMING - keeps events +# TODO - NOT-READY -- event["attachedMessageIds"] should be updated by resolver +# BE AWARE!! - it can take up all your memory +# O(N*M) +def get_attached_message_ids_index(events: Iterable[Th2Event]) -> Dict[str, list]: + """Returns dict of lists of related events by unique message IDs. + + Notes: + - This object can occupy large amount of memory for big collections of events - use with caution + Keeps in memory all events that are linked to messages. + - Event path from root to event, it's a string of event names separated by `/`. + + Args: + events (Iterable[Th2Event]): TH2-Events + + Returns: + Dict[str, list] + + Example: + >>> get_attached_message_ids_index(events=events) + { + eventId: { + eventName: "example event name", + eventPath: "rootName/.../currentEventName" + }, + ... + } + """ + result = defaultdict(list) + for event in events: + for message_id in options.EVENT_FIELDS_RESOLVER.get_attached_messages_ids(event): + result[message_id].append(event) + + return result diff --git a/th2_data_services/utils/event_utils/totals.py b/th2_data_services/utils/event_utils/totals.py new file mode 100644 index 00000000..91c75839 --- /dev/null +++ b/th2_data_services/utils/event_utils/totals.py @@ -0,0 +1,200 @@ +# Copyright 2023-2025 Exactpro (Exactpro Systems Limited) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +from typing import Callable, Dict, Iterable, List +from collections import defaultdict + +from deprecated.classic import deprecated + +from th2_data_services.utils._types import Th2Event +from th2_data_services.utils.aggregation_classes import CategoryTotal, TotalCategoryTable +from th2_data_services.utils.total_category_calculator import TotalCategoryCalculator +from th2_data_services.utils.category import Category + +from th2_data_services.config import options + + +""" +These functions return how many events were in some category. +""" + + +# USEFUL +# STREAMING +# TODO - NOT-READY -- event["successful"] should be updated by resolver +# categorizer - expects that it will return str +# def get_category_totals( +# events: Iterable[Th2Event], categorizer: Callable[[Dict], str], ignore_status: bool = False +# ) -> StatsTotal: +# """Returns dictionary quantities of events for different categories. +# +# Args: +# events (List[Dict]): TH2-Events +# categorizer (Callable): Categorizer function +# ignore_status (bool): Concatenate status string, defaults to False. +# +# Returns: +# Dict[str, int] +# +# Example: +# >>> get_category_totals(events=events, +# categorizer=lambda e: e["eventType"]) +# defaultdict(, {'Service event [ok]': 9531, 'Info [ok]': 469}) +# >>> get_category_totals(events=events, +# categorizer=lambda e: e["eventType"], +# ignore_status=True) +# defaultdict(, {'Service event': 9531, 'Info': 469}) +# """ +# event_categories = defaultdict(int) +# for event in events: +# category = categorizer(event) +# if not ignore_status: +# status = " [ok]" if options.EVENT_FIELDS_RESOLVER.get_status(event) else " [fail]" +# category += status +# event_categories[category] += 1 +# +# return CategoryTotal(event_categories) + +# TODO - we have categorizer and Category now +# It's a good idea to unite them +@deprecated( + reason='Use "get_category_totals2" instead. \n' + "It provides more advantages. \n" + "Make sure, it has another interface.\n" + "Example:\n" + ' metrics = [Category("date", lambda m: m["eventType"])] \n ' + ' totals.get_category_totals2(events, metrics).sort_by("date")' +) +def get_category_totals( + events: Iterable[Th2Event], categorizer: Callable[[Dict], str], ignore_status: bool = False +) -> CategoryTotal: + """Returns dictionary quantities of events for different categories. + + Args: + events (List[Dict]): TH2-Events + categorizer (Callable): Categorizer function + ignore_status (bool): Concatenate status string, defaults to False. + + Returns: + Dict[str, int] + + Example: + >>> get_category_totals(events=events, + categorizer=lambda e: e["eventType"]) + defaultdict(, {'Service event [ok]': 9531, 'Info [ok]': 469}) + >>> get_category_totals(events=events, + categorizer=lambda e: e["eventType"], + ignore_status=True) + defaultdict(, {'Service event': 9531, 'Info': 469}) + """ + event_categories = defaultdict(int) + for event in events: + category = categorizer(event) + if not ignore_status: + status = " [ok]" if options.EVENT_FIELDS_RESOLVER.get_status(event) else " [fail]" + category += status + event_categories[category] += 1 + + return CategoryTotal(event_categories) + + +# TODO - it will be renamed to get_category_totals before release +def get_category_totals2( + events: Iterable[Th2Event], + categories: List[Category], + # order=None +) -> TotalCategoryTable: + """More advanced totals with multiple columns. + + Examples: + metrics = [ + Category('date', lambda m: Th2TimestampConverter.to_datetime(m['startTimestamp']).date()) ] + totals.get_category_totals2(events, metrics).sort_by('date') + + Args: + events: + categories: + + Returns: + TotalCategoryTable + """ + # if order is None: + # order = [metrics] + # else: + # order = [order] + if isinstance(categories, Category): + categories = [categories] + + ctc = TotalCategoryCalculator(categories, [categories]) + ctc.handle_objects(events) + tct = ctc.get_table(categories) + return tct + + +def get_attached_messages_totals(events: Iterable[Th2Event]) -> CategoryTotal: + # USEFUL + # STREAMING + # TODO - NOT-READY -- event["attachedMessageIds"] should be updated by resolver + """Returns dictionary quantities of messages attached to events for each stream. + + Args: + events (List[Dict]): TH2-Events + + Returns: + Dict[str, int] + + Example: + >>> get_attached_messages_totals(events=events) + defaultdict(, {'envtn2_msfix5:first': 25262, + 'envtn2_jpmfix1:second': 1702, ...) + """ + streams = defaultdict(int) + for event in events: + for message_id in options.EVENT_FIELDS_RESOLVER.get_attached_messages_ids(event): + key = message_id[: message_id.rindex(":")] + streams[key] += 1 + + return CategoryTotal(streams) + + +def get_type_totals(events: Iterable[Th2Event]) -> CategoryTotal: + # TODO - USEFULL ??? Do we need ignore status?? + # partly the same as get_category_totals and WO ignore status + # Because it's the same we can you get_category_totals inside + # + # STREAMING + # TODO - NOT-READY -- event["successful"] should be updated by resolver + """Returns dictionary quantities of events for different event types. + + Args: + events (List[Dict]): TH2-Events + + Returns: + Dict[str, int] + + Example: + >>> get_type_totals(events=events) + { + "eventType eventStatus": count, + ... + } + """ + event_types = defaultdict(int) + for event in events: + status = " [ok]" if options.EVENT_FIELDS_RESOLVER.get_status(event) else " [fail] " + event_type = options.EVENT_FIELDS_RESOLVER.get_type(event) + status + event_types[event_type] += 1 + + return CategoryTotal(event_types) diff --git a/th2_data_services/utils/experimental.py b/th2_data_services/utils/experimental.py new file mode 100644 index 00000000..9037d523 --- /dev/null +++ b/th2_data_services/utils/experimental.py @@ -0,0 +1,219 @@ +# Copyright 2023-2025 Exactpro (Exactpro Systems Limited) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +from typing import List + +import th2_data_services.utils +from th2_data_services.config import options +from th2_data_services.utils.converters import flatten_dict +from th2_data_services.utils.message_utils import message_utils + + +def prepare_story_from_storage( + provider_url: str, story_items: List, event_body_processors=None +): # noqa + # TODO: Add docstrings. + smart = set() + messages_ids = set() + events_ids = set() + collect_ids_for_story(story_items, smart, events_ids, messages_ids) + + if len(smart) > 0: + raise SystemError("Smart Reports elements are not supported") + + data_source = HTTPProvider5DataSource(provider_url) + messages = [] + if len(messages_ids) > 0: + m_list = [s[s.index(":") + 1 :] for s in messages_ids] + messages = data_source.command(http.GetMessagesById(m_list, True)) + events = [] + if len(events_ids) > 0: + e_list = [s[s.index(":") + 1 :] for s in events_ids] + events = data_source.command(http.GetEventsById(e_list, True)) + + result = prepare_story( + story_items, + json_path=None, + events=events, + event_body_processors=event_body_processors, + messages=messages, + ) + return result + + +############################ +# PrepareStory and its functions [start] +########################### +# If I remember correct - the idea to create a function, that will help to create +# bug reports faster! +# TODO - so it can become something like BugReportUtils class + + +def collect_element(p, l, elements_to_collect, collected_data): # noqa + # TODO: Add docstrings + for element in elements_to_collect: + sub_list = element[element.index(":") + 1 :].split("/") + if len(sub_list) != len(p): + continue + match = True + for i in range(len(sub_list)): + if not p[len(p) - i - 1].startswith(sub_list[i]): + match = False + break + if match: + collected_data[element] = (p, l) + + +def create_parallel_tables(story_item, collected_data): # noqa + # TODO: Add docstrings + sub_table_names = [] + sub_table_names.extend(story_item.keys()) + keys_lists = [] + max_keys = 0 + for n in sub_table_names: + keys_list = [] + for k, v in collected_data[story_item[n]][1].items(): + if type(v) not in [dict, list]: + keys_list.append(k) + + if len(keys_list) > max_keys: + max_keys = len(keys_list) + keys_lists.append(keys_list) + + result = [] + header = [] + for s_t_n in sub_table_names: + header.extend([s_t_n, "", " "]) + result.append(header) + for i in range(max_keys): + row = [] + for j in range(len(sub_table_names)): + key = keys_lists[j][i] if i < len(keys_lists[j]) else "" + val = ( + collected_data[story_item[sub_table_names[j]]][1][key] + if i < len(keys_lists[j]) + else "" + ) + row.extend([key, val, " "]) + result.append(row) + return result + + +def collect_ids_for_story(story_items_list, smart, events, messages): # noqa + # TODO: Add docstrings + for item in story_items_list: + if type(item) == str: + if item.startswith("smart:"): + smart.add(item) + if item.startswith("event:"): + events.add(item) + if item.startswith("message:"): + messages.add(item) + if item.startswith("message_raw:"): + messages.add(item) + if item.startswith("message_dict:"): + messages.add(item) + if item.startswith("event_dict:"): + events.add(item) + + if type(item) == dict: + for v in item.values(): + if v.startswith("smart:"): + smart.add(v) + if v.startswith("event:"): + events.add(v) + if v.startswith("message:"): + messages.add(v) + + +def prepare_story( + story_items_list, json_path=None, events=None, event_body_processors=None, messages=None +): # noqa + # TODO: Add docstrings + smart_report_elements_to_collect = set() + events_to_collect = set() + messages_to_collect = set() + + collect_ids_for_story( + story_items_list, smart_report_elements_to_collect, events_to_collect, messages_to_collect + ) + + collected_data = {} + # print(smart_report_elements_to_collect) + if json_path is not None: + th2_data_services.utils.json_tree.tree_walk_from_jsons( + json_path, + lambda p, n, l: collect_element(p, l, smart_report_elements_to_collect, collected_data), + None, + ) + if events is not None: + # print("Collecting ", events_to_collect) + for e in events: + e_key = "event:" + e["eventId"] + if e_key in events_to_collect: + b = e["body"] + if event_body_processors is not None and e["eventType"] in event_body_processors: + b = event_body_processors[e["eventType"]](b) + collected_data[e_key] = (e, b) + e_key = "event_dict:" + e["eventId"] + if e_key in events_to_collect: + b = e["body"] + if event_body_processors is not None and e["eventType"] in event_body_processors: + b = event_body_processors[e["eventType"]](b) + collected_data[e_key] = (e, b) + + if messages is not None: + # print("Collecting ", messages_to_collect) + for mm in messages: + sub_list = message_utils.expand_message(mm) + for m in sub_list: + for key in messages_to_collect: + if m["messageId"] in key: + # print("Found: ", key) + b = { + "_message_type": m["messageType"], + "_message_session": m["sessionId"], + "_message_direction": m["direction"], + "_message_timestamp": message_utils.extract_timestamp(m), + } + b.update( + flatten_dict(options.MESSAGE_FIELDS_RESOLVER.get_body(m)["fields"]) + ) + collected_data[key] = (m, b) + + result = [] + for item in story_items_list: + if type(item) == str: + if ( + item.startswith("smart:") + or item.startswith("event:") + or item.startswith("message:") + ): + table = [["field", "value"]] + l = collected_data[item] + for k, v in l[1].items(): + if type(v) not in [dict, list]: + table.append([k, str(v)]) + result.append(table) + elif item.startswith("message_raw:"): + result.append(message_utils.get_raw_body_str(collected_data[item][0])) + elif item.startswith("message_dict:") or item.startswith("event_dict:"): + result.append(collected_data[item][1]) + else: + result.append(item) + if type(item) == dict: + result.append(create_parallel_tables(item, collected_data)) + + return result diff --git a/th2_data_services/utils/json_tree.py b/th2_data_services/utils/json_tree.py new file mode 100644 index 00000000..28e7e357 --- /dev/null +++ b/th2_data_services/utils/json_tree.py @@ -0,0 +1,502 @@ +# Copyright 2023-2025 Exactpro (Exactpro Systems Limited) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +import json +from collections import defaultdict +from datetime import datetime +from functools import partial +from os import listdir, path +from pathlib import Path +from typing import List, Dict, Tuple, Callable + +from th2_data_services.utils.path_utils import transform_filename_to_valid +from th2_data_services.utils.event_utils.event_utils import extract_start_timestamp +from th2_data_services.utils.event_utils.select import ( + get_children_from_parents_as_list, + get_children_from_parent_id, +) + + +# TODO +# 1. What index is? +# 2. JsonTREE should become a class, from my point of view + + +# NOT STREAMING +def get_event_tree_from_parent_events( + events: List[Dict], + parents: List[Dict], + depth: int, + max_children: int, + body_to_simple_processors: Dict = None, +) -> Tuple[Dict, Dict]: + """Generate tree object based on parents events list. + + Args: + events (Dict[List]): TH2-Events + parents (Dict[List]): TH2-Events + depth (int): Max iteration + max_children (int): Max children + body_to_simple_processors (Dict, optional): Body transformer function, defaults to None + + Returns: + Tuple(Dict, Dict): Tree, Index + + Example: + >>> get_event_tree_from_parent_events(events=events, + parents=parent_events, + depth=10, + max_children=100) + ( + { # tree + "info": { "stats": EventType+Status (Frequency Table) } + "rootId": { + "info": { event_details...} + "body" { ... } # If event has body + "parentId": { + "info": { event_details...} + "body" { ... } # If event has body + "childId": { ... } + } + } + "rootId2": { ... } + } + , + { # index + "rootId": { + "info": { event_details...} + "body" { ... } # If event has body + "parentId": { + "info": { event_details...} + "body" { ... } # If event has body + "childId": { ... } + } + } + "rootId2": { ... } + } + ) + """ + index = {} + iteration = 0 + stats = defaultdict(int, TOTAL=0) + tree = {"info": {"stats": stats}} + current_children = parents + while len(current_children) > 0 and iteration < depth: + for child in current_children: + leaf = { + "info": { + "name": child["eventName"], + "type": child["eventType"], + "id": child["eventId"], + "time": extract_start_timestamp(child), + }, + "body": child["body"], + } + if len(child["attachedMessageIds"]) > 0: + leaf["info"]["attachedMessageIds"] = child["attachedMessageIds"] + + if iteration == 0: + dt = tree + else: + dt = index[child["parentEventId"]] + + child_event_status = "[ok]" if child["successful"] else "[fail]" + leaf_index = len(dt) + + if "body" in dt: + leaf_index -= 1 + + child_event_str = f"{leaf_index} {child_event_status} {child['eventName']}" + dt[child_event_str] = leaf + index[child["eventId"]] = leaf + + # Calculating stats + stats_key = f"{child['eventType']} {child_event_status}" + stats[stats_key] += 1 + stats["TOTAL"] += 1 + + # Simplifying body + if len(child["body"]) == 0: + leaf.pop("body") + + if body_to_simple_processors is not None: + event_type = child["eventType"] + if event_type in body_to_simple_processors: + leaf["body"] = body_to_simple_processors[event_type](child["body"]) + + current_children = get_children_from_parents_as_list(events, current_children, max_children) + print( + f"get_event_tree_from_parent - {iteration} len_children={len(current_children)} {datetime.now()}" + ) + iteration += 1 + + return tree, index + + +# NOT STREAMING +def get_event_tree_from_parent_id( + events: List[Dict], + parent_id: str, + depth: int, + max_children: int, + body_to_simple_processors: Dict = None, +) -> Dict: + """Generate tree object based on parent event id. + + Args: + events (List[Dict]): TH2-Events + parent_id (str): Parent ID + depth (int): Max Iteration + max_children (int): Max Children + body_to_simple_processors (Dict, optional): Body Transformer Function. Defaults to None. e.g. {eventType: processor_function} + + Returns: + Dict: Tree + + Example: + >>> get_event_tree_from_parent_id(events=events, + parent_id="demo_parent_id", + depth=10, + max_children=1000) + { # tree + "info": { + "stats": EventType+Status (Frequency Table) + parent_event_details... + } + "child_id": { + "info": { event_details...} + "child_id": { + "info": { event_details...} + "body" { ... } # If event has body + "childId": { ... } + } + } + "child_id2": { ... } + } + """ + current_children, parent = get_children_from_parent_id(events, parent_id, max_children) + print(f"get_event_tree_from_parent - initial {datetime.now()}") + tree, _ = get_event_tree_from_parent_events( + events, current_children, depth, max_children, body_to_simple_processors + ) + tree["info"].update( + { + "name": parent["eventName"], + "type": parent["eventType"], + "time": extract_start_timestamp(parent), + } + ) + if len(parent["body"]) != 0: + tree["body"] = parent["body"] + + return tree + + +# NOT STREAMING +def save_tree_as_json( + tree: Dict, json_file_path: str, file_categorizer: Callable = None +) -> List[str]: + """Saves Tree As JSON Format. + + Will create a few json files in the path json_file_path. + + Args: + tree (Dict): TH2-Events transformed into tree (with util methods) + json_file_path (str): JSON Path (must end with .json) + file_categorizer (Callable, optional): File categorizer function. Defaults to None. + + Returns: + List of created filenames. + + Example: + >>> save_tree_as_json(tree=az_tree, + json_file_path="path/to/output.json", + # file_categorizer=lambda key, leaf: key + ) + """ + created_filenames = [] + path = Path(json_file_path).resolve().absolute().with_suffix(".json") + + path = path.parent / transform_filename_to_valid(path.name.replace(".json", "_summary.json")) + + # path = json_file_path.replace(".json", "_summary.json") + # path_filename = json_file_path.replace(".json", "_summary.json") + # path = path.parent / transform_filename_to_valid(path) + arranged_tree = {} + summary = {"stats": tree["info"]["stats"]} + types_set = list( + set((type_[: type_.index(" [")] for type_ in tree["info"]["stats"] if type_ != "TOTAL")) + ) + summary["types_list"] = types_set + + created_filenames.append(str(path)) + + with open(path, "w") as summary_file: + json.dump(summary, summary_file, indent=3) + + if file_categorizer is not None: + for key, leaf in tree.items(): + if key == "info" or key == "body": + continue + category = file_categorizer(key, leaf) + if category not in arranged_tree: + arranged_tree[category] = {} + arranged_tree[file_categorizer(key, leaf)][key] = leaf + else: + arranged_tree["tree"] = tree + + for key, leaf in arranged_tree.items(): + path = path.parent / transform_filename_to_valid(path.name.replace(".json", f"_{key}.json")) + # path = json_file_path.replace(".json", f"_{key}.json") + # path = transform_filename_to_valid(path) + with open(path, "w") as out_file: + created_filenames.append(str(path)) + json.dump(leaf, out_file, indent=3) + + return created_filenames + + +# STREAMING +def transform_tree(index: Dict, post_processors: Dict[str, Callable[[Dict], Dict]]) -> None: + """Transform Tree. + + Args: + index (Dict): TH2-Events transformed into tree index (from util functions) + post_processors (Dict): Post Processors + + Returns: + None, Modifies "index" + + Example: + # TODO: Add example... + """ + for leaf in index.values(): + leaf_type = leaf["info"]["type"] + if leaf_type in post_processors: + modified_leaf = post_processors[leaf_type](leaf) + leaf.clear() + leaf.update(modified_leaf) + + +# STREAMING? | Depends On `processor` +def process_trees_from_jsons(path_pattern: str, processor: Callable) -> None: + """Loads JSON files locally and processes them with given function. + + Args: + path_pattern: Path to json file(s) + processor: Processor function + + Example: + >>> process_trees_from_jsons( + path_to_json_files="path/to/files.json", + processor: # TODO: Add processor example + ) + """ + dir_path = path_pattern[: path_pattern.rindex("/")] if "/" in path_pattern else "" + pattern = path_pattern[path_pattern.rindex("/") + 1 :] if "/" in path_pattern else path_pattern + pattern = pattern.replace(".json", "") + files = listdir(dir_path) + for file in files: + if pattern in file: + with open(path.join(dir_path, file)) as f: + tree = json.load(f) + # TODO: Does data change here? How does this work? + processor(tree) + + +# STREAMING +def tree_walk( + tree: Dict, processor: Callable, tree_filter: Callable = None, root_path: List = [] +) -> None: + """Process tree by processor [Recursive method]. + + Args: + tree: TH2-Events transformed into tree (from util functions) + processor (Callable): Processor function + tree_filter (Callable, optional): Tree filter function. Defaults to None. + root_path (List, optional): Root path. Defaults to []. + + Examples: + >>> tree_walk(tree=az_tree, + processor=lambda path, name, leaf: leaf.update({name: "/".join(path)}), + tree_filter=lambda path, name, leaf: "[fail]" in name), + # root_path=[rootName, ..., eventName]) + + """ + for name, leaf in tree.items(): + if name == "info" or type(leaf) is not dict: + continue + new_path = [name, *root_path] + if tree_filter is not None: + if tree_filter(new_path, name, leaf): + processor(new_path, name, leaf) + else: + processor(new_path, name, leaf) + + tree_walk(leaf, processor, tree_filter=tree_filter, root_path=new_path) + + +# STREAMING +def tree_walk_from_jsons(path_pattern: str, processor: Callable, tree_filter: Callable) -> None: + """Loads JSON file(s) and processes them with given function. + + Args: + path_pattern: Path to json file(s) + processor: Processor function + tree_filter: Tree filter function + + Examples: + >>> tree_walk_from_jsons( + path_to_json_files="path/to/files.json", + processor=lambda path, name, leaf: leaf.update({name: "/".join(path)}), + tree_filter=lambda path, name, leaf: "[fail]" in name + ) + """ + process_trees_from_jsons( + path_pattern, lambda tree: tree_walk(tree, processor, tree_filter=tree_filter) + ) + + +# STREAMING +def tree_update_totals( + categorizer: Callable, tree: Dict, path: List[str], name: str, leaf: Dict +) -> None: + """Updates tree by categorizer function as keys. + + Args: + categorizer: Categorizer function + tree: Tree + path: Event path (from root to event) + name: Event name + leaf: Leaf (event) + + Examples: + # TODO: Add example + """ + category = categorizer(path, name, leaf) + if category not in tree: + tree[category] = 1 + else: + tree[category] += 1 + + +# STREAMING +def tree_get_category_totals(tree: Dict, categorizer: Callable, tree_filter: Callable) -> Dict: + """Returns category totals from tree. + + Args: + tree: TH2-Events transformed into tree (from util functions) + categorizer: Categorizer function + tree_filter: Tree filter function + + Returns: + Dict + + Examples: + >>> tree_get_category_totals( + tree=az_tree, + categorizer=lambda path, name, leaf: leaf['info']['type'] if 'info' in leaf else None, + tree_filter=lambda path, name, leaf: "[fail]" not in name) + { + 'Outgoing message': 941, + 'sendMessage': 95, + ... + } + """ + result = {} + tree_walk( + tree, processor=partial(tree_update_totals, categorizer, result), tree_filter=tree_filter + ) + return result + + +# STREAMING +def tree_get_category_totals_from_jsons( + path_pattern, categorizer: Callable, tree_filter: Callable +) -> Dict: + """Returns category totals from JSON file(s). + + Args: + path_pattern: Path to JSON file(s) + categorizer: Categorizer function + tree_filter: Tree filter function + + Returns: + Dict + + Examples: + # TODO: Add example + """ + result = {} + process_trees_from_jsons( + path_pattern, + lambda tree: tree_walk( + tree, partial(tree_update_totals, categorizer, result), tree_filter=tree_filter + ), + ) + return result + + +# NOT STREAMING +def search_tree(tree: Dict, tree_filter: Callable[[List, str, Dict], Dict]) -> List[Dict]: + """Searches tree by filter function. + + Args: + tree: TH2-Events transformed into tree (from util functions) + tree_filter: Filter function. + + Returns: + List[Dict] + + Example: + >>> search_tree(tree=az_tree, + tree_filter=lambda path, name, leaf: "[fail]" in name) + [ + {**TH2-Event}, # "[fail]" in eventName + ... + ] + """ + result = [] + tree_walk(tree, lambda path, name, leaf: result.append((path, leaf)), tree_filter=tree_filter) + return result + + +# NOT STREAMING +def search_tree_from_jsons( + path_to_json_files, tree_filter: Callable[[List, str, Dict], Dict] +) -> List: + """Searches tree by filter function from JSON file(s). + + Args: + path_to_json_files: JSON file(s) location + tree_filter: Filter function. + + Returns: + List + + Examples: + >>> search_tree_from_jsons( + path_to_json_files="path/to/files.json", + tree_filter=lambda path, name, leaf: "[fail]" in name + ) + """ + result = [] + process_trees_from_jsons( + path_to_json_files, + lambda tree: tree_walk( + tree, lambda path, name, leaf: result.append((path, leaf)), tree_filter=tree_filter + ), + ) + return result diff --git a/th2_data_services/events_tree/__init__.py b/th2_data_services/utils/message_utils/__init__.py similarity index 82% rename from th2_data_services/events_tree/__init__.py rename to th2_data_services/utils/message_utils/__init__.py index a0231a28..fdcd85bc 100644 --- a/th2_data_services/events_tree/__init__.py +++ b/th2_data_services/utils/message_utils/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) +# Copyright 2023-2025 Exactpro (Exactpro Systems Limited) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -12,4 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -from .events_tree import EventsTree + +from . import frequencies +from . import message_utils diff --git a/th2_data_services/utils/message_utils/frequencies.py b/th2_data_services/utils/message_utils/frequencies.py new file mode 100644 index 00000000..13340f95 --- /dev/null +++ b/th2_data_services/utils/message_utils/frequencies.py @@ -0,0 +1,69 @@ +# Copyright 2023-2025 Exactpro (Exactpro Systems Limited) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +# from th2_data_services import MESSAGE_FIELDS_RESOLVER +from typing import Callable, Iterable, List +from th2_data_services.utils import misc_utils +from th2_data_services.utils.aggregation_classes import FrequencyCategoryTable + +from th2_data_services.config import options + +Th2Message = dict + +# NOT STREAMABLE +def get_category_frequencies( + messages: Iterable[Th2Message], + categories: List[str], + categorizer: Callable, + aggregation_level: str = "seconds", + filter_: Callable = None, + gap_mode: int = 1, + zero_anchor: bool = False, + object_expander=options.MESSAGE_FIELDS_RESOLVER.expand_message, + include_total: bool = False, +) -> FrequencyCategoryTable: # noqa + """Returns message frequencies based on categorizer. + + Returns timestamps in UTC format. + + For more info please see: https://github.com/th2-net/th2-data-services/blob/dev_2.0.0/documentation/frequencies.md + + Args: + messages: Messages stored in any iterable + categories: Categories list + categorizer: Categorizer function + aggregation_level: Aggregation level + filter: Message filter function + gap_mode: 1 - Every range starts with actual message timestamp, 2 - Ranges are split equally, 3 - Same as 2, but filled with empty ranges in between + zero_anchor: If False anchor used is first timestamp from message, if True anchor is 0 + + Returns: + List[List] + """ + return misc_utils.get_objects_frequencies2( + messages, + categories, + categorizer, + # TODO -- we shouldn't know internal structure!!! - epochSeconds + timestamp_function=lambda message: options.MESSAGE_FIELDS_RESOLVER.get_timestamp(message)[ + "epochSecond" + ], + aggregation_level=aggregation_level, + object_expander=object_expander, + objects_filter=filter_, + gap_mode=gap_mode, + zero_anchor=zero_anchor, + include_total=include_total, + ) diff --git a/th2_data_services/utils/message_utils/message_utils.py b/th2_data_services/utils/message_utils/message_utils.py new file mode 100644 index 00000000..d897fdc9 --- /dev/null +++ b/th2_data_services/utils/message_utils/message_utils.py @@ -0,0 +1,425 @@ +# Copyright 2023-2025 Exactpro (Exactpro Systems Limited) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +import base64 +from collections import defaultdict +from th2_data_services.config import options +from typing import Callable, Dict, Iterable, List, Set + +from deprecated.classic import deprecated + +import th2_data_services.utils.display +import th2_data_services.utils.time +from th2_data_services.utils._types import Th2Message +from th2_data_services.utils.converters import flatten_dict +from th2_data_services.utils._is_sorted_result import IsSortedResult + + +# DON'T USE `options` like this. By default MESSAGE_FIELDS_RESOLVER.expand_message == None +# It will bring to errors. +# expand_message = options.MESSAGE_FIELDS_RESOLVER.expand_message + +# STREAMABLE +def get_totals( + messages: Iterable[Th2Message], + categorizers: List[Callable[[Dict], str]], + filter_: Callable = None, +) -> Dict[str, int]: + """Returns dictionary quantities of events for different message categories. + + The result contains calculation for keys: "category1 category2 ... categoryN". + + Warnings: + expand_message function is not backward-compatible. + If you use it in your scripts, there is no guarantee that everything will + work if you change data-source because different data-sources has different + messages structure. + + Args: + messages: TH2-Messages - iterable messages object. + categorizers: List of categorizer functions + filter_: Filter functon, defaults to None + + Returns: + Dict[str, int] + like - {str_value_that_was_by_categorizer_func: cnt} + """ + result = defaultdict(int) + for message in messages: + expanded_messages: List[Dict[str, str]] = options.mfr.expand_message(message) + for expanded_message in expanded_messages: + if filter_ is not None and not filter_(expanded_message): + continue + keys = [] + for categorizer in categorizers: + keys.append(categorizer(expanded_message)) + key = " ".join(keys) + result[key] += 1 + + return result + + +# STREAMABLE +# Prints Dictionary quantities of events for different message categories +# parameters are: iterable messages object +# category_list: list categorizer functions +# result contains calculation for keys: "category1 category2 ... categoryN" +# result: table -> stdout +def print_totals( + messages: Iterable[Th2Message], categorizers: List[Callable], filter_: Callable = None +) -> None: + """Prints dictionary quantities of events for different message categories. + + Args: + messages: TH2-Messages + categorizers: List of categorizer functions + filter_: Filter functon, defaults to None + + """ + result = get_totals(messages, categorizers, filter_) + th2_data_services.utils.display.print_stats_dict(result) + + +# NOT STREAMABLE +# TODO - Can we have single function for events and messages? +def get_some( + messages: Iterable[Th2Message], max_count: int, start: int = 0, filter_: Callable = None +) -> List[Th2Message]: + """Returns limited list of messages from the stream. + + Warnings: + expand_message function is not backward-compatible. + If you use it in your scripts, there is no guarantee that everything will + work if you change data-source because different data-sources has different + messages structure. + + Args: + messages: TH2-Messages + max_count: Maximum messages to retrieve + start: Extract events starting form this number, defaults to 0 + filter_: Filter function, defaults to None + + Returns: + Iterable[Th2Message] + """ + result = [] + counter = 0 + limit = start + max_count + + for message in messages: + expanded_messages: List[Dict[str, str]] = options.mfr.expand_message(message) + for expanded_message in expanded_messages: + if filter_ is not None and not filter_(expanded_message): + continue + if counter >= start: + result.append(expanded_message) + counter += 1 + if counter >= limit: + break + if counter >= limit: + break + result.sort(key=extract_time, reverse=False) + + return result + + +# NOT STREAMABLE +# Prints limited list of messages from the stream in dictionary format +# parameters are: iterable messages object +# max: maximum messages to retrieve +# start(optional): extract events starting form this number (to investigate middle of the stream) +# maxPrint(optional): maximum messages to print +# result: List of message objects in dictionary format -> stdout +def print_some_raw( + messages: Iterable[Th2Message], max_count: int, start: int = 0, filter_: Callable = None +) -> None: + """Prints limited list of messages from the stream in dictionary format. + + Args: + messages: TH2-Messages + max_count: Maximum messages to retrieve + start: Extract events starting form this number, defaults to 0 + filter_: Filter function, defaults to None + + """ + result = get_some(messages, max_count, start, filter_) + max_count = max(max_count + 1, len(result)) + for i in range(max_count): + print(result[i]) + + +# NOT STREAMABLE +# Prints limited list of messages from the stream in ascii from raw binary format +# parameters are: iterable messages object +# max: maximum messages to retrieve +# start(optional): extract events starting form this number (to investigate middle of the stream) +# maxPrint(optional): maximum messages to print +# result: List of message objects in ascii from raw binary format -> stdout +def print_some_raw_source( + messages: Iterable[Th2Message], max_count: int, start: int = 0, filter_: Callable = None +) -> None: + """Prints limited list of messages from the stream in ascii from raw binary format. + + Args: + messages: TH2-Messages + max_count: Maximum messages to retrieve + start: Extract events starting form this number, defaults to 0 + filter_: Filter function, defaults to None + + """ + result = get_some(messages, max_count, start, filter_) + max_count = max(max_count + 1, len(result)) + for i in range(max_count): + print_message_raw_source(result[i]) + + +# NOT STREAMABLE +# Prints limited list of messages from the stream in dictionary format +# parameters are: iterable messages object +# max: maximum messages to retrieve +# start(optional): extract events starting form this number (to investigate middle of the stream) +# maxPrint(optional): maximum messages to print +# result: List of message objects in dictionary format -> stdout +def print_some( + messages: Iterable[Th2Message], max_count: int, start: int = 0, filter_: Callable = None +) -> None: + """Prints limited list of messages from the stream in dictionary format. + + Args: + messages: TH2-Messages + max_count: Maximum messages to retrieve + start: Extract events starting form this number, defaults to 0 + filter_: Filter function, defaults to None + + """ + result = get_some(messages, max_count, start, filter_) + max_count = max(max_count + 1, len(result)) + for i in range(max_count): + print_message(result[i]) + + +# STREAMABLE +# TODO - We will not use this in the future, I think, because LwDP can provide JSON_PARSED immediately. +@deprecated( + "This function only make sense if you have data in Protobuf style format.\n" + "Use DS-LwDP>=2.0.2.* to get messages in JSON-PARSED format.\n" + "Use `th2_data_services.utils.converters.flatten_dict` instead of this function." +) +def message_fields_to_flat_dict(message: dict, result: Dict, prefix: str): # noqa + # Actual if provider returns data in Protobuf style + for field, content in message["fields"].items(): + if "simpleValue" in content: + result[prefix + field] = content["simpleValue"] + + if "messageValue" in content: + new_prefix = f"{prefix}{field}." + message_fields_to_flat_dict(content["messageValue"], result, new_prefix) + + if "listValue" in content: + list_values = content["listValue"]["values"] + for i in range(len(list_values)): + new_prefix = f"{prefix}{field}." + message_fields_to_flat_dict( + {"fields": {str(i): list_values[i]}}, result, new_prefix + ) + + +def message_to_dict(message: Th2Message): + """The function was moved to recon-lw repository. + + Args: + message: 123 + + Returns: + None + """ + raise Exception( + "'message_to_dict' function was moved to recon-lw repository. \n" + "Please notify th2 DEV team if you don't not agree." + ) + + +# STREAMABLE +def extract_time(message: Th2Message) -> str: + """Extracts timestamp from message. + + Args: + message: TH2-Message + + Returns: + str + """ + return th2_data_services.utils.time.extract_timestamp( + options.MESSAGE_FIELDS_RESOLVER.get_timestamp(message) + ) + + +# STREAMABLE +def print_message(message: Th2Message) -> None: + """Print message (verbose). + + Args: + message: TH2-Message + + """ + print( + f"{extract_time(message)} > {options.MESSAGE_FIELDS_RESOLVER.get_session_id(message)} " + f"{options.MESSAGE_FIELDS_RESOLVER.get_direction(message)} " + f"{options.MESSAGE_FIELDS_RESOLVER.get_type(message)} " + f"{flatten_dict(options.MESSAGE_FIELDS_RESOLVER.get_body(message))}" + ) + + +# STREAMABLE +# Todo: Is This Useful +def get_raw_body_str(message: Dict): # noqa + my_bytes = base64.b64decode( + options.MESSAGE_FIELDS_RESOLVER.get_body_base64(message).encode("ascii") + ) + my_bytes = my_bytes.replace(b"\x01", b".") + raw_body = my_bytes.decode("ascii") + return raw_body + + +# STREAMABLE +# TODO: Is This Useful? +def print_message_raw_source(message: Th2Message) -> None: # noqa + raw_body = get_raw_body_str(message) + print( + f"{extract_time(message)} > {options.MESSAGE_FIELDS_RESOLVER.get_session_id(message)} " + f"{options.MESSAGE_FIELDS_RESOLVER.get_direction(message)} " + f"{options.MESSAGE_FIELDS_RESOLVER.get_type(message)} " + f"{raw_body}" + ) + + +# STREAMABLE +# TODO: Is This Useful? +# Resolves set of message IDs +# parameters are: iterable messages object +# ids_set: set of messages IDs to resolve +# result: resolved IDs removed from set +def resolve_count_message_ids(messages: Iterable[Th2Message], ids: Set) -> None: + """Resolves set of message IDs count. Modifies `ids`. + + Args: + messages: TH2-Messages + ids: Set of messages IDs to resolve + + Returns: + None, Modifies `ids` + """ + for message in messages: + if options.MESSAGE_FIELDS_RESOLVER.get_id(message) in ids: + ids.remove(options.MESSAGE_FIELDS_RESOLVER.get_id(message)) + + +# NOT STREAMABLE +# Resolves set of message IDs +# parameters are: iterable messages object +# ids_set: set of messages IDs to resolve +# result: dictionary {message_id: message object}, resolved IDs removed from set +def resolve_message_ids(messages: Iterable[Th2Message], ids: Set) -> Dict[str, Th2Message]: + """Resolves set of message IDs. Modifies `ids`. + + Args: + messages: TH2-Messages + ids: Set of messages IDs to resolve + + Returns: + Dict[str, Th2Message] + """ + result = {} + for message in messages: + msg_id = options.MESSAGE_FIELDS_RESOLVER.get_id(message) + if msg_id in ids: + result[msg_id] = message + ids.remove(msg_id) + + return result + + +# NOT STREAMABLE +# TODO: Is This Useful? +def get_messages_examples( + messages: Iterable[Th2Message], + categories: List[str], + categorizer: Callable, + filter_: Callable = None, +) -> Dict: # noqa + """TODO: Add Docstrings + + Warnings: + expand_message function is not backward-compatible. + If you use it in your scripts, there is no guarantee that everything will + work if you change data-source because different data-sources has different + messages structure. + + Args: + messages: + categories: + categorizer: + filter_: + + Returns: + {category_name: message} + """ + + result = {} + categories = set(categories) + for message in messages: + expanded_messages: List[Dict[str, str]] = options.mfr.expand_message(message) + for expanded_message in expanded_messages: + if filter_ is not None and not filter_(expanded_message): + continue + c = categorizer(expanded_message) # ??? + if c in categories: + if c not in result: + result[c] = expanded_message + if len(result) == len(categories): + return result + + return result + + +def is_sorted(messages: Iterable[Th2Message]) -> IsSortedResult: + """Checks whether messages are sorted. + + Args: + messages (Dict): Th2-Messages + + Returns: + IsSortedResult: Whether messages are sorted and additional info (e.g. index of the first unsorted element). + """ + is_sorted_result = IsSortedResult() + flag = True + previous_timestamp = None + i = 0 + for message in messages: + if flag: + previous_timestamp = options.mfr.get_timestamp(message) + flag = False + current_timestamp = options.MESSAGE_FIELDS_RESOLVER.get_timestamp(message) + if previous_timestamp["epochSecond"] > current_timestamp["epochSecond"] or ( + previous_timestamp["epochSecond"] == current_timestamp["epochSecond"] + and previous_timestamp["nano"] > current_timestamp["nano"] + ): + is_sorted_result.status = False + is_sorted_result.first_unsorted = i + break + previous_timestamp = current_timestamp + i += 1 + + return is_sorted_result diff --git a/th2_data_services/utils/misc_utils.py b/th2_data_services/utils/misc_utils.py new file mode 100644 index 00000000..e3898d6f --- /dev/null +++ b/th2_data_services/utils/misc_utils.py @@ -0,0 +1,594 @@ +# Copyright 2023-2025 Exactpro (Exactpro Systems Limited) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +from collections import defaultdict +from typing import Any, Callable, Dict, Iterable, List, Tuple, Literal +from datetime import datetime, timezone + +from deprecated.classic import deprecated + +from th2_data_services.utils._types import Th2Event + +# TODO - we have special converters for it in ds-2.0 (ProtobufTimestampConverter) +from th2_data_services.utils.aggregation_classes import CategoryFrequencies, FrequencyCategoryTable +from th2_data_services.utils.time import ( + timestamp_aggregation_key, + _timestamp_rounded_down, + _time_str_to_seconds, + _round_timestamp_string_aggregation, +) + + +# TODO - we have get_objects_frequencies and get_objects_frequencies2 -- we need to unify it + + +@deprecated(reason='Use "get_objects_frequencies2" instead. It provides more advantages.') +def get_objects_frequencies( + objects_stream: Iterable[Th2Event], + categories: List, # TODO - can be None to collect all values or [] + categorizer: Callable, + timestamp_function: Callable, + aggregation_level: str = "seconds", + object_expander: Callable = None, + objects_filter: Callable = None, +) -> CategoryFrequencies: + """Returns objects frequencies based on categorizer. + + Returns timestamps in UTC format. + + Args: + objects_stream: Objects stream + categories: Categories list + categorizer: Categorizer function + timestamp_function: Timestamp function + aggregation_level: Aggregation level + object_expander: Object expander function + objects_filter: Object filter function + + Returns: + List[List] + """ + frequencies = {} + anchor = 0 + categories_set = set() + for obj in objects_stream: + expanded_objects = [obj] if object_expander is None else object_expander(obj) + for expanded_object in expanded_objects: + if objects_filter is not None: + if not objects_filter(expanded_object): + continue + + if anchor == 0: + anchor = timestamp_function(expanded_object) + + if not categories: + epoch = timestamp_aggregation_key( + anchor, timestamp_function(expanded_object), aggregation_level + ) + category = categorizer(expanded_object) + categories_set.add(category) + if epoch not in frequencies: + frequencies[epoch] = {category: 1} + elif category not in frequencies[epoch]: + frequencies[epoch][category] = 1 + else: + frequencies[epoch][category] += 1 + else: + for i in range(len(categories)): + if categorizer(expanded_object) == categories[i]: + epoch = timestamp_aggregation_key( + anchor, timestamp_function(expanded_object), aggregation_level + ) + if epoch not in frequencies: + frequencies[epoch] = [0] * len(categories) + frequencies[epoch][i] += 1 + + header = ["timestamp"] + if categories: + header.extend(categories) + else: + header.extend(categories_set) + + results = [header] + timestamps = list(sorted(frequencies.keys())) + for timestamp in timestamps: + line = [datetime.fromtimestamp(timestamp, tz=timezone.utc).strftime("%Y-%m-%dT%H:%M:%S")] + if categories: + line.extend(frequencies[timestamp]) + else: + for category in categories_set: + line.append(frequencies[timestamp][category]) if category in frequencies[ + timestamp + ] else line.append(0) + + results.append(line) + + return CategoryFrequencies(results) + + +# STREAMABLE +def get_objects_frequencies2( + objects_stream: Iterable[Th2Event], + categories: List[str], # TODO - can be None to collect all values or [] + categorizer: Callable, + timestamp_function: Callable, + aggregation_level: str = "seconds", + object_expander: Callable = None, + objects_filter: Callable = None, + gap_mode: Literal[1, 2, 3] = 1, + zero_anchor: bool = False, + include_total: bool = True, +) -> FrequencyCategoryTable: + # TODO - used by both messages and events get_category_frequencies + """Returns objects frequencies based on categorizer. + + Returns timestamps in UTC format. + + For more info please see: https://github.com/th2-net/th2-data-services/blob/dev_2.0.0/documentation/frequencies.md + + Args: + objects_stream: Objects stream + categories: Categories list. + Provide [] or None to collect all possible values. + categorizer: Categorizer function + timestamp_function: Timestamp function + aggregation_level: Aggregation level + object_expander: Object expander function + objects_filter: Object filter function + gap_mode: + 1 - Every range starts with actual message timestamp, + 2 - Ranges are split equally, + 3 - Same as 2, but filled with empty ranges in between + zero_anchor: If False anchor used is first timestamp from message, if True anchor is 0 + include_total: Will add Total column if True. + + Returns: + List[List] + + Examples: + It'll return the table like this. + +--------+-------------------+-----------------+-------------------+------------+---------------+---------+ + | | timestamp_start | timestamp_end | ExecutionReport | NewOrder | OrderCancel | Total | + +========+===================+=================+===================+============+===============+=========+ + | | 2023-08-13 | 2023-08-14 | 1 | 1 | 2 | 4 | + +--------+-------------------+-----------------+-------------------+------------+---------------+---------+ + | | 2023-08-14 | 2023-08-15 | 1 | 1 | 2 | 4 | + +--------+-------------------+-----------------+-------------------+------------+---------------+---------+ + | | 2023-08-16 | 2023-08-17 | 0 | 2 | 3 | 5 | + +--------+-------------------+-----------------+-------------------+------------+---------------+---------+ + | | 2023-08-17 | 2023-08-18 | 1 | 0 | 1 | 2 | + +--------+-------------------+-----------------+-------------------+------------+---------------+---------+ + | | 2023-08-19 | 2023-08-20 | 1 | 1 | 0 | 2 | + +--------+-------------------+-----------------+-------------------+------------+---------------+---------+ + | | 2023-08-20 | 2023-08-21 | 0 | 0 | 2 | 2 | + +--------+-------------------+-----------------+-------------------+------------+---------------+---------+ + | | 2023-08-21 | 2023-08-22 | 1 | 3 | 0 | 4 | + +--------+-------------------+-----------------+-------------------+------------+---------------+---------+ + | | 2023-08-22 | 2023-08-23 | 1 | 0 | 0 | 1 | + +--------+-------------------+-----------------+-------------------+------------+---------------+---------+ + | | 2023-08-23 | 2023-08-24 | 0 | 3 | 0 | 3 | + +--------+-------------------+-----------------+-------------------+------------+---------------+---------+ + | | 2023-08-24 | 2023-08-25 | 0 | 2 | 1 | 3 | + +--------+-------------------+-----------------+-------------------+------------+---------------+---------+ + | count | | | | | | 10 | + +--------+-------------------+-----------------+-------------------+------------+---------------+---------+ + | totals | | | 6 | 13 | 11 | 30 | + +--------+-------------------+-----------------+-------------------+------------+---------------+---------+ + """ + if gap_mode == 1 and zero_anchor: + raise Exception("gap_mode=1 and zero_anchor=True are not supported together") + TOTAL_FIELD = "Total" + frequencies = {} + anchor = 0 + categories_set = set() + object_list = [] + for obj in objects_stream: + object_list += [obj] if object_expander is None else object_expander(obj) + + object_list = sorted(object_list, key=timestamp_function) + + for obj in object_list: + if objects_filter is not None: + if not objects_filter(obj): + continue + + if not zero_anchor: + if anchor == 0: + anchor = _timestamp_rounded_down(timestamp_function(obj), aggregation_level) + if ( + gap_mode == 1 + and timestamp_aggregation_key(anchor, timestamp_function(obj), aggregation_level) + != anchor + ): + anchor = _timestamp_rounded_down(timestamp_function(obj), aggregation_level) + if not categories: + epoch = timestamp_aggregation_key(anchor, timestamp_function(obj), aggregation_level) + if include_total: + if epoch not in frequencies: + frequencies[epoch] = {TOTAL_FIELD: 0} + if TOTAL_FIELD not in frequencies[epoch]: + frequencies[epoch][TOTAL_FIELD] = 1 + else: + frequencies[epoch][TOTAL_FIELD] += 1 + category = categorizer(obj) + categories_set.add(category) + if epoch not in frequencies: + frequencies[epoch] = {category: 0} + if category not in frequencies[epoch]: + frequencies[epoch][category] = 1 + else: + frequencies[epoch][category] += 1 + else: + for category in categories: + if categorizer(obj) == category: + epoch = timestamp_aggregation_key( + anchor, timestamp_function(obj), aggregation_level + ) + if epoch not in frequencies: + frequencies[epoch] = {category: 0} + if category not in frequencies[epoch]: + frequencies[epoch][category] = 0 + frequencies[epoch][category] += 1 + if include_total: + if TOTAL_FIELD not in frequencies[epoch]: + frequencies[epoch][TOTAL_FIELD] = 0 + frequencies[epoch][TOTAL_FIELD] += 1 + + sorted_categories = sorted(categories_set) + + header = ["timestamp_start", "timestamp_end"] + if categories: + header.extend(categories) + else: + header.extend(sorted_categories) + + if include_total: + header.append(TOTAL_FIELD) + + results = [header] + timestamps = list(sorted(frequencies.keys())) + # Expected that timestamp is seconds. + if gap_mode == 3: + last_timestamp = timestamps[0] + timestamps_with_zeros = [timestamps[0]] + for timestamp in timestamps[1:]: + for zero_timestamp in range( + last_timestamp + _time_str_to_seconds(aggregation_level), + timestamp, + _time_str_to_seconds(aggregation_level), + ): + timestamps_with_zeros.append(zero_timestamp) + frequencies[zero_timestamp] = [] + timestamps_with_zeros.append(timestamp) + last_timestamp = timestamp + timestamps = timestamps_with_zeros + + for timestamp in timestamps: + st_string = _round_timestamp_string_aggregation(timestamp, aggregation_level) + et_string = _round_timestamp_string_aggregation( + timestamp + _time_str_to_seconds(aggregation_level), aggregation_level + ) + line = [st_string, et_string] + if categories: + line.extend(frequencies[timestamp].values()) + else: + for category in sorted_categories: + line.append(frequencies[timestamp][category]) if category in frequencies[ + timestamp + ] else line.append(0) + if include_total: + line.append(sum(line[2:])) + + results.append(line) + + r = FrequencyCategoryTable(header=header, rows=results[1:]) + + return r + + +# STREAMABLE (?) +def analyze_stream_sequence( + stream: Iterable[Th2Event], + sequence_extractor: Callable, + timestamp_extractor: Callable, + seq_filter: Callable = None, + object_expander: Callable = None, +) -> List[Dict]: + """Analyzes stream sequence. + + Args: + stream: Sequence of objects + sequence_extractor: Sequence extractor function + timestamp_extractor: Timestamp extractor function + seq_filter: Sequence filter function + object_expander: Object expander function + + Returns: + List[Dict] + """ + stream_list = [] # SortedKeyList(key=lambda t: t[0]) + zero_indexes = 0 + for obj in stream: + expanded_objects = [obj] if object_expander is None else object_expander(obj) + for expanded_object in expanded_objects: + if seq_filter is not None and not seq_filter(expanded_object): + continue + seq = sequence_extractor(expanded_object) + if seq == 0: + zero_indexes += 1 + continue + + stream_list.append((seq, timestamp_extractor(expanded_object))) + + result = [] + if len(stream_list) == 0: + result.append({"type": "summary", "is_empty": True}) + return result + + if zero_indexes > 0: + result.append({"type": "summary", "zero_sequence_numbers": zero_indexes}) + + print(f"Got stream len = {len(stream_list)}") + + # split into intervals between + stream_list.sort(key=lambda t: t[1]) + prev_start = 0 + chunks = [] + for i in range(1, len(stream_list)): + if stream_list[i][0] < stream_list[i - 1][0]: + chunks.append(stream_list[prev_start:i]) # New chunk + prev_start = i + + chunks.append(stream_list[prev_start:]) # New chunk + print(f"Got {len(chunks)} chunks") + + # check gaps in each interval + for chunk in chunks: + chunk.sort(key=lambda t: t[0]) + result.append( + { + "type": "chunk_summary", + "seq_1": chunk[0][0], + "seq_2": chunk[len(chunk) - 1][0], + "timestamp_1": chunk[0][1], + "timestamp_2": chunk[len(chunk) - 1][1], + } + ) + + prev_seq = -1 + prev_time = None + for entry in chunk: + curr_seq = entry[0] + curr_time = entry[1] + if prev_seq != -1: + if curr_seq - prev_seq > 1: + result.append( + { + "type": "gap", + "seq_1": prev_seq, + "seq_2": curr_seq, + "timestamp_1": prev_time, + "timestamp_2": curr_time, + } + ) + if curr_seq == prev_seq: + result.append( + { + "type": "duplicate", + "seq": prev_seq, + "timestamp_1": prev_time, + "timestamp_2": curr_time, + } + ) + prev_seq = curr_seq + prev_time = curr_time + + return result + + +# STREAMABLE ? +def process_objects_stream( + stream: Iterable[Th2Event], processors: List[Tuple[Callable, Dict]], expander: Callable = None +) -> None: + """Processes object stream with processors. + + Args: + stream: Object stream + processors: Processor function: params + expander: Object expander function + + """ + for obj in stream: + if expander is None: + for processor, params in processors: + processor(obj, **params) + else: + expaned_objects = expander(obj) + for expaned_object in expaned_objects: + for processor, params in processors: + processor(expaned_object, **params) + + +# TODO: Is this useful? +# similar to totals for events, but evenets also have status field +def get_category_totals_p( + obj: Dict, categorizer: Callable, obj_filter: Callable, result +) -> Any: # noqa + # TODO: Add docstings + if obj is None: + return get_category_totals_p, { + "categorizer": categorizer, + "obj_filter": obj_filter, + "result": result, + } + + if obj_filter is not None and not obj_filter(obj): + return None + + category = categorizer(obj) + if category not in result: + result[category] = 1 + else: + result[category] = result[category] + 1 + + return None + + +def get_category_examples_p( + obj: Dict, + categorizer: Callable, + obj_filter: Callable, + cat_filter: Callable, + max_qty: int, + result, +) -> Any: # noqa + if obj is None: + return get_category_examples_p, { + "categorizer": categorizer, + "obj_filter": obj_filter, + "cat_filter": cat_filter, + "max_qty": max_qty, + "result": result, + } + if obj_filter is not None and not obj_filter(obj): + return None + + category = categorizer(obj) + if cat_filter is not None and not cat_filter(category): + return None + + if category not in result: + result[category] = [obj] + return None + if len(result[category]) < max_qty: + result[category].append(obj) + + +# TODO: Is this useful? +# Used by get_category_measurement_p +def update_int_measurement(metric: int, measurement_data): # noqa + # TODO: Add docstings + count = 1 + if "count" in measurement_data: + count = measurement_data["count"] + + m_avg = float(metric) + m_max = metric + m_min = metric + if count > 1: + m_prev_avg = measurement_data["avg"] + m_avg = m_prev_avg * count / (count + 1) + float(metric) / (count + 1) + m_max = measurement_data["max"] + m_min = measurement_data["min"] + if metric > m_max: + m_max = metric + if metric < m_min: + m_min = metric + + measurement_data["count"] = count + 1 + measurement_data["avg"] = m_avg + measurement_data["min"] = m_min + measurement_data["max"] = m_max + + if "distr" not in measurement_data: + measurement_data["distr"] = {metric: 1} + else: + if metric not in measurement_data["distr"]: + measurement_data["distr"][metric] = 1 + else: + measurement_data["distr"][metric] += 1 + + +# TODO: Is this useful? +def get_category_measurement_p(obj, categorizer, measurement_func, obj_filter, result): # noqa + # TODO: Add docstrings + + if obj is None: + return get_category_measurement_p, { + "categorizer": categorizer, + "measurement_func": measurement_func, + "obj_filter": obj_filter, + "result": result, + } + + if obj_filter is not None and not obj_filter(obj): + return None + + category = categorizer(obj) + value = measurement_func(obj) + data_point = {} + if category not in result: + result[category] = data_point + else: + data_point = result[category] + + update_int_measurement(value, data_point) + return None + + +# STREAMABLE +def create_qty_distribution(categories: Dict, category_filter: Callable) -> Dict: + """Returns qty distribution. + + Args: + categories: Categories dictionary + category_filter: Category filter + + Returns: + Dict + """ + result = defaultdict(int) + for key, value in categories.items(): + if category_filter(key): + result[value] += 1 + + return result + + +def calc_percentile_in_measurement_dict(d): # noqa + # TODO - something strange .. + # nothing uses it. + # it doesn't return anything + for item in d.values(): + distr = item["distr"] + total = item["count"] + x_series = list(distr.keys()) + x_series.sort() + sum = 0 + x_prev = 0 + for x in x_series: + sum += distr[x] + if sum > 0.5 * total: + if "max50" not in item: + item["max50"] = x_prev + if sum > 0.9 * total: + if "max90" not in item: + item["max90"] = x_prev + if sum > 0.99 * total: + if "max99" not in item: + item["max99"] = x_prev + if sum > 0.999 * total: + if "max99.9" not in item: + item["max99.9"] = x_prev + x_prev = x + + if "max50" not in item: + item["max50"] = x_prev + if "max90" not in item: + item["max90"] = x_prev + if "max99" not in item: + item["max99"] = x_prev + if "max99.9" not in item: + item["max99.9"] = x_prev diff --git a/th2_data_services/utils/path_utils.py b/th2_data_services/utils/path_utils.py new file mode 100644 index 00000000..110a0f73 --- /dev/null +++ b/th2_data_services/utils/path_utils.py @@ -0,0 +1,122 @@ +# Copyright 2023-2025 Exactpro (Exactpro Systems Limited) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from typing import Union + +from th2_data_services.config import options +from pathlib import Path +import os + + +def transform_filename_to_valid(filename: str) -> str: + """Transforms filename to valid OS name. + + Args: + filename: string filename + + Returns: + Valid filename. + + """ + chars = set(options.FORBIDDEN_CHARACTERS_IN_FILENAME) + res_name = "" + for sym in filename: + if sym in chars: + res_sym = options.FORBIDDEN_CHARACTERS_IN_FILENAME_CHANGE_TO + else: + res_sym = sym + + res_name += res_sym + + return res_name[: options.MAX_PATH] + + +def transform_filepath_to_valid(filepath: Path) -> Path: + """Transforms filepath to valid OS name. + + Args: + filepath: Path object. + + Returns: + Valid path. + """ + path_len = len(str(filepath)) + parent_path_len = len(str(filepath.parent)) + + # -2 because we also have to add '/' symbol and at least 1 symbol for filename + if parent_path_len >= options.MAX_PATH - 2: + raise ValueError( + f"It's impossible to create valid path for provided one: {filepath}. " + f"Because its parent part is longer than Max possible OS path. {parent_path_len} >= {options.MAX_PATH-2}." + ) + + max_filename_len = options.MAX_PATH - parent_path_len + valid_filename = transform_filename_to_valid(filepath.name)[:max_filename_len] + + return filepath.parent / valid_filename + + +def check_if_filename_valid(filename: str): + """Returns status and reason string. + + Args: + filename: string. + + Returns: + Status and reason. + """ + # Length check. + if len(filename) > options.MAX_PATH: + return ( + False, + f"Filename length is more than MAX possible one. " + f"{len(filename)} > {options.MAX_PATH}, filename: '{filename}'", + ) + + # Forbidden chars check. + chars = set(options.FORBIDDEN_CHARACTERS_IN_FILENAME) + for sym in filename: + if sym in chars: + return False, f"Forbidden char: '{sym}', filename: '{filename}'" + + return True, "" + + +def check_if_file_exists(filename: Union[str, Path]): + """Raises error if file doesn't exist. + + Args: + filename: string. + + Raises: + FileNotFoundError: if file doesn't exist. + ValueError: if filename contains illegal characters. + """ + fp = Path(filename).resolve().absolute() + try: + if not fp.exists(): + raise FileNotFoundError(f"{fp} doesn't exist") + + if not fp.is_file(): + raise FileExistsError(f"{fp} isn't file") + except OSError as e: + if os.name == "nt" and e.winerror == 123: + illegal_characters = set([char for char in filename if char in r'\/:*?"<>|']) + illegal_characters_str = ", ".join(illegal_characters) + raise ValueError( + f"Invalid file path: {fp}. " + f"It contains illegal characters: {illegal_characters_str}" + ) + else: + raise e diff --git a/th2_data_services/utils/perfect_table.py b/th2_data_services/utils/perfect_table.py new file mode 100644 index 00000000..a6700137 --- /dev/null +++ b/th2_data_services/utils/perfect_table.py @@ -0,0 +1,337 @@ +# Copyright 2023-2025 Exactpro (Exactpro Systems Limited) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +import re +from copy import copy +from operator import itemgetter +from typing import List, Union +from tabulate import tabulate + +from collections import namedtuple, defaultdict +import csv + + +def pars_arg(arg) -> str: # noqa + res = re.sub("[^0-9a-zA-Z]+", "_", arg) + if res[0].isdigit(): + res = "n_" + res + + return res + + +def namedtuple_with_slice(name, args): # noqa + args_dict = {arg: pars_arg(arg) for arg in args} + new_args = [pars_arg(arg) for arg in args] + cls = namedtuple(name, new_args) # TODO - we can have the same values!!! + + # TODO - I think we don't need getitem for strings. (strings column names. + # We would not do `row.abc` but we often have abc like 'a b 123 c' so it's not a problem. + # It means we don't need named tuples more + # We need to get only via item NOT ATTRIBUTE + def getitem(self, index): + # `type(self)` can result in issues in case of multiple inheritance. + # But shouldn't be an issue here. + if isinstance(index, int): + value = super(type(self), self).__getitem__( + index + ) # Superclass for namedtuple is sequence + elif isinstance(index, slice): + value = super(type(self), self).__getitem__(index) + cls = namedtuple(name, new_args[index]) + cls.__getitem__ = getitem + value = cls(*value) + elif isinstance(index, str): + value = getattr(self, args_dict[index]) + # raise Exception('I dont can stings now') + return value + + cls.__getitem__ = getitem + return cls + + +class RowBase(tuple): + _column_idx = {} # {COL_NAME: index} + + def __new__(cls, *args: list): + if not cls._column_idx: + raise Exception("Row class is not initialized.") + + return super().__new__(cls, args) + + def __init__(self, *args: list): # noqa + if len(self._column_idx) != len(args): + raise Exception( + f"The number of provided values '{len(args)}' != the number of columns '{len(self._column_idx)}'" + ) + super().__init__() + + @property + def keys(self): + return self._column_idx.keys() + + def _get_idx(self, col_name) -> int: + try: + return self._column_idx[col_name] + except KeyError: + raise Exception(f"Row class doesn't have '{col_name}' column") + + def __getitem__(self, index): + # `type(self)` can result in issues in case of multiple inheritance. + # But shouldn't be an issue here. + if isinstance(index, int): + value = super().__getitem__(index) + # elif isinstance(index, slice): + # new_column_idx = + # value = self.__getitem__(index) + # cls = namedtuple(name, new_args[index]) + # cls.__getitem__ = getitem + # value = cls(*value) + elif isinstance(index, str): + value = self[self._get_idx(index)] + else: + raise Exception("Some unexpected situation") + + return value + + +def row_cls_init(name, args): + """Init RowBase.""" + cls = type(name, (RowBase,), {}) + cls._column_idx = {k: idx for idx, k in enumerate(args)} + return cls + + +# TODO - this table should be placed to another repo in the future. +class PerfectTable: + def __init__(self, header: List[str]): # noqa + self._headers = tuple(str(h) for h in header) + self.row_class: RowBase = self._create_row_class(self._headers) + self._rows = [] + self._columns = defaultdict(tuple) + # self._add_headers_as_attr() + + def _create_row_class(self, headers) -> RowBase: + # return namedtuple_with_slice("Row", headers) + return row_cls_init("Row", headers) + + def __contains__(self, item): + return item in self._headers + + def __iter__(self): + return iter(self._rows) + + def __getitem__(self, item): + if isinstance(item, int) or isinstance(item, slice): + return self._rows[item] + elif isinstance(item, str): + return self.get_column(item) + + def __repr__(self): + # use tabulate + return tabulate(self.get_list_repr(), headers="firstrow", tablefmt="grid") + + def _repr_html_(self): + # TODO - non zero and non None values we can highlight + # FOR Jupyter + return tabulate(self.get_list_repr(), headers="firstrow", tablefmt="html") + + # def _add_headers_as_attr(self): + # args_dict = {pars_arg(arg): arg + # for arg in args} + # new_args = [pars_arg(arg) for arg in args] + # # TODO - doesn't work + # for h in self.header: + # prop = property(lambda self: self.get_column(h)) # self._create_prop_for_attrs(h) + # setattr(self, h, prop) + + def _check_columns_existence(self, columns): + for c in columns: + if c not in self.header: + raise ValueError(f"Column '{c}' is not in the table columns: {self.header}") + + def get_list_repr(self): + return [self.header, *self.rows] + + @classmethod + def read_csv(self, path, strip=False): + # TODO - check pandas name + self._path = path + + with open(path, "r") as f_obj: + reader = csv.reader(f_obj, delimiter=",") + + rows = tuple( + row for row in reader + ) # 'generator' object is not subscriptable if generator + + self._headers = tuple(rows[0]) + self.row_class = self._create_row_class(self.header) + x: list + if strip: + self._rows = [ + self.row_class(*[v.strip() for v in x if isinstance(v, str)]) for x in rows[1:] + ] + else: + self._rows = [self.row_class(*x) for x in rows[1:]] + + # # TODO - I think it's worth initializing it lazily, on demand. + # # It someone requested the column, we should add it at this time + # self._columns = defaultdict(tuple) + # for idx, name in enumerate(self._headers): + # self._columns[name] = tuple(row[idx] for row in self._rows[1:]) + + # Add headers as attributes. + for h in self._headers: + setattr(self, h, self._columns[h]) + + def to_csv(self, path): + with open(path, "w", newline="") as f: + writer = csv.writer(f) + writer.writerow(self._headers) + writer.writerows(self._rows) + + # @property + # def path(self): + # """Returns the path to csv file.""" + # return self._path + + def _create_prop_for_attrs(self, name): + @property + def get_col_prop(self): + return self.get_column(name) + + return get_col_prop + + def get_column(self, name): + # Lazy get by column. + r = self._columns[name] + if r: + return r + else: + col_idx = self.header.index(name) + self._columns[name] = tuple(row[col_idx] for row in self.rows) + return self._columns[name] + + @property + def header(self): + """Returns a list of header names.""" + return self._headers + + @property + def rows(self): + """Returns a list of rows.""" + return self._rows + + def add_rows(self, rows): + """Add rows to the table. + + Args: + rows: rows of data, should be an iterable of lists, each list with as many + elements as the table has fields + """ + for row in rows: + self.add_row(row) + + def _append_row(self, row: List): + self._rows.append(self.row_class(*row)) + + def add_row(self, row: List): + """Add a row to the table. + + Args: + row: row of data, should be a list with as many elements as the table + has fields + """ + if self.header and len(row) != len(self.header): + raise ValueError( + "Row has incorrect number of values, " + f"(actual) {len(row)}!={len(self.header)} (expected)" + ) + self._append_row(row) + + def filter(self, condition): + """Returns new table. Not update current. + + Args: + condition: any function with one argument Row. So you apply some filter to every Row. + Row is the Row class. + + Returns: + new Table + + Example: + tbl.filter(lambda row: row['column_ABC'] == 'my string') + + """ + new = self.__class__(header=self.header) + for row in self.rows: + if condition(row): + new.add_row(row) + return new + + def sort_by(self, columns: Union[List[str], str], ascending=True): + """Sort (updates the object) and returns self.""" + if isinstance(columns, str): + columns = [columns] + + self._check_columns_existence(columns) + + s_rows = self.rows + for sort_col in columns[::-1]: + s_rows = sorted(s_rows, key=itemgetter(sort_col), reverse=not ascending) + + self._rows = s_rows + + return self + + def change_columns_order(self, columns_order: List[str]): + self._check_columns_existence(columns_order) + header_len = len(self.header) + assert len(columns_order) == header_len + + # {col_name: idx} in the original table + c_idxes = {c_name: self.header.index(c_name) for c_name in columns_order} + + new_header = columns_order + orig_rows = copy(self.rows) + self._headers = tuple(new_header) + self._rows = [] + self.row_class = self._create_row_class(new_header) + for row in orig_rows: + self._append_row([row[c_idxes[column_name]] for column_name in columns_order]) + + return self + + +if __name__ == "__main__": + t = PerfectTable(["a", "b", "c"]) + t.add_rows( + [ + (4, "c", 0), + (3, "z", 1), + (3, "a", 2), + (3, "x", 3), + (1, "b", 4), + ] + ) + + print(t.sort_by(["a", "b", "c"])) + # print(t.sort_by(['b', 'a'])) + print(t.change_columns_order(["b", "c", "a"])) + print(t.sort_by("b", ascending=True)) + print(t.header) + print(t["a"]) + print(t["b"]) + print(t["c"]) diff --git a/th2_data_services/utils/script_report_utils.py b/th2_data_services/utils/script_report_utils.py new file mode 100644 index 00000000..f0976f71 --- /dev/null +++ b/th2_data_services/utils/script_report_utils.py @@ -0,0 +1,829 @@ +# Copyright 2023-2025 Exactpro (Exactpro Systems Limited) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +from typing import List, Dict + +from th2_data_services.config import options +from th2_data_services.utils.converters import flatten_dict +from th2_data_services.utils.event_utils import event_utils +from datetime import datetime +import th2_data_services.utils.json_tree + +# TODO +# 1. Takes flat_list to put result in this dict. +# It's better to create this dict inside and return as a result. +# Now don't return anything! +from th2_data_services.utils.viewer_structs.verification import ( + verification_fields_to_flat_dict, + verification_fields_to_simple_dict, + simplify_body_verification, +) + + +def tag_rows_to_flat_dict(collection: Dict, flat_list: Dict, prefix: str) -> None: # noqa + """ + + rows are used in 'Tree table', 'Table' but not in the Verification (uses fields) + + Args: + collection: 'Tree table' or 'Table' + flat_list: NOT a list - dict. Used just to put result to this object. + prefix: + + Returns: + + """ + rows: dict = collection["rows"] + # tag - field name + for tag, row in rows.items(): + if row["type"] == "row": + # TODO: Remove comment? + # flat_list[prefix+tag] = row["columns"]["fieldValue"] + columns_values = [str(column) for column in row["columns"].values()] + flat_list[prefix + tag] = ",".join(columns_values) + if row["type"] == "collection": + new_prefix = f"{prefix}{tag}." + tag_rows_to_flat_dict(row, flat_list, new_prefix) + + +# TODO - looks really strange that we use space before '#' in such strings +# REQUIRE CLARIFICATION +def item_status_fail(str_irem) -> bool: # noqa + # TODO: Add docstrings + if len(str_irem) < 2: + return False + if str_irem[1] == "#": + return True + + return False + + +############################ +# Simplify functions set [start] +########################### +# + + +def simplify_body_outgoing_message(body) -> Dict: # noqa + # TODO: Add docstrings + simple_form = {} + tree = body[0] + tag_rows_to_flat_dict(tree, simple_form, "") + return simple_form + + +# TODO - do we really have to iterate over tree_table(body) like a list? +# Why do we expect that it'll be a list? +def simplify_body_tree_table_list(body) -> Dict: # noqa + # TODO: Add docstrings + simple_form = {} + for element in body: + tag_rows_to_flat_dict(element, simple_form, "") + return simple_form + + +############################ +# Simplify functions set [end] +########################### + + +def enrich_events_tree_with_attached_messages(index, messages, filter_lambda) -> Dict: # noqa + # This function expects the message will be without list in the body. + # So expected message format is: + # { + # .. + # body: {fields: {}, metadata: {}} + # } + # TODO: Add docstrings + resolved_messages = {} + leaves = [] + for name, leaf in index.items(): + if filter_lambda(name, leaf): + if "attachedMessageIds" in leaf["info"]: + leaves.append(leaf) + for msg_id in leaf["info"]["attachedMessageIds"]: + resolved_messages[msg_id] = {} + + print("Messages to resolve: ", len(resolved_messages)) + print("Leaves to update: ", len(leaves)) + + for m in messages: + if m["messageId"] in resolved_messages: + resolved_messages[m["messageId"]] = ( + flatten_dict(options.MESSAGE_FIELDS_RESOLVER.get_body(m)), + m["bodyBase64"], + ) + + for leaf in leaves: + raw_messages = [] + for i in range(0, len(leaf["info"]["attachedMessageIds"])): + leaf["message " + str(i)] = resolved_messages[leaf["info"]["attachedMessageIds"][i]][0] + raw_messages.append(resolved_messages[leaf["info"]["attachedMessageIds"][i]][1]) + leaf["info"]["raw"] = raw_messages + + +def find_child_by_type(leaf: Dict, type: str) -> List: # noqa + """Finds child by type. + + Args: + leaf: Child leaf + type: Type to match + + Returns: + List + """ + result = [] + for name, child in leaf.items(): + if "info" in child: + if child["info"]["type"] == type: + result.append((name, child)) + + return result + + +def find_child_by_types(leaf, types): + """Finds child by type. + + Args: + leaf: Child leaf + types: List of types to match + + Returns: + List + """ + result = [] + for name, child in leaf.items(): + if "info" in child: + if child["info"]["type"] in types: + result.append((name, child)) + + return result + + +# TODO: Should it be in this file, or perhaps misc? +def id_tags() -> List[str]: # noqa + return [ + "ClOrdID", + "OrigClOrdID", + "NegotiationID", + "QuoteRespID", + "QuoteID", + "OrderID", + "TrdMatchID", + "IOIID", + "QuoteReqID", + "RegulatoryTradeID", + "QuoteMsgID", + "TradeReportID", + "ClientOrderID", + "OriginalClientOrderID", + ] + + +# TODO: Should it be in this file, or perhaps misc? +def defining_tags() -> List[str]: # noqa + return [ + "OrdStatus", + "ExecType", + "header.MsgType", + "LeavesQty", + "QuoteRespType", + "QuoteStatus", + "QuoteType", + "CxlRejReason", + "Text", + "IOITransType", + "QuoteRequestRejectReason", + "TrdRptStatus", + "OrderStatus", + "header.MessageType", + "LeavesQuantity", + "ReasonText", + ] + + +def format_expected_event(expected_event_str: str, alias_by_id: Dict) -> str: # noqa + # TODO: Add docstrings + for k, v in alias_by_id.items(): + expected_event_str = expected_event_str.replace(k, v) + + return expected_event_str + + +def format_actual_event(actual_message_dict, actual_message_str, alias_by_id): # noqa + # TODO: Add docstrings + updated_str = actual_message_str + for k in id_tags(): + if k in actual_message_dict: + v = actual_message_dict[k] + if v in alias_by_id: + v = alias_by_id[v] + updated_str += ", {0}={1}".format(k, v) + + for k in defining_tags(): + if k in actual_message_dict: + updated_str += ", {0}={1}".format(k, actual_message_dict[k]) + + return updated_str + + +def find_corresponding_missing_filter(expectation_string, verifications_list): # noqa + # TODO: Add docstrings + + for item in verifications_list: + if item[1]["info"]["type"] != "Filter": + continue + + found = True + keys_found = 0 + tags = item[1]["body"] + for k, v in tags.items(): + if "EQUAL" not in v: + continue + if "True" not in v: + continue + + keys_found = keys_found + 1 + stripped_val = v[v.index("'") + 1 : v.rindex("'")] + if "." in k: + if k[k.rindex(".") + 1 :] + "=" + stripped_val not in expectation_string: + found = False + break + elif k + "=" + stripped_val not in expectation_string: + found = False + break + if keys_found == 0 and "=" not in expectation_string: + return item + if found and keys_found > 0: + return item + + return None + + +def find_corresponding_verification( + expectation_string, verifications_list, already_used_verifications_set +): # noqa + # TODO: Add docstrings + for item in verifications_list: + found = True + keys_found = 0 + if item[0] in already_used_verifications_set: + continue + tags = item[1]["body"] + # print(expectation_string) + for k, v in tags.items(): + if v[0] == "!": + keys_found = keys_found + 1 + stripped_val = v[3 : v.index("[") - 1] + # print(k, "=", v, "=", stripped_val) + if "." in k: + if k[k.rindex(".") + 1 :] + "=" + stripped_val not in expectation_string: + found = False + break + elif k + "=" + stripped_val not in expectation_string: + found = False + break + if keys_found == 0 and "=" not in expectation_string: + return item + if found and keys_found > 0: + return item + return None + + +def process_step_request_id(request_tags, alias_by_id, custom_id_tags): # noqa + # TODO: Add docstrings + request_id = "" + for k in custom_id_tags: + if k in request_tags: + v = request_tags[k] + if len(v) < 3: + # very short value + if request_id != "": + request_id += "," + request_id += k + "=" + v + continue + if v in alias_by_id: + alias = alias_by_id[v] + else: + alias = "R" + str(len(alias_by_id) + 1) + alias_by_id[v] = alias + if request_id != "": + request_id += "," + request_id += k + "=" + alias + + return request_id + + +def get_val_from_verification(formatted_val): # noqa + # TODO: Add docstrings + value = formatted_val[3:] + if " [" in value: + value = value[: value.index(" [")] + return value + + +def extract_ids_from_dict( + fields, is_this_request, is_this_verification, custom_id_tags, r_result, i_result +): # noqa + # TODO: Add docstrings + for id_field in custom_id_tags: + if id_field in fields: + v = fields[id_field] + if is_this_verification: + v = get_val_from_verification(v) + if len(v) > 3: + if (v not in r_result) and (v not in i_result): + if is_this_request: + alias = "O" + str(len(r_result) + 1) + r_result[v] = alias + else: + alias = "I" + str(len(i_result) + 1) + i_result[v] = alias + + +def matrix_model_test_case_analyze_ids(report_leaf, custom_id_tags): # noqa + # TODO: Add docstrings + r_result = {} + i_result = {} + for step_name, step_leaf in report_leaf.items(): + if step_name in ["info", "body"]: + continue + if "multiSendMessage" in step_name: + messages = find_child_by_type(step_leaf, "Outgoing message") + for sub_step_name, sub_step in messages: + extract_ids_from_dict( + sub_step["body"], True, False, custom_id_tags, r_result, i_result + ) + if "place" in step_name: + outgoing = find_child_by_type(step_leaf, "Outgoing message") + if len(outgoing) != 0: + extract_ids_from_dict( + outgoing[0][1]["body"], True, False, custom_id_tags, r_result, i_result + ) + for sub_leaf_name, sub_leaf in step_leaf.items(): + if "response" in sub_leaf_name and "Received" in sub_leaf_name: + extract_ids_from_dict( + sub_leaf["body"], False, False, custom_id_tags, r_result, i_result + ) + if "Check sequence rule" in step_name: + actual_messages_leaf = find_child_by_type(step_leaf, "preFiltering")[0][1] + for v, v_leaf in actual_messages_leaf.items(): + if v in ["info", "body"]: + continue + extract_ids_from_dict( + v_leaf["body"], False, True, custom_id_tags, r_result, i_result + ) + + result = {} + result.update(r_result) + result.update(i_result) + return result + + +def matrix_model_test_case_processor(report_leaf): # noqa + # TODO: Add docstrings + customization_dict = None # TODO: What is customization_dict? + custom_id_tags = [] + if customization_dict is not None and "id_tags" in customization_dict: + custom_id_tags = customization_dict["id_tags"] + else: + custom_id_tags = id_tags() + + requests = [] + alias_by_id = matrix_model_test_case_analyze_ids(report_leaf, custom_id_tags) + check_rules = [] + for step_name, step_leaf in report_leaf.items(): + if step_name in ["info", "body"]: + continue + if "place" in step_name: + outgoing = find_child_by_type(step_leaf, "Outgoing message") + if len(outgoing) == 0: + print("Error in place order Event") + print(report_leaf["info"]["name"]) + print(step_name) + message = {"body": {}} + else: + message = outgoing[0][1] + + more_info = {} + if "[fail]" in step_name: + more_info["fail"] = True + request_data = { + "REQ_MORE_INFO": more_info, + "REQ_orig_name": step_name, + "REQ_id": process_step_request_id(message["body"], alias_by_id, custom_id_tags), + "REQ_event": step_leaf["info"]["id"], + } + + for sub_leaf_name, sub_leaf in step_leaf.items(): + if sub_leaf_name in ["info", "body"]: + continue + if sub_leaf["info"]["type"] in ["Send message", "Outgoing message"]: + continue + if sub_leaf["info"]["type"] == "message": + more_info["response"] = sub_leaf["body"] + continue + more_info[sub_leaf_name] = sub_leaf + + request_data.update(message["body"]) + request_data["TH2_event"] = step_leaf["info"]["id"] + requests.append(request_data) + if "multiSendMessage" in step_name: + messages = find_child_by_type(step_leaf, "Outgoing message") + for sub_step_name, sub_step in messages: + request_data = { + "REQ_orig_name": sub_step_name, + "REQ_id": process_step_request_id( + sub_step["body"], alias_by_id, custom_id_tags + ), + "TH2_event": sub_step["info"]["id"], + } + request_data.update(sub_step["body"]) + requests.append(request_data) + if "Check sequence rule" in step_name: + actual_messages_leaf = find_child_by_type(step_leaf, "preFiltering")[0][1] + check_rule_actual_messages = [] + for v, v_leaf in actual_messages_leaf.items(): + if v in ["info", "body"]: + continue + + check_rule_actual = {"TH2_event": v_leaf["info"]["id"]} + if "attachedMessageIds" in v_leaf["info"]: + check_rule_actual["EVN_attached_msg_id"] = v_leaf["info"]["attachedMessageIds"][ + 0 + ] + for tag, val in v_leaf["body"].items(): + check_rule_actual[tag] = get_val_from_verification(val) + check_rule_actual_messages.append(check_rule_actual) + + i_summary = 0 + i_extra = 0 + sequence_leaf = find_child_by_type(step_leaf, "checkSequence")[0][1] + expected_leaf = find_child_by_type(step_leaf, "checkMessages")[0][1] + verifications = find_child_by_types(expected_leaf, ["Verification", "Filter"]) + matched_messages_ids = set() + for v in verifications: + if "attachedMessageIds" in v[1]["info"]: + for m_id in v[1]["info"]["attachedMessageIds"]: + matched_messages_ids.add(m_id) + + summary = {} + already_used_verifications = set() + for r in sequence_leaf["body"][1]["rows"]: + i_summary = i_summary + 1 + if r["expectedMessage"] != "" and r["actualMessage"] != "": + ver = find_corresponding_verification( + r["expectedMessage"], verifications, already_used_verifications + ) + if ver is None: + match_status = " [??]" + else: + match_status = " [ok]" if "[ok]" in ver[0] else " [fail]" + already_used_verifications.add(ver[0]) + + summary_key = ( + str(i_summary) + + match_status + + " Match " + + format_expected_event(r["expectedMessage"], alias_by_id) + ) + if ver is None: + summary[summary_key] = { + "#Error": "Cant find corresponding verification", + "#ExpectedMessage": r["expectedMessage"], + } + else: + summary[summary_key] = ver[1]["body"] + summary[summary_key]["TH2_event"] = ver[1]["info"]["id"] + elif r["expectedMessage"] != "" and r["actualMessage"] == "": + missing_key = ( + str(i_summary) + + " [fail] Missing " + + format_expected_event(r["expectedMessage"], alias_by_id) + ) + missing_filter = find_corresponding_missing_filter( + r["expectedMessage"], verifications + ) + if missing_filter is None: + summary[missing_key] = { + "#Error": "Cant find corresponding filter", + "#ExpectedMessage": r["expectedMessage"], + } + else: + summary[missing_key] = missing_filter[1]["body"] + summary[missing_key]["TH2_event"] = missing_filter[1]["info"]["id"] + + elif r["actualMessage"] != "" and r["expectedMessage"] == "": + next_extra_found = False + while (not next_extra_found) and i_extra < len(check_rule_actual_messages): + m_id = check_rule_actual_messages[i_extra]["EVN_attached_msg_id"] + if m_id not in matched_messages_ids: + next_extra_found = True + else: + i_extra = i_extra + 1 + if i_extra < len(check_rule_actual_messages): + extra_key = ( + str(i_summary) + + " [fail] Extra " + + format_actual_event( + check_rule_actual_messages[i_extra], r["actualMessage"], alias_by_id + ) + ) + summary[extra_key] = check_rule_actual_messages[i_extra] + i_extra = i_extra + 1 + else: + extra_key = str(i_summary) + " [fail] Extra " + r["actualMessage"] + "[??]" + summary[extra_key] = {"#Error": "Cant find actual message"} + + check_rules.append({"actual_messages": check_rule_actual_messages, "summary": summary}) + + result = {"view_instruction": "summary_and_tree", "key_ids": alias_by_id} + n = 1 + for r in requests: + str_status = "[ok] " + if "REQ_MORE_INFO" in r and "fail" in r["REQ_MORE_INFO"] and r["REQ_MORE_INFO"]["fail"]: + str_status = "[fail] " + r["view_instruction"] = "table" + name = r["REQ_orig_name"] + name = name[name.index("]") + 2 :] + if " with id:" in name: + name = name[: name.index(" with id:")] + result[str(n) + " " + str_status + name + " " + r["REQ_id"]] = r + n = n + 1 + + for cr in check_rules: + for line in cr["summary"].keys(): + result[str(n) + " " + line[line.index(" ") + 1 :]] = cr["summary"][line] + cr["summary"][line]["view_instruction"] = "table" + n = n + 1 + + result["TH2_event"] = report_leaf["info"]["id"] + return result + + +def generate_generic_tree_and_index(events, parents_filter): # noqa + # TODO: Add docstrings + filtered = events.filter(parents_filter) + parents = event_utils.get_roots(filtered, 10000) + if len(parents) == 0: + raise SystemError("Reports parents not found") + + print("Generating report for: ", len(parents), " parents") + return generate_generic_tree_and_index_from_parents_list(events, parents) + + +# TODO +# 1. Hardcoded values -- it's better to move them to function parameters with that values +def generate_generic_tree_and_index_from_parents_list(events, parents): # noqa + # TODO: Add docstrings + tree, index = th2_data_services.utils.json_tree.get_event_tree_from_parent_events( + events, + parents, + depth=10, + max_children=1000000, + body_to_simple_processors={ + "Outgoing message": simplify_body_outgoing_message, + "message": simplify_body_outgoing_message, + "Verification": simplify_body_verification, + "Filter": simplify_body_tree_table_list, + }, + ) + + return tree, index + + +def generate_model_matrix_tree_and_index(events, parents_filter, extra=None): # noqa + # TODO: Add docstrings + tree, index = generate_generic_tree_and_index(events, parents_filter) + th2_data_services.utils.json_tree.transform_tree( + index, + { + "ModelCase": matrix_model_test_case_processor + if extra is None + else extra_post_processor(matrix_model_test_case_processor, extra) + }, + ) + return tree, index + + +def generate_matrix_json_report_limited_batches( + events, reports_path, parents_filter, par_btch_len, extra=None +): # noqa + # TODO: Add docstrings + post_processors = { + "ModelCase": matrix_model_test_case_processor + if extra is None + else extra_post_processor(matrix_model_test_case_processor, extra) + } + + generate_generic_json_report_limited_batches( + events, reports_path, parents_filter, par_btch_len, post_processors + ) + + +def extra_post_processor(main_processor, extra_processor): # noqa + # TODO: Add docstrings + return lambda report_leaf: extra_processor(main_processor(report_leaf)) + + +def generate_generic_json_report_limited_batches( + events, reports_path: str, parents_filter, par_btch_len, post_processors_dict=None +): # noqa + # TODO: Add return value -- paths + # TODO: Add docstrings + filtered = events.filter(parents_filter) + parents = event_utils.get_some(filtered, event_type=None, max_count=10000) + if len(parents) == 0: + raise SystemError("Reports parents not found") + + n_steps = (len(parents) // par_btch_len) + 1 + print("Building ", len(parents), "trees in ", n_steps, " steps") + for i in range(n_steps): + print("Step", i + 1) + number_base = i * par_btch_len + batch_end = ( + (i + 1) * par_btch_len if (i + 1) * par_btch_len < len(parents) else len(parents) + ) + sublist = parents[number_base:batch_end] + tree, index = generate_generic_tree_and_index_from_parents_list(events, sublist) + if post_processors_dict is not None: + print("Post processing ", datetime.now()) + th2_data_services.utils.json_tree.transform_tree(index, post_processors_dict) + tree_shtrikh = {} + for k, v in tree.items(): + if k == "info": + tree_shtrikh[k] = v + continue + + if " " not in k: + print("$$$$ " + k) + k_shtrikh = str(int(k[: k.index(" ")]) + number_base) + k[k.index(" ") :] + tree_shtrikh[k_shtrikh] = v + + print("Saving json ", datetime.now()) + th2_data_services.utils.json_tree.save_tree_as_json( + tree_shtrikh, reports_path, lambda n, l: n + ) + + +def generate_generic_json_report(events, reports_path: str, parents_filter, one_file=False): # noqa + # TODO: Add docstrings + tree, index = generate_generic_tree_and_index(events, parents_filter) + th2_data_services.utils.json_tree.save_tree_as_json( + tree, reports_path, lambda n, l: "all" if one_file else n + ) + + +def generate_model_matrix_json_report( + events, reports_path: str, parents_filter, one_file=False +): # noqa + # TODO: Add docstrings + tree, index = generate_model_matrix_tree_and_index(events, parents_filter) + + th2_data_services.utils.json_tree.save_tree_as_json( + tree, reports_path, lambda n, l: "all" if one_file else n + ) + + +############################ +# PrepareStory and its functions [end] +########################### + + +ver_dict = { + "type": "verification", + "fields": { + "Field A": { + "type": "field", + "operation": "NOT_EMPTY", + "status": "PASSED", + "key": False, + "actual": "value", + "expected": "*", + }, + "Field B": { + "type": "field", + "operation": "EQUAL", + "status": "PASSED", + "key": True, + "actual": "2531410", + "expected": "2531410", + }, + "Sub message A": { + "type": "collection", + "operation": "EQUAL", + "key": False, + "actual": "1", + "expected": "1", + "fields": { + "Field C": { + "type": "field", + "operation": "NOT_EQUAL", + "status": "FAILED", + "key": False, + "actual": "9", + "expected": "9", + } + }, + }, + }, +} + +tree_table = { + "type": "treeTable", + "name": "tableName", # this one is optional + "rows": { + "Row A with some custom name": { + "type": "row", + "columns": { + "Column 1 with some custom name": "some text (A1)", + "Column 2": "some text (A2)", + }, + }, + "Row B with some other name": { + "type": "collection", + "rows": { + "Row BA": { + "type": "row", + "columns": { + "Column 1 with some custom name": "some text (BA1)", + "Column 2": "some text (BA2)", + }, + }, + "Row BB": { + "type": "row", + "columns": { + "Column 1 with some custom name": "some text (BB1)", + "Column 2": "some text (BB2)", + }, + }, + }, + }, + }, +} + + +def test_verification_fields_to_flat_dict(): # noqa + flat_list = {} + verification_fields_to_flat_dict( + collection=ver_dict, flat_list=flat_list, prefix="hz", failed_collection=True + ) + print(flat_list) + """ + failed_collection=False + {'hzField A': ' value [*]', + 'hzField B': '! 2531410 [2531410]', + 'hzSub message A.Field C': ' # 9 [9]'} + + failed_collection=True + {'hzField A': ' # value [*]', + 'hzField B': '!# 2531410 [2531410]', + 'hzSub message A.Field C': ' # 9 [9]'} + """ + + +def test_verification_fields_to_simple_dict(): # noqa + flat_list = {} + verification_fields_to_simple_dict( + collection=ver_dict, parent=flat_list, failed_collection=True + ) + print(flat_list) + """ + failed_collection=False + {'Field A': ' value [*]', + 'Field B': '! 2531410 [2531410]', + '# Sub message A': {'Field C': ' # 9 [9]'}} + + failed_collection=True + {'Field A': ' # value [*]', + 'Field B': '!# 2531410 [2531410]', + '# Sub message A': {'Field C': ' # 9 [9]'}} + """ + + +def test_simplify_body_tree_table_list(): # noqa + # TODO - expects tree_table - like a list + r = simplify_body_tree_table_list([tree_table]) + print(r) + """ + {'Row A with some custom name': 'some text (A1),some text (A2)', + 'Row B with some other name.Row BA': 'some text (BA1),some text (BA2)', + 'Row B with some other name.Row BB': 'some text (BB1),some text (BB2)'} + """ + + +if __name__ == "__main__": + # test_verification_fields_to_flat_dict() + test_verification_fields_to_simple_dict() diff --git a/th2_data_services/sse_client.py b/th2_data_services/utils/sse_client.py similarity index 92% rename from th2_data_services/sse_client.py rename to th2_data_services/utils/sse_client.py index f9f1d942..5faf5f9d 100644 --- a/th2_data_services/sse_client.py +++ b/th2_data_services/utils/sse_client.py @@ -1,4 +1,4 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) +# Copyright 2022-2025 Exactpro (Exactpro Systems Limited) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. + import sseclient from sseclient import _FIELD_SEPARATOR @@ -48,7 +49,7 @@ def events(self): # Ignore unknown fields. if field not in event.__dict__: - self._logger.debug("Saw invalid field %s while parsing " "Server Side Event", field) + # LOG self._logger.debug("Saw invalid field %s while parsing " "Server Side Event", field) continue if len(data) > 1: @@ -83,5 +84,5 @@ def events(self): event.event = event.event or "message" # Dispatch the event - self._logger.debug("Dispatching %s...", event) + # LOG self._logger.debug("Dispatching %s...", event) yield event diff --git a/th2_data_services/provider/v6/interfaces/__init__.py b/th2_data_services/utils/stream_utils/__init__.py similarity index 86% rename from th2_data_services/provider/v6/interfaces/__init__.py rename to th2_data_services/utils/stream_utils/__init__.py index 0c0563dc..cc4a5c40 100644 --- a/th2_data_services/provider/v6/interfaces/__init__.py +++ b/th2_data_services/utils/stream_utils/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) +# Copyright 2024-2025 Exactpro (Exactpro Systems Limited) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -12,4 +12,5 @@ # See the License for the specific language governing permissions and # limitations under the License. -from .command import * + +from . import stream_utils diff --git a/th2_data_services/utils/stream_utils/stream_utils.py b/th2_data_services/utils/stream_utils/stream_utils.py new file mode 100644 index 00000000..e4e9f2da --- /dev/null +++ b/th2_data_services/utils/stream_utils/stream_utils.py @@ -0,0 +1,46 @@ +# Copyright 2024-2025 Exactpro (Exactpro Systems Limited) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +from typing import Iterable, Callable, Any +from th2_data_services.utils._is_sorted_result import IsSortedResult + + +def is_sorted(obj: Iterable, get_timestamp_func: Callable[[Any], Any]) -> IsSortedResult: + """Checks whether stream is sorted. + + Args: + obj: Stream + get_timestamp_func: This function is responsible for getting the timestamp. + + Returns: + IsSortedResult: Whether stream is sorted and additional info (e.g. index of the first unsorted element). + """ + is_sorted_result = IsSortedResult() + flag = True + previous_timestamp = None + i = 0 + for record in obj: + if flag: + previous_timestamp = get_timestamp_func(record) + flag = False + current_timestamp = get_timestamp_func(record) + if previous_timestamp > current_timestamp: + is_sorted_result.status = False + is_sorted_result.first_unsorted = i + break + previous_timestamp = current_timestamp + i += 1 + + return is_sorted_result diff --git a/th2_data_services/utils/time.py b/th2_data_services/utils/time.py new file mode 100644 index 00000000..a8eeb7d6 --- /dev/null +++ b/th2_data_services/utils/time.py @@ -0,0 +1,372 @@ +# Copyright 2023-2025 Exactpro (Exactpro Systems Limited) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +from datetime import datetime, timezone +from functools import wraps, partial +from typing import Dict, Union, Callable +from deprecated.classic import deprecated +import time as time_ +from th2_data_services.utils.converters import Th2TimestampConverter, DatetimeConverter + + +def extract_timestamp(timestamp_element: Dict) -> str: + """Returns datetime string in the format: 2023-10-02T10:47:20.413072000.""" + return Th2TimestampConverter.to_datetime_str(timestamp_element) + + +@deprecated("Use `extract_timestamp` instead") +def extract_time_string(timestamp_element) -> str: + """Extracts timestamp from argument. + + Args: + timestamp_element: + + Returns: + str representation of th2-timestamp(protobuf) e.g. 2023-03-09T05:37:53.263895000 + """ + return extract_timestamp(timestamp_element) + + +# TODO - to be honest, the name of the function is difficult +def time_interval_filter_seconds_precision( + timestamp_element: Dict, start_timestamp: Union[int, float], end_timestamp: Union[int, float] +) -> bool: + """Returns if th2-timestamp within time range. + + Please note: + It takes SECONDS only! + + Args: + timestamp_element: ProtobufTimestamp dict. + start_timestamp: Start timestamp in `unix time` format. + end_timestamp: End timestamp in `unix time` format. + + Returns: + bool + """ + return start_timestamp <= timestamp_element["epochSecond"] <= end_timestamp + + +def timestamp_delta_us(start_timestamp: Dict, end_timestamp: Dict) -> int: + """Returns timestamp delta in microseconds. + + Args: + start_timestamp: Start timestamp + end_timestamp: End timestamp + + Returns: + int + """ + st_seconds, st_nanoseconds = Th2TimestampConverter.parse_timestamp_int(start_timestamp) + et_seconds, et_nanoseconds = Th2TimestampConverter.parse_timestamp_int(end_timestamp) + + seconds_delta = (et_seconds - st_seconds) * 1000000 + nano_delta = (et_nanoseconds - st_nanoseconds) / 1000 + return seconds_delta + nano_delta + + +def time_slice_object_filter( + timestamp_field: str, start_timestamp_iso: str, duration_seconds: int +) -> Callable: # noqa + """Returns filter function for `Data.filter` method. + + Filter elements that from time moment `A` to `A+duration_seconds`. + + Args: + timestamp_field: expects the field name that contains ProtobufTimestamp + It usually 'timestamp' field. + start_timestamp_iso: string in the ISO 8601 format. + Example: 2009-05-28T16:15:00 or 2021-12-25 + Note: It cannot take strings with `Z` in the end. + duration_seconds: seconds. + + Returns: + Filter function. + + Examples: + 1. data.filter(time_slice_object_filter('startTimestamp', '2009-05-28T16:15:00, 300)) + """ + # TODO + # 1. looks ok, but we need to think about unified timestamps + # FixMe + # 1. timestamp_field -- the problem here if the field is placed not in the root of the dict. + # 2. it expects, that `obj[timestamp_field]` == Th2Timestamp + + ts1 = DatetimeConverter.to_seconds(datetime.fromisoformat(start_timestamp_iso)) + ts2 = ts1 + duration_seconds + + # FIXME + # time_interval_filter_seconds_precision require ProtobufTimestamp var as + # a first argument now. + # + # TODO - We should do our methods universal! + return lambda obj: time_interval_filter_seconds_precision(obj[timestamp_field], ts1, ts2) + + +# TODO - add possibility to provide `aggregation_level` as int (number of seconds) +def timestamp_aggregation_key( + global_anchor_timestamp: int, timestamp: int, aggregation_level: str = "seconds" +) -> int: # noqa + """TODO: Add docstings + + Args: + global_anchor_timestamp: + timestamp: + aggregation_level: e.g. 1s, 1sec, seconds, 10m, 10min, 10h, 10hour, 1d, 2day + + Returns: + + """ + if aggregation_level == "seconds": + return timestamp + + aggregation_levels = { + "seconds": 1, + "minutes": 60, + "hours": 3600, + "days": 86400, + # TODO - should be dynamic part + "30min": 1800, + "1min": 60, + "5min": 300, + "10sec": 10, + "30sec": 30, + } + + if aggregation_level not in aggregation_levels: + if aggregation_level.endswith("sec"): + num = aggregation_level.split("sec")[0] + dynamic_aggr_level = int(num) + + elif aggregation_level.endswith("s"): + num = aggregation_level.split("s")[0] + dynamic_aggr_level = int(num) + + elif aggregation_level.endswith("min"): + num = aggregation_level.split("min")[0] + dynamic_aggr_level = int(num) * 60 + + elif aggregation_level.endswith("m"): + num = aggregation_level.split("m")[0] + dynamic_aggr_level = int(num) * 60 + + elif aggregation_level.endswith("hour"): + num = aggregation_level.split("hour")[0] + dynamic_aggr_level = int(num) * 3600 + + elif aggregation_level.endswith("h"): + num = aggregation_level.split("h")[0] + dynamic_aggr_level = int(num) * 3600 + + elif aggregation_level.endswith("day"): + num = aggregation_level.split("day")[0] + dynamic_aggr_level = int(num) * 3600 * 24 + + elif aggregation_level.endswith("d"): + num = aggregation_level.split("d")[0] + dynamic_aggr_level = int(num) * 3600 * 24 + + else: + raise KeyError( + f"Invalid aggregation level. Available levels: {', '.join(aggregation_levels)}" + ) + aggregation_levels[aggregation_level] = dynamic_aggr_level + + try: + interval = aggregation_levels[aggregation_level] + except KeyError: + raise KeyError( + f"Invalid aggregation level. Available levels: {', '.join(aggregation_levels)}" + ) + + return global_anchor_timestamp + interval * ((timestamp - global_anchor_timestamp) // interval) + + +def _timestamp_rounded_down(timestamp: int, aggregation_level: str = "seconds"): + """Extracts timestamp rounded down to aggeegation level type. + + Args: + timestamp: Timestamp in epoch seconds + aggregation_level: String of aggregation level like: "5s", "2d", "3m", "hours" + + Returns: + Rounded down timestamp to aggregation level, for example: If timestamp is equivalent to 2023-04-05T23:12:15 and aggregation level is "5d" + function will return timestamp equivalent to 2023-04-05 + """ + dynamic_aggr_level = 1 + aggregation_levels = { + "seconds": 1, + "minutes": 60, + "hours": 3600, + "days": 86400, + # TODO - should be dynamic part + "30min": 60, + "1min": 60, + "5min": 60, + "10sec": 1, + "30sec": 1, + } + + if aggregation_level not in aggregation_levels: + if aggregation_level.endswith("sec") or aggregation_level.endswith("s"): + dynamic_aggr_level = 1 + + elif aggregation_level.endswith("min") or aggregation_level.endswith("m"): + dynamic_aggr_level = 60 + + elif aggregation_level.endswith("hour") or aggregation_level.endswith("h"): + dynamic_aggr_level = 3600 + + elif aggregation_level.endswith("day") or aggregation_level.endswith("d"): + dynamic_aggr_level = 86400 + + else: + raise KeyError( + f"Invalid aggregation level. Available levels: {', '.join(aggregation_levels)}" + ) + aggregation_levels[aggregation_level] = dynamic_aggr_level + + try: + dynamic_aggr_level = aggregation_levels[aggregation_level] + except KeyError: + raise KeyError( + f"Invalid aggregation level. Available levels: {', '.join(aggregation_levels)}" + ) + + return (timestamp // dynamic_aggr_level) * dynamic_aggr_level + + +def _round_timestamp_string_aggregation(timestamp: int, aggregation_level: str = "seconds"): + """Returns timestamp string rounded down to aggeegation level type. + + Args: + timestamp: Timestamp in epoch seconds + aggregation_level: String of aggregation level like: "5s", "2d", "3m", "hours" + + Returns: + Rounded down timestamp string to aggregation level, for example: If timestamp is equivalent to 2023-04-05T23:12:15 and aggregation level is "5d" + function will return string 2023-04-05 + """ + # First check full strings to ensure .endswith("s") doesn't catch it. + if aggregation_level == "seconds": + return datetime.fromtimestamp(timestamp, tz=timezone.utc).strftime("%Y-%m-%dT%H:%M:%S") + + if aggregation_level == "minutes" or aggregation_level == "hours": + return datetime.fromtimestamp(timestamp, tz=timezone.utc).strftime("%Y-%m-%dT%H:%M") + + if aggregation_level == "days": + return datetime.fromtimestamp(timestamp, tz=timezone.utc).strftime("%Y-%m-%d") + + if aggregation_level.endswith("sec") or aggregation_level.endswith("s"): + return datetime.fromtimestamp(timestamp, tz=timezone.utc).strftime("%Y-%m-%dT%H:%M:%S") + + if aggregation_level.endswith("min") or aggregation_level.endswith("m"): + return datetime.fromtimestamp(timestamp, tz=timezone.utc).strftime("%Y-%m-%dT%H:%M") + + if aggregation_level.endswith("hour") or aggregation_level.endswith("h"): + return datetime.fromtimestamp(timestamp, tz=timezone.utc).strftime("%Y-%m-%dT%H:%M") + + if aggregation_level.endswith("day") or aggregation_level.endswith("d"): + return datetime.fromtimestamp(timestamp, tz=timezone.utc).strftime("%Y-%m-%d") + + raise KeyError("Invalid aggregation level") + + +def _time_str_to_seconds(time_str: str): + """Returns the amount of seconds in aggregation level. + + Args: + time_str: Aggregation level string like: "5s", "2d", "3m", "hours" + + Returns: + Number of seconds in string, for example: "5s" returns 5, "3m" returns 180 and etc. + """ + if time_str == "seconds": + return 1 + + if time_str == "minutes": + return 60 + + if time_str == "hours": + return 3600 + + if time_str == "days": + return 86400 + + if time_str.endswith("sec"): + num = time_str.split("sec")[0] + return int(num) + + elif time_str.endswith("s"): + num = time_str.split("s")[0] + return int(num) + + elif time_str.endswith("min"): + num = time_str.split("min")[0] + return int(num) * 60 + + elif time_str.endswith("m"): + num = time_str.split("m")[0] + return int(num) * 60 + + elif time_str.endswith("hour"): + num = time_str.split("hour")[0] + return int(num) * 3600 + + elif time_str.endswith("h"): + num = time_str.split("h")[0] + return int(num) * 3600 + + elif time_str.endswith("day"): + num = time_str.split("day")[0] + return int(num) * 3600 * 24 + + elif time_str.endswith("d"): + num = time_str.split("d")[0] + return int(num) * 3600 * 24 + + raise KeyError("Invalid time string") + + +def calculate_time(func=None, return_as_last_value=False): + """Calculate time decorator. + + Apply for your functions to calculate the work time of it. + + Args: + func: + return_as_last_value: if True will return (func return value, calc_time). + + Returns: + prints calc time or returns (func return value, calc_time). + """ + if func is None: + return partial(calculate_time, return_as_last_value=return_as_last_value) + + @wraps(func) + def inner1(*args, **kwargs): + # storing time before function execution + begin = time_.time() + + v = func(*args, **kwargs) + + calc_time = time_.time() - begin + if return_as_last_value: + return v, calc_time + else: + print("Total time taken in : ", func.__name__, calc_time) + return v + + return inner1 diff --git a/th2_data_services/utils/total_category_calculator.py b/th2_data_services/utils/total_category_calculator.py new file mode 100644 index 00000000..c1ff8f4a --- /dev/null +++ b/th2_data_services/utils/total_category_calculator.py @@ -0,0 +1,245 @@ +# Copyright 2023-2025 Exactpro (Exactpro Systems Limited) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +import time +from random import choice +from typing import List, Tuple, Union, Dict, Sequence, TypeVar +from prettytable import PrettyTable +from collections import Counter +import itertools + +from th2_data_services.utils.aggregation_classes import TotalCategoryTable +from th2_data_services.utils.category import Category + +""" +Suppose there are 3 metrics +A, B, C + +A happens In, Out + +B - any value + +C - also any + +Combinations need to be made. + +A +AB +AC + +B +BC + +C + +ABC + +The order affects only the display. + +example +1. A: in, B: 0, C: x + +a += 1 +ab = {in/0: +=1} + + +""" + +CategoryCombination = TypeVar("CategoryCombination", Sequence[str], Sequence[Category]) + + +def get_all_metric_combinations(metrics: Union[List[str], List[Category]]): + """Returns all combinations of provided metrics.""" + metric_combinations = [] + + for L in range(len(metrics) + 1): + for subset in itertools.combinations(metrics, L): + if subset: + metric_combinations.append(subset) + + return metric_combinations + + +# First you need to pull out all the metrics, and only then connect + + +class TotalCategoryCalculator: + def __init__( + self, + categories: List[Category], + combinations: Union[List[Sequence[str]], List[Sequence[Category]]], + ): + """Calculates, aggregates to tables and prints categories combinations. + + This class allows you to calculate any metrics and their combinations in stream-like way. + It calculates how many times do we met some combination of tags. + + It does not accumulate all data in memory. + Keeps calculated metrics only. + + categories: [Category('a'), Category(b)] + combinations: e.g. [(a,),(a,b)]. You can put metric objects or metrics names. + + """ + assert isinstance(categories, list) + self.metrics = categories + self.combinations: List[Tuple[str]] = [] + + metric: Category + for comb in combinations: + new_comb = self._prepare_combination(comb) + self.combinations.append(new_comb) + + self.counter_field_name = "count" + self._counters: Dict[Tuple[str], Counter] = {} + + for v in self.combinations: + self._counters[v] = Counter() + + def _get_counter(self, combination: Tuple[str]) -> Counter: + """Returns counter for the combination. + + Expects prepared combination (after _prepare_combination method). + """ + try: + return self._counters[combination] + except KeyError: + raise Exception( + f"Unknown combination. The following combination '{combination}' is not provided to constructor." + ) + + def _prep_combination_keep_order(self, combination: CategoryCombination) -> List[str]: + """Returns combination in the required view.""" + new_comb = [] + for cv in combination: + if isinstance(cv, str): + new_comb.append(cv) + elif isinstance(cv, Category): + new_comb.append(cv.name) + else: + raise ValueError(f"Unexpected combination value, {combination}") + + return new_comb + + def _prepare_combination(self, combination: CategoryCombination) -> Tuple[str]: + """Returns combination in the required view.""" + new_comb = [] + for cv in combination: + if isinstance(cv, str): + new_comb.append(cv) + elif isinstance(cv, Category): + new_comb.append(cv.name) + else: + raise ValueError(f"Unexpected combination value, {combination}") + + new_comb.sort() # Because ABC == CAB == BAC == CBA ... + + return tuple(new_comb) + + def handle_objects(self, objects): + for o in objects: + self.append(o) + + # TODO - it's good that we have this, and not immediately all the messages are twisted inside. + # because get_category_totals_p takes 1 element, in order to be able to iterate over + # iterator processors.!! + def append(self, m: dict): + """Put some object to take it into account.""" + metric_values = {} + for metric in self.metrics: + metric_values[metric.name] = metric.get_func(m) + + # concat them == values + + for v in self.combinations: # v = ['session', 'direction'] + val_for_counter = tuple([metric_values[metric] for metric in v]) + self._counters[v].update([val_for_counter]) + + def get_table(self, combination: CategoryCombination) -> TotalCategoryTable: + """Returns a TotalCategoryTable class for certain combination. + + Args: + combination: Union[Tuple[str], List[str]] + + Returns: + TotalCategoryTable + + """ + orig_comb = combination + comb: Category + orig_columns_order = self._prep_combination_keep_order(orig_comb) + orig_columns_order.append(self.counter_field_name) + + combination = self._prepare_combination(combination) + + t = PrettyTable() + t.field_names = [*combination, self.counter_field_name] + counter = self._get_counter(combination) # The object with calculated combinations. + + for key, cnt in counter.items(): + t.add_row([*key, cnt]) + + return ( + TotalCategoryTable(header=t.field_names, rows=t.rows) + .change_columns_order(orig_columns_order) + .sort_by([self.counter_field_name], ascending=False) + ) + + def show(self): + """Prints all tables. + + Sorted by cnt. + """ + for combination in self.combinations: + t = self.get_table(combination) + t.reversesort = True + t.sortby = self.counter_field_name + print(t) + + +if __name__ == "__main__": + messages = [] + for i in range(1_000): + dir = choice(["IN", "OUT"]) + session = choice(["s1", "s2", "s3", "s4"]) + session = choice(["2023-05-04", "2023-04-03", "2023-05-03", "2023-05-12"]) + messageType = choice(["NewOrderSingle", "Cancel", "Amend"]) + messages.append({"direction": dir, "sessionId": session, "messageType": messageType}) + + t1 = time.time() + direction_m = Category("direction", lambda m: m["direction"]) + session_m = Category("session", lambda m: m["sessionId"]) + message_type_m = Category("messageType", lambda m: m["messageType"]) + + metrics_list = [ + direction_m, + session_m, + message_type_m, + ] + + all_metrics_combinations = get_all_metric_combinations(metrics_list) + print(all_metrics_combinations) + sc = TotalCategoryCalculator(metrics_list, all_metrics_combinations) + + for m in messages: + sc.append(m) + + sc.show() + + print(time.time() - t1) + tbl = sc.get_table(["direction", "messageType", session_m]) + print(tbl) + print(tbl.transpose_column("session")) + print(time.time() - t1) diff --git a/th2_data_services/utils/update_imports.sh b/th2_data_services/utils/update_imports.sh new file mode 100644 index 00000000..49432554 --- /dev/null +++ b/th2_data_services/utils/update_imports.sh @@ -0,0 +1,21 @@ +#!/bin/bash +# v 1.1.0 + +#find . -type f -exec sed -i.bak "s/th2_data_services/th2_data_services/g" {} \; +#sed 's/th2_data_services/th2_data_services/g' th2_data_services/utils/* + + + +echo +date +echo +echo "Files for sed:" +echo "-------------------------------" +grep -Rc th2_data_services * +echo +echo "-------------------------------" +read -p 'Enter y to continue: ' agree + +if [[ $agree == 'y' ]]; then + grep -R th2_data_services * -l | xargs sed -i "s/th2_data_services/th2_data_services/g" +fi diff --git a/th2_data_services/provider/v5/filters/__init__.py b/th2_data_services/utils/viewer_structs/__init__.py similarity index 90% rename from th2_data_services/provider/v5/filters/__init__.py rename to th2_data_services/utils/viewer_structs/__init__.py index c46552ee..a126e90d 100644 --- a/th2_data_services/provider/v5/filters/__init__.py +++ b/th2_data_services/utils/viewer_structs/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2022 Exactpro (Exactpro Systems Limited) +# Copyright 2023-2025 Exactpro (Exactpro Systems Limited) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/th2_data_services/utils/viewer_structs/verification.py b/th2_data_services/utils/viewer_structs/verification.py new file mode 100644 index 00000000..fe22abd7 --- /dev/null +++ b/th2_data_services/utils/viewer_structs/verification.py @@ -0,0 +1,164 @@ +# Copyright 2023-2025 Exactpro (Exactpro Systems Limited) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +from typing import Dict + + +def format_comparison_line(field: Dict, failed_collection: bool = False) -> str: # noqa + # TODO: Add docstrings + key_piece = "!" if field["key"] else " " + status_piece = "? " + no_val_or_no_group = "no_group" if failed_collection else "no_val" + if "status" in field: + status_piece = "# " if field["status"] == "FAILED" else " " + expected_piece = ( + f" [{field['expected']}]" if "expected" in field else f" [{no_val_or_no_group}]" + ) + actual_piece = field["actual"] if "actual" in field else no_val_or_no_group + return key_piece + status_piece + actual_piece + expected_piece + + +# TODO +# 1. Takes flat_list to put result in this dict. +# It's better to create this dict inside and return as a result. +# Now don't return anything! +# 2. We can move this function to Viewer utils and grouped to VerificationUtil class +# 3. verification_fields_to_simple_dict adds '#' to field name if Failed, but this func - NOT. +# 4. What's the idea of failed_collection ?? +def verification_fields_to_flat_dict( + collection: Dict, flat_list: Dict, prefix, failed_collection: bool = False +): # noqa + """ + If a field A has a sub-field B, dot notation sting will be returned. + + Examples: + failed_collection=False + {'hzField A': ' value [*]', + 'hzField B': '! 2531410 [2531410]', + 'hzSub message A.Field C': ' # 9 [9]'} + + failed_collection=True + {'hzField A': ' # value [*]', + 'hzField B': '!# 2531410 [2531410]', + 'hzSub message A.Field C': ' # 9 [9]'} + + Args: + collection: verification collection like here https://exactpro.atlassian.net/wiki/spaces/TH2/pages/63766549/rpt-viewer+supported+event+content#Verification + flat_list: NOT a list - dict. Used just to put result to this object. + prefix: prefix that will be added before each field name. + failed_collection: ??? + + Returns: + + """ + if "fields" not in collection: + flat_list.update(collection) + return + + fields = collection["fields"] + # tag - is field name here. + for tag, field in fields.items(): + if field["type"] == "field": + flat_list[prefix + tag] = format_comparison_line(field, failed_collection) + if field["type"] == "collection": + next_failed_collection = ( + "status" in field and field["status"] == "FAILED" + ) or failed_collection + new_prefix = f"{prefix}{tag}." + verification_fields_to_flat_dict(field, flat_list, new_prefix, next_failed_collection) + + +def check_if_verification_leaf_failed(leaf: Dict) -> bool: # noqa + # TODO: Add docstrings + if "fields" not in leaf: + return False + + fields = leaf["fields"] + for tag, field in fields.items(): + if field["type"] == "field": + if "status" not in field: + return True + if field["status"] == "FAILED": + return True + if field["type"] == "collection": + if "status" in field and field["status"] == "FAILED": + return True + if check_if_verification_leaf_failed(field): + return True + return False + + +# TODO +# 1. Takes parent (like flat_list) to put result in this dict. +# It's better to create this dict inside and return as a result. +# Now don't return anything! +# 2. We can move this function to Viewer utils and grouped to VerificationUtil class +# 3. In 'verification_fields_to_flat_dict' we can provide prefix but here - NO! +def verification_fields_to_simple_dict( + collection: Dict, parent: Dict, failed_collection: bool = False +) -> None: # noqa + """ + + Examples: + failed_collection=False + {'Field A': ' value [*]', + 'Field B': '! 2531410 [2531410]', + '# Sub message A': {'Field C': ' # 9 [9]'}} + + failed_collection=True + {'Field A': ' # value [*]', + 'Field B': '!# 2531410 [2531410]', + '# Sub message A': {'Field C': ' # 9 [9]'}} + + Args: + collection: verification collection like here https://exactpro.atlassian.net/wiki/spaces/TH2/pages/63766549/rpt-viewer+supported+event+content#Verification + parent: NOT a list - dict. Used just to put result to this object. + failed_collection: ?? + + Returns: + + """ + if "fields" not in collection: + parent.update(collection) + return + fields = collection["fields"] + for tag, field in fields.items(): + if field["type"] == "field": + parent[tag] = format_comparison_line(field, failed_collection) + if field["type"] == "collection": + prefix = "# " if check_if_verification_leaf_failed(field) else " " + parent[prefix + tag] = {} + next_failed_collection = "status" in field and field["status"] == "FAILED" + verification_fields_to_simple_dict(field, parent[prefix + tag], next_failed_collection) + + +def simplify_body_verification(body) -> Dict: # noqa + # Fields -> Simple Dict + # TODO: Add docstrings + simple_form = {} + tree = body[0] + verification_fields_to_flat_dict(tree, simple_form, "") + return simple_form + + +def simplify_body_verification2(body) -> Dict: # noqa + # Fields -> Flat Dict + # Rename to ? + # TODO: Is this useful? + # TODO: Add docstrings + simple_form = {} + tree = body[0] + verification_fields_to_simple_dict(tree, simple_form) + return simple_form diff --git a/uncomment_logs.sh b/uncomment_logs.sh new file mode 100755 index 00000000..b229651e --- /dev/null +++ b/uncomment_logs.sh @@ -0,0 +1,3 @@ +#!/bin/bash +cd th2_data_services +perl -i -pe 's/^(#LOG )(.*)/$2 #LOG/' $(find . -type f) diff --git a/update_readme_toc.sh b/update_readme_toc.sh new file mode 100755 index 00000000..0cc3d97b --- /dev/null +++ b/update_readme_toc.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +TOC_GEN_FILE='gh-md-toc' + +function install_toc_generator() { + wget https://raw.githubusercontent.com/ekalinin/github-markdown-toc/master/gh-md-toc + chmod a+x gh-md-toc +} + +function main() { + echo 'Add TOC to README.md' + + # check_if_toc_generator_exists + if [ ! -f $TOC_GEN_FILE ]; then + install_toc_generator + fi + + ./gh-md-toc --no-backup --hide-footer README.md + + exit 0 +} + +main