appium-gesture-actions


Nameappium-gesture-actions JSON
Version 0.2.1 PyPI version JSON
download
home_pageNone
SummaryGesture actions library for Appium
upload_time2024-11-20 13:35:14
maintainerNone
docs_urlNone
authorNone
requires_python>=3.9
licenseNone
keywords actions appium drag and drop gestures pinch scroll swipe zoom
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # Appium Gestures Library

This library is to provide a number gesture/interaction functions for Appium mobile automation.  
The gestures are platform agnostic, which allows the user to provide a WebElement - or locators for both Android and iOS in the same function call.  

## Available Functions

### Swipe Gestures

- [x] up()
- [x] down()
- [x] left()
- [x] right()
- [x] next()
- [x] previous()
- [x] on_element()
- [x] element_into_view()

### Drag and Drop Gestures

- [x] drag_and_drop()

### Pinch Gestures

- [x] open()
- [x] close()

-----

[Documentation](https://tanakrit-d.github.io/appium-gesture-actions/index.html)

-----

## Compatibility

- [x] Android  
  Requires: `appium driver install uiautomator2`
- [x] iOS (unverified)  
  Requires: `appium driver install xcuitest`

## Install

```bash
pip install appium-gesture-actions
# or
uv add appium-gesture-actions
```

### Changelog

```md
## 0.2.1 (2024-11-21) 🥳

- Renamed package
- Complete re-write of functionality
- Added platform-specific code
- Added a number of new gestures
  - Drag and Drop
  - Pinch/Zoom In
  - Pinch/Zoom Out
- Added safe inserts for Swipe On Element
- Added error handling
- Added API docs
- Changed to uv for packaging
```

See full list of changes: [CHANGES.md](https://github.com/tanakrit-d/appium-gesture-actions/raw/main/CHANGES.md)

## To-do

- [x] Expand functionality to include gestures
- [x] Add cross-platform functionality
- [x] Robust error handling
- [x] Add documentation
- [x] Add examples for other gestures
- [x] Return bool for most functions
- [ ] Return WebElement on `element_into_view()`
- [ ] Completely rewrite the tests
- [ ] Allow for the specifying of values in sub-classes (such as `_max_attempts` or `CROP_FACTOR_` in `SwipeGestures`)
- [ ] Reduce minimum Python version
- [ ] Remove direct accessing of `ActionBuilder` - or not..
- [ ] Handling of different orientations
- [ ] Allow for re-initialisation of viewport calculations

## Demo and Example Usage

![Library Demo](https://github.com/tanakrit-d/appium-gesture-actions/raw/main/demo/example.gif)

```python
from appium.gesture.actions import GestureActions
from appium.gesture.enums import Direction, SeekDirection, UiSelector

class TestDemo(TestCore):
    def test_cool_stuff(self):
        # Initialise class object
        action = GestureActions(self.driver, self.options["platformName"])

        # Drag and Drop
        image_element = driver.find_element(
            by=AppiumBy.XPATH,
            value='//android.widget.ImageView[0]',
        )
        delete_element = driver.find_element(
            by=AppiumBy.XPATH,
            value='//android.widget.ImageView[1]',
        )
        action.drag_drop.drag_and_drop(image_element, delete_element)

        # Swipe
        action.swipe.up()
        action.swipe.next()

        # Pinch
        action.pinch.open(image_element)

        # Swipe on Element
        action.swipe.on_element(
            image_element,
            Direction.LEFT,
        )

        # Scroll to Element (Android - UiAutomator)
        action.swipe.element_into_view(
            value_a='new UiSelector().description("Save")',
            locator_method_a=AppiumBy.ANDROID_UIAUTOMATOR,
        )

        # Scroll to Element (Android - XPATH)
        action.swipe.element_into_view(
            value_a="//android.widget.ImageView",
            locator_method_a=AppiumBy.XPATH,
            direction=SeekDirection.UP,
        )

        # Scroll to Element (Multi-platform, single code base)
        action.swipe.element_into_view(
            value_a='//android.widget.Button[@content-desc="Save"]',
            value_i="label == 'Save'"
            locator_method_a=AppiumBy.XPATH,
            locator_method_i=AppiumBy.IOS_PREDICATE,
            direction=SeekDirection.DOWN,
        )
```

## An Explainer on Swipe Element Into View

This function (part of the [SwipeGestures](https://github.com/tanakrit-d/appium-gesture-actions/blob/ae1d229d14ced2a20169982d6284fcf7ed92c22b/src/appium/gesture/swipe.py#L45) class) has cross-platform support.  
It is achieved by using parameters with different suffixes (`_a` and `_i` for Android and iOS respectively).  

This will allow you to use a single function call for use on both platforms.

Additionally, it includes a fallback method (which is less efficient) if the element cannot be located initially.  
This is achieved by scrolling the viewport until the element is located, or the maximum number of swipes is achieved (default: 5).  
An example situation would be if an element is not yet present in the viewport and is loaded after scrolling.  
If this situation applies to you, the `direction` parameter will need to be specified.  

### A Quick Word on Perform Navigation (Full and Partial)

The fallback method will calculate the viewport size, and then define a scrollable region based on crop factors to avoid triggering the notification shade/center or multi-tasking view.  
If it cannot locate the element, it will call `_perform_navigation_partial_` until it does - or it exceeds the max attempts.  
In the event that the element *is* present but *not* in the viewport, it will calculate the distance to the element.  
Then, it will determine the correct number of full (and if necessary) partial swipes to bring the element into the center of the viewport.  

Additionally, the `if actions_partial > SWIPE_ACTION_THRESHOLD` check ensures the pixel distance is large enough to warrant an action.  
When this value is less than 50px, the swipe action will be interpreted by the OS as a double-tap.

Please look at `_fallback_scroll_to_element` if you would like to learn more.  
https://github.com/tanakrit-d/appium-gesture-actions/blob/ae1d229d14ced2a20169982d6284fcf7ed92c22b/src/appium/gesture/swipe.py#L176

## Defining a Scrollable Region

This library divides the viewport into four bounds: upper, lower, left, and right. The default values cannot be overwritten (this will change in a future release).  
Using these bounds, we then define a 'scrollable region'. We can then perform our scroll/swipe actions within this space.  
The impetus for this is to recreate scrolling/swiping behaviour more similar to a user and avoid hardcoding coordinates.  
Additionally, it avoids the automation attempting to perform actions on top of elements (such as headers or footers).  
![Viewport Diagram](https://github.com/tanakrit-d/appium-gesture-actions/raw/main/resources/viewport_scrollable_bounds.png)

## Defining Element Points

The importance of dynamically generating 'points' of an element to interact with allows us to account for re-sizing under a number of conditions (such as different devices/resolutions).

For the purpose of this library, we are only concerned with two attributes of an element: position and size.  
The element's coordinates within the viewport is considered the top-left-point.

We can then use the element size to determine where it occupies relative to the view-port position.
![Element Diagram](https://github.com/tanakrit-d/appium-gesture-actions/raw/main/resources/understanding_element_position-dimension.png)

```python
top_left_point      = element.location["x"], element.location["y"]
top_mid_point       = element.location["x"] + (element.size["width"] // 2), element.location["y"]
top_right_point     = element.location["x"] + element.size["width"], element.location["y"]

left_mid_point      = element.location["x"], element.location["y"] + (element.size["height"] // 2)
mid_point           = element.location["x"] + (element.size["width"] // 2), element.location["y"] + (element.size["height"] // 2)
right_mid_point     = element.location["x"] + element.size["width"], element.location["y"] + (element.size["height"] // 2)

bottom_left_point   = element.location["x"], element.location["y"] + element.size["height"]
bottom_mid_point    = element.location["x"] + (element.size["width"] // 2), element.location["y"] + element.size["height"]
bottom_right_point  = element.location["x"] + element.size["width"], element.location["y"] + element.size["height"]
```

Using the example element from the image, the above calculations would output as follows:  

```console
Top-Left-Point:  (20, 20)  
Top-Mid-Point:  (40, 20)  
Top-Right-Point:  (60, 20)
  
Left-Mid-Point:  (20, 30)  
Mid-Point:  (40, 30)  
Right-Mid-Point:  (60, 30)
  
Bottom-Left-Point:  (20, 40)  
Bottom-Mid-Point:  (40, 40)  
Bottom-Right-Point:  (60, 40)
```

An example of this is available here: [demo/calc_coordinates.py](https://github.com/tanakrit-d/appium-gesture-actions/blob/dc16c82864212b68ee55c79540518810e5a4ee5a/demo/calc_coordinates.py)

## Notes

### Gesture Execution, Design Decisions, and Documentation

I wrote this library based on issues I had with automating scroll-to-element functionality in my testing.  
The majority of the tutorials or documentation I have found on the subject is either sparse, low quality and SEO orientated, or relies on hardcoding coordinates for the scroll actions.  
Additionally, I did not find these to be robust enough or support different screen sizes when using the same code for different devices.  

-----

The [Appium Python Client](https://github.com/appium/python-client/blob/master/appium/webdriver/extensions/action_helpers.py) implementation relies on `ActionChains`, and the `.swipe()` and `.scroll()` functions require either both elements to be directly provided - or the x and y coordinates to be specified.

In this library, `Drag and Drop` and `Pinch` call the Selenium JavaScript `.execute_script()` function - which is more reliable and robust than using `ActionChains`.  

Initially, a prototype implementation using `ActionChains` was attempted, however the performance was poor and buggy since Selenium implements a number of logical checks when executing it.  
I found it threw numerous exceptions due to some form of built-in element detection.  

`Swipe` contains a combination of `.execute_script()` and `ActionChains`.  

For Android, the preferred method is `AppiumBy.ANDROID_UIAUTOMATOR` which uses `new UiScrollable()` as it is incredibly quick and reliable.  
It will use `ActionChains` if any other locator method is called.  

For iOS, it will initially attempt to use `.execute_script()`, and then fallback to `ActionChains` if the element cannot be located.

I would recommend reading the following documentation which helped inform the design and implementation.  

- [Appium XCUITest Driver](https://appium.github.io/appium-xcuitest-driver/latest/reference/execute-methods/)
  - [NSPredicate Cheatsheet](http://realm.io.s3-website-us-east-1.amazonaws.com/assets/downloads/NSPredicateCheatsheet.pdf)
- [Appium UiAutomator2 Driver](https://github.com/appium/appium-uiautomator2-driver/blob/master/docs/android-mobile-gestures.md)
  - [Android Developer Reference: UiScrollable](https://developer.android.com/reference/androidx/test/uiautomator/UiScrollable)
  - [Android Developer Reference: UiSelector](https://developer.android.com/reference/androidx/test/uiautomator/UiSelector)
- [Appium Swipe Tutorial](https://appium.github.io/appium.io/docs/en/writing-running-appium/tutorial/swipe-tutorial/)

### Android

If you would like to see the pointer interactions and coordinates, this can be enabled on a device level in `Settings > Developer Options > Pointer location`

## Contributing

Contributions or feedback is welcome! Please feel free to submit a Pull Request.  
As this is my first Python package I am open to any and all suggestions :^)

## Support

If you encounter any issues or have questions, please file an issue on the GitHub repository.

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "appium-gesture-actions",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.9",
    "maintainer_email": null,
    "keywords": "actions, appium, drag and drop, gestures, pinch, scroll, swipe, zoom",
    "author": null,
    "author_email": null,
    "download_url": "https://files.pythonhosted.org/packages/e9/4d/f3f6b30ab1a6c46f3fb78ad31536e1fb1bafb552d264ead60166dc7cec6b/appium_gesture_actions-0.2.1.tar.gz",
    "platform": null,
    "description": "# Appium Gestures Library\n\nThis library is to provide a number gesture/interaction functions for Appium mobile automation.  \nThe gestures are platform agnostic, which allows the user to provide a WebElement - or locators for both Android and iOS in the same function call.  \n\n## Available Functions\n\n### Swipe Gestures\n\n- [x] up()\n- [x] down()\n- [x] left()\n- [x] right()\n- [x] next()\n- [x] previous()\n- [x] on_element()\n- [x] element_into_view()\n\n### Drag and Drop Gestures\n\n- [x] drag_and_drop()\n\n### Pinch Gestures\n\n- [x] open()\n- [x] close()\n\n-----\n\n[Documentation](https://tanakrit-d.github.io/appium-gesture-actions/index.html)\n\n-----\n\n## Compatibility\n\n- [x] Android  \n  Requires: `appium driver install uiautomator2`\n- [x] iOS (unverified)  \n  Requires: `appium driver install xcuitest`\n\n## Install\n\n```bash\npip install appium-gesture-actions\n# or\nuv add appium-gesture-actions\n```\n\n### Changelog\n\n```md\n## 0.2.1 (2024-11-21) \ud83e\udd73\n\n- Renamed package\n- Complete re-write of functionality\n- Added platform-specific code\n- Added a number of new gestures\n  - Drag and Drop\n  - Pinch/Zoom In\n  - Pinch/Zoom Out\n- Added safe inserts for Swipe On Element\n- Added error handling\n- Added API docs\n- Changed to uv for packaging\n```\n\nSee full list of changes: [CHANGES.md](https://github.com/tanakrit-d/appium-gesture-actions/raw/main/CHANGES.md)\n\n## To-do\n\n- [x] Expand functionality to include gestures\n- [x] Add cross-platform functionality\n- [x] Robust error handling\n- [x] Add documentation\n- [x] Add examples for other gestures\n- [x] Return bool for most functions\n- [ ] Return WebElement on `element_into_view()`\n- [ ] Completely rewrite the tests\n- [ ] Allow for the specifying of values in sub-classes (such as `_max_attempts` or `CROP_FACTOR_` in `SwipeGestures`)\n- [ ] Reduce minimum Python version\n- [ ] Remove direct accessing of `ActionBuilder` - or not..\n- [ ] Handling of different orientations\n- [ ] Allow for re-initialisation of viewport calculations\n\n## Demo and Example Usage\n\n![Library Demo](https://github.com/tanakrit-d/appium-gesture-actions/raw/main/demo/example.gif)\n\n```python\nfrom appium.gesture.actions import GestureActions\nfrom appium.gesture.enums import Direction, SeekDirection, UiSelector\n\nclass TestDemo(TestCore):\n    def test_cool_stuff(self):\n        # Initialise class object\n        action = GestureActions(self.driver, self.options[\"platformName\"])\n\n        # Drag and Drop\n        image_element = driver.find_element(\n            by=AppiumBy.XPATH,\n            value='//android.widget.ImageView[0]',\n        )\n        delete_element = driver.find_element(\n            by=AppiumBy.XPATH,\n            value='//android.widget.ImageView[1]',\n        )\n        action.drag_drop.drag_and_drop(image_element, delete_element)\n\n        # Swipe\n        action.swipe.up()\n        action.swipe.next()\n\n        # Pinch\n        action.pinch.open(image_element)\n\n        # Swipe on Element\n        action.swipe.on_element(\n            image_element,\n            Direction.LEFT,\n        )\n\n        # Scroll to Element (Android - UiAutomator)\n        action.swipe.element_into_view(\n            value_a='new UiSelector().description(\"Save\")',\n            locator_method_a=AppiumBy.ANDROID_UIAUTOMATOR,\n        )\n\n        # Scroll to Element (Android - XPATH)\n        action.swipe.element_into_view(\n            value_a=\"//android.widget.ImageView\",\n            locator_method_a=AppiumBy.XPATH,\n            direction=SeekDirection.UP,\n        )\n\n        # Scroll to Element (Multi-platform, single code base)\n        action.swipe.element_into_view(\n            value_a='//android.widget.Button[@content-desc=\"Save\"]',\n            value_i=\"label == 'Save'\"\n            locator_method_a=AppiumBy.XPATH,\n            locator_method_i=AppiumBy.IOS_PREDICATE,\n            direction=SeekDirection.DOWN,\n        )\n```\n\n## An Explainer on Swipe Element Into View\n\nThis function (part of the [SwipeGestures](https://github.com/tanakrit-d/appium-gesture-actions/blob/ae1d229d14ced2a20169982d6284fcf7ed92c22b/src/appium/gesture/swipe.py#L45) class) has cross-platform support.  \nIt is achieved by using parameters with different suffixes (`_a` and `_i` for Android and iOS respectively).  \n\nThis will allow you to use a single function call for use on both platforms.\n\nAdditionally, it includes a fallback method (which is less efficient) if the element cannot be located initially.  \nThis is achieved by scrolling the viewport until the element is located, or the maximum number of swipes is achieved (default: 5).  \nAn example situation would be if an element is not yet present in the viewport and is loaded after scrolling.  \nIf this situation applies to you, the `direction` parameter will need to be specified.  \n\n### A Quick Word on Perform Navigation (Full and Partial)\n\nThe fallback method will calculate the viewport size, and then define a scrollable region based on crop factors to avoid triggering the notification shade/center or multi-tasking view.  \nIf it cannot locate the element, it will call `_perform_navigation_partial_` until it does - or it exceeds the max attempts.  \nIn the event that the element *is* present but *not* in the viewport, it will calculate the distance to the element.  \nThen, it will determine the correct number of full (and if necessary) partial swipes to bring the element into the center of the viewport.  \n\nAdditionally, the `if actions_partial > SWIPE_ACTION_THRESHOLD` check ensures the pixel distance is large enough to warrant an action.  \nWhen this value is less than 50px, the swipe action will be interpreted by the OS as a double-tap.\n\nPlease look at `_fallback_scroll_to_element` if you would like to learn more.  \nhttps://github.com/tanakrit-d/appium-gesture-actions/blob/ae1d229d14ced2a20169982d6284fcf7ed92c22b/src/appium/gesture/swipe.py#L176\n\n## Defining a Scrollable Region\n\nThis library divides the viewport into four bounds: upper, lower, left, and right. The default values cannot be overwritten (this will change in a future release).  \nUsing these bounds, we then define a 'scrollable region'. We can then perform our scroll/swipe actions within this space.  \nThe impetus for this is to recreate scrolling/swiping behaviour more similar to a user and avoid hardcoding coordinates.  \nAdditionally, it avoids the automation attempting to perform actions on top of elements (such as headers or footers).  \n![Viewport Diagram](https://github.com/tanakrit-d/appium-gesture-actions/raw/main/resources/viewport_scrollable_bounds.png)\n\n## Defining Element Points\n\nThe importance of dynamically generating 'points' of an element to interact with allows us to account for re-sizing under a number of conditions (such as different devices/resolutions).\n\nFor the purpose of this library, we are only concerned with two attributes of an element: position and size.  \nThe element's coordinates within the viewport is considered the top-left-point.\n\nWe can then use the element size to determine where it occupies relative to the view-port position.\n![Element Diagram](https://github.com/tanakrit-d/appium-gesture-actions/raw/main/resources/understanding_element_position-dimension.png)\n\n```python\ntop_left_point      = element.location[\"x\"], element.location[\"y\"]\ntop_mid_point       = element.location[\"x\"] + (element.size[\"width\"] // 2), element.location[\"y\"]\ntop_right_point     = element.location[\"x\"] + element.size[\"width\"], element.location[\"y\"]\n\nleft_mid_point      = element.location[\"x\"], element.location[\"y\"] + (element.size[\"height\"] // 2)\nmid_point           = element.location[\"x\"] + (element.size[\"width\"] // 2), element.location[\"y\"] + (element.size[\"height\"] // 2)\nright_mid_point     = element.location[\"x\"] + element.size[\"width\"], element.location[\"y\"] + (element.size[\"height\"] // 2)\n\nbottom_left_point   = element.location[\"x\"], element.location[\"y\"] + element.size[\"height\"]\nbottom_mid_point    = element.location[\"x\"] + (element.size[\"width\"] // 2), element.location[\"y\"] + element.size[\"height\"]\nbottom_right_point  = element.location[\"x\"] + element.size[\"width\"], element.location[\"y\"] + element.size[\"height\"]\n```\n\nUsing the example element from the image, the above calculations would output as follows:  \n\n```console\nTop-Left-Point:  (20, 20)  \nTop-Mid-Point:  (40, 20)  \nTop-Right-Point:  (60, 20)\n  \nLeft-Mid-Point:  (20, 30)  \nMid-Point:  (40, 30)  \nRight-Mid-Point:  (60, 30)\n  \nBottom-Left-Point:  (20, 40)  \nBottom-Mid-Point:  (40, 40)  \nBottom-Right-Point:  (60, 40)\n```\n\nAn example of this is available here: [demo/calc_coordinates.py](https://github.com/tanakrit-d/appium-gesture-actions/blob/dc16c82864212b68ee55c79540518810e5a4ee5a/demo/calc_coordinates.py)\n\n## Notes\n\n### Gesture Execution, Design Decisions, and Documentation\n\nI wrote this library based on issues I had with automating scroll-to-element functionality in my testing.  \nThe majority of the tutorials or documentation I have found on the subject is either sparse, low quality and SEO orientated, or relies on hardcoding coordinates for the scroll actions.  \nAdditionally, I did not find these to be robust enough or support different screen sizes when using the same code for different devices.  \n\n-----\n\nThe [Appium Python Client](https://github.com/appium/python-client/blob/master/appium/webdriver/extensions/action_helpers.py) implementation relies on `ActionChains`, and the `.swipe()` and `.scroll()` functions require either both elements to be directly provided - or the x and y coordinates to be specified.\n\nIn this library, `Drag and Drop` and `Pinch` call the Selenium JavaScript `.execute_script()` function - which is more reliable and robust than using `ActionChains`.  \n\nInitially, a prototype implementation using `ActionChains` was attempted, however the performance was poor and buggy since Selenium implements a number of logical checks when executing it.  \nI found it threw numerous exceptions due to some form of built-in element detection.  \n\n`Swipe` contains a combination of `.execute_script()` and `ActionChains`.  \n\nFor Android, the preferred method is `AppiumBy.ANDROID_UIAUTOMATOR` which uses `new UiScrollable()` as it is incredibly quick and reliable.  \nIt will use `ActionChains` if any other locator method is called.  \n\nFor iOS, it will initially attempt to use `.execute_script()`, and then fallback to `ActionChains` if the element cannot be located.\n\nI would recommend reading the following documentation which helped inform the design and implementation.  \n\n- [Appium XCUITest Driver](https://appium.github.io/appium-xcuitest-driver/latest/reference/execute-methods/)\n  - [NSPredicate Cheatsheet](http://realm.io.s3-website-us-east-1.amazonaws.com/assets/downloads/NSPredicateCheatsheet.pdf)\n- [Appium UiAutomator2 Driver](https://github.com/appium/appium-uiautomator2-driver/blob/master/docs/android-mobile-gestures.md)\n  - [Android Developer Reference: UiScrollable](https://developer.android.com/reference/androidx/test/uiautomator/UiScrollable)\n  - [Android Developer Reference: UiSelector](https://developer.android.com/reference/androidx/test/uiautomator/UiSelector)\n- [Appium Swipe Tutorial](https://appium.github.io/appium.io/docs/en/writing-running-appium/tutorial/swipe-tutorial/)\n\n### Android\n\nIf you would like to see the pointer interactions and coordinates, this can be enabled on a device level in `Settings > Developer Options > Pointer location`\n\n## Contributing\n\nContributions or feedback is welcome! Please feel free to submit a Pull Request.  \nAs this is my first Python package I am open to any and all suggestions :^)\n\n## Support\n\nIf you encounter any issues or have questions, please file an issue on the GitHub repository.\n",
    "bugtrack_url": null,
    "license": null,
    "summary": "Gesture actions library for Appium",
    "version": "0.2.1",
    "project_urls": {
        "homepage": "https://github.com/tanakrit-d/appium-gesture-actions",
        "issues": "https://github.com/tanakrit-d/appium-gesture-actions/issues",
        "repository": "https://github.com/tanakrit-d/appium-gesture-actions"
    },
    "split_keywords": [
        "actions",
        " appium",
        " drag and drop",
        " gestures",
        " pinch",
        " scroll",
        " swipe",
        " zoom"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "2ef308adbedba2f212ecbf2d5dde78f53efcb0b8f68a03d99cb10b5ad96acdb3",
                "md5": "44a8cad608b05768e2bf6288ff98c8fd",
                "sha256": "54d6c7bfbb872d7e45dde328df8fcaa257c361b4978ec22c9d94f3e538f87d6e"
            },
            "downloads": -1,
            "filename": "appium_gesture_actions-0.2.1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "44a8cad608b05768e2bf6288ff98c8fd",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.9",
            "size": 6198,
            "upload_time": "2024-11-20T13:35:13",
            "upload_time_iso_8601": "2024-11-20T13:35:13.771538Z",
            "url": "https://files.pythonhosted.org/packages/2e/f3/08adbedba2f212ecbf2d5dde78f53efcb0b8f68a03d99cb10b5ad96acdb3/appium_gesture_actions-0.2.1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "e94df3f6b30ab1a6c46f3fb78ad31536e1fb1bafb552d264ead60166dc7cec6b",
                "md5": "1c2e14f7690c261fbe35edc20a5c6d8e",
                "sha256": "acef2542c89f558f5a022c8e0d60b0e9e0d88826dbc1a335e7fc59e191b7f083"
            },
            "downloads": -1,
            "filename": "appium_gesture_actions-0.2.1.tar.gz",
            "has_sig": false,
            "md5_digest": "1c2e14f7690c261fbe35edc20a5c6d8e",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.9",
            "size": 14020,
            "upload_time": "2024-11-20T13:35:14",
            "upload_time_iso_8601": "2024-11-20T13:35:14.851908Z",
            "url": "https://files.pythonhosted.org/packages/e9/4d/f3f6b30ab1a6c46f3fb78ad31536e1fb1bafb552d264ead60166dc7cec6b/appium_gesture_actions-0.2.1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-11-20 13:35:14",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "tanakrit-d",
    "github_project": "appium-gesture-actions",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "requirements": [],
    "lcname": "appium-gesture-actions"
}
        
Elapsed time: 0.46619s