pyJPI 0.1.13__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of pyJPI might be problematic. Click here for more details.

pyjpi-0.1.13/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2020 by @CoMPaTech
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
pyjpi-0.1.13/PKG-INFO ADDED
@@ -0,0 +1,145 @@
1
+ Metadata-Version: 2.4
2
+ Name: pyJPI
3
+ Version: 0.1.13
4
+ Summary: A library to access Android devices which run JPI
5
+ Author-email: Pierre Wieser <p.wieser@trychlos.org>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/trychlos/pyjpi
8
+ Project-URL: Issues, https://github.com/trychlos/pyjpi/issues
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Operating System :: OS Independent
11
+ Requires-Python: >=3.10
12
+ Description-Content-Type: text/markdown
13
+ License-File: LICENSE
14
+ Dynamic: license-file
15
+
16
+ # pyJPI - An asynchronous Python module to interact with Android devices running JPI
17
+
18
+ [![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-green.svg)](https://github.com/trychlos/pyjpi)
19
+ [![Latest release](https://github.com/trychlos/pyjpi/workflows/Latest%20release/badge.svg)](https://github.com/trychlos/pyjpi/actions)
20
+ [![Newest commit](https://github.com/trychlos/pyjpi/workflows/Latest%20commit/badge.svg)](https://github.com/trychlos/pyjpi/actions)
21
+
22
+ [![PyPI version fury.io](https://badge.fury.io/py/pyjpi.svg)](https://pypi.python.org/pypi/pyjpi/)
23
+
24
+ <!--
25
+ [![CodeRabbit.ai is Awesome](https://img.shields.io/badge/AI-orange?label=CodeRabbit&color=orange&link=https%3A%2F%2Fcoderabbit.ai)](https://coderabbit.ai)
26
+ [![renovate maintained](https://img.shields.io/badge/maintained%20with-renovate-blue?logo=renovatebot)](https://github.com/compatech/python-airos/issues/8)
27
+
28
+ [![CodeFactor](https://www.codefactor.io/repository/github/compatech/python-airos/badge)](https://www.codefactor.io/repository/github/plugwise/python-airos)
29
+ [![codecov](https://codecov.io/gh/compatech/python-airos/graph/badge.svg?token=WI5K2IZWNS)](https://codecov.io/gh/compatech/python-airos)
30
+
31
+ [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=CoMPaTech_python-airos&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=CoMPaTech_python-airos)
32
+ [![Technical Debt](https://sonarcloud.io/api/project_badges/measure?project=CoMPaTech_python-airos&metric=sqale_index)](https://sonarcloud.io/summary/new_code?id=CoMPaTech_python-airos)
33
+ [![Code Smells](https://sonarcloud.io/api/project_badges/measure?project=CoMPaTech_python-airos&metric=code_smells)](https://sonarcloud.io/summary/new_code?id=CoMPaTech_python-airos)
34
+ -->
35
+
36
+ ## Overview
37
+
38
+ `pyJPI` is an asynchronous Python library designed to programmatically interact with Android devices running JPI.
39
+
40
+ This library is a key component for a core integration with [Home Assistant](https://www.home-assistant.io).
41
+
42
+ More details on the integration can be found on the [JPI](https://www.home-assistant.io/integrations/jpi/) page.
43
+
44
+ ## Features
45
+
46
+ - Asynchronous operations are built with ``aiohttp` for non-blocking I/O, which is perfect for integrations and background tasks.
47
+ - API: `battInfo`
48
+ - API: `get`
49
+ - API: `getDeviceName`
50
+
51
+ ## Installation
52
+
53
+ You can install `pyJPI` from PyPI using pip:
54
+
55
+ ```Bash
56
+ pip install pyjpi
57
+ ```
58
+
59
+ ## Usage
60
+
61
+ Here is a more detailed example of how to use the library to connect, fetch status, and perform an action on an Android device running JPI.
62
+
63
+ ```Python
64
+ import aiohttp
65
+ from pyjpi import jpiInit
66
+
67
+ async def main():
68
+ """Main function to demonstrate library usage."""
69
+ # Create an aiohttp session with SSL verification disabled.
70
+ # Be cautious with this setting; it's useful for self-signed certificates
71
+ # but not recommended for production environments without proper validation.
72
+ session = aiohttp.ClientSession( connector=aiohttp.TCPConnector( verify_ssl=False ))
73
+
74
+ # Get a handle on the pyJPI library.
75
+ handle = await jpiInit( session )
76
+
77
+ # Have an URL somewhere.
78
+ url = "http://myhost.example.com:8080"
79
+
80
+ # Then just has to call the library functions.
81
+ try:
82
+ res = await handle.get( url )
83
+ # returns a dict { resp: ClientResponse, text: str } or False
84
+ res = await handle.getDeviceName( url )
85
+ # returns the device name as set by the manufacturer (a single string) or False
86
+ res = await handle.battInfo( url )
87
+ # returns a dict { level: integer, charging: bool, power: bool }
88
+
89
+
90
+ if __name__ == "__main__":
91
+ main()
92
+ ```
93
+
94
+ ## Available functions
95
+
96
+ - `async jpiInit( session: aiohttp.ClientSession ) -> JPILibrary`:
97
+
98
+ Initializes the library.
99
+
100
+ Returns a handle on it.
101
+
102
+ ## Available classes
103
+
104
+ - `JPILibrary`:
105
+
106
+ The class which manages the devices accesses.
107
+
108
+ ## Available `JPILibrary` methods
109
+
110
+ - `async get( url: str) -> dict`:
111
+
112
+ Runs a HTTP GET method on the specified URL.
113
+
114
+ Returns a dict with:
115
+
116
+ ```Python
117
+ resp: the `aiohttp.ClientResponse`
118
+ text: the resp.text() content
119
+ ```
120
+
121
+ - `async getDeviceName( url: str) -> str`:
122
+
123
+ Runs a HTTP GET method on f"{url}?action=getDeviceName" url.
124
+
125
+ Returns a string which contains the device name as set by the manufacturer.
126
+
127
+ - `async battInfo( url: str) -> dict`:
128
+
129
+ Runs a HTTP GET method on on f"{url}?action=battInfo" url.
130
+
131
+ Returns a dict with:
132
+
133
+ ```Python
134
+ level: an integer with the current battery level in %
135
+ charging: a boolean which says if the battery is currently charging
136
+ power: a boolean which says if the power is on on the device.
137
+ ```
138
+
139
+ ## Contributing
140
+
141
+ We welcome contributions as well as additional codeowners to `pyjpi`.
142
+
143
+ ## Issues & help
144
+
145
+ In case of support or error, please report your issue request to our [Issues tracker](https://github.com/trychlos/pyjpi/issues).
pyjpi-0.1.13/README.md ADDED
@@ -0,0 +1,130 @@
1
+ # pyJPI - An asynchronous Python module to interact with Android devices running JPI
2
+
3
+ [![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-green.svg)](https://github.com/trychlos/pyjpi)
4
+ [![Latest release](https://github.com/trychlos/pyjpi/workflows/Latest%20release/badge.svg)](https://github.com/trychlos/pyjpi/actions)
5
+ [![Newest commit](https://github.com/trychlos/pyjpi/workflows/Latest%20commit/badge.svg)](https://github.com/trychlos/pyjpi/actions)
6
+
7
+ [![PyPI version fury.io](https://badge.fury.io/py/pyjpi.svg)](https://pypi.python.org/pypi/pyjpi/)
8
+
9
+ <!--
10
+ [![CodeRabbit.ai is Awesome](https://img.shields.io/badge/AI-orange?label=CodeRabbit&color=orange&link=https%3A%2F%2Fcoderabbit.ai)](https://coderabbit.ai)
11
+ [![renovate maintained](https://img.shields.io/badge/maintained%20with-renovate-blue?logo=renovatebot)](https://github.com/compatech/python-airos/issues/8)
12
+
13
+ [![CodeFactor](https://www.codefactor.io/repository/github/compatech/python-airos/badge)](https://www.codefactor.io/repository/github/plugwise/python-airos)
14
+ [![codecov](https://codecov.io/gh/compatech/python-airos/graph/badge.svg?token=WI5K2IZWNS)](https://codecov.io/gh/compatech/python-airos)
15
+
16
+ [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=CoMPaTech_python-airos&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=CoMPaTech_python-airos)
17
+ [![Technical Debt](https://sonarcloud.io/api/project_badges/measure?project=CoMPaTech_python-airos&metric=sqale_index)](https://sonarcloud.io/summary/new_code?id=CoMPaTech_python-airos)
18
+ [![Code Smells](https://sonarcloud.io/api/project_badges/measure?project=CoMPaTech_python-airos&metric=code_smells)](https://sonarcloud.io/summary/new_code?id=CoMPaTech_python-airos)
19
+ -->
20
+
21
+ ## Overview
22
+
23
+ `pyJPI` is an asynchronous Python library designed to programmatically interact with Android devices running JPI.
24
+
25
+ This library is a key component for a core integration with [Home Assistant](https://www.home-assistant.io).
26
+
27
+ More details on the integration can be found on the [JPI](https://www.home-assistant.io/integrations/jpi/) page.
28
+
29
+ ## Features
30
+
31
+ - Asynchronous operations are built with ``aiohttp` for non-blocking I/O, which is perfect for integrations and background tasks.
32
+ - API: `battInfo`
33
+ - API: `get`
34
+ - API: `getDeviceName`
35
+
36
+ ## Installation
37
+
38
+ You can install `pyJPI` from PyPI using pip:
39
+
40
+ ```Bash
41
+ pip install pyjpi
42
+ ```
43
+
44
+ ## Usage
45
+
46
+ Here is a more detailed example of how to use the library to connect, fetch status, and perform an action on an Android device running JPI.
47
+
48
+ ```Python
49
+ import aiohttp
50
+ from pyjpi import jpiInit
51
+
52
+ async def main():
53
+ """Main function to demonstrate library usage."""
54
+ # Create an aiohttp session with SSL verification disabled.
55
+ # Be cautious with this setting; it's useful for self-signed certificates
56
+ # but not recommended for production environments without proper validation.
57
+ session = aiohttp.ClientSession( connector=aiohttp.TCPConnector( verify_ssl=False ))
58
+
59
+ # Get a handle on the pyJPI library.
60
+ handle = await jpiInit( session )
61
+
62
+ # Have an URL somewhere.
63
+ url = "http://myhost.example.com:8080"
64
+
65
+ # Then just has to call the library functions.
66
+ try:
67
+ res = await handle.get( url )
68
+ # returns a dict { resp: ClientResponse, text: str } or False
69
+ res = await handle.getDeviceName( url )
70
+ # returns the device name as set by the manufacturer (a single string) or False
71
+ res = await handle.battInfo( url )
72
+ # returns a dict { level: integer, charging: bool, power: bool }
73
+
74
+
75
+ if __name__ == "__main__":
76
+ main()
77
+ ```
78
+
79
+ ## Available functions
80
+
81
+ - `async jpiInit( session: aiohttp.ClientSession ) -> JPILibrary`:
82
+
83
+ Initializes the library.
84
+
85
+ Returns a handle on it.
86
+
87
+ ## Available classes
88
+
89
+ - `JPILibrary`:
90
+
91
+ The class which manages the devices accesses.
92
+
93
+ ## Available `JPILibrary` methods
94
+
95
+ - `async get( url: str) -> dict`:
96
+
97
+ Runs a HTTP GET method on the specified URL.
98
+
99
+ Returns a dict with:
100
+
101
+ ```Python
102
+ resp: the `aiohttp.ClientResponse`
103
+ text: the resp.text() content
104
+ ```
105
+
106
+ - `async getDeviceName( url: str) -> str`:
107
+
108
+ Runs a HTTP GET method on f"{url}?action=getDeviceName" url.
109
+
110
+ Returns a string which contains the device name as set by the manufacturer.
111
+
112
+ - `async battInfo( url: str) -> dict`:
113
+
114
+ Runs a HTTP GET method on on f"{url}?action=battInfo" url.
115
+
116
+ Returns a dict with:
117
+
118
+ ```Python
119
+ level: an integer with the current battery level in %
120
+ charging: a boolean which says if the battery is currently charging
121
+ power: a boolean which says if the power is on on the device.
122
+ ```
123
+
124
+ ## Contributing
125
+
126
+ We welcome contributions as well as additional codeowners to `pyjpi`.
127
+
128
+ ## Issues & help
129
+
130
+ In case of support or error, please report your issue request to our [Issues tracker](https://github.com/trychlos/pyjpi/issues).
@@ -0,0 +1,145 @@
1
+ Metadata-Version: 2.4
2
+ Name: pyJPI
3
+ Version: 0.1.13
4
+ Summary: A library to access Android devices which run JPI
5
+ Author-email: Pierre Wieser <p.wieser@trychlos.org>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/trychlos/pyjpi
8
+ Project-URL: Issues, https://github.com/trychlos/pyjpi/issues
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Operating System :: OS Independent
11
+ Requires-Python: >=3.10
12
+ Description-Content-Type: text/markdown
13
+ License-File: LICENSE
14
+ Dynamic: license-file
15
+
16
+ # pyJPI - An asynchronous Python module to interact with Android devices running JPI
17
+
18
+ [![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-green.svg)](https://github.com/trychlos/pyjpi)
19
+ [![Latest release](https://github.com/trychlos/pyjpi/workflows/Latest%20release/badge.svg)](https://github.com/trychlos/pyjpi/actions)
20
+ [![Newest commit](https://github.com/trychlos/pyjpi/workflows/Latest%20commit/badge.svg)](https://github.com/trychlos/pyjpi/actions)
21
+
22
+ [![PyPI version fury.io](https://badge.fury.io/py/pyjpi.svg)](https://pypi.python.org/pypi/pyjpi/)
23
+
24
+ <!--
25
+ [![CodeRabbit.ai is Awesome](https://img.shields.io/badge/AI-orange?label=CodeRabbit&color=orange&link=https%3A%2F%2Fcoderabbit.ai)](https://coderabbit.ai)
26
+ [![renovate maintained](https://img.shields.io/badge/maintained%20with-renovate-blue?logo=renovatebot)](https://github.com/compatech/python-airos/issues/8)
27
+
28
+ [![CodeFactor](https://www.codefactor.io/repository/github/compatech/python-airos/badge)](https://www.codefactor.io/repository/github/plugwise/python-airos)
29
+ [![codecov](https://codecov.io/gh/compatech/python-airos/graph/badge.svg?token=WI5K2IZWNS)](https://codecov.io/gh/compatech/python-airos)
30
+
31
+ [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=CoMPaTech_python-airos&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=CoMPaTech_python-airos)
32
+ [![Technical Debt](https://sonarcloud.io/api/project_badges/measure?project=CoMPaTech_python-airos&metric=sqale_index)](https://sonarcloud.io/summary/new_code?id=CoMPaTech_python-airos)
33
+ [![Code Smells](https://sonarcloud.io/api/project_badges/measure?project=CoMPaTech_python-airos&metric=code_smells)](https://sonarcloud.io/summary/new_code?id=CoMPaTech_python-airos)
34
+ -->
35
+
36
+ ## Overview
37
+
38
+ `pyJPI` is an asynchronous Python library designed to programmatically interact with Android devices running JPI.
39
+
40
+ This library is a key component for a core integration with [Home Assistant](https://www.home-assistant.io).
41
+
42
+ More details on the integration can be found on the [JPI](https://www.home-assistant.io/integrations/jpi/) page.
43
+
44
+ ## Features
45
+
46
+ - Asynchronous operations are built with ``aiohttp` for non-blocking I/O, which is perfect for integrations and background tasks.
47
+ - API: `battInfo`
48
+ - API: `get`
49
+ - API: `getDeviceName`
50
+
51
+ ## Installation
52
+
53
+ You can install `pyJPI` from PyPI using pip:
54
+
55
+ ```Bash
56
+ pip install pyjpi
57
+ ```
58
+
59
+ ## Usage
60
+
61
+ Here is a more detailed example of how to use the library to connect, fetch status, and perform an action on an Android device running JPI.
62
+
63
+ ```Python
64
+ import aiohttp
65
+ from pyjpi import jpiInit
66
+
67
+ async def main():
68
+ """Main function to demonstrate library usage."""
69
+ # Create an aiohttp session with SSL verification disabled.
70
+ # Be cautious with this setting; it's useful for self-signed certificates
71
+ # but not recommended for production environments without proper validation.
72
+ session = aiohttp.ClientSession( connector=aiohttp.TCPConnector( verify_ssl=False ))
73
+
74
+ # Get a handle on the pyJPI library.
75
+ handle = await jpiInit( session )
76
+
77
+ # Have an URL somewhere.
78
+ url = "http://myhost.example.com:8080"
79
+
80
+ # Then just has to call the library functions.
81
+ try:
82
+ res = await handle.get( url )
83
+ # returns a dict { resp: ClientResponse, text: str } or False
84
+ res = await handle.getDeviceName( url )
85
+ # returns the device name as set by the manufacturer (a single string) or False
86
+ res = await handle.battInfo( url )
87
+ # returns a dict { level: integer, charging: bool, power: bool }
88
+
89
+
90
+ if __name__ == "__main__":
91
+ main()
92
+ ```
93
+
94
+ ## Available functions
95
+
96
+ - `async jpiInit( session: aiohttp.ClientSession ) -> JPILibrary`:
97
+
98
+ Initializes the library.
99
+
100
+ Returns a handle on it.
101
+
102
+ ## Available classes
103
+
104
+ - `JPILibrary`:
105
+
106
+ The class which manages the devices accesses.
107
+
108
+ ## Available `JPILibrary` methods
109
+
110
+ - `async get( url: str) -> dict`:
111
+
112
+ Runs a HTTP GET method on the specified URL.
113
+
114
+ Returns a dict with:
115
+
116
+ ```Python
117
+ resp: the `aiohttp.ClientResponse`
118
+ text: the resp.text() content
119
+ ```
120
+
121
+ - `async getDeviceName( url: str) -> str`:
122
+
123
+ Runs a HTTP GET method on f"{url}?action=getDeviceName" url.
124
+
125
+ Returns a string which contains the device name as set by the manufacturer.
126
+
127
+ - `async battInfo( url: str) -> dict`:
128
+
129
+ Runs a HTTP GET method on on f"{url}?action=battInfo" url.
130
+
131
+ Returns a dict with:
132
+
133
+ ```Python
134
+ level: an integer with the current battery level in %
135
+ charging: a boolean which says if the battery is currently charging
136
+ power: a boolean which says if the power is on on the device.
137
+ ```
138
+
139
+ ## Contributing
140
+
141
+ We welcome contributions as well as additional codeowners to `pyjpi`.
142
+
143
+ ## Issues & help
144
+
145
+ In case of support or error, please report your issue request to our [Issues tracker](https://github.com/trychlos/pyjpi/issues).
@@ -0,0 +1,13 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ pyJPI.egg-info/PKG-INFO
5
+ pyJPI.egg-info/SOURCES.txt
6
+ pyJPI.egg-info/dependency_links.txt
7
+ pyJPI.egg-info/top_level.txt
8
+ pyjpi/__init__.py
9
+ pyjpi/library.py
10
+ tests/test_jpi_init.py
11
+ tests/test_lib_battinfo.py
12
+ tests/test_lib_get.py
13
+ tests/test_lib_getdevicename.py
@@ -0,0 +1 @@
1
+ pyjpi
@@ -0,0 +1,28 @@
1
+ """JPI Library."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import asyncio
6
+ from importlib.metadata import PackageNotFoundError, version
7
+
8
+ import aiohttp
9
+
10
+ from .library import JPILibrary
11
+
12
+
13
+ async def _get_version() -> str:
14
+ """Returns the version of the package (hopefully)."""
15
+ try:
16
+ return await asyncio.to_thread(version, "pyJPI")
17
+ except PackageNotFoundError:
18
+ return "0+local"
19
+
20
+
21
+ async def jpiInit(session: aiohttp.ClientSession) -> JPILibrary:
22
+ """
23
+ Initialize the library.
24
+ Returns an object with an initialized HTTP session.
25
+ This same object will have to be provided later on each called method.
26
+ """
27
+ package_version = await _get_version()
28
+ return JPILibrary(session, package_version)
@@ -0,0 +1,96 @@
1
+ """
2
+ A library to interact with JPI devices.
3
+ Rationale: according to HomeAssistant documentation, the integration MUST not interact directly with the physical devices.
4
+ Instead, it MUST use a library published on pyPI repository.
5
+ This file is so the first version of such the interaction library.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from datetime import datetime
11
+ import logging
12
+
13
+ from aiohttp.web import HTTPError
14
+
15
+
16
+ class JPILibrary:
17
+ """Class for the pyJPI library."""
18
+
19
+ def __init__(self, session, version):
20
+ """Initialize a HTTP session."""
21
+ self._session = session
22
+ self._initialized = datetime.now()
23
+ self._log = logging.getLogger(__name__)
24
+ self._log.debug("JPILibrary v%s successfully instantiated", version)
25
+
26
+ def _batt_parse_text(self, text: str) -> dict:
27
+ """
28
+ Parse battery info text into a structured dictionary.
29
+ Input:
30
+ Niveau: 52%
31
+ En charge: NON
32
+ Alim. connectée: NON
33
+ Output:
34
+ {'level': 52, 'charging': False, 'power': False}
35
+ """
36
+ result = {}
37
+ for line in text.splitlines():
38
+ if not line.strip():
39
+ continue # skip empty lines
40
+ key, value = line.split(":", 1)
41
+ key = key.strip()
42
+ value = value.strip()
43
+
44
+ if key == "Niveau":
45
+ result["level"] = int(value.strip("%"))
46
+ elif key == "En charge":
47
+ result["charging"] = value.upper() == "OUI"
48
+ elif key == "Alim. connectée":
49
+ result["power"] = value.upper() == "OUI"
50
+ return result
51
+
52
+ async def battInfo(self, url: str):
53
+ """
54
+ Returns the battery informations as a hash:
55
+ level: <int>
56
+ charging: <bool>
57
+ power: <bool>
58
+ """
59
+ target = f"{url}?action=battInfo"
60
+ resp = await self.get(target)
61
+ result = None
62
+ self._log.debug("battInfo resp=%s", resp)
63
+ if resp:
64
+ result = self._batt_parse_text(resp["text"])
65
+ return result
66
+
67
+ async def getDeviceName(self, url: str):
68
+ """
69
+ Returns the device name as provided by the manufacturer.
70
+ E.g. Samsung sets that as 'Samsung SM-J320FN' for a Galaxy J3.
71
+ """
72
+ target = f"{url}?action=getDeviceName"
73
+ resp = await self.get(target)
74
+ self._log.debug("getDeviceName resp=%s", resp)
75
+ device_name = None
76
+ if resp:
77
+ device_name = resp["text"]
78
+ return device_name
79
+
80
+ async def get(self, url: str):
81
+ """
82
+ Returns an object containing the raw HTTP response from GETting the provided url plus the got text content.
83
+ Uses async I/O to avoid blocking the main event loop.
84
+ Throw an exception in case of an error.
85
+ """
86
+ resp = None
87
+ result = None
88
+ try:
89
+ resp = await self._session.get(url)
90
+ except HTTPError as e:
91
+ self._log.error("HTTPError exception: %s", e)
92
+ return False
93
+ if resp:
94
+ text = await resp.text()
95
+ result = {"text": text, "resp": resp}
96
+ return result
@@ -0,0 +1,26 @@
1
+ [build-system]
2
+ requires = ["setuptools >= 77.0.3"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "pyJPI"
7
+ version = "0.1.13"
8
+ authors = [
9
+ { name="Pierre Wieser", email="p.wieser@trychlos.org" },
10
+ ]
11
+ description = "A library to access Android devices which run JPI"
12
+ readme = "README.md"
13
+ requires-python = ">=3.10"
14
+ classifiers = [
15
+ "Programming Language :: Python :: 3",
16
+ "Operating System :: OS Independent",
17
+ ]
18
+ license = "MIT"
19
+ license-files = ["LICEN[CS]E*"]
20
+
21
+ [project.urls]
22
+ Homepage = "https://github.com/trychlos/pyjpi"
23
+ Issues = "https://github.com/trychlos/pyjpi/issues"
24
+
25
+ [tool.setuptools_scm]
26
+ write_to = "pyjpi/._version_.py"
pyjpi-0.1.13/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,15 @@
1
+ """Test jpiInit() calls."""
2
+
3
+ from unittest.mock import MagicMock
4
+
5
+ import pytest
6
+
7
+ from pyjpi import jpiInit, JPILibrary
8
+
9
+
10
+ @pytest.mark.asyncio
11
+ async def test_jpiInit_returns_library():
12
+ """Test for jpiInit() function."""
13
+ session = MagicMock() # acts like a ClientSession for this test
14
+ lib = await jpiInit(session)
15
+ assert isinstance(lib, JPILibrary)
@@ -0,0 +1,49 @@
1
+ """Tests for JPILibrary methods."""
2
+
3
+ from unittest.mock import AsyncMock, MagicMock
4
+
5
+ import pytest
6
+
7
+ from pyjpi import jpiInit
8
+
9
+ from .const import URL
10
+
11
+
12
+ @pytest.mark.asyncio
13
+ async def test_battInfo_parses_and_returns_expected_dict():
14
+ """Test for 'action=battInfo' query."""
15
+
16
+ class FakeResp:
17
+ """Fake response context manager."""
18
+
19
+ status = 200
20
+
21
+ def raise_for_status(self): # pylint: disable=C0116
22
+ return None
23
+
24
+ async def text(self):
25
+ """Returns a fake (but with the expected format) answer."""
26
+ return "Niveau: 87%\nEn charge: OUI\nAlim. connectée: NON"
27
+
28
+ async def __aenter__(self):
29
+ return self
30
+
31
+ async def __aexit__(self, *exc):
32
+ return None
33
+
34
+ session = MagicMock()
35
+ session.get = AsyncMock(return_value=FakeResp())
36
+
37
+ lib = await jpiInit(session)
38
+
39
+ info = await lib.battInfo(URL)
40
+
41
+ assert isinstance(info, dict)
42
+ assert set(info.keys()) == {"level", "charging", "power"}
43
+ assert isinstance(info["level"], int)
44
+ assert isinstance(info["charging"], bool)
45
+ assert isinstance(info["power"], bool)
46
+ assert info == {"level": 87, "charging": True, "power": False}
47
+
48
+ # keep assertion flexible re: extra kwargs
49
+ assert session.get.await_args.args[0] == f"{URL}?action=battInfo"
@@ -0,0 +1,38 @@
1
+ """Tests for JPILibrary methods."""
2
+
3
+ from unittest.mock import AsyncMock, MagicMock
4
+
5
+ import pytest
6
+
7
+ from pyjpi import jpiInit
8
+
9
+ from .const import URL
10
+
11
+
12
+ @pytest.mark.asyncio
13
+ async def test_get_uses_session_and_returns_text():
14
+ """Test for a HTTP GET method."""
15
+
16
+ class FakeResp:
17
+ """Fake response context manager."""
18
+
19
+ status = 200
20
+
21
+ async def text(self): # pylint: disable=C0116
22
+ return "OK"
23
+
24
+ async def __aenter__(self):
25
+ return self
26
+
27
+ async def __aexit__(self, *exc):
28
+ pass
29
+
30
+ session = MagicMock()
31
+ session.get = AsyncMock(return_value=FakeResp())
32
+
33
+ lib = await jpiInit(session)
34
+ out = await lib.get(URL)
35
+ assert out["text"] == "OK"
36
+ assert out["resp"].status == 200
37
+
38
+ session.get.assert_awaited_once_with(URL)
@@ -0,0 +1,45 @@
1
+ """Tests for JPILibrary methods."""
2
+
3
+ from unittest.mock import AsyncMock, MagicMock
4
+
5
+ import pytest
6
+
7
+ from pyjpi import jpiInit
8
+
9
+ from .const import URL
10
+
11
+
12
+ @pytest.mark.asyncio
13
+ async def test_getDeviceName_returns_device_name_string(): # pylint: disable=W0631,C0103
14
+ """Test for 'action=getDeviceName' query."""
15
+
16
+ class FakeResp:
17
+ """Fake response context manager."""
18
+
19
+ status = 200
20
+
21
+ def raise_for_status(self): # pylint: disable=C0116
22
+ return None
23
+
24
+ async def text(self):
25
+ """Returns a fake (but with the expected format) answer."""
26
+ return "Pixel-XL (JPI)"
27
+
28
+ async def __aenter__(self):
29
+ return self
30
+
31
+ async def __aexit__(self, *exc):
32
+ return None
33
+
34
+ session = MagicMock()
35
+ session.get = AsyncMock(return_value=FakeResp())
36
+
37
+ lib = await jpiInit(session)
38
+
39
+ name = await lib.getDeviceName(URL)
40
+
41
+ assert isinstance(name, str)
42
+ assert name == "Pixel-XL (JPI)"
43
+
44
+ # keep assertion flexible re: extra kwargs
45
+ assert session.get.await_args.args[0] == f"{URL}?action=getDeviceName"