tox-gh-actions


Nametox-gh-actions JSON
Version 3.1.3 PyPI version JSON
download
home_pagehttps://github.com/ymyzk/tox-gh-actions
SummarySeamless integration of tox into GitHub Actions
upload_time2023-07-06 15:36:50
maintainerYusuke Miyazaki
docs_urlNone
authorYusuke Miyazaki
requires_python>=3.7
licenseMIT
keywords virtual environments isolated testing
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # tox-gh-actions <!-- omit in toc -->

[![PyPI version](https://badge.fury.io/py/tox-gh-actions.svg)](https://badge.fury.io/py/tox-gh-actions)
[![PyPI Supported Python Versions](https://img.shields.io/pypi/pyversions/tox-gh-actions.svg)](https://pypi.python.org/pypi/tox-gh-actions/)
[![GitHub Actions (Tests)](https://github.com/ymyzk/tox-gh-actions/actions/workflows/tests.yml/badge.svg)](https://github.com/ymyzk/tox-gh-actions/actions/workflows/tests.yml)
[![codecov](https://codecov.io/gh/ymyzk/tox-gh-actions/branch/master/graph/badge.svg?token=7RWjRk2LkX)](https://codecov.io/gh/ymyzk/tox-gh-actions)

**tox-gh-actions** is a tox plugin which helps running tox on GitHub Actions
with multiple different Python versions on multiple workers in parallel.
This project is inspired by [tox-travis](https://github.com/tox-dev/tox-travis).

## Versions and Compatibility
Currently, tox-gh-actions supports both tox 3 and 4, but users need to install the appropriate version by following the table below.

| tox | tox-gh-actions | Supported by tox-gh-actions | Branch                                                    |
|-----|----------------|-----------------------------|-----------------------------------------------------------|
| 4.x | 3.x            | Yes (stable)                | [master](https://github.com/ymyzk/tox-gh-actions)         |
| 3.x | 2.x            | Yes (stable)                | [tox3](https://github.com/ymyzk/tox-gh-actions/tree/tox3) |

- [Features](#features)
- [Usage](#usage)
- [Examples](#examples)
  - [Basic Example](#basic-example)
    - [tox-gh-actions Configuration](#tox-gh-actions-configuration)
    - [Workflow Configuration](#workflow-configuration)
  - [Advanced Examples](#advanced-examples)
    - [Factor-Conditional Settings: Python Version](#factor-conditional-settings-python-version)
    - [Factor-Conditional Settings: Environment Variable](#factor-conditional-settings-environment-variable)
  - [Overriding Environments to Run](#overriding-environments-to-run)
- [Versioning](#versioning)
- [Understanding Behavior of tox-gh-actions](#understanding-behavior-of-tox-gh-actions)
  - [How tox-gh-actions Works](#how-tox-gh-actions-works)
  - [Logging](#logging)

## Features
When running tox on GitHub Actions, tox-gh-actions
* detects which environment to run based on configurations and
* provides utilities such as [grouping log lines](https://github.com/actions/toolkit/blob/main/docs/commands.md#group-and-ungroup-log-lines).

## Usage
1. Add configurations under `[gh-actions]` section along with tox's configuration.
   - It will be `pyproject.toml`, `tox.ini`, or `setup.cfg`. See [tox's documentation](https://tox.wiki/en/latest/config.html) for more details.

2. Install `tox-gh-actions` package in the GitHub Actions workflow before running `tox` command.

## Examples
### Basic Example
The following configuration will create 4 jobs when running the workflow on GitHub Actions.
- On Python 3.7 job, tox runs `py37` environment
- On Python 3.8 job, tox runs `py38` environment
- On Python 3.9 job, tox runs `py39` environment
- On Python 3.10 job, tox runs `py310` and `mypy` environments

#### tox-gh-actions Configuration
Add `[gh-actions]` section to the same file as tox's configuration.

If you're using `tox.ini`:
```ini
[tox]
envlist = py37, py38, py39, py310, mypy

[gh-actions]
python =
    3.7: py37
    3.8: py38
    3.9: py39
    3.10: py310, mypy

[testenv]
...
```

If you're using `setup.cfg`:
```ini
[tox:tox]
envlist = py37, py38, py39, py310, mypy

[gh-actions]
python =
    3.7: py37
    3.8: py38
    3.9: py39
    3.10: py310, mypy

[testenv]
...
```

If you're using `pyproject.toml`:
```toml
[tool.tox]
legacy_tox_ini = """
[tox]
envlist = py37, py38, py39, py310, mypy

[gh-actions]
python =
    3.7: py37
    3.8: py38
    3.9: py39
    3.10: py310, mypy

[testenv]
"""
```

#### Workflow Configuration
`.github/workflows/<workflow>.yml`:
```yaml
name: Python package

on:
  - push
  - pull_request

jobs:
  build:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: ['3.7', '3.8', '3.9', '3.10']

    steps:
    - uses: actions/checkout@v3
    - name: Set up Python ${{ matrix.python-version }}
      uses: actions/setup-python@v4
      with:
        python-version: ${{ matrix.python-version }}
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        python -m pip install tox tox-gh-actions
    - name: Test with tox
      run: tox
```

### Advanced Examples
#### Factor-Conditional Settings: Python Version
The following configuration will create 2 jobs when running the workflow on GitHub Actions.
- On Python 3.7 job, tox runs `py37-django22` and `py37-django32` environments
- On Python 3.8 job, tox runs `py38-django32` environment

`tox.ini`:
```ini
[tox]
envlist = py37-django{22,32}, py38-django32

[gh-actions]
python =
    3.7: py37
    3.8: py38

[testenv]
...
```

When using pre-release versions of Python, please do not specify `-beta` or `-dev` in `tox.ini`.

`.github/workflows/<workflow>.yml`:
```yaml
...
jobs:
  build:
    strategy:
      matrix:
        python-version: [3.9, 3.10.0-beta.3]
...
```

`tox.ini`:
```ini
[tox]
envlist = py39, py310

[gh-actions]
python =
    3.9: py39
    3.10: py310
    # The following won't work
    # 3.10-beta.3: py310
    # 3.10-dev: py310

[testenv]
...
```

PyPy is also supported in the `python` configuration key.
Support of Pyston is experimental and not tested by our CI.

 `tox.ini`:
```ini
[tox]
envlist = py37, py38, pypy3, pyston38

[gh-actions]
python =
    3.7: py37
    3.8: py38, mypy
    pypy-3.7: pypy3
    pyston-3.8: pyston38

[testenv]
...

[testenv:pyston38]
basepython = pyston38
```

You can also specify without minor versions in the `python` configuration key.

`tox.ini`:
```ini
[tox]
envlist = py3, pypy3

[gh-actions]
python =
    3: py3, mypy
    pypy-3: pypy3

[testenv]
...
```

If there are multiple matching Python versions in the configuration, only the most precise one is used.
For example, if you are running CPython 3.8 and `gh-actions.python` has both `3` and `3.8`,
tox-gh-actions gets factors only from the key `3.8`.

_Changed in 3.0_: `pypy3` is not supported in the configuration anymore. Please use `pypy-3` instead.

#### Factor-Conditional Settings: Environment Variable
You can also use environment variable to decide which environment to run.
The following is an example to install different dependency based on platform.
It will create 9 jobs when running the workflow on GitHub Actions.
- On Python 3.8/ubuntu-latest job, tox runs `py38-linux` environment
- On Python 3.9/ubuntu-latest job, tox runs `py39-linux` environment
- and so on.

`.github/workflows/<workflow>.yml`:
```yaml
name: Python package

on:
  - push
  - pull_request

jobs:
  build:
    runs-on: ${{ matrix.platform }}
    strategy:
      matrix:
        platform: [ubuntu-latest, macos-latest, windows-latest]
        python-version: ['3.8', '3.9', '3.10']

    steps:
    - uses: actions/checkout@v3
    - name: Set up Python ${{ matrix.python-version }}
      uses: actions/setup-python@v4
      with:
        python-version: ${{ matrix.python-version }}
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        python -m pip install tox tox-gh-actions
    - name: Test with tox
      run: tox
      env:
        PLATFORM: ${{ matrix.platform }}
```

`tox.ini`:
```ini
[tox]
envlist = py{38,39,310}-{linux,macos,windows}

[gh-actions]
python =
    3.8: py38
    3.9: py39
    3.10: py310

[gh-actions:env]
PLATFORM =
    ubuntu-latest: linux
    macos-latest: macos
    windows-latest: windows

[testenv]
deps =
  <common dependency>
  linux: <Linux specific deps>
  macos: <macOS specific deps>
  windows: <Windows specific deps>
...
```

_Changed in 3.0_: Environment variables should not use lowercase letters.
Because of the limitation in tox's configuration loading API,
tox-gh-actions always convert keys in `[gh-actions:env]` to uppercase.

### Overriding Environments to Run
_Changed in 2.0_: When a list of environments to run is specified explicitly via `-e` option or `TOXENV` environment variable ([tox's help](https://tox.wiki/en/latest/cli_interface.html#tox-run--e)),
tox-gh-actions respects the given environments and simply runs the given environments without enforcing its configuration.

Before 2.0, tox-gh-actions was always enforcing its configuration even when a list of environments is given explicitly.

## Versioning
This project follows [PEP 440](https://www.python.org/dev/peps/pep-0440/) and uses a format of major.minor.patch (X.Y.Z).
The major version (X) will be incremented when we make backward incompatible changes to a public API.
The public API of this project is the configuration of tox-gh-actions.
The major version can be also incremented when we require a new version of tox.

This project tries not to introduce backward incompatibles changes as much as possible so that users don't need to
update their project's configuration too frequently.

tox-gh-actions 3.x may drop support of unsupported Python 3.y versions in the future without bumping its major version.

## Understanding Behavior of tox-gh-actions
### How tox-gh-actions Works
See [ARCHITECTURE.md](./ARCHITECTURE.md) for more details.

### Logging
tox-gh-actions writes log messages using the standard `logging` module.
This is handy for understanding behavior of tox-gh-actions and for debugging tox-gh-actions.
To see the log messages, please run `tox -vv`.

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/ymyzk/tox-gh-actions",
    "name": "tox-gh-actions",
    "maintainer": "Yusuke Miyazaki",
    "docs_url": null,
    "requires_python": ">=3.7",
    "maintainer_email": "miyazaki.dev@gmail.com",
    "keywords": "virtual,environments,isolated,testing",
    "author": "Yusuke Miyazaki",
    "author_email": "miyazaki.dev@gmail.com",
    "download_url": "https://files.pythonhosted.org/packages/b1/9e/3433f72030662ac92b022683fcc5ac836d1fc09153e5d87dc876f43b8c54/tox-gh-actions-3.1.3.tar.gz",
    "platform": "any",
    "description": "# tox-gh-actions <!-- omit in toc -->\n\n[![PyPI version](https://badge.fury.io/py/tox-gh-actions.svg)](https://badge.fury.io/py/tox-gh-actions)\n[![PyPI Supported Python Versions](https://img.shields.io/pypi/pyversions/tox-gh-actions.svg)](https://pypi.python.org/pypi/tox-gh-actions/)\n[![GitHub Actions (Tests)](https://github.com/ymyzk/tox-gh-actions/actions/workflows/tests.yml/badge.svg)](https://github.com/ymyzk/tox-gh-actions/actions/workflows/tests.yml)\n[![codecov](https://codecov.io/gh/ymyzk/tox-gh-actions/branch/master/graph/badge.svg?token=7RWjRk2LkX)](https://codecov.io/gh/ymyzk/tox-gh-actions)\n\n**tox-gh-actions** is a tox plugin which helps running tox on GitHub Actions\nwith multiple different Python versions on multiple workers in parallel.\nThis project is inspired by [tox-travis](https://github.com/tox-dev/tox-travis).\n\n## Versions and Compatibility\nCurrently, tox-gh-actions supports both tox 3 and 4, but users need to install the appropriate version by following the table below.\n\n| tox | tox-gh-actions | Supported by tox-gh-actions | Branch                                                    |\n|-----|----------------|-----------------------------|-----------------------------------------------------------|\n| 4.x | 3.x            | Yes (stable)                | [master](https://github.com/ymyzk/tox-gh-actions)         |\n| 3.x | 2.x            | Yes (stable)                | [tox3](https://github.com/ymyzk/tox-gh-actions/tree/tox3) |\n\n- [Features](#features)\n- [Usage](#usage)\n- [Examples](#examples)\n  - [Basic Example](#basic-example)\n    - [tox-gh-actions Configuration](#tox-gh-actions-configuration)\n    - [Workflow Configuration](#workflow-configuration)\n  - [Advanced Examples](#advanced-examples)\n    - [Factor-Conditional Settings: Python Version](#factor-conditional-settings-python-version)\n    - [Factor-Conditional Settings: Environment Variable](#factor-conditional-settings-environment-variable)\n  - [Overriding Environments to Run](#overriding-environments-to-run)\n- [Versioning](#versioning)\n- [Understanding Behavior of tox-gh-actions](#understanding-behavior-of-tox-gh-actions)\n  - [How tox-gh-actions Works](#how-tox-gh-actions-works)\n  - [Logging](#logging)\n\n## Features\nWhen running tox on GitHub Actions, tox-gh-actions\n* detects which environment to run based on configurations and\n* provides utilities such as [grouping log lines](https://github.com/actions/toolkit/blob/main/docs/commands.md#group-and-ungroup-log-lines).\n\n## Usage\n1. Add configurations under `[gh-actions]` section along with tox's configuration.\n   - It will be `pyproject.toml`, `tox.ini`, or `setup.cfg`. See [tox's documentation](https://tox.wiki/en/latest/config.html) for more details.\n\n2. Install `tox-gh-actions` package in the GitHub Actions workflow before running `tox` command.\n\n## Examples\n### Basic Example\nThe following configuration will create 4 jobs when running the workflow on GitHub Actions.\n- On Python 3.7 job, tox runs `py37` environment\n- On Python 3.8 job, tox runs `py38` environment\n- On Python 3.9 job, tox runs `py39` environment\n- On Python 3.10 job, tox runs `py310` and `mypy` environments\n\n#### tox-gh-actions Configuration\nAdd `[gh-actions]` section to the same file as tox's configuration.\n\nIf you're using `tox.ini`:\n```ini\n[tox]\nenvlist = py37, py38, py39, py310, mypy\n\n[gh-actions]\npython =\n    3.7: py37\n    3.8: py38\n    3.9: py39\n    3.10: py310, mypy\n\n[testenv]\n...\n```\n\nIf you're using `setup.cfg`:\n```ini\n[tox:tox]\nenvlist = py37, py38, py39, py310, mypy\n\n[gh-actions]\npython =\n    3.7: py37\n    3.8: py38\n    3.9: py39\n    3.10: py310, mypy\n\n[testenv]\n...\n```\n\nIf you're using `pyproject.toml`:\n```toml\n[tool.tox]\nlegacy_tox_ini = \"\"\"\n[tox]\nenvlist = py37, py38, py39, py310, mypy\n\n[gh-actions]\npython =\n    3.7: py37\n    3.8: py38\n    3.9: py39\n    3.10: py310, mypy\n\n[testenv]\n\"\"\"\n```\n\n#### Workflow Configuration\n`.github/workflows/<workflow>.yml`:\n```yaml\nname: Python package\n\non:\n  - push\n  - pull_request\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        python-version: ['3.7', '3.8', '3.9', '3.10']\n\n    steps:\n    - uses: actions/checkout@v3\n    - name: Set up Python ${{ matrix.python-version }}\n      uses: actions/setup-python@v4\n      with:\n        python-version: ${{ matrix.python-version }}\n    - name: Install dependencies\n      run: |\n        python -m pip install --upgrade pip\n        python -m pip install tox tox-gh-actions\n    - name: Test with tox\n      run: tox\n```\n\n### Advanced Examples\n#### Factor-Conditional Settings: Python Version\nThe following configuration will create 2 jobs when running the workflow on GitHub Actions.\n- On Python 3.7 job, tox runs `py37-django22` and `py37-django32` environments\n- On Python 3.8 job, tox runs `py38-django32` environment\n\n`tox.ini`:\n```ini\n[tox]\nenvlist = py37-django{22,32}, py38-django32\n\n[gh-actions]\npython =\n    3.7: py37\n    3.8: py38\n\n[testenv]\n...\n```\n\nWhen using pre-release versions of Python, please do not specify `-beta` or `-dev` in `tox.ini`.\n\n`.github/workflows/<workflow>.yml`:\n```yaml\n...\njobs:\n  build:\n    strategy:\n      matrix:\n        python-version: [3.9, 3.10.0-beta.3]\n...\n```\n\n`tox.ini`:\n```ini\n[tox]\nenvlist = py39, py310\n\n[gh-actions]\npython =\n    3.9: py39\n    3.10: py310\n    # The following won't work\n    # 3.10-beta.3: py310\n    # 3.10-dev: py310\n\n[testenv]\n...\n```\n\nPyPy is also supported in the `python` configuration key.\nSupport of Pyston is experimental and not tested by our CI.\n\n `tox.ini`:\n```ini\n[tox]\nenvlist = py37, py38, pypy3, pyston38\n\n[gh-actions]\npython =\n    3.7: py37\n    3.8: py38, mypy\n    pypy-3.7: pypy3\n    pyston-3.8: pyston38\n\n[testenv]\n...\n\n[testenv:pyston38]\nbasepython = pyston38\n```\n\nYou can also specify without minor versions in the `python` configuration key.\n\n`tox.ini`:\n```ini\n[tox]\nenvlist = py3, pypy3\n\n[gh-actions]\npython =\n    3: py3, mypy\n    pypy-3: pypy3\n\n[testenv]\n...\n```\n\nIf there are multiple matching Python versions in the configuration, only the most precise one is used.\nFor example, if you are running CPython 3.8 and `gh-actions.python` has both `3` and `3.8`,\ntox-gh-actions gets factors only from the key `3.8`.\n\n_Changed in 3.0_: `pypy3` is not supported in the configuration anymore. Please use `pypy-3` instead.\n\n#### Factor-Conditional Settings: Environment Variable\nYou can also use environment variable to decide which environment to run.\nThe following is an example to install different dependency based on platform.\nIt will create 9 jobs when running the workflow on GitHub Actions.\n- On Python 3.8/ubuntu-latest job, tox runs `py38-linux` environment\n- On Python 3.9/ubuntu-latest job, tox runs `py39-linux` environment\n- and so on.\n\n`.github/workflows/<workflow>.yml`:\n```yaml\nname: Python package\n\non:\n  - push\n  - pull_request\n\njobs:\n  build:\n    runs-on: ${{ matrix.platform }}\n    strategy:\n      matrix:\n        platform: [ubuntu-latest, macos-latest, windows-latest]\n        python-version: ['3.8', '3.9', '3.10']\n\n    steps:\n    - uses: actions/checkout@v3\n    - name: Set up Python ${{ matrix.python-version }}\n      uses: actions/setup-python@v4\n      with:\n        python-version: ${{ matrix.python-version }}\n    - name: Install dependencies\n      run: |\n        python -m pip install --upgrade pip\n        python -m pip install tox tox-gh-actions\n    - name: Test with tox\n      run: tox\n      env:\n        PLATFORM: ${{ matrix.platform }}\n```\n\n`tox.ini`:\n```ini\n[tox]\nenvlist = py{38,39,310}-{linux,macos,windows}\n\n[gh-actions]\npython =\n    3.8: py38\n    3.9: py39\n    3.10: py310\n\n[gh-actions:env]\nPLATFORM =\n    ubuntu-latest: linux\n    macos-latest: macos\n    windows-latest: windows\n\n[testenv]\ndeps =\n  <common dependency>\n  linux: <Linux specific deps>\n  macos: <macOS specific deps>\n  windows: <Windows specific deps>\n...\n```\n\n_Changed in 3.0_: Environment variables should not use lowercase letters.\nBecause of the limitation in tox's configuration loading API,\ntox-gh-actions always convert keys in `[gh-actions:env]` to uppercase.\n\n### Overriding Environments to Run\n_Changed in 2.0_: When a list of environments to run is specified explicitly via `-e` option or `TOXENV` environment variable ([tox's help](https://tox.wiki/en/latest/cli_interface.html#tox-run--e)),\ntox-gh-actions respects the given environments and simply runs the given environments without enforcing its configuration.\n\nBefore 2.0, tox-gh-actions was always enforcing its configuration even when a list of environments is given explicitly.\n\n## Versioning\nThis project follows [PEP 440](https://www.python.org/dev/peps/pep-0440/) and uses a format of major.minor.patch (X.Y.Z).\nThe major version (X) will be incremented when we make backward incompatible changes to a public API.\nThe public API of this project is the configuration of tox-gh-actions.\nThe major version can be also incremented when we require a new version of tox.\n\nThis project tries not to introduce backward incompatibles changes as much as possible so that users don't need to\nupdate their project's configuration too frequently.\n\ntox-gh-actions 3.x may drop support of unsupported Python 3.y versions in the future without bumping its major version.\n\n## Understanding Behavior of tox-gh-actions\n### How tox-gh-actions Works\nSee [ARCHITECTURE.md](./ARCHITECTURE.md) for more details.\n\n### Logging\ntox-gh-actions writes log messages using the standard `logging` module.\nThis is handy for understanding behavior of tox-gh-actions and for debugging tox-gh-actions.\nTo see the log messages, please run `tox -vv`.\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Seamless integration of tox into GitHub Actions",
    "version": "3.1.3",
    "project_urls": {
        "Homepage": "https://github.com/ymyzk/tox-gh-actions",
        "Source": "https://github.com/ymyzk/tox-gh-actions",
        "Tracker": "https://github.com/ymyzk/tox-gh-actions/issues"
    },
    "split_keywords": [
        "virtual",
        "environments",
        "isolated",
        "testing"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "257abf58404d3d1e566fac4d1cc3c3db67ee4193847da07a46c914b9447e31cd",
                "md5": "d9e57073ba243802807675d7e440bd4e",
                "sha256": "5954766fe2ed0e284f3cdc87535dfdf68d0f803f1011b17ff8cf52ed3156e6c1"
            },
            "downloads": -1,
            "filename": "tox_gh_actions-3.1.3-py2.py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "d9e57073ba243802807675d7e440bd4e",
            "packagetype": "bdist_wheel",
            "python_version": "py2.py3",
            "requires_python": ">=3.7",
            "size": 9848,
            "upload_time": "2023-07-06T15:36:48",
            "upload_time_iso_8601": "2023-07-06T15:36:48.344552Z",
            "url": "https://files.pythonhosted.org/packages/25/7a/bf58404d3d1e566fac4d1cc3c3db67ee4193847da07a46c914b9447e31cd/tox_gh_actions-3.1.3-py2.py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "b19e3433f72030662ac92b022683fcc5ac836d1fc09153e5d87dc876f43b8c54",
                "md5": "1ee2186112fffde5f48e2d895a710db9",
                "sha256": "ffd4151fe8b62c6f401a2fc5a01317835d7ab380923f6e0d063c300750308328"
            },
            "downloads": -1,
            "filename": "tox-gh-actions-3.1.3.tar.gz",
            "has_sig": false,
            "md5_digest": "1ee2186112fffde5f48e2d895a710db9",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.7",
            "size": 18428,
            "upload_time": "2023-07-06T15:36:50",
            "upload_time_iso_8601": "2023-07-06T15:36:50.381195Z",
            "url": "https://files.pythonhosted.org/packages/b1/9e/3433f72030662ac92b022683fcc5ac836d1fc09153e5d87dc876f43b8c54/tox-gh-actions-3.1.3.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-07-06 15:36:50",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "ymyzk",
    "github_project": "tox-gh-actions",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "tox-gh-actions"
}
        
Elapsed time: 1.94687s