pyMyweblog 0.0.1__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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 faanskit
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.
@@ -0,0 +1,230 @@
1
+ Metadata-Version: 2.4
2
+ Name: pyMyweblog
3
+ Version: 0.0.1
4
+ Summary: A Python library for interacting with the MyWebLog API
5
+ Author-email: Marcus Karlsson <marcus.karlsson@usa.net>
6
+ License: MIT License
7
+
8
+ Copyright (c) 2025 faanskit
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+
28
+ Project-URL: Homepage, https://github.com/faanskit/pyMyweblog
29
+ Project-URL: Repository, https://github.com/faanskit/pyMyweblog
30
+ Project-URL: Issues, https://github.com/faanskit/pyMyweblog/issues
31
+ Classifier: Development Status :: 3 - Alpha
32
+ Classifier: Intended Audience :: Developers
33
+ Classifier: License :: OSI Approved :: MIT License
34
+ Classifier: Operating System :: OS Independent
35
+ Classifier: Programming Language :: Python :: 3
36
+ Classifier: Programming Language :: Python :: 3.8
37
+ Classifier: Programming Language :: Python :: 3.9
38
+ Classifier: Programming Language :: Python :: 3.10
39
+ Classifier: Programming Language :: Python :: 3.11
40
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
41
+ Requires-Python: >=3.8
42
+ Description-Content-Type: text/markdown
43
+ License-File: LICENSE
44
+ Requires-Dist: aiohttp>=3.8.0
45
+ Provides-Extra: dev
46
+ Requires-Dist: pytest; extra == "dev"
47
+ Requires-Dist: flake8; extra == "dev"
48
+ Requires-Dist: black; extra == "dev"
49
+ Dynamic: license-file
50
+
51
+ # pyMyweblog Python Library
52
+
53
+ `pyMyweblog` is a Python library for interacting with the MyWebLog API, designed to fetch objects and bookings for aviation-related data. It is intended for use in Home Assistant integrations or other Python applications requiring access to MyWebLog services.
54
+
55
+ ## Installation
56
+
57
+ Install the library via pip:
58
+
59
+ ```bash
60
+ pip install pyMyweblog
61
+ ```
62
+
63
+ Alternatively, for local development, clone the repository and install it in editable mode:
64
+
65
+ ```bash
66
+ git clone https://github.com/faanskit/pyMyweblog.git
67
+ cd pyMyweblog
68
+ pip install -e .
69
+ ```
70
+
71
+ ## Prerequisites
72
+
73
+ To use the library, you need:
74
+ - A valid MyWebLog username and password.
75
+ - A valid `app_token` for MyWebLog [Mobile API](https://api.myweblog.se/index.php?page=mobile)
76
+
77
+ ## Usage
78
+
79
+ The `MyWebLogClient` class provides methods to interact with the MyWebLog API, such as fetching objects and bookings.
80
+
81
+ ### Example: Fetching Objects
82
+
83
+ ```python
84
+ from pyMyweblog.client import MyWebLogClient
85
+
86
+ # Initialize the client
87
+ client = MyWebLogClient(
88
+ username="your_username",
89
+ password="your_password",
90
+ app_token="your_apptoken",
91
+ )
92
+
93
+ # Fetch objects
94
+ objects = client.getObjects()
95
+ print(objects)
96
+
97
+ # Close the session
98
+ client.close()
99
+
100
+ # Alternatively, use as a context manager
101
+ with MyWebLogClient(
102
+ username="your_username",
103
+ password="your_password",
104
+ app_token="your_apptoken",
105
+ ) as client:
106
+ objects = client.getObjects()
107
+ print(objects)
108
+ ```
109
+
110
+ ### Example: Fetching Bookings
111
+
112
+ ```python
113
+ from pyMyweblog.client import MyWebLogClient
114
+
115
+ with MyWebLogClient(
116
+ username="your_username",
117
+ password="your_password",
118
+ app_token="your_apptoken",
119
+ ) as client:
120
+ bookings = client.getBookings(mybookings=True, includeSun=True)
121
+ print(bookings)
122
+ ```
123
+
124
+ ## Testing the API
125
+
126
+ Before pushing any changes, please follow these steps to ensure everything works locally.
127
+
128
+ 1. **Set environment variables** (recommended for security):
129
+ ```bash
130
+ export MYWEBLOG_USERNAME="your_username"
131
+ export MYWEBLOG_PASSWORD="your_password"
132
+ export MYWEBLOG_APPTOKEN="your_apptoken"
133
+ ```
134
+
135
+ 2. **Run the test script**:
136
+ ```bash
137
+ python scripts/test_get_objects.py
138
+ ```
139
+
140
+ This will fetch objects and print the API response in a formatted way using `pprint`.
141
+
142
+ ## Development
143
+
144
+ ### Setting Up the Development Environment
145
+
146
+ 1. **Clone the repository**:
147
+ ```bash
148
+ git clone https://github.com/faanskit/pyMyweblog.git
149
+ cd pyMyweblog
150
+ ```
151
+
152
+ 2. **Create and activate a virtual environment**:
153
+ ```bash
154
+ python -m venv venv
155
+ source venv/bin/activate # On Windows: .\venv\Scripts\activate
156
+ ```
157
+
158
+ 3. **Install dependencies**:
159
+ ```bash
160
+ pip install -e .[dev]
161
+ ```
162
+
163
+ ### Running Tests Locally Before Pushing
164
+
165
+ To ensure your code adheres to the standards and passes tests, follow these steps before you push your changes:
166
+
167
+ 1. **Install dependencies** (if not already done):
168
+ ```bash
169
+ pip install -e .[dev]
170
+ ```
171
+
172
+ 2. **Run format and lint checks**:
173
+ - **Black**: Automatically formats your code to conform to Python’s PEP 8 style.
174
+ ```bash
175
+ black .
176
+ ```
177
+
178
+ - **Flake8**: Lints your code for style issues, such as unused imports or incorrect indentation.
179
+ ```bash
180
+ flake8 .
181
+ ```
182
+
183
+ 3. **Run unit tests**:
184
+ - **Pytest**: Run all the tests in the `tests/` directory and verify they pass.
185
+ ```bash
186
+ pytest --ignore=scripts/test_get_objects.py --ignore=scripts/test_get_balance.py
187
+ ```
188
+
189
+ If all tests pass without errors, you're good to go!
190
+
191
+ ### Running Unit Tests
192
+
193
+ Unit tests are located in the `tests/` directory and use `unittest`.
194
+
195
+ ```bash
196
+ python -m unittest discover tests
197
+ ```
198
+
199
+ ### Modifying the Code
200
+
201
+ - The main API client is in `pyMyweblog/client.py`.
202
+ - Update `app_token` and `ac_id` in `MyWebLogClient` with valid values or make them configurable.
203
+ - Add new methods to `MyWebLogClient` for additional API endpoints as needed.
204
+
205
+ ### Running Test Scripts
206
+
207
+ Test scripts are located in the `scripts/` directory and use `python`.
208
+
209
+ **Example #1**:
210
+ To test the GetObjects function, you can run this script:
211
+ ```bash
212
+ python -m scripts.test_get_objects
213
+ ```
214
+
215
+ **Example #2**:
216
+ To test the GetBalance function, you can run this script:
217
+ ```bash
218
+ python -m scripts.test_get_balance
219
+ ```
220
+
221
+
222
+ ## Contributing
223
+
224
+ Contributions are welcome! Please submit issues or pull requests to the [GitHub repository](https://github.com/faanskit/pyMyweblog).
225
+
226
+ ## License
227
+
228
+ This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
229
+
230
+ For support, contact the maintainer at [marcus.karlsson@usa.net].
@@ -0,0 +1,180 @@
1
+ # pyMyweblog Python Library
2
+
3
+ `pyMyweblog` is a Python library for interacting with the MyWebLog API, designed to fetch objects and bookings for aviation-related data. It is intended for use in Home Assistant integrations or other Python applications requiring access to MyWebLog services.
4
+
5
+ ## Installation
6
+
7
+ Install the library via pip:
8
+
9
+ ```bash
10
+ pip install pyMyweblog
11
+ ```
12
+
13
+ Alternatively, for local development, clone the repository and install it in editable mode:
14
+
15
+ ```bash
16
+ git clone https://github.com/faanskit/pyMyweblog.git
17
+ cd pyMyweblog
18
+ pip install -e .
19
+ ```
20
+
21
+ ## Prerequisites
22
+
23
+ To use the library, you need:
24
+ - A valid MyWebLog username and password.
25
+ - A valid `app_token` for MyWebLog [Mobile API](https://api.myweblog.se/index.php?page=mobile)
26
+
27
+ ## Usage
28
+
29
+ The `MyWebLogClient` class provides methods to interact with the MyWebLog API, such as fetching objects and bookings.
30
+
31
+ ### Example: Fetching Objects
32
+
33
+ ```python
34
+ from pyMyweblog.client import MyWebLogClient
35
+
36
+ # Initialize the client
37
+ client = MyWebLogClient(
38
+ username="your_username",
39
+ password="your_password",
40
+ app_token="your_apptoken",
41
+ )
42
+
43
+ # Fetch objects
44
+ objects = client.getObjects()
45
+ print(objects)
46
+
47
+ # Close the session
48
+ client.close()
49
+
50
+ # Alternatively, use as a context manager
51
+ with MyWebLogClient(
52
+ username="your_username",
53
+ password="your_password",
54
+ app_token="your_apptoken",
55
+ ) as client:
56
+ objects = client.getObjects()
57
+ print(objects)
58
+ ```
59
+
60
+ ### Example: Fetching Bookings
61
+
62
+ ```python
63
+ from pyMyweblog.client import MyWebLogClient
64
+
65
+ with MyWebLogClient(
66
+ username="your_username",
67
+ password="your_password",
68
+ app_token="your_apptoken",
69
+ ) as client:
70
+ bookings = client.getBookings(mybookings=True, includeSun=True)
71
+ print(bookings)
72
+ ```
73
+
74
+ ## Testing the API
75
+
76
+ Before pushing any changes, please follow these steps to ensure everything works locally.
77
+
78
+ 1. **Set environment variables** (recommended for security):
79
+ ```bash
80
+ export MYWEBLOG_USERNAME="your_username"
81
+ export MYWEBLOG_PASSWORD="your_password"
82
+ export MYWEBLOG_APPTOKEN="your_apptoken"
83
+ ```
84
+
85
+ 2. **Run the test script**:
86
+ ```bash
87
+ python scripts/test_get_objects.py
88
+ ```
89
+
90
+ This will fetch objects and print the API response in a formatted way using `pprint`.
91
+
92
+ ## Development
93
+
94
+ ### Setting Up the Development Environment
95
+
96
+ 1. **Clone the repository**:
97
+ ```bash
98
+ git clone https://github.com/faanskit/pyMyweblog.git
99
+ cd pyMyweblog
100
+ ```
101
+
102
+ 2. **Create and activate a virtual environment**:
103
+ ```bash
104
+ python -m venv venv
105
+ source venv/bin/activate # On Windows: .\venv\Scripts\activate
106
+ ```
107
+
108
+ 3. **Install dependencies**:
109
+ ```bash
110
+ pip install -e .[dev]
111
+ ```
112
+
113
+ ### Running Tests Locally Before Pushing
114
+
115
+ To ensure your code adheres to the standards and passes tests, follow these steps before you push your changes:
116
+
117
+ 1. **Install dependencies** (if not already done):
118
+ ```bash
119
+ pip install -e .[dev]
120
+ ```
121
+
122
+ 2. **Run format and lint checks**:
123
+ - **Black**: Automatically formats your code to conform to Python’s PEP 8 style.
124
+ ```bash
125
+ black .
126
+ ```
127
+
128
+ - **Flake8**: Lints your code for style issues, such as unused imports or incorrect indentation.
129
+ ```bash
130
+ flake8 .
131
+ ```
132
+
133
+ 3. **Run unit tests**:
134
+ - **Pytest**: Run all the tests in the `tests/` directory and verify they pass.
135
+ ```bash
136
+ pytest --ignore=scripts/test_get_objects.py --ignore=scripts/test_get_balance.py
137
+ ```
138
+
139
+ If all tests pass without errors, you're good to go!
140
+
141
+ ### Running Unit Tests
142
+
143
+ Unit tests are located in the `tests/` directory and use `unittest`.
144
+
145
+ ```bash
146
+ python -m unittest discover tests
147
+ ```
148
+
149
+ ### Modifying the Code
150
+
151
+ - The main API client is in `pyMyweblog/client.py`.
152
+ - Update `app_token` and `ac_id` in `MyWebLogClient` with valid values or make them configurable.
153
+ - Add new methods to `MyWebLogClient` for additional API endpoints as needed.
154
+
155
+ ### Running Test Scripts
156
+
157
+ Test scripts are located in the `scripts/` directory and use `python`.
158
+
159
+ **Example #1**:
160
+ To test the GetObjects function, you can run this script:
161
+ ```bash
162
+ python -m scripts.test_get_objects
163
+ ```
164
+
165
+ **Example #2**:
166
+ To test the GetBalance function, you can run this script:
167
+ ```bash
168
+ python -m scripts.test_get_balance
169
+ ```
170
+
171
+
172
+ ## Contributing
173
+
174
+ Contributions are welcome! Please submit issues or pull requests to the [GitHub repository](https://github.com/faanskit/pyMyweblog).
175
+
176
+ ## License
177
+
178
+ This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
179
+
180
+ For support, contact the maintainer at [marcus.karlsson@usa.net].
@@ -0,0 +1,7 @@
1
+ """A Python library for interacting with the MyWebLog API."""
2
+
3
+ __version__ = "0.1.0"
4
+
5
+ from .client import MyWebLogClient
6
+
7
+ __all__ = ["MyWebLogClient"]
@@ -0,0 +1,194 @@
1
+ import aiohttp
2
+ import json
3
+ from typing import Any, Dict
4
+ from datetime import date
5
+
6
+
7
+ class MyWebLogClient:
8
+ """Client for interacting with the MyWebLog API."""
9
+
10
+ def __init__(
11
+ self,
12
+ username: str,
13
+ password: str,
14
+ app_token: str,
15
+ ):
16
+ """Initialize the MyWebLog client.
17
+
18
+ Args:
19
+ username (str): Username for authentication.
20
+ password (str): Password for authentication.
21
+ app_token (str): Application token for API access.
22
+ """
23
+ self.username = username
24
+ self.password = password
25
+ self.app_token = app_token
26
+ self.ac_id = "TBD"
27
+ self.base_url = "https://api.myweblog.se/api_mobile.php?version=2.0.3"
28
+ self.session = None
29
+ print(
30
+ f"Connecting to MyWebLog API at {self.base_url} "
31
+ f"with user {self.username}"
32
+ )
33
+
34
+ async def __aenter__(self):
35
+ self.session = aiohttp.ClientSession()
36
+ return self
37
+
38
+ async def __aexit__(self, exc_type, exc, tb):
39
+ if self.session:
40
+ await self.session.close()
41
+ self.session = None
42
+
43
+ async def _myWeblogPost(self, qtype: str, data: Dict[str, Any]) -> Dict[str, Any]:
44
+ """Send a POST request to the MyWebLog API.
45
+
46
+ Args:
47
+ qtype (str): Query type for the API request (e.g., 'GetObjects').
48
+ data (Dict[str, Any]): Data to include in the request body.
49
+
50
+ Returns:
51
+ Dict[str, Any]: Response from the API.
52
+ """
53
+ if not self.session:
54
+ raise RuntimeError(
55
+ "ClientSession is not initialized. Use 'async with' context."
56
+ )
57
+ payload = {
58
+ "qtype": qtype,
59
+ "mwl_u": self.username,
60
+ "mwl_p": self.password,
61
+ "returnType": "JSON",
62
+ "charset": "UTF-8",
63
+ "app_token": self.app_token,
64
+ "language": "se",
65
+ **data,
66
+ }
67
+ async with self.session.post(self.base_url, data=payload) as resp:
68
+ resp.raise_for_status()
69
+ # API returns text/plain; manually decode as JSON
70
+ response = await resp.text()
71
+ return json.loads(response)
72
+
73
+ async def getObjects(self) -> Dict[str, Any]:
74
+ """Get objects from the MyWebLog API.
75
+
76
+ Returns:
77
+ Dict[str, Any]: Response from the API.
78
+ Output example:
79
+ {
80
+ 'APIVersion': str,
81
+ 'qType': str,
82
+ 'result': {
83
+ 'Object': [
84
+ {
85
+ 'ID': str,
86
+ 'regnr': str,
87
+ 'model': str,
88
+ 'club_id': str,
89
+ 'clubname': str,
90
+ 'bobject_cat': str (optional),
91
+ 'comment': str (optional),
92
+ 'activeRemarks': [
93
+ {
94
+ 'remarkID': str,
95
+ 'remarkBy': str,
96
+ 'remarkCategory': str,
97
+ 'remarkDate': str,
98
+ 'remarkText': str
99
+ },
100
+ ...
101
+ ] (optional),
102
+ 'flightData': {
103
+ 'initial': {...},
104
+ 'logged': {...},
105
+ 'total': {...}
106
+ },
107
+ 'ftData': {...},
108
+ 'maintTimeDate': {...} (optional)
109
+ },
110
+ ...
111
+ ],
112
+ 'Result': str
113
+ }
114
+ }
115
+ Notable fields per object:
116
+ - ID (str): Object ID
117
+ - regnr (str): Registration or name
118
+ - model (str): Model/type
119
+ - club_id (str): Club ID
120
+ - clubname (str): Club name
121
+ - bobject_cat (str, optional): Object category
122
+ - comment (str, optional): Comment/description
123
+ - activeRemarks (list, optional): List of active remarks
124
+ - flightData (dict): Flight time and usage data
125
+ - ftData (dict): Flight totals
126
+ - maintTimeDate (dict, optional): Maintenance info
127
+ """
128
+ data = {"includeObjectThumbnail": 0}
129
+ return await self._myWeblogPost("GetObjects", data)
130
+
131
+ async def getBookings(
132
+ self, mybookings: bool = True, includeSun: bool = True
133
+ ) -> Dict[str, Any]:
134
+ """Get bookings from the MyWebLog API.
135
+
136
+ Args:
137
+ mybookings (bool): Whether to fetch only user's bookings.
138
+ includeSun (bool): Whether to include sunrise/sunset data.
139
+
140
+ Returns:
141
+ Dict[str, Any]: Response from the API.
142
+ Output:
143
+ ID (int)
144
+ ac_id (int)
145
+ regnr (string)
146
+ bobject_cat (int)
147
+ club_id (int)
148
+ user_id (int)
149
+ bStart (timestamp)
150
+ bEnd (timestamp)
151
+ typ (string)
152
+ primary_booking (bool)
153
+ fritext (string)
154
+ elevuserid (int)
155
+ platserkvar (int)
156
+ fullname (string)
157
+ email (string)
158
+ completeMobile (string)
159
+ sunData (dict): Reference airport data and dates
160
+ """
161
+ today = date.today().strftime("%Y-%m-%d")
162
+ data = {
163
+ "ac_id": self.ac_id,
164
+ "mybookings": int(mybookings),
165
+ "from_date": today,
166
+ "to_date": today,
167
+ "includeSun": int(includeSun),
168
+ }
169
+ return await self._myWeblogPost("GetBookings", data)
170
+
171
+ async def getBalance(self) -> Dict[str, Any]:
172
+ """Get the balance of the current user from the MyWebLog API.
173
+
174
+ Returns:
175
+ Dict[str, Any]: Response from the API.
176
+ Output example:
177
+ {
178
+ 'Fornamn': str,
179
+ 'Partikel': str,
180
+ 'Efternamn': str,
181
+ 'fullname': str,
182
+ 'Balance': float,
183
+ 'currency_symbol': str,
184
+ 'int_curr_symbol': str
185
+ }
186
+ """
187
+ data = {}
188
+ return await self._myWeblogPost("GetBalance", data)
189
+
190
+ async def close(self) -> None:
191
+ """Close the HTTP session."""
192
+ if self.session:
193
+ await self.session.close()
194
+ self.session = None
@@ -0,0 +1,230 @@
1
+ Metadata-Version: 2.4
2
+ Name: pyMyweblog
3
+ Version: 0.0.1
4
+ Summary: A Python library for interacting with the MyWebLog API
5
+ Author-email: Marcus Karlsson <marcus.karlsson@usa.net>
6
+ License: MIT License
7
+
8
+ Copyright (c) 2025 faanskit
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+
28
+ Project-URL: Homepage, https://github.com/faanskit/pyMyweblog
29
+ Project-URL: Repository, https://github.com/faanskit/pyMyweblog
30
+ Project-URL: Issues, https://github.com/faanskit/pyMyweblog/issues
31
+ Classifier: Development Status :: 3 - Alpha
32
+ Classifier: Intended Audience :: Developers
33
+ Classifier: License :: OSI Approved :: MIT License
34
+ Classifier: Operating System :: OS Independent
35
+ Classifier: Programming Language :: Python :: 3
36
+ Classifier: Programming Language :: Python :: 3.8
37
+ Classifier: Programming Language :: Python :: 3.9
38
+ Classifier: Programming Language :: Python :: 3.10
39
+ Classifier: Programming Language :: Python :: 3.11
40
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
41
+ Requires-Python: >=3.8
42
+ Description-Content-Type: text/markdown
43
+ License-File: LICENSE
44
+ Requires-Dist: aiohttp>=3.8.0
45
+ Provides-Extra: dev
46
+ Requires-Dist: pytest; extra == "dev"
47
+ Requires-Dist: flake8; extra == "dev"
48
+ Requires-Dist: black; extra == "dev"
49
+ Dynamic: license-file
50
+
51
+ # pyMyweblog Python Library
52
+
53
+ `pyMyweblog` is a Python library for interacting with the MyWebLog API, designed to fetch objects and bookings for aviation-related data. It is intended for use in Home Assistant integrations or other Python applications requiring access to MyWebLog services.
54
+
55
+ ## Installation
56
+
57
+ Install the library via pip:
58
+
59
+ ```bash
60
+ pip install pyMyweblog
61
+ ```
62
+
63
+ Alternatively, for local development, clone the repository and install it in editable mode:
64
+
65
+ ```bash
66
+ git clone https://github.com/faanskit/pyMyweblog.git
67
+ cd pyMyweblog
68
+ pip install -e .
69
+ ```
70
+
71
+ ## Prerequisites
72
+
73
+ To use the library, you need:
74
+ - A valid MyWebLog username and password.
75
+ - A valid `app_token` for MyWebLog [Mobile API](https://api.myweblog.se/index.php?page=mobile)
76
+
77
+ ## Usage
78
+
79
+ The `MyWebLogClient` class provides methods to interact with the MyWebLog API, such as fetching objects and bookings.
80
+
81
+ ### Example: Fetching Objects
82
+
83
+ ```python
84
+ from pyMyweblog.client import MyWebLogClient
85
+
86
+ # Initialize the client
87
+ client = MyWebLogClient(
88
+ username="your_username",
89
+ password="your_password",
90
+ app_token="your_apptoken",
91
+ )
92
+
93
+ # Fetch objects
94
+ objects = client.getObjects()
95
+ print(objects)
96
+
97
+ # Close the session
98
+ client.close()
99
+
100
+ # Alternatively, use as a context manager
101
+ with MyWebLogClient(
102
+ username="your_username",
103
+ password="your_password",
104
+ app_token="your_apptoken",
105
+ ) as client:
106
+ objects = client.getObjects()
107
+ print(objects)
108
+ ```
109
+
110
+ ### Example: Fetching Bookings
111
+
112
+ ```python
113
+ from pyMyweblog.client import MyWebLogClient
114
+
115
+ with MyWebLogClient(
116
+ username="your_username",
117
+ password="your_password",
118
+ app_token="your_apptoken",
119
+ ) as client:
120
+ bookings = client.getBookings(mybookings=True, includeSun=True)
121
+ print(bookings)
122
+ ```
123
+
124
+ ## Testing the API
125
+
126
+ Before pushing any changes, please follow these steps to ensure everything works locally.
127
+
128
+ 1. **Set environment variables** (recommended for security):
129
+ ```bash
130
+ export MYWEBLOG_USERNAME="your_username"
131
+ export MYWEBLOG_PASSWORD="your_password"
132
+ export MYWEBLOG_APPTOKEN="your_apptoken"
133
+ ```
134
+
135
+ 2. **Run the test script**:
136
+ ```bash
137
+ python scripts/test_get_objects.py
138
+ ```
139
+
140
+ This will fetch objects and print the API response in a formatted way using `pprint`.
141
+
142
+ ## Development
143
+
144
+ ### Setting Up the Development Environment
145
+
146
+ 1. **Clone the repository**:
147
+ ```bash
148
+ git clone https://github.com/faanskit/pyMyweblog.git
149
+ cd pyMyweblog
150
+ ```
151
+
152
+ 2. **Create and activate a virtual environment**:
153
+ ```bash
154
+ python -m venv venv
155
+ source venv/bin/activate # On Windows: .\venv\Scripts\activate
156
+ ```
157
+
158
+ 3. **Install dependencies**:
159
+ ```bash
160
+ pip install -e .[dev]
161
+ ```
162
+
163
+ ### Running Tests Locally Before Pushing
164
+
165
+ To ensure your code adheres to the standards and passes tests, follow these steps before you push your changes:
166
+
167
+ 1. **Install dependencies** (if not already done):
168
+ ```bash
169
+ pip install -e .[dev]
170
+ ```
171
+
172
+ 2. **Run format and lint checks**:
173
+ - **Black**: Automatically formats your code to conform to Python’s PEP 8 style.
174
+ ```bash
175
+ black .
176
+ ```
177
+
178
+ - **Flake8**: Lints your code for style issues, such as unused imports or incorrect indentation.
179
+ ```bash
180
+ flake8 .
181
+ ```
182
+
183
+ 3. **Run unit tests**:
184
+ - **Pytest**: Run all the tests in the `tests/` directory and verify they pass.
185
+ ```bash
186
+ pytest --ignore=scripts/test_get_objects.py --ignore=scripts/test_get_balance.py
187
+ ```
188
+
189
+ If all tests pass without errors, you're good to go!
190
+
191
+ ### Running Unit Tests
192
+
193
+ Unit tests are located in the `tests/` directory and use `unittest`.
194
+
195
+ ```bash
196
+ python -m unittest discover tests
197
+ ```
198
+
199
+ ### Modifying the Code
200
+
201
+ - The main API client is in `pyMyweblog/client.py`.
202
+ - Update `app_token` and `ac_id` in `MyWebLogClient` with valid values or make them configurable.
203
+ - Add new methods to `MyWebLogClient` for additional API endpoints as needed.
204
+
205
+ ### Running Test Scripts
206
+
207
+ Test scripts are located in the `scripts/` directory and use `python`.
208
+
209
+ **Example #1**:
210
+ To test the GetObjects function, you can run this script:
211
+ ```bash
212
+ python -m scripts.test_get_objects
213
+ ```
214
+
215
+ **Example #2**:
216
+ To test the GetBalance function, you can run this script:
217
+ ```bash
218
+ python -m scripts.test_get_balance
219
+ ```
220
+
221
+
222
+ ## Contributing
223
+
224
+ Contributions are welcome! Please submit issues or pull requests to the [GitHub repository](https://github.com/faanskit/pyMyweblog).
225
+
226
+ ## License
227
+
228
+ This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
229
+
230
+ For support, contact the maintainer at [marcus.karlsson@usa.net].
@@ -0,0 +1,11 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ pyMyweblog/__init__.py
5
+ pyMyweblog/client.py
6
+ pyMyweblog.egg-info/PKG-INFO
7
+ pyMyweblog.egg-info/SOURCES.txt
8
+ pyMyweblog.egg-info/dependency_links.txt
9
+ pyMyweblog.egg-info/requires.txt
10
+ pyMyweblog.egg-info/top_level.txt
11
+ tests/test_client.py
@@ -0,0 +1,6 @@
1
+ aiohttp>=3.8.0
2
+
3
+ [dev]
4
+ pytest
5
+ flake8
6
+ black
@@ -0,0 +1 @@
1
+ pyMyweblog
@@ -0,0 +1,42 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "pyMyweblog"
7
+ version = "0.0.1"
8
+ description = "A Python library for interacting with the MyWebLog API"
9
+ readme = "README.md"
10
+ authors = [{ name = "Marcus Karlsson", email = "marcus.karlsson@usa.net" }]
11
+ license = { file = "LICENSE" }
12
+ requires-python = ">=3.8"
13
+ dependencies = [
14
+ "aiohttp>=3.8.0"
15
+ ]
16
+ classifiers = [
17
+ "Development Status :: 3 - Alpha",
18
+ "Intended Audience :: Developers",
19
+ "License :: OSI Approved :: MIT License",
20
+ "Operating System :: OS Independent",
21
+ "Programming Language :: Python :: 3",
22
+ "Programming Language :: Python :: 3.8",
23
+ "Programming Language :: Python :: 3.9",
24
+ "Programming Language :: Python :: 3.10",
25
+ "Programming Language :: Python :: 3.11",
26
+ "Topic :: Software Development :: Libraries :: Python Modules"
27
+ ]
28
+
29
+ [project.urls]
30
+ Homepage = "https://github.com/faanskit/pyMyweblog"
31
+ Repository = "https://github.com/faanskit/pyMyweblog"
32
+ Issues = "https://github.com/faanskit/pyMyweblog/issues"
33
+
34
+ [project.optional-dependencies]
35
+ dev = [
36
+ "pytest",
37
+ "flake8",
38
+ "black"
39
+ ]
40
+
41
+ [tool.setuptools.packages.find]
42
+ include = ["pyMyweblog*"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,339 @@
1
+ import unittest
2
+ from unittest.mock import patch, AsyncMock, Mock
3
+ import json
4
+ from datetime import date
5
+ import aiohttp
6
+ from pyMyweblog.client import MyWebLogClient
7
+
8
+
9
+ class TestMyWebLogClient(unittest.IsolatedAsyncioTestCase):
10
+ """Test cases for MyWebLogClient (aiohttp/async version)."""
11
+
12
+ def setUp(self):
13
+ """Set up test parameters."""
14
+ self.username = "test_user"
15
+ self.password = "test_pass"
16
+ self.app_token = "test_token"
17
+ self.ac_id = "TBD"
18
+ self.base_url = "https://api.myweblog.se/api_mobile.php?version=2.0.3"
19
+
20
+ async def asyncTearDown(self):
21
+ """Clean up after each test (no manual session handling needed)."""
22
+ pass
23
+
24
+ @patch("aiohttp.ClientSession.post")
25
+ async def test_get_objects_success(self, mock_post):
26
+ """Test successful retrieval of objects."""
27
+ # Mock API response
28
+ mock_response = AsyncMock()
29
+ mock_response.status = 200
30
+ mock_response.text = AsyncMock(
31
+ return_value=json.dumps(
32
+ {
33
+ "objects": [
34
+ {
35
+ "ID": 1,
36
+ "regnr": "SE-ABC",
37
+ "club_id": 123,
38
+ "clubname": "Test Club",
39
+ "model": "Cessna 172",
40
+ }
41
+ ]
42
+ }
43
+ )
44
+ )
45
+ # Mock raise_for_status to avoid RuntimeWarning
46
+ mock_response.raise_for_status = Mock()
47
+ mock_post.return_value.__aenter__.return_value = mock_response
48
+
49
+ # Use context manager to handle session
50
+ async with MyWebLogClient(
51
+ self.username, self.password, self.app_token
52
+ ) as client:
53
+ result = await client.getObjects()
54
+
55
+ # Verify response
56
+ self.assertEqual(
57
+ result,
58
+ {
59
+ "objects": [
60
+ {
61
+ "ID": 1,
62
+ "regnr": "SE-ABC",
63
+ "club_id": 123,
64
+ "clubname": "Test Club",
65
+ "model": "Cessna 172",
66
+ }
67
+ ]
68
+ },
69
+ )
70
+
71
+ # Verify request
72
+ mock_post.assert_called_once_with(
73
+ self.base_url,
74
+ data={
75
+ "includeObjectThumbnail": 0,
76
+ "qtype": "GetObjects",
77
+ "mwl_u": self.username,
78
+ "mwl_p": self.password,
79
+ "returnType": "JSON",
80
+ "charset": "UTF-8",
81
+ "app_token": self.app_token,
82
+ "language": "se",
83
+ },
84
+ )
85
+
86
+ @patch("aiohttp.ClientSession.post")
87
+ async def test_get_bookings_success(self, mock_post):
88
+ """Test successful retrieval of bookings with default parameters."""
89
+ # Mock API response
90
+ mock_response = AsyncMock()
91
+ mock_response.status = 200
92
+ mock_response.text = AsyncMock(
93
+ return_value=json.dumps(
94
+ {
95
+ "bookings": [
96
+ {
97
+ "ID": 101,
98
+ "ac_id": self.ac_id,
99
+ "regnr": "SE-ABC",
100
+ "bStart": "2025-04-18 08:00:00",
101
+ "bEnd": "2025-04-18 10:00:00",
102
+ "fullname": "Test User",
103
+ }
104
+ ],
105
+ "sunData": {
106
+ "refAirport": {"name": "Test Airport"},
107
+ "dates": {
108
+ "2025-04-18": {"sunrise": "06:00", "sunset": "20:00"}
109
+ },
110
+ },
111
+ }
112
+ )
113
+ )
114
+ mock_response.raise_for_status = Mock() # Mock raise_for_status
115
+ mock_post.return_value.__aenter__.return_value = mock_response
116
+
117
+ # Use context manager to handle session
118
+ async with MyWebLogClient(
119
+ self.username, self.password, self.app_token
120
+ ) as client:
121
+ today = date.today().strftime("%Y-%m-%d")
122
+ result = await client.getBookings(mybookings=True, includeSun=True)
123
+
124
+ # Verify response
125
+ self.assertEqual(
126
+ result,
127
+ {
128
+ "bookings": [
129
+ {
130
+ "ID": 101,
131
+ "ac_id": self.ac_id,
132
+ "regnr": "SE-ABC",
133
+ "bStart": "2025-04-18 08:00:00",
134
+ "bEnd": "2025-04-18 10:00:00",
135
+ "fullname": "Test User",
136
+ }
137
+ ],
138
+ "sunData": {
139
+ "refAirport": {"name": "Test Airport"},
140
+ "dates": {"2025-04-18": {"sunrise": "06:00", "sunset": "20:00"}},
141
+ },
142
+ },
143
+ )
144
+
145
+ # Verify request
146
+ mock_post.assert_called_once_with(
147
+ self.base_url,
148
+ data={
149
+ "ac_id": self.ac_id,
150
+ "mybookings": 1,
151
+ "from_date": today,
152
+ "to_date": today,
153
+ "includeSun": 1,
154
+ "qtype": "GetBookings",
155
+ "mwl_u": self.username,
156
+ "mwl_p": self.password,
157
+ "returnType": "JSON",
158
+ "charset": "UTF-8",
159
+ "app_token": self.app_token,
160
+ "language": "se",
161
+ },
162
+ )
163
+
164
+ @patch("aiohttp.ClientSession.post")
165
+ async def test_get_bookings_no_sun_data(self, mock_post):
166
+ """Test retrieval of bookings with includeSun=False."""
167
+ # Mock API response
168
+ mock_response = AsyncMock()
169
+ mock_response.status = 200
170
+ mock_response.text = AsyncMock(
171
+ return_value=json.dumps(
172
+ {
173
+ "bookings": [
174
+ {
175
+ "ID": 102,
176
+ "ac_id": self.ac_id,
177
+ "regnr": "SE-XYZ",
178
+ "bStart": "2025-04-18 09:00:00",
179
+ "bEnd": "2025-04-18 11:00:00",
180
+ "fullname": "Test User",
181
+ }
182
+ ]
183
+ }
184
+ )
185
+ )
186
+ mock_response.raise_for_status = Mock() # Mock raise_for_status
187
+ mock_post.return_value.__aenter__.return_value = mock_response
188
+
189
+ # Use context manager to handle session
190
+ async with MyWebLogClient(
191
+ self.username, self.password, self.app_token
192
+ ) as client:
193
+ today = date.today().strftime("%Y-%m-%d")
194
+ result = await client.getBookings(mybookings=False, includeSun=False)
195
+
196
+ # Verify response
197
+ self.assertEqual(
198
+ result,
199
+ {
200
+ "bookings": [
201
+ {
202
+ "ID": 102,
203
+ "ac_id": self.ac_id,
204
+ "regnr": "SE-XYZ",
205
+ "bStart": "2025-04-18 09:00:00",
206
+ "bEnd": "2025-04-18 11:00:00",
207
+ "fullname": "Test User",
208
+ }
209
+ ]
210
+ },
211
+ )
212
+
213
+ # Verify request
214
+ mock_post.assert_called_once_with(
215
+ self.base_url,
216
+ data={
217
+ "ac_id": self.ac_id,
218
+ "mybookings": 0,
219
+ "from_date": today,
220
+ "to_date": today,
221
+ "includeSun": 0,
222
+ "qtype": "GetBookings",
223
+ "mwl_u": self.username,
224
+ "mwl_p": self.password,
225
+ "returnType": "JSON",
226
+ "charset": "UTF-8",
227
+ "app_token": self.app_token,
228
+ "language": "se",
229
+ },
230
+ )
231
+
232
+ @patch("aiohttp.ClientSession.post")
233
+ async def test_get_balance_success(self, mock_post):
234
+ """Test successful retrieval of user balance."""
235
+ # Mock API response
236
+ mock_response = AsyncMock()
237
+ mock_response.status = 200
238
+ mock_response.text = AsyncMock(
239
+ return_value=json.dumps(
240
+ {
241
+ "Fornamn": "Test",
242
+ "Partikel": "",
243
+ "Efternamn": "User",
244
+ "fullname": "Test User",
245
+ "Balance": 1500.75,
246
+ "currency_symbol": "SEK",
247
+ "int_curr_symbol": "kr",
248
+ }
249
+ )
250
+ )
251
+ mock_response.raise_for_status = Mock() # Mock raise_for_status
252
+ mock_post.return_value.__aenter__.return_value = mock_response
253
+
254
+ # Use context manager to handle session
255
+ async with MyWebLogClient(
256
+ self.username, self.password, self.app_token
257
+ ) as client:
258
+ result = await client.getBalance()
259
+
260
+ # Verify response
261
+ self.assertEqual(
262
+ result,
263
+ {
264
+ "Fornamn": "Test",
265
+ "Partikel": "",
266
+ "Efternamn": "User",
267
+ "fullname": "Test User",
268
+ "Balance": 1500.75,
269
+ "currency_symbol": "SEK",
270
+ "int_curr_symbol": "kr",
271
+ },
272
+ )
273
+
274
+ # Verify request
275
+ mock_post.assert_called_once_with(
276
+ self.base_url,
277
+ data={
278
+ "qtype": "GetBalance",
279
+ "mwl_u": self.username,
280
+ "mwl_p": self.password,
281
+ "returnType": "JSON",
282
+ "charset": "UTF-8",
283
+ "app_token": self.app_token,
284
+ "language": "se",
285
+ },
286
+ )
287
+
288
+ @patch("aiohttp.ClientSession.post")
289
+ async def test_myweblog_post_failure(self, mock_post):
290
+ """Test handling of HTTP request failure."""
291
+ # Mock API failure
292
+ mock_response = AsyncMock()
293
+ mock_response.status = 400
294
+ mock_response.text = AsyncMock(return_value="Bad Request")
295
+ mock_response.raise_for_status = Mock(
296
+ side_effect=aiohttp.ClientResponseError(
297
+ request_info=Mock(), history=(), status=400, message="Bad Request"
298
+ )
299
+ )
300
+ mock_post.return_value.__aenter__.return_value = mock_response
301
+
302
+ # Use context manager to handle session
303
+ async with MyWebLogClient(
304
+ self.username, self.password, self.app_token
305
+ ) as client:
306
+ with self.assertRaises(aiohttp.ClientResponseError):
307
+ await client.getObjects()
308
+
309
+ @patch("aiohttp.ClientSession")
310
+ async def test_close(self, mock_session):
311
+ """Test session closure."""
312
+ mock_session_instance = mock_session.return_value
313
+ mock_session_instance.close = AsyncMock()
314
+
315
+ async with MyWebLogClient(
316
+ self.username, self.password, self.app_token
317
+ ) as client:
318
+ pass # No explicit close call; rely on context manager
319
+
320
+ mock_session_instance.close.assert_awaited_once()
321
+ # Verify session is None after closure
322
+ self.assertIsNone(client.session)
323
+
324
+ @patch("aiohttp.ClientSession")
325
+ async def test_context_manager(self, mock_session):
326
+ """Test context manager functionality."""
327
+ mock_session_instance = mock_session.return_value
328
+ mock_session_instance.close = AsyncMock()
329
+
330
+ async with MyWebLogClient(
331
+ self.username, self.password, self.app_token
332
+ ) as client:
333
+ self.assertIsInstance(client, MyWebLogClient)
334
+
335
+ mock_session_instance.close.assert_awaited_once()
336
+
337
+
338
+ if __name__ == "__main__":
339
+ unittest.main()