py-geth 4.3.0__py3-none-any.whl → 5.2.0__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.
geth/install.py CHANGED
@@ -1,6 +1,10 @@
1
1
  """
2
2
  Install geth
3
3
  """
4
+ from __future__ import (
5
+ annotations,
6
+ )
7
+
4
8
  import contextlib
5
9
  import functools
6
10
  import os
@@ -8,29 +12,40 @@ import stat
8
12
  import subprocess
9
13
  import sys
10
14
  import tarfile
15
+ from typing import (
16
+ Any,
17
+ Generator,
18
+ )
19
+
20
+ import requests
21
+ from requests.exceptions import (
22
+ ConnectionError,
23
+ HTTPError,
24
+ Timeout,
25
+ )
26
+
27
+ from geth.exceptions import (
28
+ PyGethException,
29
+ PyGethKeyError,
30
+ PyGethOSError,
31
+ PyGethValueError,
32
+ )
33
+ from geth.types import (
34
+ IO_Any,
35
+ )
11
36
 
12
- V1_11_0 = "v1.11.0"
13
- V1_11_1 = "v1.11.1"
14
- V1_11_2 = "v1.11.2"
15
- V1_11_3 = "v1.11.3"
16
- V1_11_4 = "v1.11.4"
17
- V1_11_5 = "v1.11.5"
18
- V1_11_6 = "v1.11.6"
19
- V1_12_0 = "v1.12.0"
20
- V1_12_1 = "v1.12.1"
21
- V1_12_2 = "v1.12.2"
22
- V1_13_0 = "v1.13.0"
23
- V1_13_1 = "v1.13.1"
24
- V1_13_2 = "v1.13.2"
25
- V1_13_3 = "v1.13.3"
26
- V1_13_4 = "v1.13.4"
27
- V1_13_5 = "v1.13.5"
28
- V1_13_6 = "v1.13.6"
29
- V1_13_7 = "v1.13.7"
30
- V1_13_8 = "v1.13.8"
31
- V1_13_9 = "v1.13.9"
32
- V1_13_10 = "v1.13.10"
33
- V1_13_11 = "v1.13.11"
37
+ V1_14_0 = "v1.14.0"
38
+ V1_14_2 = "v1.14.2"
39
+ V1_14_3 = "v1.14.3"
40
+ V1_14_4 = "v1.14.4"
41
+ V1_14_5 = "v1.14.5"
42
+ V1_14_6 = "v1.14.6"
43
+ V1_14_7 = "v1.14.7"
44
+ V1_14_8 = "v1.14.8"
45
+ V1_14_9 = "v1.14.9"
46
+ V1_14_10 = "v1.14.10"
47
+ V1_14_11 = "v1.14.11"
48
+ V1_14_12 = "v1.14.12"
34
49
 
35
50
 
36
51
  LINUX = "linux"
@@ -42,7 +57,7 @@ WINDOWS = "win32"
42
57
  # System utilities.
43
58
  #
44
59
  @contextlib.contextmanager
45
- def chdir(path):
60
+ def chdir(path: str) -> Generator[None, None, None]:
46
61
  original_path = os.getcwd()
47
62
  try:
48
63
  os.chdir(path)
@@ -51,7 +66,7 @@ def chdir(path):
51
66
  os.chdir(original_path)
52
67
 
53
68
 
54
- def get_platform():
69
+ def get_platform() -> str:
55
70
  if sys.platform.startswith("linux"):
56
71
  return LINUX
57
72
  elif sys.platform == OSX:
@@ -59,11 +74,11 @@ def get_platform():
59
74
  elif sys.platform == WINDOWS:
60
75
  return WINDOWS
61
76
  else:
62
- raise KeyError(f"Unknown platform: {sys.platform}")
77
+ raise PyGethKeyError(f"Unknown platform: {sys.platform}")
63
78
 
64
79
 
65
- def is_executable_available(program):
66
- def is_exe(fpath):
80
+ def is_executable_available(program: str) -> bool:
81
+ def is_exe(fpath: str) -> bool:
67
82
  return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
68
83
 
69
84
  fpath = os.path.dirname(program)
@@ -80,7 +95,7 @@ def is_executable_available(program):
80
95
  return False
81
96
 
82
97
 
83
- def ensure_path_exists(dir_path):
98
+ def ensure_path_exists(dir_path: str) -> bool:
84
99
  """
85
100
  Make sure that a path exists
86
101
  """
@@ -90,13 +105,16 @@ def ensure_path_exists(dir_path):
90
105
  return False
91
106
 
92
107
 
93
- def ensure_parent_dir_exists(path):
108
+ def ensure_parent_dir_exists(path: str) -> None:
94
109
  ensure_path_exists(os.path.dirname(path))
95
110
 
96
111
 
97
112
  def check_subprocess_call(
98
- command, message=None, stderr=subprocess.STDOUT, **proc_kwargs
99
- ):
113
+ command: list[str],
114
+ message: str | None = None,
115
+ stderr: IO_Any = subprocess.STDOUT,
116
+ **proc_kwargs: Any,
117
+ ) -> int:
100
118
  if message:
101
119
  print(message)
102
120
  print(f"Executing: {' '.join(command)}")
@@ -105,8 +123,11 @@ def check_subprocess_call(
105
123
 
106
124
 
107
125
  def check_subprocess_output(
108
- command, message=None, stderr=subprocess.STDOUT, **proc_kwargs
109
- ):
126
+ command: list[str],
127
+ message: str | None = None,
128
+ stderr: IO_Any = subprocess.STDOUT,
129
+ **proc_kwargs: Any,
130
+ ) -> Any:
110
131
  if message:
111
132
  print(message)
112
133
  print(f"Executing: {' '.join(command)}")
@@ -114,23 +135,23 @@ def check_subprocess_output(
114
135
  return subprocess.check_output(command, stderr=stderr, **proc_kwargs)
115
136
 
116
137
 
117
- def chmod_plus_x(executable_path):
138
+ def chmod_plus_x(executable_path: str) -> None:
118
139
  current_st = os.stat(executable_path)
119
140
  os.chmod(executable_path, current_st.st_mode | stat.S_IEXEC)
120
141
 
121
142
 
122
- def get_go_executable_path():
143
+ def get_go_executable_path() -> str:
123
144
  return os.environ.get("GO_BINARY", "go")
124
145
 
125
146
 
126
- def is_go_available():
147
+ def is_go_available() -> bool:
127
148
  return is_executable_available(get_go_executable_path())
128
149
 
129
150
 
130
151
  #
131
152
  # Installation filesystem path utilities
132
153
  #
133
- def get_base_install_path(identifier):
154
+ def get_base_install_path(identifier: str) -> str:
134
155
  if "GETH_BASE_INSTALL_PATH" in os.environ:
135
156
  return os.path.join(
136
157
  os.environ["GETH_BASE_INSTALL_PATH"],
@@ -146,21 +167,21 @@ def get_base_install_path(identifier):
146
167
  )
147
168
 
148
169
 
149
- def get_source_code_archive_path(identifier):
170
+ def get_source_code_archive_path(identifier: str) -> str:
150
171
  return os.path.join(
151
172
  get_base_install_path(identifier),
152
173
  "release.tar.gz",
153
174
  )
154
175
 
155
176
 
156
- def get_source_code_extract_path(identifier):
177
+ def get_source_code_extract_path(identifier: str) -> str:
157
178
  return os.path.join(
158
179
  get_base_install_path(identifier),
159
180
  "source",
160
181
  )
161
182
 
162
183
 
163
- def get_source_code_path(identifier):
184
+ def get_source_code_path(identifier: str) -> str:
164
185
  return os.path.join(
165
186
  get_base_install_path(identifier),
166
187
  "source",
@@ -168,7 +189,7 @@ def get_source_code_path(identifier):
168
189
  )
169
190
 
170
191
 
171
- def get_build_path(identifier):
192
+ def get_build_path(identifier: str) -> str:
172
193
  source_code_path = get_source_code_path(identifier)
173
194
  return os.path.join(
174
195
  source_code_path,
@@ -176,7 +197,7 @@ def get_build_path(identifier):
176
197
  )
177
198
 
178
199
 
179
- def get_built_executable_path(identifier):
200
+ def get_built_executable_path(identifier: str) -> str:
180
201
  build_path = get_build_path(identifier)
181
202
  return os.path.join(
182
203
  build_path,
@@ -185,7 +206,7 @@ def get_built_executable_path(identifier):
185
206
  )
186
207
 
187
208
 
188
- def get_executable_path(identifier):
209
+ def get_executable_path(identifier: str) -> str:
189
210
  base_install_path = get_base_install_path(identifier)
190
211
  return os.path.join(
191
212
  base_install_path,
@@ -202,29 +223,27 @@ DOWNLOAD_SOURCE_CODE_URI_TEMPLATE = (
202
223
  )
203
224
 
204
225
 
205
- def download_source_code_release(identifier):
226
+ def download_source_code_release(identifier: str) -> None:
206
227
  download_uri = DOWNLOAD_SOURCE_CODE_URI_TEMPLATE.format(identifier)
207
228
  source_code_archive_path = get_source_code_archive_path(identifier)
208
229
 
209
230
  ensure_parent_dir_exists(source_code_archive_path)
231
+ try:
232
+ response = requests.get(download_uri)
233
+ response.raise_for_status()
234
+ with open(source_code_archive_path, "wb") as f:
235
+ f.write(response.content)
210
236
 
211
- command = [
212
- "wget",
213
- download_uri,
214
- "-c", # resume previously incomplete download.
215
- "-O",
216
- source_code_archive_path,
217
- ]
218
-
219
- return check_subprocess_call(
220
- command,
221
- message=f"Downloading source code release from {download_uri}",
222
- )
237
+ print(f"Downloading source code release from {download_uri}")
223
238
 
239
+ except (HTTPError, Timeout, ConnectionError) as e:
240
+ raise PyGethException(
241
+ f"An error occurred while downloading from {download_uri}: {e}"
242
+ )
224
243
 
225
- def extract_source_code_release(identifier):
226
- source_code_archive_path = get_source_code_archive_path(identifier)
227
244
 
245
+ def extract_source_code_release(identifier: str) -> None:
246
+ source_code_archive_path = get_source_code_archive_path(identifier)
228
247
  source_code_extract_path = get_source_code_extract_path(identifier)
229
248
  ensure_path_exists(source_code_extract_path)
230
249
 
@@ -234,7 +253,7 @@ def extract_source_code_release(identifier):
234
253
 
235
254
  with tarfile.open(source_code_archive_path, "r:gz") as archive_file:
236
255
 
237
- def is_within_directory(directory, target):
256
+ def is_within_directory(directory: str, target: str) -> bool:
238
257
  abs_directory = os.path.abspath(directory)
239
258
  abs_target = os.path.abspath(target)
240
259
 
@@ -242,20 +261,20 @@ def extract_source_code_release(identifier):
242
261
 
243
262
  return prefix == abs_directory
244
263
 
245
- def safe_extract(tar, path="."):
264
+ def safe_extract(tar: tarfile.TarFile, path: str = ".") -> None:
246
265
  for member in tar.getmembers():
247
266
  member_path = os.path.join(path, member.name)
248
267
  if not is_within_directory(path, member_path):
249
- raise Exception("Attempted Path Traversal in Tar File")
268
+ raise PyGethException("Attempted Path Traversal in Tar File")
250
269
 
251
270
  tar.extractall(path)
252
271
 
253
272
  safe_extract(archive_file, source_code_extract_path)
254
273
 
255
274
 
256
- def build_from_source_code(identifier):
275
+ def build_from_source_code(identifier: str) -> None:
257
276
  if not is_go_available():
258
- raise OSError(
277
+ raise PyGethOSError(
259
278
  "The `go` runtime was not found but is required to build geth. If "
260
279
  "the `go` executable is not in your $PATH you can specify the path "
261
280
  "using the environment variable GO_BINARY to specify the path."
@@ -272,7 +291,7 @@ def build_from_source_code(identifier):
272
291
 
273
292
  built_executable_path = get_built_executable_path(identifier)
274
293
  if not os.path.exists(built_executable_path):
275
- raise OSError(
294
+ raise PyGethOSError(
276
295
  "Built executable not found in expected location: "
277
296
  f"{built_executable_path}"
278
297
  )
@@ -285,12 +304,14 @@ def build_from_source_code(identifier):
285
304
  if os.path.islink(executable_path):
286
305
  os.remove(executable_path)
287
306
  else:
288
- raise OSError(f"Non-symlink file already present at `{executable_path}`")
307
+ raise PyGethOSError(
308
+ f"Non-symlink file already present at `{executable_path}`"
309
+ )
289
310
  os.symlink(built_executable_path, executable_path)
290
311
  chmod_plus_x(executable_path)
291
312
 
292
313
 
293
- def install_from_source_code_release(identifier):
314
+ def install_from_source_code_release(identifier: str) -> None:
294
315
  download_source_code_release(identifier)
295
316
  extract_source_code_release(identifier)
296
317
  build_from_source_code(identifier)
@@ -308,94 +329,63 @@ def install_from_source_code_release(identifier):
308
329
  print(f"geth successfully installed at: {executable_path}\n\n{version_output}\n\n")
309
330
 
310
331
 
311
- install_v1_11_0 = functools.partial(install_from_source_code_release, V1_11_0)
312
- install_v1_11_1 = functools.partial(install_from_source_code_release, V1_11_1)
313
- install_v1_11_2 = functools.partial(install_from_source_code_release, V1_11_2)
314
- install_v1_11_3 = functools.partial(install_from_source_code_release, V1_11_3)
315
- install_v1_11_4 = functools.partial(install_from_source_code_release, V1_11_4)
316
- install_v1_11_5 = functools.partial(install_from_source_code_release, V1_11_5)
317
- install_v1_11_6 = functools.partial(install_from_source_code_release, V1_11_6)
318
- install_v1_12_0 = functools.partial(install_from_source_code_release, V1_12_0)
319
- install_v1_12_1 = functools.partial(install_from_source_code_release, V1_12_1)
320
- install_v1_12_2 = functools.partial(install_from_source_code_release, V1_12_2)
321
- install_v1_13_0 = functools.partial(install_from_source_code_release, V1_13_0)
322
- install_v1_13_1 = functools.partial(install_from_source_code_release, V1_13_1)
323
- install_v1_13_2 = functools.partial(install_from_source_code_release, V1_13_2)
324
- install_v1_13_3 = functools.partial(install_from_source_code_release, V1_13_3)
325
- install_v1_13_4 = functools.partial(install_from_source_code_release, V1_13_4)
326
- install_v1_13_5 = functools.partial(install_from_source_code_release, V1_13_5)
327
- install_v1_13_6 = functools.partial(install_from_source_code_release, V1_13_6)
328
- install_v1_13_7 = functools.partial(install_from_source_code_release, V1_13_7)
329
- install_v1_13_8 = functools.partial(install_from_source_code_release, V1_13_8)
330
- install_v1_13_9 = functools.partial(install_from_source_code_release, V1_13_9)
331
- install_v1_13_10 = functools.partial(install_from_source_code_release, V1_13_10)
332
- install_v1_13_11 = functools.partial(install_from_source_code_release, V1_13_11)
333
-
332
+ install_v1_14_0 = functools.partial(install_from_source_code_release, V1_14_0)
333
+ install_v1_14_2 = functools.partial(install_from_source_code_release, V1_14_2)
334
+ install_v1_14_3 = functools.partial(install_from_source_code_release, V1_14_3)
335
+ install_v1_14_4 = functools.partial(install_from_source_code_release, V1_14_4)
336
+ install_v1_14_5 = functools.partial(install_from_source_code_release, V1_14_5)
337
+ install_v1_14_6 = functools.partial(install_from_source_code_release, V1_14_6)
338
+ install_v1_14_7 = functools.partial(install_from_source_code_release, V1_14_7)
339
+ install_v1_14_8 = functools.partial(install_from_source_code_release, V1_14_8)
340
+ install_v1_14_9 = functools.partial(install_from_source_code_release, V1_14_9)
341
+ install_v1_14_10 = functools.partial(install_from_source_code_release, V1_14_10)
342
+ install_v1_14_11 = functools.partial(install_from_source_code_release, V1_14_11)
343
+ install_v1_14_12 = functools.partial(install_from_source_code_release, V1_14_12)
334
344
 
335
345
  INSTALL_FUNCTIONS = {
336
346
  LINUX: {
337
- V1_11_0: install_v1_11_0,
338
- V1_11_1: install_v1_11_1,
339
- V1_11_2: install_v1_11_2,
340
- V1_11_3: install_v1_11_3,
341
- V1_11_4: install_v1_11_4,
342
- V1_11_5: install_v1_11_5,
343
- V1_11_6: install_v1_11_6,
344
- V1_12_0: install_v1_12_0,
345
- V1_12_1: install_v1_12_1,
346
- V1_12_2: install_v1_12_2,
347
- V1_13_0: install_v1_13_0,
348
- V1_13_1: install_v1_13_1,
349
- V1_13_2: install_v1_13_2,
350
- V1_13_3: install_v1_13_3,
351
- V1_13_4: install_v1_13_4,
352
- V1_13_5: install_v1_13_5,
353
- V1_13_6: install_v1_13_6,
354
- V1_13_7: install_v1_13_7,
355
- V1_13_8: install_v1_13_8,
356
- V1_13_9: install_v1_13_9,
357
- V1_13_10: install_v1_13_10,
358
- V1_13_11: install_v1_13_11,
347
+ V1_14_0: install_v1_14_0,
348
+ V1_14_2: install_v1_14_2,
349
+ V1_14_3: install_v1_14_3,
350
+ V1_14_4: install_v1_14_4,
351
+ V1_14_5: install_v1_14_5,
352
+ V1_14_6: install_v1_14_6,
353
+ V1_14_7: install_v1_14_7,
354
+ V1_14_8: install_v1_14_8,
355
+ V1_14_9: install_v1_14_9,
356
+ V1_14_10: install_v1_14_10,
357
+ V1_14_11: install_v1_14_11,
358
+ V1_14_12: install_v1_14_12,
359
359
  },
360
360
  OSX: {
361
- V1_11_0: install_v1_11_0,
362
- V1_11_1: install_v1_11_1,
363
- V1_11_2: install_v1_11_2,
364
- V1_11_3: install_v1_11_3,
365
- V1_11_4: install_v1_11_4,
366
- V1_11_5: install_v1_11_5,
367
- V1_11_6: install_v1_11_6,
368
- V1_12_0: install_v1_12_0,
369
- V1_12_1: install_v1_12_1,
370
- V1_12_2: install_v1_12_2,
371
- V1_13_0: install_v1_13_0,
372
- V1_13_1: install_v1_13_1,
373
- V1_13_2: install_v1_13_2,
374
- V1_13_3: install_v1_13_3,
375
- V1_13_4: install_v1_13_4,
376
- V1_13_5: install_v1_13_5,
377
- V1_13_6: install_v1_13_6,
378
- V1_13_7: install_v1_13_7,
379
- V1_13_8: install_v1_13_8,
380
- V1_13_9: install_v1_13_9,
381
- V1_13_10: install_v1_13_10,
382
- V1_13_11: install_v1_13_11,
361
+ V1_14_0: install_v1_14_0,
362
+ V1_14_2: install_v1_14_2,
363
+ V1_14_3: install_v1_14_3,
364
+ V1_14_4: install_v1_14_4,
365
+ V1_14_5: install_v1_14_5,
366
+ V1_14_6: install_v1_14_6,
367
+ V1_14_7: install_v1_14_7,
368
+ V1_14_8: install_v1_14_8,
369
+ V1_14_9: install_v1_14_9,
370
+ V1_14_10: install_v1_14_10,
371
+ V1_14_11: install_v1_14_11,
372
+ V1_14_12: install_v1_14_12,
383
373
  },
384
374
  }
385
375
 
386
376
 
387
- def install_geth(identifier, platform=None):
377
+ def install_geth(identifier: str, platform: str | None = None) -> None:
388
378
  if platform is None:
389
379
  platform = get_platform()
390
380
 
391
381
  if platform not in INSTALL_FUNCTIONS:
392
- raise ValueError(
382
+ raise PyGethValueError(
393
383
  "Installation of go-ethereum is not supported on your platform "
394
384
  f"({platform}). Supported platforms are: "
395
385
  f"{', '.join(sorted(INSTALL_FUNCTIONS.keys()))}"
396
386
  )
397
387
  elif identifier not in INSTALL_FUNCTIONS[platform]:
398
- raise ValueError(
388
+ raise PyGethValueError(
399
389
  f"Installation of geth=={identifier} is not supported. Must be one of "
400
390
  f"{', '.join(sorted(INSTALL_FUNCTIONS[platform].keys()))}"
401
391
  )
geth/main.py CHANGED
@@ -1,6 +1,24 @@
1
+ from __future__ import (
2
+ annotations,
3
+ )
4
+
1
5
  import re
2
6
 
3
7
  import semantic_version
8
+ from typing_extensions import (
9
+ Unpack,
10
+ )
11
+
12
+ from geth.exceptions import (
13
+ PyGethTypeError,
14
+ PyGethValueError,
15
+ )
16
+ from geth.types import (
17
+ GethKwargsTypedDict,
18
+ )
19
+ from geth.utils.validation import (
20
+ validate_geth_kwargs,
21
+ )
4
22
 
5
23
  from .utils.encoding import (
6
24
  force_text,
@@ -10,25 +28,29 @@ from .wrapper import (
10
28
  )
11
29
 
12
30
 
13
- def get_geth_version_info_string(**geth_kwargs):
31
+ def get_geth_version_info_string(**geth_kwargs: Unpack[GethKwargsTypedDict]) -> str:
14
32
  if "suffix_args" in geth_kwargs:
15
- raise TypeError(
33
+ raise PyGethTypeError(
16
34
  "The `get_geth_version` function cannot be called with the "
17
35
  "`suffix_args` parameter"
18
36
  )
19
37
  geth_kwargs["suffix_args"] = ["version"]
38
+ validate_geth_kwargs(geth_kwargs)
20
39
  stdoutdata, stderrdata, command, proc = geth_wrapper(**geth_kwargs)
21
- return stdoutdata
40
+ return stdoutdata.decode("utf-8")
22
41
 
23
42
 
24
43
  VERSION_REGEX = r"Version: (.*)\n"
25
44
 
26
45
 
27
- def get_geth_version(**geth_kwargs):
46
+ def get_geth_version(
47
+ **geth_kwargs: Unpack[GethKwargsTypedDict],
48
+ ) -> semantic_version.Version:
49
+ validate_geth_kwargs(geth_kwargs)
28
50
  version_info_string = get_geth_version_info_string(**geth_kwargs)
29
51
  version_match = re.search(VERSION_REGEX, force_text(version_info_string, "utf8"))
30
52
  if not version_match:
31
- raise ValueError(
53
+ raise PyGethValueError(
32
54
  f"Did not match version string in geth output:\n{version_info_string}"
33
55
  )
34
56
  version_string = version_match.groups()[0]