Open-AutoTools 0.0.4rc1__py3-none-any.whl → 0.0.4rc2__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.
@@ -2,6 +2,7 @@ import click
2
2
  from .core import run
3
3
  from ..utils.loading import LoadingAnimation
4
4
  from ..utils.updates import check_for_updates
5
+ from ..utils.text import safe_text
5
6
 
6
7
  # CLI COMMAND TO DISPLAY NETWORK INFORMATION AND RUN DIAGNOSTICS
7
8
  @click.command()
@@ -19,6 +20,6 @@ def autoip(test, speed, monitor, interval, ports, dns, location, no_ip):
19
20
  test=test, speed=speed, monitor=monitor, interval=interval,
20
21
  ports=ports, dns=dns, location=location, no_ip=no_ip
21
22
  )
22
- click.echo(output)
23
+ click.echo(safe_text(output))
23
24
  update_msg = check_for_updates()
24
25
  if update_msg: click.echo(update_msg)
autotools/autoip/core.py CHANGED
@@ -183,7 +183,7 @@ def _display_connectivity_tests(output):
183
183
  output.append("\nConnectivity Tests:")
184
184
  results = test_connectivity()
185
185
  for name, success, latency in results:
186
- status = f" {latency}ms" if success else " Failed"
186
+ status = f"OK {latency}ms" if success else "X Failed"
187
187
  output.append(f"{name:<15} {status}")
188
188
 
189
189
  # DISPLAYS LOCATION INFORMATION
@@ -4,6 +4,7 @@ import sys
4
4
  import os
5
5
  import re
6
6
  from ..utils.updates import check_for_updates
7
+ from ..utils.text import safe_text
7
8
 
8
9
  # CLI COMMAND TO RUN TEST SUITE WITH PYTEST
9
10
  @click.command()
@@ -32,12 +33,12 @@ def _install_test_dependencies():
32
33
  import pytest
33
34
  import pytest_cov
34
35
  except ImportError:
35
- click.echo(click.style("\n pytest and/or pytest-cov not found. Installing...", fg='yellow', bold=True))
36
+ click.echo(safe_text(click.style("\n[X] pytest and/or pytest-cov not found. Installing...", fg='yellow', bold=True)))
36
37
  try:
37
- subprocess.run(['pip', 'install', 'pytest', 'pytest-cov'], check=True)
38
- click.echo(click.style(" Successfully installed pytest and pytest-cov", fg='green', bold=True))
38
+ subprocess.run([sys.executable, '-m', 'pip', 'install', 'pytest', 'pytest-cov'], check=True)
39
+ click.echo(safe_text(click.style("[OK] Successfully installed pytest and pytest-cov", fg='green', bold=True)))
39
40
  except subprocess.CalledProcessError as e:
40
- click.echo(click.style(f"\n Failed to install dependencies: {str(e)}", fg='red', bold=True))
41
+ click.echo(safe_text(click.style(f"\n[X] Failed to install dependencies: {str(e)}", fg='red', bold=True)))
41
42
  sys.exit(1)
42
43
 
43
44
  # BUILDS THE TEST COMMAND ARGUMENTS BY ADDING THE CORRECT TEST PATH AND OPTIONS
@@ -149,10 +150,10 @@ def _run_test_process(cmd):
149
150
  coverage_data = _process_test_output(process)
150
151
  _handle_test_result(process, coverage_data)
151
152
  except subprocess.CalledProcessError as e:
152
- click.echo(click.style(f"\n TESTS FAILED WITH RETURN CODE {e.returncode}", fg='red', bold=True))
153
+ click.echo(safe_text(click.style(f"\n[X] TESTS FAILED WITH RETURN CODE {e.returncode}", fg='red', bold=True)))
153
154
  sys.exit(1)
154
155
  except Exception as e:
155
- click.echo(click.style(f"\n ERROR RUNNING TESTS: {str(e)}", fg='red', bold=True))
156
+ click.echo(safe_text(click.style(f"\n[X] ERROR RUNNING TESTS: {str(e)}", fg='red', bold=True)))
156
157
  sys.exit(1)
157
158
 
158
159
  # PREPARES ENVIRONMENT FOR TEST PROCESS
@@ -198,8 +199,8 @@ def _process_test_output(process):
198
199
  # HANDLES TEST RESULT AND DISPLAYS COVERAGE
199
200
  def _handle_test_result(process, coverage_data):
200
201
  if process.returncode == 0:
201
- click.echo(click.style("\n ALL TESTS PASSED !", fg='green', bold=True))
202
+ click.echo(safe_text(click.style("\n[OK] ALL TESTS PASSED !", fg='green', bold=True)))
202
203
  _display_coverage_metrics(coverage_data)
203
204
  else:
204
- click.echo(click.style("\n SOME TESTS FAILED!", fg='red', bold=True))
205
+ click.echo(safe_text(click.style("\n[X] SOME TESTS FAILED!", fg='red', bold=True)))
205
206
  sys.exit(1)
@@ -3,11 +3,17 @@ import gc
3
3
  import sys
4
4
  import time
5
5
  import click
6
- import resource
7
6
  import tracemalloc
8
7
  from contextlib import contextmanager
9
8
  from typing import Dict, List, Tuple, Optional
10
9
 
10
+ try:
11
+ import resource
12
+ RESOURCE_AVAILABLE = True
13
+ except ImportError:
14
+ resource = None
15
+ RESOURCE_AVAILABLE = False
16
+
11
17
  try:
12
18
  import psutil
13
19
  PSUTIL_AVAILABLE = True
@@ -19,9 +25,10 @@ ENABLE_PERFORMANCE_METRICS = False
19
25
  if os.getenv('AUTOTOOLS_DISABLE_PERF', '').lower() in ('1', 'true', 'yes'): ENABLE_PERFORMANCE_METRICS = False
20
26
 
21
27
  # FLAG TO ENABLE/DISABLE TRACEMALLOC (CAN BE SLOW IN PRODUCTION)
22
- # ENABLE BY DEFAULT IN TEST ENVIRONMENTS (DETECTED BY PRESENCE OF PYTEST OR TEST IN SYS.ARGV)
28
+ # ONLY ENABLE IF EXPLICITLY REQUESTED VIA ENV VAR OR IF PYTEST IS ACTUALLY RUNNING
29
+ # DO NOT ENABLE BASED ON ARGUMENT VALUES TO AVOID FALSE POSITIVES (EXAMPLE: "test" AS COMMAND ARGUMENT)
23
30
  _ENV_TRACEMALLOC = os.getenv('AUTOTOOLS_ENABLE_TRACEMALLOC', '').lower() in ('1', 'true', 'yes')
24
- _IS_TEST_ENV = 'pytest' in sys.modules or any('test' in arg.lower() or 'pytest' in arg.lower() for arg in sys.argv)
31
+ _IS_TEST_ENV = 'pytest' in sys.modules or any(arg.endswith('pytest') or arg.endswith('py.test') for arg in sys.argv)
25
32
  ENABLE_TRACEMALLOC = _ENV_TRACEMALLOC or _IS_TEST_ENV
26
33
 
27
34
  # PERFORMANCE METRICS COLLECTOR
@@ -133,47 +140,72 @@ class PerformanceMetrics:
133
140
 
134
141
  # RECORDS CPU USAGE AT START
135
142
  def _record_cpu_start(self):
136
- usage = resource.getrusage(resource.RUSAGE_SELF)
137
- self.cpu_user_start = usage.ru_utime
138
- self.cpu_sys_start = usage.ru_stime
143
+ if PSUTIL_AVAILABLE:
144
+ process = psutil.Process()
145
+ cpu_times = process.cpu_times()
146
+ self.cpu_user_start = cpu_times.user
147
+ self.cpu_sys_start = cpu_times.system
148
+ elif RESOURCE_AVAILABLE:
149
+ usage = resource.getrusage(resource.RUSAGE_SELF)
150
+ self.cpu_user_start = usage.ru_utime
151
+ self.cpu_sys_start = usage.ru_stime
152
+ else:
153
+ self.cpu_user_start = time.process_time()
154
+ self.cpu_sys_start = 0.0
139
155
 
140
156
  # RECORDS CPU USAGE AT END
141
157
  def _record_cpu_end(self):
142
- usage = resource.getrusage(resource.RUSAGE_SELF)
143
- self.cpu_user_end = usage.ru_utime
144
- self.cpu_sys_end = usage.ru_stime
158
+ if PSUTIL_AVAILABLE:
159
+ process = psutil.Process()
160
+ cpu_times = process.cpu_times()
161
+ self.cpu_user_end = cpu_times.user
162
+ self.cpu_sys_end = cpu_times.system
163
+ elif RESOURCE_AVAILABLE:
164
+ usage = resource.getrusage(resource.RUSAGE_SELF)
165
+ self.cpu_user_end = usage.ru_utime
166
+ self.cpu_sys_end = usage.ru_stime
167
+ else:
168
+ self.cpu_user_end = time.process_time()
169
+ self.cpu_sys_end = 0.0
145
170
 
146
171
  # RECORDS MEMORY USAGE AT START
147
172
  def _record_rss_start(self):
148
173
  if PSUTIL_AVAILABLE:
149
174
  process = psutil.Process()
150
175
  self.rss_start = process.memory_info().rss / (1024 * 1024) # MB
151
- else:
176
+ elif RESOURCE_AVAILABLE:
152
177
  usage = resource.getrusage(resource.RUSAGE_SELF)
153
178
  self.rss_start = usage.ru_maxrss / 1024 # MB (LINUX) OR KB (MACOS)
154
179
  if sys.platform == 'darwin':
155
180
  self.rss_start = self.rss_start / 1024 # CONVERT KB TO MB ON MACOS
181
+ else:
182
+ self.rss_start = 0.0
156
183
 
157
184
  # RECORDS MEMORY USAGE AT END
158
185
  def _record_rss_end(self):
159
- if PSUTIL_AVAILABLE:
160
- process = psutil.Process()
161
- mem_info = process.memory_info()
162
- self.rss_peak = mem_info.rss / (1024 * 1024) # MB
186
+ if PSUTIL_AVAILABLE: self._record_rss_end_psutil()
187
+ elif RESOURCE_AVAILABLE: self._record_rss_end_resource()
188
+ else: self.rss_peak = self.rss_start if self.rss_start is not None else 0.0
163
189
 
164
- try:
165
- if hasattr(process, 'memory_info_ex'):
166
- mem_ext = process.memory_info_ex()
167
- if hasattr(mem_ext, 'peak_wss'):
168
- self.rss_peak = max(self.rss_peak, mem_ext.peak_wss / (1024 * 1024))
169
- except Exception:
170
- pass
171
- else:
172
- usage = resource.getrusage(resource.RUSAGE_SELF)
173
- rss_current = usage.ru_maxrss / 1024
174
- if sys.platform == 'darwin':
175
- rss_current = rss_current / 1024
176
- self.rss_peak = max(self.rss_start, rss_current) if self.rss_start else rss_current
190
+ # RECORDS MEMORY USAGE AT END USING PSUTIL
191
+ def _record_rss_end_psutil(self):
192
+ process = psutil.Process()
193
+ mem_info = process.memory_info()
194
+ self.rss_peak = mem_info.rss / (1024 * 1024) # MB
195
+
196
+ try:
197
+ if hasattr(process, 'memory_info_ex'):
198
+ mem_ext = process.memory_info_ex()
199
+ if hasattr(mem_ext, 'peak_wss'): self.rss_peak = max(self.rss_peak, mem_ext.peak_wss / (1024 * 1024))
200
+ except Exception:
201
+ pass
202
+
203
+ # RECORDS MEMORY USAGE AT END USING RESOURCE
204
+ def _record_rss_end_resource(self):
205
+ usage = resource.getrusage(resource.RUSAGE_SELF)
206
+ rss_current = usage.ru_maxrss / 1024
207
+ if sys.platform == 'darwin': rss_current = rss_current / 1024
208
+ self.rss_peak = max(self.rss_start, rss_current) if self.rss_start else rss_current
177
209
 
178
210
  # RECORDS FILESYSTEM I/O AT START
179
211
  def _record_fs_start(self):
@@ -217,15 +249,15 @@ class PerformanceMetrics:
217
249
 
218
250
  # CALCULATES DURATION METRICS IN MILLISECONDS
219
251
  def _calculate_durations(self) -> Tuple[float, float, float]:
220
- total_duration_ms = (self.process_end - self.process_start) * 1000 if self.process_end and self.process_start else 0
221
- startup_duration_ms = (self.startup_end - self.startup_start) * 1000 if self.startup_end and self.startup_start else 0
222
- command_duration_ms = (self.command_end - self.command_start) * 1000 if self.command_end and self.command_start else 0
252
+ total_duration_ms = (self.process_end - self.process_start) * 1000 if self.process_end is not None and self.process_start is not None else 0
253
+ startup_duration_ms = (self.startup_end - self.startup_start) * 1000 if self.startup_end is not None and self.startup_start is not None else 0
254
+ command_duration_ms = (self.command_end - self.command_start) * 1000 if self.command_end is not None and self.command_start is not None else 0
223
255
  return total_duration_ms, startup_duration_ms, command_duration_ms
224
256
 
225
257
  # CALCULATES CPU TIME METRICS IN MILLISECONDS
226
258
  def _calculate_cpu_time(self) -> Tuple[float, float, float]:
227
- cpu_user_ms = (self.cpu_user_end - self.cpu_user_start) * 1000 if self.cpu_user_end and self.cpu_user_start else 0
228
- cpu_sys_ms = (self.cpu_sys_end - self.cpu_sys_start) * 1000 if self.cpu_sys_end and self.cpu_sys_start else 0
259
+ cpu_user_ms = (self.cpu_user_end - self.cpu_user_start) * 1000 if self.cpu_user_end is not None and self.cpu_user_start is not None else 0
260
+ cpu_sys_ms = (self.cpu_sys_end - self.cpu_sys_start) * 1000 if self.cpu_sys_end is not None and self.cpu_sys_start is not None else 0
229
261
  cpu_time_total_ms = cpu_user_ms + cpu_sys_ms
230
262
  return cpu_time_total_ms, cpu_user_ms, cpu_sys_ms
231
263
 
@@ -260,9 +292,9 @@ class PerformanceMetrics:
260
292
 
261
293
  # CALCULATES FILESYSTEM I/O METRICS
262
294
  def _calculate_fs_io(self) -> Tuple[int, int, int]:
263
- fs_bytes_read_total = self.fs_read_end - self.fs_read_start if self.fs_read_end and self.fs_read_start else 0
264
- fs_bytes_written_total = self.fs_write_end - self.fs_write_start if self.fs_write_end and self.fs_write_start else 0
265
- fs_ops_count = self.fs_ops_end - self.fs_ops_start if self.fs_ops_end and self.fs_ops_start else 0
295
+ fs_bytes_read_total = self.fs_read_end - self.fs_read_start if self.fs_read_end is not None and self.fs_read_start is not None else 0
296
+ fs_bytes_written_total = self.fs_write_end - self.fs_write_start if self.fs_write_end is not None and self.fs_write_start is not None else 0
297
+ fs_ops_count = self.fs_ops_end - self.fs_ops_start if self.fs_ops_end is not None and self.fs_ops_start is not None else 0
266
298
  return fs_bytes_read_total, fs_bytes_written_total, fs_ops_count
267
299
 
268
300
  # CALCULATES AND RETURNS ALL PERFORMANCE METRICS AS A DICTIONARY
@@ -0,0 +1,21 @@
1
+ import os
2
+
3
+ # READ REQUIREMENTS FROM A FILE AND RETURN AS A LIST
4
+ # HANDLES MISSING FILES GRACEFULLY BY RETURNING AN EMPTY LIST
5
+ # THE FILENAME IS RELATIVE TO THE PROJECT ROOT (WHERE SETUP.PY IS LOCATED)
6
+ def read_requirements(filename="requirements.txt"):
7
+ project_root = os.path.join(os.path.dirname(__file__), "..", "..")
8
+ requirements_path = os.path.join(os.path.abspath(project_root), filename)
9
+
10
+ try:
11
+ with open(requirements_path, "r", encoding="utf-8") as fh:
12
+ requirements = []
13
+
14
+ for line in fh:
15
+ line = line.strip()
16
+ if line.startswith("-r") or line.startswith("--requirement"): continue
17
+ if line and not line.startswith("#"): requirements.append(line)
18
+
19
+ return requirements
20
+ except FileNotFoundError:
21
+ return []
@@ -0,0 +1,16 @@
1
+ import sys
2
+ from typing import Any
3
+
4
+ # ENSURE TEXT IS SAFE TO WRITE TO THE CURRENT STDOUT ENCODING
5
+ # SOME WINDOWS TERMINALS USE LEGACY ENCODINGS THAT CANNOT ENCODE CERTAIN CHARACTERS
6
+ def safe_text(text: Any) -> Any:
7
+ if not isinstance(text, str): return text
8
+
9
+ encoding = getattr(sys.stdout, "encoding", None) or "utf-8"
10
+
11
+ try:
12
+ text.encode(encoding)
13
+ return text
14
+ except Exception:
15
+ try: return text.encode(encoding, errors="replace").decode(encoding)
16
+ except Exception: return text.encode("ascii", errors="replace").decode("ascii")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: Open-AutoTools
3
- Version: 0.0.4rc1
3
+ Version: 0.0.4rc2
4
4
  Summary: A suite of automated tools accessible via CLI with a simple `autotools` command
5
5
  Home-page: https://github.com/BabylooPro/Open-AutoTools
6
6
  Author: BabylooPro
@@ -14,37 +14,17 @@ Classifier: Operating System :: OS Independent
14
14
  Requires-Python: >=3.10
15
15
  Description-Content-Type: text/markdown
16
16
  License-File: LICENSE
17
- Requires-Dist: build>=1.4.0
18
- Requires-Dist: wheel>=0.45.1
19
- Requires-Dist: Brotli==1.1.0
20
- Requires-Dist: certifi==2024.2.2
21
- Requires-Dist: charset-normalizer==3.3.2
22
- Requires-Dist: click==8.1.3
23
- Requires-Dist: cryptography==42.0.2
24
- Requires-Dist: halo>=0.0.31
25
- Requires-Dist: idna==3.6
26
- Requires-Dist: importlib-metadata>=7.0.1
27
- Requires-Dist: packaging>=23.0
28
- Requires-Dist: platformdirs==4.2.0
29
- Requires-Dist: pycryptodomex==3.20.0
30
- Requires-Dist: pyperclip==1.8.2
17
+ Requires-Dist: click>=8.1.3
18
+ Requires-Dist: requests>=2.31.0
31
19
  Requires-Dist: python-dotenv>=1.0.0
32
- Requires-Dist: requests>=2.32.2
33
- Requires-Dist: tomli==2.0.1
34
- Requires-Dist: tqdm==4.66.2
35
- Requires-Dist: urllib3==2.2.1
36
- Requires-Dist: websockets==13.0.1
37
- Requires-Dist: yapf==0.40.2
38
- Requires-Dist: zipp==3.17.0
20
+ Requires-Dist: packaging>=23.0
21
+ Requires-Dist: halo>=0.0.31
22
+ Requires-Dist: pyperclip>=1.8.2
39
23
  Requires-Dist: netifaces>=0.11.0
40
24
  Requires-Dist: speedtest-cli>=2.1.3
41
25
  Requires-Dist: psutil>=5.9.0
42
- Requires-Dist: setuptools>=40.8.0
43
- Requires-Dist: pytest>=7.4.0
44
- Requires-Dist: pytest-cov>=4.1.0
45
- Requires-Dist: pytest-sugar>=1.0.0
46
- Requires-Dist: pytest-xdist>=3.5.0
47
- Requires-Dist: pytest-timeout>=2.2.0
26
+ Requires-Dist: cryptography>=42.0.2
27
+ Provides-Extra: dev
48
28
  Dynamic: author
49
29
  Dynamic: author-email
50
30
  Dynamic: classifier
@@ -54,6 +34,7 @@ Dynamic: home-page
54
34
  Dynamic: license
55
35
  Dynamic: license-file
56
36
  Dynamic: project-url
37
+ Dynamic: provides-extra
57
38
  Dynamic: requires-dist
58
39
  Dynamic: requires-python
59
40
  Dynamic: summary
@@ -4,8 +4,8 @@ autotools/autocaps/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuF
4
4
  autotools/autocaps/commands.py,sha256=dSsLCmAYtDyk3EudtGw_iLOUbJGMAVDA_kw88sk5v4Y,434
5
5
  autotools/autocaps/core.py,sha256=v0VGndr_6LAN7j5eQiUe1dGnP8GMRNsZmOoL-Z5hJbM,259
6
6
  autotools/autoip/__init__.py,sha256=T_5hz9G4reFPXDucdzRoMFPYlAKwTPt9TejOpkRPgn0,23
7
- autotools/autoip/commands.py,sha256=4-SX_a4EHfNIQcskzBuZKCqY30Vxauo34Zh_p2SuuVw,1194
8
- autotools/autoip/core.py,sha256=8BCzZJaM8CsRFHNi_QZ5kLyZKTXC7WaNPzHvy9BS0Ko,9200
7
+ autotools/autoip/commands.py,sha256=5jIgko1bu7qYoDP_eDkBvNe0mAvT2SKni1WX_8wIOWI,1240
8
+ autotools/autoip/core.py,sha256=Nv67E2ZNpzx0Sy8_v8H5FxSJ4lXTpcYu8cnEjDWS_KE,9197
9
9
  autotools/autolower/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
10
  autotools/autolower/commands.py,sha256=9bW56LqjMbX2k_ZLHMw1JiM-FuhmLo81558N-WSsN2w,437
11
11
  autotools/autolower/core.py,sha256=PLxP9eKoC_NY-ZGPgTxRLxNufv0VGrmOJjjSC_n1zog,259
@@ -13,16 +13,18 @@ autotools/autopassword/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBd
13
13
  autotools/autopassword/commands.py,sha256=c2ciHxoG7hEUhlRV5z-7A8GooBx8njtVcQvIPa74U58,3050
14
14
  autotools/autopassword/core.py,sha256=xSD4--oqEgnWQD4mlymUfL_qbH_7J8caqfenGCYBXcA,2481
15
15
  autotools/autotest/__init__.py,sha256=G4bK86_araxN2j10W8wEX-ol9zXKNhXq8FtPcOj4_p4,55
16
- autotools/autotest/commands.py,sha256=A2bNZFEhJUWwwtYR8mXolGKVizsvQ9lf03wuyPVFDKM,7557
16
+ autotools/autotest/commands.py,sha256=JENOzikauyjsqC5K_Dbsa1XwZhGPXm8cXnoAUomR36I,7693
17
17
  autotools/utils/__init__.py,sha256=2uAirI6ZbOwSFPSg5wuEjA0gMWf1XBJ4yP_WcGeND7M,183
18
18
  autotools/utils/commands.py,sha256=VEkmaHM7taRfKaU_DJngt9F6aD1zyGJW7t42ojQFpLQ,308
19
19
  autotools/utils/loading.py,sha256=yvXQI6FdIJBjRb40R2LTIgDxxNyiv_23p5ixYkQcGtg,752
20
- autotools/utils/performance.py,sha256=X3yUmCn0xvP9aSI42aDt23XXgE7wcSESHWbEjcpbY3g,16522
20
+ autotools/utils/performance.py,sha256=wa9dL9NM8XzLz5yEkQvV9jjKXj8qAVWf6QrIzMyFqA0,17945
21
+ autotools/utils/requirements.py,sha256=hngCUozh_r9lGXk0CmL7H9JOpvk1whEZp9uaa-oXCrI,822
22
+ autotools/utils/text.py,sha256=Ay_mD8cz1M5Z5prYGkVdkr1zBHrVfObpLRzH8wSFa7M,572
21
23
  autotools/utils/updates.py,sha256=FrwGGMI9rv-bUrsIpttRnBNXUAOlPpBb85GcYXa_o6A,1447
22
24
  autotools/utils/version.py,sha256=ruKZcuLN77yO2x0AwjfyaHlncaHE-8GDzzSIBr-agTc,3082
23
- open_autotools-0.0.4rc1.dist-info/licenses/LICENSE,sha256=SpbSRxNWos2l0-geleCa6d0L9G_bOsZRkY4rB9OduJ0,1069
24
- open_autotools-0.0.4rc1.dist-info/METADATA,sha256=FK2uRIzx33-jFWl7o5mfkvIX-c4ZMBD0kwHRr-Em3Cs,3425
25
- open_autotools-0.0.4rc1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
26
- open_autotools-0.0.4rc1.dist-info/entry_points.txt,sha256=wmO-wROjqX5-Dr69PWxOD3m5HUueprQp-7jDsU3RMTU,190
27
- open_autotools-0.0.4rc1.dist-info/top_level.txt,sha256=x5ZRvdQw7DQnVmR0YDqVSAuuS94KTHDmk6uIeW7YOPw,10
28
- open_autotools-0.0.4rc1.dist-info/RECORD,,
25
+ open_autotools-0.0.4rc2.dist-info/licenses/LICENSE,sha256=SpbSRxNWos2l0-geleCa6d0L9G_bOsZRkY4rB9OduJ0,1069
26
+ open_autotools-0.0.4rc2.dist-info/METADATA,sha256=Pv904AIKjcW3Pfl9wMPDKYFauKarvyfE8vxc9MQu9gA,2792
27
+ open_autotools-0.0.4rc2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
28
+ open_autotools-0.0.4rc2.dist-info/entry_points.txt,sha256=wmO-wROjqX5-Dr69PWxOD3m5HUueprQp-7jDsU3RMTU,190
29
+ open_autotools-0.0.4rc2.dist-info/top_level.txt,sha256=x5ZRvdQw7DQnVmR0YDqVSAuuS94KTHDmk6uIeW7YOPw,10
30
+ open_autotools-0.0.4rc2.dist-info/RECORD,,