Kea2-python 0.0.1b0__py3-none-any.whl → 0.0.1b1__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 Kea2-python might be problematic. Click here for more details.
- kea2/__init__.py +1 -1
- kea2/absDriver.py +4 -0
- kea2/adbUtils.py +5 -0
- kea2/assets/quicktest.py +3 -3
- kea2/cli.py +1 -1
- kea2/keaUtils.py +54 -12
- kea2/kea_launcher.py +10 -1
- kea2/u2Driver.py +15 -5
- {kea2_python-0.0.1b0.dist-info → kea2_python-0.0.1b1.dist-info}/METADATA +5 -1
- {kea2_python-0.0.1b0.dist-info → kea2_python-0.0.1b1.dist-info}/RECORD +14 -14
- {kea2_python-0.0.1b0.dist-info → kea2_python-0.0.1b1.dist-info}/WHEEL +0 -0
- {kea2_python-0.0.1b0.dist-info → kea2_python-0.0.1b1.dist-info}/entry_points.txt +0 -0
- {kea2_python-0.0.1b0.dist-info → kea2_python-0.0.1b1.dist-info}/licenses/LICENSE +0 -0
- {kea2_python-0.0.1b0.dist-info → kea2_python-0.0.1b1.dist-info}/top_level.txt +0 -0
kea2/__init__.py
CHANGED
kea2/absDriver.py
CHANGED
kea2/adbUtils.py
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import subprocess
|
|
2
2
|
from typing import List, Optional
|
|
3
|
+
from .utils import getLogger
|
|
4
|
+
|
|
5
|
+
logger = getLogger(__name__)
|
|
6
|
+
|
|
3
7
|
|
|
4
8
|
def run_adb_command(cmd: List[str], timeout=10):
|
|
5
9
|
"""
|
|
@@ -13,6 +17,7 @@ def run_adb_command(cmd: List[str], timeout=10):
|
|
|
13
17
|
str: The standard output from the command. If an error occurs, returns None.
|
|
14
18
|
"""
|
|
15
19
|
full_cmd = ["adb"] + cmd
|
|
20
|
+
logger.debug(f"{' '.join(full_cmd)}")
|
|
16
21
|
try:
|
|
17
22
|
result = subprocess.run(full_cmd, capture_output=True, text=True, timeout=timeout)
|
|
18
23
|
if result.returncode != 0:
|
kea2/assets/quicktest.py
CHANGED
|
@@ -57,7 +57,7 @@ PACKAGE_NAME = "it.feio.android.omninotes.alpha"
|
|
|
57
57
|
FILE_NAME = "omninotes.apk"
|
|
58
58
|
|
|
59
59
|
|
|
60
|
-
def check_installation():
|
|
60
|
+
def check_installation(serial=None):
|
|
61
61
|
import os
|
|
62
62
|
from pathlib import Path
|
|
63
63
|
if not os.path.exists(Path(".") / FILE_NAME):
|
|
@@ -65,7 +65,7 @@ def check_installation():
|
|
|
65
65
|
import urllib.request
|
|
66
66
|
urllib.request.urlretrieve(URL, FILE_NAME)
|
|
67
67
|
|
|
68
|
-
d = u2.connect()
|
|
68
|
+
d = u2.connect(serial)
|
|
69
69
|
# automatically install omni-notes
|
|
70
70
|
if PACKAGE_NAME not in d.app_list():
|
|
71
71
|
print("[INFO] Installing omninotes.", flush=True)
|
|
@@ -74,7 +74,7 @@ def check_installation():
|
|
|
74
74
|
|
|
75
75
|
|
|
76
76
|
if __name__ == "__main__":
|
|
77
|
-
check_installation()
|
|
77
|
+
check_installation(serial=None)
|
|
78
78
|
KeaTestRunner.setOptions(
|
|
79
79
|
Options(
|
|
80
80
|
driverName="d",
|
kea2/cli.py
CHANGED
kea2/keaUtils.py
CHANGED
|
@@ -19,9 +19,10 @@ from .utils import TimeStamp, getProjectRoot, getLogger
|
|
|
19
19
|
from .u2Driver import StaticU2UiObject
|
|
20
20
|
import uiautomator2 as u2
|
|
21
21
|
import types
|
|
22
|
+
|
|
22
23
|
PRECONDITIONS_MARKER = "preconds"
|
|
23
24
|
PROP_MARKER = "prop"
|
|
24
|
-
|
|
25
|
+
MAX_TRIES_MARKER = "max_tries"
|
|
25
26
|
|
|
26
27
|
logger = getLogger(__name__)
|
|
27
28
|
|
|
@@ -30,14 +31,14 @@ logger = getLogger(__name__)
|
|
|
30
31
|
PropName = NewType("PropName", str)
|
|
31
32
|
PropertyStore = NewType("PropertyStore", Dict[PropName, TestCase])
|
|
32
33
|
|
|
33
|
-
|
|
34
|
-
LOGFILE = f"fastbot_{
|
|
35
|
-
RESFILE = f"result_{
|
|
34
|
+
STAMP = TimeStamp().getTimeStamp()
|
|
35
|
+
LOGFILE = f"fastbot_{STAMP}.log"
|
|
36
|
+
RESFILE = f"result_{STAMP}.json"
|
|
36
37
|
|
|
37
38
|
def precondition(precond: Callable[[Any], bool]) -> Callable:
|
|
38
39
|
"""the decorator @precondition
|
|
39
40
|
|
|
40
|
-
|
|
41
|
+
@precondition specifies when the property could be executed.
|
|
41
42
|
A property could have multiple preconditions, each of which is specified by @precondition.
|
|
42
43
|
"""
|
|
43
44
|
def accept(f):
|
|
@@ -56,7 +57,7 @@ def precondition(precond: Callable[[Any], bool]) -> Callable:
|
|
|
56
57
|
def prob(p: float):
|
|
57
58
|
"""the decorator @prob
|
|
58
59
|
|
|
59
|
-
|
|
60
|
+
@prob specify the propbability of execution when a property is satisfied.
|
|
60
61
|
"""
|
|
61
62
|
p = float(p)
|
|
62
63
|
if not 0 < p <= 1.0:
|
|
@@ -73,6 +74,26 @@ def prob(p: float):
|
|
|
73
74
|
return accept
|
|
74
75
|
|
|
75
76
|
|
|
77
|
+
def max_tries(n: int):
|
|
78
|
+
"""the decorator @max_tries
|
|
79
|
+
|
|
80
|
+
@max_tries specify the maximum tries of executing a property.
|
|
81
|
+
"""
|
|
82
|
+
n = int(n)
|
|
83
|
+
if not n > 0:
|
|
84
|
+
raise ValueError("The maxium tries should be a positive integer.")
|
|
85
|
+
def accept(f):
|
|
86
|
+
@wraps(f)
|
|
87
|
+
def precondition_wrapper(*args, **kwargs):
|
|
88
|
+
return f(*args, **kwargs)
|
|
89
|
+
|
|
90
|
+
setattr(precondition_wrapper, MAX_TRIES_MARKER, n)
|
|
91
|
+
|
|
92
|
+
return precondition_wrapper
|
|
93
|
+
|
|
94
|
+
return accept
|
|
95
|
+
|
|
96
|
+
|
|
76
97
|
@dataclass
|
|
77
98
|
class Options:
|
|
78
99
|
"""
|
|
@@ -96,10 +117,16 @@ class Options:
|
|
|
96
117
|
throttle: int = 200
|
|
97
118
|
# the output_dir for saving logs and results
|
|
98
119
|
output_dir: str = "output"
|
|
120
|
+
# the stamp for log file and result file, default: current time stamp
|
|
121
|
+
log_stamp: str = None
|
|
99
122
|
|
|
100
123
|
def __post_init__(self):
|
|
101
124
|
if self.serial and self.Driver:
|
|
102
125
|
self.Driver.setDeviceSerial(self.serial)
|
|
126
|
+
if self.log_stamp:
|
|
127
|
+
global LOGFILE, RESFILE
|
|
128
|
+
LOGFILE = f"fastbot_{self.log_stamp}.log"
|
|
129
|
+
RESFILE = f"result_{self.log_stamp}.json"
|
|
103
130
|
|
|
104
131
|
|
|
105
132
|
@dataclass
|
|
@@ -151,6 +178,9 @@ class JsonResult(TextTestResult):
|
|
|
151
178
|
super().addError(test, err)
|
|
152
179
|
self.res[getFullPropName(test)].error += 1
|
|
153
180
|
|
|
181
|
+
def getExcuted(self, test: TestCase):
|
|
182
|
+
return self.res[getFullPropName(test)].executed
|
|
183
|
+
|
|
154
184
|
|
|
155
185
|
def activateFastbot(options: Options, port=None) -> threading.Thread:
|
|
156
186
|
"""
|
|
@@ -274,6 +304,8 @@ class KeaTestRunner(TextTestRunner):
|
|
|
274
304
|
global LOGFILE, RESFILE
|
|
275
305
|
LOGFILE = output_dir / Path(LOGFILE)
|
|
276
306
|
RESFILE = output_dir / Path(RESFILE)
|
|
307
|
+
logger.debug(f"Log file: {LOGFILE}")
|
|
308
|
+
logger.debug(f"Result file: {RESFILE}")
|
|
277
309
|
|
|
278
310
|
def run(self, test):
|
|
279
311
|
|
|
@@ -333,7 +365,7 @@ class KeaTestRunner(TextTestRunner):
|
|
|
333
365
|
, flush=True)
|
|
334
366
|
|
|
335
367
|
try:
|
|
336
|
-
propsSatisfiedPrecond = self.getValidProperties()
|
|
368
|
+
propsSatisfiedPrecond = self.getValidProperties(result)
|
|
337
369
|
except requests.ConnectionError:
|
|
338
370
|
print(
|
|
339
371
|
"[INFO] Exploration times up (--running-minutes)."
|
|
@@ -425,6 +457,8 @@ class KeaTestRunner(TextTestRunner):
|
|
|
425
457
|
"""
|
|
426
458
|
block_widgets: List[str] = self._getBlockedWidgets()
|
|
427
459
|
URL = f"http://localhost:{self.scriptDriver.lport}/stepMonkey"
|
|
460
|
+
logger.debug(f"Sending request: {URL}")
|
|
461
|
+
logger.debug(f"Blocking widgets: {block_widgets}")
|
|
428
462
|
r = requests.post(
|
|
429
463
|
url=URL,
|
|
430
464
|
json={
|
|
@@ -440,12 +474,14 @@ class KeaTestRunner(TextTestRunner):
|
|
|
440
474
|
"""
|
|
441
475
|
send a stop monkey request to the server and get the xml string.
|
|
442
476
|
"""
|
|
443
|
-
|
|
477
|
+
URL = f"http://localhost:{self.scriptDriver.lport}/stopMonkey"
|
|
478
|
+
logger.debug(f"Sending request: {URL}")
|
|
479
|
+
r = requests.get(URL)
|
|
444
480
|
|
|
445
481
|
res = r.content.decode(encoding="utf-8")
|
|
446
482
|
print(f"[Server INFO] {res}", flush=True)
|
|
447
483
|
|
|
448
|
-
def getValidProperties(self) -> PropertyStore:
|
|
484
|
+
def getValidProperties(self, result: JsonResult) -> PropertyStore:
|
|
449
485
|
|
|
450
486
|
xml_raw = self.stepMonkey()
|
|
451
487
|
staticCheckerDriver = self.options.Driver.getStaticChecker(hierarchy=xml_raw)
|
|
@@ -470,6 +506,10 @@ class KeaTestRunner(TextTestRunner):
|
|
|
470
506
|
break
|
|
471
507
|
# if all the precond passed. make it the candidate prop.
|
|
472
508
|
if valid:
|
|
509
|
+
logger.debug(f"precond satisfied: {getFullPropName(test)}")
|
|
510
|
+
if result.getExcuted(test) >= getattr(prop, MAX_TRIES_MARKER, float("inf")):
|
|
511
|
+
logger.debug(f"{getFullPropName(test)} has reached its max_tries. Skip.")
|
|
512
|
+
continue
|
|
473
513
|
validProps[propName] = test
|
|
474
514
|
return validProps
|
|
475
515
|
|
|
@@ -570,6 +610,8 @@ class KeaTestRunner(TextTestRunner):
|
|
|
570
610
|
|
|
571
611
|
return blocked_widgets
|
|
572
612
|
|
|
573
|
-
def
|
|
574
|
-
|
|
575
|
-
|
|
613
|
+
def __del__(self):
|
|
614
|
+
"""tearDown method. Cleanup the env.
|
|
615
|
+
"""
|
|
616
|
+
if self.options.Driver:
|
|
617
|
+
self.options.Driver.tearDown()
|
kea2/kea_launcher.py
CHANGED
|
@@ -76,6 +76,14 @@ def _set_runner_parser(subparsers: "argparse._SubParsersAction[argparse.Argument
|
|
|
76
76
|
help="The name of driver in script.",
|
|
77
77
|
)
|
|
78
78
|
|
|
79
|
+
parser.add_argument(
|
|
80
|
+
"--log-stamp",
|
|
81
|
+
dest="log_stamp",
|
|
82
|
+
type=str,
|
|
83
|
+
required=False,
|
|
84
|
+
help="the stamp for log file and result file, default: current time stamp",
|
|
85
|
+
)
|
|
86
|
+
|
|
79
87
|
parser.add_argument(
|
|
80
88
|
"extra",
|
|
81
89
|
nargs=argparse.REMAINDER,
|
|
@@ -138,7 +146,8 @@ def run(args=None):
|
|
|
138
146
|
serial=args.serial,
|
|
139
147
|
running_mins=args.running_minutes if args.running_minutes else 10,
|
|
140
148
|
maxStep=args.max_step if args.max_step else 500,
|
|
141
|
-
throttle=args.throttle_ms if args.throttle_ms else 200
|
|
149
|
+
throttle=args.throttle_ms if args.throttle_ms else 200,
|
|
150
|
+
log_stamp=args.log_stamp
|
|
142
151
|
)
|
|
143
152
|
|
|
144
153
|
KeaTestRunner.setOptions(options)
|
kea2/u2Driver.py
CHANGED
|
@@ -8,7 +8,7 @@ from typing import Dict, List, Union
|
|
|
8
8
|
from lxml import etree
|
|
9
9
|
from .absDriver import AbstractScriptDriver, AbstractStaticChecker, AbstractDriver
|
|
10
10
|
from .adbUtils import list_forwards, remove_forward, create_forward
|
|
11
|
-
from .utils import TimeStamp
|
|
11
|
+
from .utils import TimeStamp, getLogger
|
|
12
12
|
|
|
13
13
|
TIME_STAMP = TimeStamp().getTimeStamp()
|
|
14
14
|
|
|
@@ -16,6 +16,8 @@ import logging
|
|
|
16
16
|
logging.getLogger("urllib3").setLevel(logging.INFO)
|
|
17
17
|
logging.getLogger("uiautomator2").setLevel(logging.INFO)
|
|
18
18
|
|
|
19
|
+
logger = getLogger(__name__)
|
|
20
|
+
|
|
19
21
|
"""
|
|
20
22
|
The definition of U2ScriptDriver
|
|
21
23
|
"""
|
|
@@ -57,16 +59,13 @@ class U2ScriptDriver(AbstractScriptDriver):
|
|
|
57
59
|
setattr(self.d._dev, "msg", "meta")
|
|
58
60
|
print(f"[U2] local port: {lport}", flush=True)
|
|
59
61
|
return lport
|
|
60
|
-
|
|
62
|
+
|
|
61
63
|
self._remove_remote_port(8090)
|
|
62
64
|
self.d.lport = get_u2_forward_port()
|
|
63
65
|
self._remove_remote_port(9008)
|
|
64
66
|
|
|
65
67
|
return self.d
|
|
66
68
|
|
|
67
|
-
def tearDown(self):
|
|
68
|
-
self.d.stop_uiautomator()
|
|
69
|
-
|
|
70
69
|
def _remove_remote_port(self, port:int):
|
|
71
70
|
"""remove the forward port
|
|
72
71
|
"""
|
|
@@ -76,6 +75,11 @@ class U2ScriptDriver(AbstractScriptDriver):
|
|
|
76
75
|
forward_local = forward["local"]
|
|
77
76
|
remove_forward(local_spec=forward_local, device=self.deviceSerial)
|
|
78
77
|
|
|
78
|
+
def tearDown(self):
|
|
79
|
+
logger.debug("U2Driver tearDown: stop_uiautomator")
|
|
80
|
+
self.d.stop_uiautomator()
|
|
81
|
+
logger.debug("U2Driver tearDown: remove forward")
|
|
82
|
+
self._remove_remote_port(8090)
|
|
79
83
|
|
|
80
84
|
"""
|
|
81
85
|
The definition of U2StaticChecker
|
|
@@ -231,6 +235,7 @@ class U2StaticDevice(u2.Device):
|
|
|
231
235
|
|
|
232
236
|
def __getattr__(self, attr):
|
|
233
237
|
"""Proxy other methods to script_driver"""
|
|
238
|
+
# logger.debug(f"{attr} not exists in static checker, proxy to script_driver.")
|
|
234
239
|
return getattr(self._script_driver, attr)
|
|
235
240
|
|
|
236
241
|
class _XPathEntry(u2.xpath.XPathEntry):
|
|
@@ -293,6 +298,10 @@ class U2Driver(AbstractDriver):
|
|
|
293
298
|
self.staticChecker = U2StaticChecker()
|
|
294
299
|
return self.staticChecker.getInstance(hierarchy)
|
|
295
300
|
|
|
301
|
+
@classmethod
|
|
302
|
+
def tearDown(self):
|
|
303
|
+
self.scriptDriver.tearDown()
|
|
304
|
+
|
|
296
305
|
|
|
297
306
|
"""
|
|
298
307
|
Other Utils
|
|
@@ -311,6 +320,7 @@ def forward_port(self, remote: Union[int, str]) -> int:
|
|
|
311
320
|
return int(f.local[len("tcp:") :])
|
|
312
321
|
local_port = get_free_port()
|
|
313
322
|
self.forward("tcp:" + str(local_port), remote)
|
|
323
|
+
logger.debug(f"forwading port: tcp:{local_port} -> {remote}")
|
|
314
324
|
return local_port
|
|
315
325
|
|
|
316
326
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: Kea2-python
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.1b1
|
|
4
4
|
Summary: A python library for supporting and customizing automated UI testing for mobile apps
|
|
5
5
|
Author-email: Xixian Liang <xixian@stu.ecnu.edu.cn>
|
|
6
6
|
Requires-Python: >=3.8
|
|
@@ -16,6 +16,10 @@ Dynamic: license-file
|
|
|
16
16
|
[](https://pepy.tech/projects/kea2-python)
|
|
17
17
|

|
|
18
18
|
|
|
19
|
+
<div>
|
|
20
|
+
<img src="https://github.com/user-attachments/assets/58f68b00-cc9c-4620-9e2e-66c43cf7caae" style="border-radius: 14px; width: 20%; height: 20%;"/>
|
|
21
|
+
</div>
|
|
22
|
+
|
|
19
23
|
Kea2 is an easy-to-use Python library for supporting, customizing and improving automated UI testing for mobile apps. The library is currently built on top of [Fastbot](https://github.com/bytedance/Fastbot_Android) and [uiautomator2](https://github.com/openatx/uiautomator2), and targeting [Android](https://en.wikipedia.org/wiki/Android_(operating_system)) apps.
|
|
20
24
|
|
|
21
25
|
### Kea2 has three important features:
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
kea2/__init__.py,sha256=
|
|
2
|
-
kea2/absDriver.py,sha256=
|
|
3
|
-
kea2/adbUtils.py,sha256=
|
|
4
|
-
kea2/cli.py,sha256=
|
|
5
|
-
kea2/keaUtils.py,sha256=
|
|
6
|
-
kea2/kea_launcher.py,sha256=
|
|
1
|
+
kea2/__init__.py,sha256=QW4OVa1NHcX-DxC7Nr-ozo1G1wxfARnRh63bB08a1Yw,132
|
|
2
|
+
kea2/absDriver.py,sha256=X99d-OP77EIiDwTLvWVkgDUtqscoxmWeOb-EcaOPWGI,1294
|
|
3
|
+
kea2/adbUtils.py,sha256=JhsQiJ_GZG3iPcFHsBDwkSfQJ9R5dMRKr5fVOgCAe_E,9088
|
|
4
|
+
kea2/cli.py,sha256=E309FofSYGls6OP8BNE-d3Ft_hGQpm61gRKz9TgS-Bk,2752
|
|
5
|
+
kea2/keaUtils.py,sha256=8apsnAlmVnNaMmFFZjTcPqlU-RpztFYvPPY2Gay-jhA,21808
|
|
6
|
+
kea2/kea_launcher.py,sha256=90zppG2XkaU7YyGnqbb0FCfG5dDV6zCx08rMIsGLZbs,4374
|
|
7
7
|
kea2/logWatcher.py,sha256=hd8banPiCa6aCQ6d_MznWKOdzK_A2X_dPbrx-usjxgE,1927
|
|
8
|
-
kea2/u2Driver.py,sha256=
|
|
8
|
+
kea2/u2Driver.py,sha256=IsQ0IvVuyUY16ZAVqeerzqr_3Cu5laeeGvoeCA1_ztU,11065
|
|
9
9
|
kea2/utils.py,sha256=zjuoVwts2qVX9GnTaPoiqarfcSvyfW6cAD3ESf_dmrQ,1284
|
|
10
10
|
kea2/assets/fastbot-thirdpart.jar,sha256=0SZ_OoZFWDGMnazgXKceHgKvXdUDoIa3Gb2bcifaikk,85664
|
|
11
11
|
kea2/assets/framework.jar,sha256=rTluOJJKj2DFwh7ascXso1udYdWv00BxBwSQ3Vmv-fw,1149240
|
|
12
12
|
kea2/assets/monkeyq.jar,sha256=TjszvflvE59ev9RhVhkfS_0L46VYZbL2wvpKRyA8ZMk,460366
|
|
13
|
-
kea2/assets/quicktest.py,sha256=
|
|
13
|
+
kea2/assets/quicktest.py,sha256=j-fIryvspXObaNm3kWzgM0LMFes4h7EXT5C9xUWGUVo,2887
|
|
14
14
|
kea2/assets/u2.jar,sha256=G9fFf-AZ0CdaZrk27V1-pfJE2Y5eO6PRzPShTnIe-U8,3746525
|
|
15
15
|
kea2/assets/fastbot_configs/ADBKeyBoard.apk,sha256=L3Kva4gCQALo10EzinCvHrIbffGE3p94qSNbnS8CxP0,163634
|
|
16
16
|
kea2/assets/fastbot_configs/abl.strings,sha256=Rn8_YEbVGOJqndIY_-kWnR5NaoFI-cuB-ij10Ddhl90,75
|
|
@@ -25,9 +25,9 @@ kea2/assets/fastbot_libs/arm64-v8a/libfastbot_native.so,sha256=dA2Tf74-gDrCFdeCl
|
|
|
25
25
|
kea2/assets/fastbot_libs/armeabi-v7a/libfastbot_native.so,sha256=GWcL8M8WfQAd9CfOM6pRYbOnxeycN-LiL7Mf59YIadE,1334420
|
|
26
26
|
kea2/assets/fastbot_libs/x86/libfastbot_native.so,sha256=k-aw1gEXRWMKZRNHIggKNuZy0wC1y2BnveJGEIO6rbo,2036856
|
|
27
27
|
kea2/assets/fastbot_libs/x86_64/libfastbot_native.so,sha256=tiofhlf4uMQcU5WAvrdLgTBME0lb83hVUoGtTwxmE8A,2121416
|
|
28
|
-
kea2_python-0.0.
|
|
29
|
-
kea2_python-0.0.
|
|
30
|
-
kea2_python-0.0.
|
|
31
|
-
kea2_python-0.0.
|
|
32
|
-
kea2_python-0.0.
|
|
33
|
-
kea2_python-0.0.
|
|
28
|
+
kea2_python-0.0.1b1.dist-info/licenses/LICENSE,sha256=nM9PPjcsXVo5SzNsjRqWgA-gdJlwqZZcRDSC6Qf6bVE,2034
|
|
29
|
+
kea2_python-0.0.1b1.dist-info/METADATA,sha256=e307QrCqtPZ8y4Z8ucayAiydj___hwr3bxkhaQCcwow,22622
|
|
30
|
+
kea2_python-0.0.1b1.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
|
|
31
|
+
kea2_python-0.0.1b1.dist-info/entry_points.txt,sha256=mFX06TyxXiUAJQ6JZn8QHzfn8n5R8_KJ5W-pTm_fRCA,39
|
|
32
|
+
kea2_python-0.0.1b1.dist-info/top_level.txt,sha256=TsgNH4PQoNOVhegpO7AcjutMVWp6Z4KDL1pBH9FnMmk,5
|
|
33
|
+
kea2_python-0.0.1b1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|