# robotframework-gevent
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
[![All Contributors](https://img.shields.io/badge/all_contributors-1-orange.svg?style=flat-square)](#contributors-)
<!-- ALL-CONTRIBUTORS-BADGE:END -->
Run keywords asynchronously with the power of gevent
[![Version](https://img.shields.io/pypi/v/robotframework-gevent.svg)](https://pypi.python.org/pypi/robotframework-gevent)
![](https://raw.githubusercontent.com/eldaduzman/robotframework-gevent/main/docs/badges/coverage-badge.svg)
![](https://raw.githubusercontent.com/eldaduzman/robotframework-gevent/main/docs/badges/pylint.svg)
![](https://raw.githubusercontent.com/eldaduzman/robotframework-gevent/main/docs/badges/mutscore.svg)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
## installation:
```bash
pip install robotframework-gevent
```
## Usage:
```robotframework
# simple-test.robot
*** Settings ***
Library Collections
Library String
Library GeventLibrary
Library RequestsLibrary
*** Test Cases ***
Test1
[Documentation] Simple test flow with gevent greenlets
Log Hello World
Create Gevent Bundle alias=alias1 # Create a bundle of coroutines
Sleep 10s alias=alias1 # run your synchronous keyword
# register all your keywords as coroutines to the gevent bundle
Add Coroutine Sleep Wrapper alias=alias1
Add Coroutine Sleep 20s alias=alias1
Add Coroutine Sleep 10s alias=alias1
Add Coroutine GET https://jsonplaceholder.typicode.com/posts/1 alias=alias1
Add Coroutine Convert To Lower Case UPPER
# Run your coroutines and get the values by order
${values} Run Coroutines alias=alias1
Log Many @{values}
# The 3rd coroutine was a request, take it's value
${jsonplaceholder_resp} Get From List ${values} 3
# assert the returned response code to be 200
Status Should Be 200 ${jsonplaceholder_resp}
# assert that the returned `userId` field equals to 1
Should Be Equal As Strings 1 ${jsonplaceholder_resp.json()['userId']}
*** Keywords ***
Sleep Wrapper
Sleep 1s
```
See - [Keyword Documentation](https://eldaduzman.github.io/robotframework-gevent/GeventLibrary.html)
### run test:
```
>>> robot simple-test.robot
```
### Possible result
After test is completed go to `log.html`:
![](https://raw.githubusercontent.com/eldaduzman/robotframework-gevent/main/docs/images/Possible-Log-File.png)
Owing to the fact that keywords are executed asynchronously, we cannot know the order of keyword execution, so instead they are printed in a table format
### For more examples
go to [examples](https://github.com/eldaduzman/robotframework-gevent/tree/main/examples)
## Motivation
Modern software architecture is `event driven`, with many background process.
Servers are being more pro-active instead of re-active as we see in a `client server` architecture.
In order to test such systems, we need the ability to run coroutines in our test scripts.
With the power of [gevent](http://www.gevent.org/), we can run several coroutines in greenlets, so integrating them into our robotframework test script will provide super powers to our testing efforts!
## Why gevent?
Concurrency can be achieved in 3 different ways:
1. Multiprocessing - running each task in it's own `process`.
The cons of such an approach would be massive consumption of resources, namely CPU and memory, as this means to allocate an entire `memory heap` to each task.
Another problem is a possible need for `Inter-Process Communication (IPC)` that might be costly.
2. Multithreading - running each task in a `thread`.
Unlike multiprocessing, now all tasks run on the same memory heap and separated by threads, which the CPU coordinates using `round-robin`.
However, python's `Global Interpreter Lock` (GIL) prevents these threads from acting concurrently, it might perform context switching when IO operation occurs but there's no control for that.
3. Asynchronous IO - running all tasks on a single thread, while IO operations won't block the progress of the program, while code execution is committed by an `event loop` that `selects` between attached `coroutines`.
This is highly efficient in resources consumption when compared to multithreading and multiprocessing, but it requires some modifications to the original code.
`Blocking` IO statements can hog the event loop and the code will not be concurrent.
`gevent` allows programmers to write seemingly regular "blocking" python code, but it will enforce asynchronous IO compliance by `monkey patching`
## File structure
```
| LICENSE
| .gitignore
| .pylintrc
| pyproject.toml
| poetry.lock
| README.md
|
+---src
| \---GeventLibrary
| | \---exceptions
| | | __init__.py
| | \---keywords
| | | __init__.py
| | | gevent_keywords.py
| | __init__.py
| | gevent_library.py
|
+---atests
| | __init__.robot
| | simple-test.robot
| |
| \---utests
| | __init__.py
| | test_bundle_creation.py
```
## Code styling
### `black` used for auto-formatting code [read](https://pypi.org/project/black/),
### `pylint` used for code linting and pep8 compliance [read](https://pypi.org/project/pylint/),
### `mypy` used for type hinting [read](https://pypi.org/project/mypy/),
### `robocop` static code analyzer for robotframework [read](https://pypi.org/project/robotframework-robocop/),
### `perflint` pylint extension for performance linting [read](https://betterprogramming.pub/use-perflint-a-performance-linter-for-python-eae8e54f1e99)
### `cosmic-ray` Python tool for mutation testing [read](https://python.plainenglish.io/python-mutation-testing-with-cosmic-ray-4b78eb9e0676)
## links
1. [Robotframework](https://robotframework.org/)
2. [gevent](http://www.gevent.org/)
## Contributors ✨
Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
<!-- prettier-ignore-start -->
<!-- markdownlint-disable -->
<table>
<tbody>
<tr>
<td align="center"><a href="https://github.com/MalikMlitat"><img src="https://avatars.githubusercontent.com/u/19836100?v=4?s=100" width="100px;" alt="MalikMlitat"/><br /><sub><b>MalikMlitat</b></sub></a><br /><a href="https://github.com/eldaduzman/robotframework-gevent/commits?author=MalikMlitat" title="Documentation">📖</a></td>
</tr>
</tbody>
</table>
<!-- markdownlint-restore -->
<!-- prettier-ignore-end -->
<!-- ALL-CONTRIBUTORS-LIST:END -->
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
Raw data
{
"_id": null,
"home_page": "https://github.com/eldaduzman/robotframework-gevent",
"name": "robotframework-gevent",
"maintainer": "",
"docs_url": null,
"requires_python": ">=3.8,<4.0",
"maintainer_email": "",
"keywords": "robotframework,rpa,automation,asynchronous",
"author": "Eldad Uzman",
"author_email": "eldadu1985@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/f9/8c/c1373c03c7528774bd29bfddd4118b4215fa023ed44dff0c445a9ce35101/robotframework_gevent-0.7.0.tar.gz",
"platform": null,
"description": "# robotframework-gevent\n<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->\n[![All Contributors](https://img.shields.io/badge/all_contributors-1-orange.svg?style=flat-square)](#contributors-)\n<!-- ALL-CONTRIBUTORS-BADGE:END -->\nRun keywords asynchronously with the power of gevent\n\n\n[![Version](https://img.shields.io/pypi/v/robotframework-gevent.svg)](https://pypi.python.org/pypi/robotframework-gevent)\n![](https://raw.githubusercontent.com/eldaduzman/robotframework-gevent/main/docs/badges/coverage-badge.svg)\n![](https://raw.githubusercontent.com/eldaduzman/robotframework-gevent/main/docs/badges/pylint.svg)\n![](https://raw.githubusercontent.com/eldaduzman/robotframework-gevent/main/docs/badges/mutscore.svg)\n\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\n\n## installation:\n```bash\npip install robotframework-gevent\n```\n\n## Usage:\n\n```robotframework\n# simple-test.robot\n*** Settings ***\n\nLibrary Collections\nLibrary String\nLibrary GeventLibrary\nLibrary RequestsLibrary\n\n\n*** Test Cases ***\nTest1\n [Documentation] Simple test flow with gevent greenlets\n Log Hello World\n Create Gevent Bundle alias=alias1 # Create a bundle of coroutines\n Sleep 10s alias=alias1 # run your synchronous keyword\n # register all your keywords as coroutines to the gevent bundle\n Add Coroutine Sleep Wrapper alias=alias1\n Add Coroutine Sleep 20s alias=alias1\n Add Coroutine Sleep 10s alias=alias1\n Add Coroutine GET https://jsonplaceholder.typicode.com/posts/1 alias=alias1\n Add Coroutine Convert To Lower Case UPPER\n\n # Run your coroutines and get the values by order\n ${values} Run Coroutines alias=alias1\n Log Many @{values}\n\n # The 3rd coroutine was a request, take it's value\n ${jsonplaceholder_resp} Get From List ${values} 3\n\n # assert the returned response code to be 200\n Status Should Be 200 ${jsonplaceholder_resp}\n # assert that the returned `userId` field equals to 1\n Should Be Equal As Strings 1 ${jsonplaceholder_resp.json()['userId']}\n\n\n*** Keywords ***\nSleep Wrapper\n Sleep 1s\n\n```\n\n\nSee - [Keyword Documentation](https://eldaduzman.github.io/robotframework-gevent/GeventLibrary.html)\n### run test:\n```\n>>> robot simple-test.robot\n```\n### Possible result\n\nAfter test is completed go to `log.html`:\n\n![](https://raw.githubusercontent.com/eldaduzman/robotframework-gevent/main/docs/images/Possible-Log-File.png)\n\n\nOwing to the fact that keywords are executed asynchronously, we cannot know the order of keyword execution, so instead they are printed in a table format\n\n\n### For more examples\n\ngo to [examples](https://github.com/eldaduzman/robotframework-gevent/tree/main/examples)\n## Motivation\n\nModern software architecture is `event driven`, with many background process.\nServers are being more pro-active instead of re-active as we see in a `client server` architecture.\n\nIn order to test such systems, we need the ability to run coroutines in our test scripts.\n\nWith the power of [gevent](http://www.gevent.org/), we can run several coroutines in greenlets, so integrating them into our robotframework test script will provide super powers to our testing efforts!\n\n## Why gevent?\n\nConcurrency can be achieved in 3 different ways:\n\n1. Multiprocessing - running each task in it's own `process`.\n The cons of such an approach would be massive consumption of resources, namely CPU and memory, as this means to allocate an entire `memory heap` to each task.\n Another problem is a possible need for `Inter-Process Communication (IPC)` that might be costly.\n\n2. Multithreading - running each task in a `thread`.\n Unlike multiprocessing, now all tasks run on the same memory heap and separated by threads, which the CPU coordinates using `round-robin`.\n However, python's `Global Interpreter Lock` (GIL) prevents these threads from acting concurrently, it might perform context switching when IO operation occurs but there's no control for that.\n\n\n3. Asynchronous IO - running all tasks on a single thread, while IO operations won't block the progress of the program, while code execution is committed by an `event loop` that `selects` between attached `coroutines`.\n This is highly efficient in resources consumption when compared to multithreading and multiprocessing, but it requires some modifications to the original code.\n `Blocking` IO statements can hog the event loop and the code will not be concurrent.\n `gevent` allows programmers to write seemingly regular \"blocking\" python code, but it will enforce asynchronous IO compliance by `monkey patching`\n\n## File structure\n```\n\n| LICENSE\n| .gitignore\n| .pylintrc\n| pyproject.toml\n| poetry.lock\n| README.md\n\n| \n+---src\n| \\---GeventLibrary\n| | \\---exceptions\n| | | __init__.py\n| | \\---keywords\n| | | __init__.py\n| | | gevent_keywords.py\n| | __init__.py\n| | gevent_library.py\n| \n+---atests\n| | __init__.robot\n| | simple-test.robot\n| | \n| \\---utests\n| | __init__.py\n| | test_bundle_creation.py\n\n```\n## Code styling\n### `black` used for auto-formatting code [read](https://pypi.org/project/black/),\n### `pylint` used for code linting and pep8 compliance [read](https://pypi.org/project/pylint/),\n### `mypy` used for type hinting [read](https://pypi.org/project/mypy/),\n### `robocop` static code analyzer for robotframework [read](https://pypi.org/project/robotframework-robocop/),\n### `perflint` pylint extension for performance linting [read](https://betterprogramming.pub/use-perflint-a-performance-linter-for-python-eae8e54f1e99)\n### `cosmic-ray` Python tool for mutation testing [read](https://python.plainenglish.io/python-mutation-testing-with-cosmic-ray-4b78eb9e0676)\n\n## links\n1. [Robotframework](https://robotframework.org/)\n2. [gevent](http://www.gevent.org/)\n## Contributors \u2728\n\nThanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):\n\n<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->\n<!-- prettier-ignore-start -->\n<!-- markdownlint-disable -->\n<table>\n <tbody>\n <tr>\n <td align=\"center\"><a href=\"https://github.com/MalikMlitat\"><img src=\"https://avatars.githubusercontent.com/u/19836100?v=4?s=100\" width=\"100px;\" alt=\"MalikMlitat\"/><br /><sub><b>MalikMlitat</b></sub></a><br /><a href=\"https://github.com/eldaduzman/robotframework-gevent/commits?author=MalikMlitat\" title=\"Documentation\">\ud83d\udcd6</a></td>\n </tr>\n </tbody>\n</table>\n\n<!-- markdownlint-restore -->\n<!-- prettier-ignore-end -->\n\n<!-- ALL-CONTRIBUTORS-LIST:END -->\n\nThis project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Run keywords asynchronously with the power of gevent",
"version": "0.7.0",
"project_urls": {
"Homepage": "https://github.com/eldaduzman/robotframework-gevent",
"Repository": "https://github.com/eldaduzman/robotframework-gevent"
},
"split_keywords": [
"robotframework",
"rpa",
"automation",
"asynchronous"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "f98cc1373c03c7528774bd29bfddd4118b4215fa023ed44dff0c445a9ce35101",
"md5": "ca410cc2872094710bfc85d4ad760b26",
"sha256": "33e6675d22109aa8e8eddb71fa31335c2d84577fcdc8ba8d8797233130b16eaf"
},
"downloads": -1,
"filename": "robotframework_gevent-0.7.0.tar.gz",
"has_sig": false,
"md5_digest": "ca410cc2872094710bfc85d4ad760b26",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.8,<4.0",
"size": 10058,
"upload_time": "2023-12-14T20:28:41",
"upload_time_iso_8601": "2023-12-14T20:28:41.551408Z",
"url": "https://files.pythonhosted.org/packages/f9/8c/c1373c03c7528774bd29bfddd4118b4215fa023ed44dff0c445a9ce35101/robotframework_gevent-0.7.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2023-12-14 20:28:41",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "eldaduzman",
"github_project": "robotframework-gevent",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"tox": true,
"lcname": "robotframework-gevent"
}