isoc-ams 0.0.1__py2.py3-none-any.whl → 0.0.2__py2.py3-none-any.whl
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 isoc-ams might be problematic. Click here for more details.
- {isoc_ams-0.0.1.dist-info → isoc_ams-0.0.2.dist-info}/METADATA +88 -13
- isoc_ams-0.0.2.dist-info/RECORD +5 -0
- isoc_ams.py +117 -46
- isoc_ams-0.0.1.dist-info/RECORD +0 -5
- {isoc_ams-0.0.1.dist-info → isoc_ams-0.0.2.dist-info}/WHEEL +0 -0
- {isoc_ams-0.0.1.dist-info → isoc_ams-0.0.2.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: isoc-ams
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.2
|
|
4
4
|
Summary: A Python 3 module to cope with ISOC-AMS.
|
|
5
5
|
Author-email: Klaus Birkenbihl <klaus.birkenbihl@isoc.de>
|
|
6
6
|
Maintainer: Klaus Birkenbihl
|
|
@@ -13,19 +13,19 @@ Project-URL: Home, https://github.com/birkenbihl/isoc-ams
|
|
|
13
13
|
|
|
14
14
|
# isoc-ams
|
|
15
15
|
|
|
16
|
-
A Python Interface to access the 'Advanced Members Administration System' (AMS) of the 'Internet Society' (ISOC). This especially
|
|
16
|
+
A Python Interface to access the 'Advanced Members Administration System' (AMS) of the 'Internet Society' (ISOC). This especially useful for ISOC Chapter Admins who want to synchronize their Chapter Database with AMS (semi)automatically.
|
|
17
17
|
|
|
18
18
|
After 10 years+ of sorrow, millions minutes of waiting for answers from the AMS web interface, tons of useless clicks, many (in fact) rejected requests to provide an API access: the author decided to build an API himself. Even if it might not be more than a demonstrator for the functionality needed. Anyhow (see below): for now it is running on a weekly basis doing a great job in avoiding manual work.
|
|
19
19
|
|
|
20
20
|
Unfortunately the constraints are severe:
|
|
21
|
-
- access had to be through the web interface since this is the only interface provided. As a consequence it is slow, sometimes unreliable and hard to implement. At least there are working implementations of the "W3C
|
|
22
|
-
- the existing web interface is far from being stable or
|
|
21
|
+
- access had to be through the web interface since this is the only interface provided. As a consequence it is slow, sometimes unreliable and hard to implement. At least there are working implementations of the "W3C web driver" recommendation. One of them is Selenium used for this project.
|
|
22
|
+
- the existing web interface is far from being stable or guaranteed. So changes to the web interface might spoil the whole project. There is great chance that few weeks from now a new "super duper" AMS will be announced and as always after these announcements things will get worse.
|
|
23
23
|
- tests are close to impossible. There is no such thing as a TEST AMS.
|
|
24
24
|
|
|
25
25
|
Is there a possible good exit? Well, maybe some day soon - in 10 or 20 years if ISOC still exists - there will be an API provided by ISOC that makes this project obsolete. Or at least may be an all-mighty AI will step in. Let's dream on!
|
|
26
26
|
|
|
27
27
|
## Features
|
|
28
|
-
|
|
28
|
+
AMS maintains two main Lists that are relevant for the operation of this interface:
|
|
29
29
|
- a list of ISOC members registered as members of the Chapter
|
|
30
30
|
- a list of ISOC members that applied for a Chapter membership.
|
|
31
31
|
|
|
@@ -66,11 +66,15 @@ So this happens if we call the module with:
|
|
|
66
66
|
```bash
|
|
67
67
|
python -m isoc_ams
|
|
68
68
|
```
|
|
69
|
-
|
|
69
|
+
Output:
|
|
70
70
|
```
|
|
71
71
|
Username: xxx
|
|
72
72
|
Password:
|
|
73
73
|
|
|
74
|
+
********************************************
|
|
75
|
+
AMS 2025-07-03 10:49:05 START
|
|
76
|
+
********************************************
|
|
77
|
+
|
|
74
78
|
AMS 2025-07-03 10:49:07 logging in
|
|
75
79
|
AMS 2025-07-03 10:49:11 log in started
|
|
76
80
|
AMS 2025-07-03 10:49:20 now on community portal
|
|
@@ -127,12 +131,76 @@ PENDING APPLICATIONS
|
|
|
127
131
|
2 ...
|
|
128
132
|
...
|
|
129
133
|
```
|
|
134
|
+
As you can see: building the list is rather tedious: reading the Table scroll it to find the end ... and for the members list - in order to get the links for actions - we have to build 2 tables ...
|
|
135
|
+
### Running with arguments
|
|
136
|
+
Normally isoc_ams won't show any browser output - running headless. To do debugging it might useful to follow the activities in the browser. If you call isoc_ams with a -h option like
|
|
137
|
+
```bash
|
|
138
|
+
python -m isoc_ams -h
|
|
139
|
+
```
|
|
140
|
+
the browser will open and you can follow all activities real time.
|
|
141
|
+
|
|
142
|
+
An argument -i tells the module that there will be (or is) input available with actions to execute. An argument -d tells isoc_ams to make a dry run where actions are computed but not executed.
|
|
143
|
+
|
|
144
|
+
Again an example:
|
|
145
|
+
```bash
|
|
146
|
+
python -m isoc_ams -i -d
|
|
147
|
+
```
|
|
148
|
+
Output:
|
|
149
|
+
```
|
|
150
|
+
Username: xxx
|
|
151
|
+
Username:klaus.birkenbihl@isoc.de
|
|
152
|
+
Password:
|
|
153
|
+
|
|
154
|
+
********************************************
|
|
155
|
+
AMS 2025-07-09 16:25:06 START DRYRUN
|
|
156
|
+
********************************************
|
|
157
|
+
|
|
158
|
+
AMS 2025-07-09 16:25:06 logging in
|
|
159
|
+
AMS 2025-07-09 16:25:09 log in started
|
|
160
|
+
AMS 2025-07-09 16:25:17 now on community portal
|
|
161
|
+
AMS 2025-07-09 16:25:21 waiting for Chapter Leader portal
|
|
162
|
+
AMS 2025-07-09 16:25:21 Chapter Leader portal OK
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
AMS 2025-07-09 16:25:21 start build members list
|
|
166
|
+
...
|
|
167
|
+
AMS 2025-07-09 16:26:12 records collected / total 58 / 58
|
|
168
|
+
AMS 2025-07-09 16:26:12 members list finished
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
AMS 2025-07-09 16:26:12 start build pending applications
|
|
172
|
+
...
|
|
173
|
+
AMS 2025-07-09 16:26:25 records collected / total 9 / 9
|
|
174
|
+
AMS 2025-07-09 16:26:25 pending application list finished
|
|
130
175
|
|
|
131
|
-
|
|
176
|
+
|
|
177
|
+
MEMBERS
|
|
178
|
+
1 2217734 Johannes Piesepampel self@piesepampel.com
|
|
179
|
+
...
|
|
180
|
+
|
|
181
|
+
PENDING APPLICATIONS
|
|
182
|
+
1 23232 Franz Piesepampel franz@piesepampel.com 2025-01-22
|
|
183
|
+
2 22556 Abdul Piesepampel abdul@piesepampel.com 2025-03-21
|
|
184
|
+
...
|
|
185
|
+
READING COMMANDS:
|
|
186
|
+
deny 23232 22556 123
|
|
187
|
+
AMS 2025-07-09 18:17:51 Denied 2323284 Franz Piesepampel
|
|
188
|
+
AMS 2025-07-09 18:17:51 Denied 2333463 Abdul Piesepampel
|
|
189
|
+
*******************************************************************************
|
|
190
|
+
AMS 2025-07-09 18:17:51 ISOC-ID 123 is not in pending applications list
|
|
191
|
+
*******************************************************************************
|
|
192
|
+
|
|
193
|
+
delete 2217734
|
|
194
|
+
AMS 2025-07-09 18:18:29 Deleted 22842 Franz Piesepampel
|
|
195
|
+
EOF of command input
|
|
196
|
+
Deviations from expected results:
|
|
197
|
+
Dryrun No results expected
|
|
198
|
+
All results as expected
|
|
199
|
+
```
|
|
132
200
|
|
|
133
201
|
## Using the API
|
|
134
202
|
|
|
135
|
-
isoc_ams unleashes its full power when used as API to make things happen without human intervention. Check the file "isoc_de_ams_main.py" as an example for fully automatic synchronizing of local membership administration with AMS.
|
|
203
|
+
isoc_ams unleashes its full power when used as API to make things happen without human intervention. Check the file "[isoc_de_ams_main.py](https://github.com/birkenbihl/isoc-ams/blob/main/isoc_de_ams_main.py)" as an example for fully automatic synchronizing of local membership administration with AMS.
|
|
136
204
|
|
|
137
205
|
Here an excerpt of the output:
|
|
138
206
|
```
|
|
@@ -152,19 +220,26 @@ Members:
|
|
|
152
220
|
...
|
|
153
221
|
for the following members a nagging mail will be sent to AMS-support (we are not authorized to fix it!):
|
|
154
222
|
...
|
|
155
|
-
the following members are in sync
|
|
223
|
+
the following locally registered members are in sync with AMS:
|
|
156
224
|
...
|
|
157
225
|
|
|
158
226
|
AMS 2025-07-03 12:00:32 start delete ... from AMS Chapter members list
|
|
159
227
|
...
|
|
160
228
|
|
|
161
|
-
Dear
|
|
229
|
+
Dear AMS-support team,
|
|
230
|
+
|
|
162
231
|
this is an automatic, complimentary Message from the ISOC German Chapter
|
|
163
232
|
Members Administration System (ISOC.DE MAS).
|
|
164
233
|
|
|
234
|
+
Assuming you are interested in making ISOC AMS consistent, the purpose
|
|
235
|
+
of this message is to help you with valid, up-to-date data.
|
|
236
|
+
|
|
165
237
|
The following individuals are legally registered paying members
|
|
166
|
-
of ISOC.DE - many of them for more than 25 years.
|
|
167
|
-
|
|
238
|
+
of ISOC.DE - many of them for more than 25 years. They all are
|
|
239
|
+
also registered as ISOC (global) members. Unfortunately they are
|
|
240
|
+
not registered with AMS as members of ISOC.DE. Even more we are
|
|
241
|
+
not authorized to fix this. So we forward this data to your attention:
|
|
242
|
+
|
|
168
243
|
Uwe Mayer, xxx@yyy.com (ISOC-ID=1234567)
|
|
169
244
|
...
|
|
170
245
|
|
|
@@ -180,7 +255,7 @@ not approved from pending applicants list
|
|
|
180
255
|
not removed from pending applicants list
|
|
181
256
|
...
|
|
182
257
|
```
|
|
183
|
-
See file isoc_ams.doc for doc on the API interface.
|
|
258
|
+
See file [isoc_ams.doc](https://github.com/birkenbihl/isoc-ams/blob/main/isoc_ams.doc) for doc on the API interface.
|
|
184
259
|
|
|
185
260
|
Have fun!
|
|
186
261
|
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
isoc_ams.py,sha256=pc1BLQcVs7fKDoy_FBuBe1hszEiaueGCOvPk76Qp4VI,33853
|
|
2
|
+
isoc_ams-0.0.2.dist-info/licenses/LICENSE,sha256=BJcMew_kvBWHjs-_Hd_OMHnxOLmeczeT88V4gFCT21U,1067
|
|
3
|
+
isoc_ams-0.0.2.dist-info/WHEEL,sha256=Dyt6SBfaasWElUrURkknVFAZDHSTwxg3PaTza7RSbkY,100
|
|
4
|
+
isoc_ams-0.0.2.dist-info/METADATA,sha256=3IDSf6pRGsw255-F0W1VGXPcLLJFlCHxySAs7KVnsVE,10489
|
|
5
|
+
isoc_ams-0.0.2.dist-info/RECORD,,
|
isoc_ams.py
CHANGED
|
@@ -67,8 +67,13 @@ _______
|
|
|
67
67
|
# check if all went well
|
|
68
68
|
print(difference_from_expected())
|
|
69
69
|
|
|
70
|
+
Changelog
|
|
71
|
+
_________
|
|
72
|
+
Version 0.2
|
|
73
|
+
Allow input if executed as module
|
|
74
|
+
Add dryrun to ISOC_AMS class
|
|
70
75
|
"""
|
|
71
|
-
__version__ = "0.0.
|
|
76
|
+
__version__ = "0.0.2"
|
|
72
77
|
|
|
73
78
|
from selenium import webdriver
|
|
74
79
|
from selenium.webdriver.common.by import By
|
|
@@ -116,21 +121,29 @@ class ISOC_AMS:
|
|
|
116
121
|
password: password for ISO.ORG login
|
|
117
122
|
logfile: where to write ISOC_AMS log output
|
|
118
123
|
headless: run without GUI
|
|
119
|
-
|
|
124
|
+
dryrun: only check input, no actions
|
|
120
125
|
"""
|
|
121
126
|
|
|
122
127
|
def __init__(self,
|
|
123
128
|
user: str,
|
|
124
129
|
password: str,
|
|
125
130
|
logfile: io.StringIO | str = sys.stdout,
|
|
126
|
-
headless: bool = True
|
|
131
|
+
headless: bool = True,
|
|
132
|
+
dryrun: bool = False,):
|
|
127
133
|
if _dr == "firefox" and headless:
|
|
128
134
|
_options.add_argument("--headless")
|
|
129
135
|
elif _dr == "chrome" and headless:
|
|
130
136
|
_options.add_argument("--headless=new")
|
|
131
137
|
self._members_list: dict | None = None
|
|
132
138
|
self._pending_applications_list: dict | None = None
|
|
133
|
-
self.
|
|
139
|
+
self._dryrun = dryrun
|
|
140
|
+
self._ams = _ISOC_AMS(logfile)
|
|
141
|
+
if self._dryrun:
|
|
142
|
+
self._ams.strong_msg("START DRYRUN")
|
|
143
|
+
else:
|
|
144
|
+
self._ams.strong_msg("START")
|
|
145
|
+
self._ams.login((user, password))
|
|
146
|
+
|
|
134
147
|
|
|
135
148
|
@property
|
|
136
149
|
def members_list(self) -> dict:
|
|
@@ -193,10 +206,15 @@ class ISOC_AMS:
|
|
|
193
206
|
deletes delete_list entries from AMS-list of Chapter members
|
|
194
207
|
"""
|
|
195
208
|
if type(delete_list) in (str, int):
|
|
196
|
-
delete_list =
|
|
197
|
-
for deletee in delete_list:
|
|
209
|
+
delete_list = [delete_list]
|
|
210
|
+
for deletee in map(str, delete_list):
|
|
198
211
|
if deletee in self._members_list:
|
|
199
|
-
|
|
212
|
+
deletee = str(deletee)
|
|
213
|
+
if not self._dryrun:
|
|
214
|
+
self._ams.delete(self._members_list[deletee])
|
|
215
|
+
self._ams.log("Deleted", deletee,
|
|
216
|
+
self._members_list[deletee]["first name"],
|
|
217
|
+
self._members_list[deletee]["last name"])
|
|
200
218
|
del self._members_list[deletee]
|
|
201
219
|
else:
|
|
202
220
|
self._ams.strong_msg("ISOC-ID", deletee,
|
|
@@ -214,14 +232,17 @@ class ISOC_AMS:
|
|
|
214
232
|
approves pending members on approve_list as Chapter members
|
|
215
233
|
"""
|
|
216
234
|
if type(approve_list) in (int, str):
|
|
217
|
-
approve_list =
|
|
218
|
-
for approvee in approve_list:
|
|
235
|
+
approve_list = [approve_list]
|
|
236
|
+
for approvee in map(str, approve_list):
|
|
219
237
|
if approvee in self._pending_applications_list:
|
|
220
|
-
self.
|
|
238
|
+
if not self._dryrun:
|
|
239
|
+
self._ams.approve(self._pending_applications_list[approvee])
|
|
240
|
+
self._ams.log("Approved", approvee,
|
|
241
|
+
self._pending_applications_list[approvee]["name"])
|
|
221
242
|
del self._pending_applications_list[approvee]
|
|
222
243
|
else:
|
|
223
244
|
self._ams.strong_msg("ISOC-ID", approvee,
|
|
224
|
-
"is not in pending applications list"
|
|
245
|
+
"is not in pending applications list")
|
|
225
246
|
|
|
226
247
|
def deny_pending_applications(self,
|
|
227
248
|
deny_list: list | dict | str | int,
|
|
@@ -238,15 +259,18 @@ class ISOC_AMS:
|
|
|
238
259
|
|
|
239
260
|
"""
|
|
240
261
|
if type(deny_list) in (str, int):
|
|
241
|
-
deny_list =
|
|
242
|
-
for denyee in deny_list:
|
|
262
|
+
deny_list = [deny_list],
|
|
263
|
+
for denyee in map(str, deny_list):
|
|
243
264
|
if denyee in self._pending_applications_list:
|
|
244
|
-
self.
|
|
245
|
-
|
|
265
|
+
if not self._dryrun:
|
|
266
|
+
self._ams.deny(self._pending_applications_list[denyee],
|
|
267
|
+
reason)
|
|
268
|
+
self._ams.log("Denied", denyee,
|
|
269
|
+
self._pending_applications_list[denyee]["name"])
|
|
246
270
|
del self._pending_applications_list[denyee]
|
|
247
271
|
else:
|
|
248
272
|
self._ams.strong_msg("ISOC-ID", denyee,
|
|
249
|
-
"is not in pending applications list"
|
|
273
|
+
"is not in pending applications list")
|
|
250
274
|
|
|
251
275
|
def difference_from_expected(self) -> dict:
|
|
252
276
|
"""Compare intended outcome of operations with real outcome.
|
|
@@ -267,38 +291,43 @@ class ISOC_AMS:
|
|
|
267
291
|
}
|
|
268
292
|
|
|
269
293
|
"""
|
|
270
|
-
self.
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
294
|
+
if not self._dryrun:
|
|
295
|
+
|
|
296
|
+
self._ams.log(date=False)
|
|
297
|
+
|
|
298
|
+
self._ams.strong_msg("we have to read the AMS Database tables again :(")
|
|
299
|
+
self._ams.log("... to find deviations from expected result after actions")
|
|
300
|
+
|
|
301
|
+
not_deleted = {}
|
|
302
|
+
not_approved = {}
|
|
303
|
+
not_removed_from_pending = {}
|
|
304
|
+
new_members_list = self._ams.build_members_list()
|
|
305
|
+
for nm in new_members_list:
|
|
306
|
+
if nm not in self._members_list:
|
|
307
|
+
not_deleted[nm] = new_members_list[nm]
|
|
308
|
+
for nm in self._members_list:
|
|
309
|
+
if nm not in new_members_list:
|
|
310
|
+
not_approved[nm] = self._members_list[nm]
|
|
311
|
+
new_pending_applications_list = self._ams.build_pending_applicants_list()
|
|
312
|
+
for np in new_pending_applications_list:
|
|
313
|
+
if np not in self._pending_applications_list:
|
|
314
|
+
not_removed_from_pending[np] = new_pending_applications_list[np]
|
|
315
|
+
|
|
316
|
+
return {"not deleted from members": not_deleted,
|
|
317
|
+
"not approved from pending applicants list": not_approved,
|
|
318
|
+
"not removed from pending applicants list": not_removed_from_pending}
|
|
319
|
+
else:
|
|
320
|
+
return {"Dryrun": "No results expected"}
|
|
291
321
|
|
|
292
322
|
class _ISOC_AMS(Driver):
|
|
293
323
|
|
|
294
|
-
def __init__(self,
|
|
324
|
+
def __init__(self, logfile: str = sys.stdout):
|
|
295
325
|
|
|
296
326
|
super().__init__(_options)
|
|
297
327
|
self.windows = {}
|
|
298
328
|
self.logfile = logfile
|
|
299
329
|
if type(self.logfile) is str:
|
|
300
330
|
self.logfile = open(self.log, "a")
|
|
301
|
-
self.login(user, password)
|
|
302
331
|
|
|
303
332
|
def __del__(self):
|
|
304
333
|
self.quit()
|
|
@@ -364,7 +393,7 @@ class _ISOC_AMS(Driver):
|
|
|
364
393
|
# setup session, init windows
|
|
365
394
|
#
|
|
366
395
|
|
|
367
|
-
def login(self,
|
|
396
|
+
def login(self, credentials):
|
|
368
397
|
# Sign on user and navigate to the Chapter leaders page,
|
|
369
398
|
|
|
370
399
|
self.log(date=False)
|
|
@@ -383,7 +412,7 @@ class _ISOC_AMS(Driver):
|
|
|
383
412
|
"document.getElementById('signInName').value='%s';"
|
|
384
413
|
"document.getElementById('password').value='%s';"
|
|
385
414
|
"arguments[0].click();"
|
|
386
|
-
%
|
|
415
|
+
% credentials,
|
|
387
416
|
elem)
|
|
388
417
|
|
|
389
418
|
# self.set_window_size(1600, 300)
|
|
@@ -792,14 +821,22 @@ if __name__ == "__main__":
|
|
|
792
821
|
from getpass import getpass
|
|
793
822
|
headless = True
|
|
794
823
|
if "-h" in sys.argv:
|
|
795
|
-
headless=False
|
|
824
|
+
headless = False
|
|
825
|
+
inp = False
|
|
826
|
+
if "-i" in sys.argv:
|
|
827
|
+
inp = True
|
|
828
|
+
dryrun = False
|
|
829
|
+
if "-d" in sys.argv:
|
|
830
|
+
dryrun = True
|
|
831
|
+
|
|
796
832
|
print("Username", end=":")
|
|
797
833
|
user_id = input()
|
|
798
834
|
password = getpass()
|
|
799
835
|
ams = ISOC_AMS(
|
|
800
836
|
user_id,
|
|
801
837
|
password,
|
|
802
|
-
headless=headless
|
|
838
|
+
headless=headless,
|
|
839
|
+
dryrun=dryrun)
|
|
803
840
|
members = ams.members_list
|
|
804
841
|
pendings = ams.pending_applications_list
|
|
805
842
|
|
|
@@ -807,12 +844,46 @@ if __name__ == "__main__":
|
|
|
807
844
|
i = 0
|
|
808
845
|
for k, v in members.items():
|
|
809
846
|
i += 1
|
|
810
|
-
print(i, k
|
|
847
|
+
print(i, k, v["first name"], v["last name"], v["email"])
|
|
811
848
|
|
|
812
849
|
print("\nPENDING APPLICATIONS")
|
|
813
850
|
i = 0
|
|
814
851
|
for k, v in pendings.items():
|
|
815
852
|
i += 1
|
|
816
853
|
# print(i, k, v)
|
|
817
|
-
print(i, k, v["name"], v["email"], v["
|
|
818
|
-
|
|
854
|
+
print(i, k, v["name"], v["email"], v["date"].isoformat()[:10])
|
|
855
|
+
|
|
856
|
+
if inp:
|
|
857
|
+
print('READING COMMANDS:')
|
|
858
|
+
import re
|
|
859
|
+
patt = re.compile(r'(approve|deny|delete):?\s*([\d, ]+)')
|
|
860
|
+
func = {"approve": ams.approve_pending_applications,
|
|
861
|
+
"deny": ams.deny_pending_applications,
|
|
862
|
+
"delete": ams.delete_members
|
|
863
|
+
}
|
|
864
|
+
splitter = re.compile(r'[\s,]+')
|
|
865
|
+
for rec in sys.stdin:
|
|
866
|
+
if m := patt.match(rec):
|
|
867
|
+
command = m.group(1)
|
|
868
|
+
keys = splitter.split(m.group(2))
|
|
869
|
+
func[command](keys)
|
|
870
|
+
else:
|
|
871
|
+
print(rec, "contains an error")
|
|
872
|
+
print("EOF of command input")
|
|
873
|
+
|
|
874
|
+
devs = 0
|
|
875
|
+
for data in ams.difference_from_expected().items():
|
|
876
|
+
print("Deviations from expected results:")
|
|
877
|
+
print(data[0], end=" ")
|
|
878
|
+
if type(data[1]) is str:
|
|
879
|
+
print(data[1])
|
|
880
|
+
else:
|
|
881
|
+
if data[1]:
|
|
882
|
+
devs = 1
|
|
883
|
+
for k, v in data[1].items():
|
|
884
|
+
if "members" in data[0]:
|
|
885
|
+
print(" ", v["first name"], v["last name"], v["email"], "("+k+")")
|
|
886
|
+
else:
|
|
887
|
+
print(" ", v["name"], v["email"], "("+k+")")
|
|
888
|
+
if devs == 0:
|
|
889
|
+
print("All results as expected")
|
isoc_ams-0.0.1.dist-info/RECORD
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
isoc_ams.py,sha256=_856QxwvSovWra0iOyOafpYm6K_aVVg_D14X4drq62M,31231
|
|
2
|
-
isoc_ams-0.0.1.dist-info/licenses/LICENSE,sha256=BJcMew_kvBWHjs-_Hd_OMHnxOLmeczeT88V4gFCT21U,1067
|
|
3
|
-
isoc_ams-0.0.1.dist-info/WHEEL,sha256=Dyt6SBfaasWElUrURkknVFAZDHSTwxg3PaTza7RSbkY,100
|
|
4
|
-
isoc_ams-0.0.1.dist-info/METADATA,sha256=nfcgOmUP9GbfkcXdb4UIJtqoYy-dRFkdT-PFxLOG8eQ,7746
|
|
5
|
-
isoc_ams-0.0.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|