py-geth 4.2.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,28 +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"
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"
33
49
 
34
50
 
35
51
  LINUX = "linux"
@@ -41,7 +57,7 @@ WINDOWS = "win32"
41
57
  # System utilities.
42
58
  #
43
59
  @contextlib.contextmanager
44
- def chdir(path):
60
+ def chdir(path: str) -> Generator[None, None, None]:
45
61
  original_path = os.getcwd()
46
62
  try:
47
63
  os.chdir(path)
@@ -50,7 +66,7 @@ def chdir(path):
50
66
  os.chdir(original_path)
51
67
 
52
68
 
53
- def get_platform():
69
+ def get_platform() -> str:
54
70
  if sys.platform.startswith("linux"):
55
71
  return LINUX
56
72
  elif sys.platform == OSX:
@@ -58,11 +74,11 @@ def get_platform():
58
74
  elif sys.platform == WINDOWS:
59
75
  return WINDOWS
60
76
  else:
61
- raise KeyError(f"Unknown platform: {sys.platform}")
77
+ raise PyGethKeyError(f"Unknown platform: {sys.platform}")
62
78
 
63
79
 
64
- def is_executable_available(program):
65
- def is_exe(fpath):
80
+ def is_executable_available(program: str) -> bool:
81
+ def is_exe(fpath: str) -> bool:
66
82
  return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
67
83
 
68
84
  fpath = os.path.dirname(program)
@@ -79,7 +95,7 @@ def is_executable_available(program):
79
95
  return False
80
96
 
81
97
 
82
- def ensure_path_exists(dir_path):
98
+ def ensure_path_exists(dir_path: str) -> bool:
83
99
  """
84
100
  Make sure that a path exists
85
101
  """
@@ -89,13 +105,16 @@ def ensure_path_exists(dir_path):
89
105
  return False
90
106
 
91
107
 
92
- def ensure_parent_dir_exists(path):
108
+ def ensure_parent_dir_exists(path: str) -> None:
93
109
  ensure_path_exists(os.path.dirname(path))
94
110
 
95
111
 
96
112
  def check_subprocess_call(
97
- command, message=None, stderr=subprocess.STDOUT, **proc_kwargs
98
- ):
113
+ command: list[str],
114
+ message: str | None = None,
115
+ stderr: IO_Any = subprocess.STDOUT,
116
+ **proc_kwargs: Any,
117
+ ) -> int:
99
118
  if message:
100
119
  print(message)
101
120
  print(f"Executing: {' '.join(command)}")
@@ -104,8 +123,11 @@ def check_subprocess_call(
104
123
 
105
124
 
106
125
  def check_subprocess_output(
107
- command, message=None, stderr=subprocess.STDOUT, **proc_kwargs
108
- ):
126
+ command: list[str],
127
+ message: str | None = None,
128
+ stderr: IO_Any = subprocess.STDOUT,
129
+ **proc_kwargs: Any,
130
+ ) -> Any:
109
131
  if message:
110
132
  print(message)
111
133
  print(f"Executing: {' '.join(command)}")
@@ -113,23 +135,23 @@ def check_subprocess_output(
113
135
  return subprocess.check_output(command, stderr=stderr, **proc_kwargs)
114
136
 
115
137
 
116
- def chmod_plus_x(executable_path):
138
+ def chmod_plus_x(executable_path: str) -> None:
117
139
  current_st = os.stat(executable_path)
118
140
  os.chmod(executable_path, current_st.st_mode | stat.S_IEXEC)
119
141
 
120
142
 
121
- def get_go_executable_path():
143
+ def get_go_executable_path() -> str:
122
144
  return os.environ.get("GO_BINARY", "go")
123
145
 
124
146
 
125
- def is_go_available():
147
+ def is_go_available() -> bool:
126
148
  return is_executable_available(get_go_executable_path())
127
149
 
128
150
 
129
151
  #
130
152
  # Installation filesystem path utilities
131
153
  #
132
- def get_base_install_path(identifier):
154
+ def get_base_install_path(identifier: str) -> str:
133
155
  if "GETH_BASE_INSTALL_PATH" in os.environ:
134
156
  return os.path.join(
135
157
  os.environ["GETH_BASE_INSTALL_PATH"],
@@ -145,21 +167,21 @@ def get_base_install_path(identifier):
145
167
  )
146
168
 
147
169
 
148
- def get_source_code_archive_path(identifier):
170
+ def get_source_code_archive_path(identifier: str) -> str:
149
171
  return os.path.join(
150
172
  get_base_install_path(identifier),
151
173
  "release.tar.gz",
152
174
  )
153
175
 
154
176
 
155
- def get_source_code_extract_path(identifier):
177
+ def get_source_code_extract_path(identifier: str) -> str:
156
178
  return os.path.join(
157
179
  get_base_install_path(identifier),
158
180
  "source",
159
181
  )
160
182
 
161
183
 
162
- def get_source_code_path(identifier):
184
+ def get_source_code_path(identifier: str) -> str:
163
185
  return os.path.join(
164
186
  get_base_install_path(identifier),
165
187
  "source",
@@ -167,7 +189,7 @@ def get_source_code_path(identifier):
167
189
  )
168
190
 
169
191
 
170
- def get_build_path(identifier):
192
+ def get_build_path(identifier: str) -> str:
171
193
  source_code_path = get_source_code_path(identifier)
172
194
  return os.path.join(
173
195
  source_code_path,
@@ -175,7 +197,7 @@ def get_build_path(identifier):
175
197
  )
176
198
 
177
199
 
178
- def get_built_executable_path(identifier):
200
+ def get_built_executable_path(identifier: str) -> str:
179
201
  build_path = get_build_path(identifier)
180
202
  return os.path.join(
181
203
  build_path,
@@ -184,7 +206,7 @@ def get_built_executable_path(identifier):
184
206
  )
185
207
 
186
208
 
187
- def get_executable_path(identifier):
209
+ def get_executable_path(identifier: str) -> str:
188
210
  base_install_path = get_base_install_path(identifier)
189
211
  return os.path.join(
190
212
  base_install_path,
@@ -201,29 +223,27 @@ DOWNLOAD_SOURCE_CODE_URI_TEMPLATE = (
201
223
  )
202
224
 
203
225
 
204
- def download_source_code_release(identifier):
226
+ def download_source_code_release(identifier: str) -> None:
205
227
  download_uri = DOWNLOAD_SOURCE_CODE_URI_TEMPLATE.format(identifier)
206
228
  source_code_archive_path = get_source_code_archive_path(identifier)
207
229
 
208
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)
209
236
 
210
- command = [
211
- "wget",
212
- download_uri,
213
- "-c", # resume previously incomplete download.
214
- "-O",
215
- source_code_archive_path,
216
- ]
217
-
218
- return check_subprocess_call(
219
- command,
220
- message=f"Downloading source code release from {download_uri}",
221
- )
237
+ print(f"Downloading source code release from {download_uri}")
222
238
 
239
+ except (HTTPError, Timeout, ConnectionError) as e:
240
+ raise PyGethException(
241
+ f"An error occurred while downloading from {download_uri}: {e}"
242
+ )
223
243
 
224
- def extract_source_code_release(identifier):
225
- source_code_archive_path = get_source_code_archive_path(identifier)
226
244
 
245
+ def extract_source_code_release(identifier: str) -> None:
246
+ source_code_archive_path = get_source_code_archive_path(identifier)
227
247
  source_code_extract_path = get_source_code_extract_path(identifier)
228
248
  ensure_path_exists(source_code_extract_path)
229
249
 
@@ -233,7 +253,7 @@ def extract_source_code_release(identifier):
233
253
 
234
254
  with tarfile.open(source_code_archive_path, "r:gz") as archive_file:
235
255
 
236
- def is_within_directory(directory, target):
256
+ def is_within_directory(directory: str, target: str) -> bool:
237
257
  abs_directory = os.path.abspath(directory)
238
258
  abs_target = os.path.abspath(target)
239
259
 
@@ -241,20 +261,20 @@ def extract_source_code_release(identifier):
241
261
 
242
262
  return prefix == abs_directory
243
263
 
244
- def safe_extract(tar, path="."):
264
+ def safe_extract(tar: tarfile.TarFile, path: str = ".") -> None:
245
265
  for member in tar.getmembers():
246
266
  member_path = os.path.join(path, member.name)
247
267
  if not is_within_directory(path, member_path):
248
- raise Exception("Attempted Path Traversal in Tar File")
268
+ raise PyGethException("Attempted Path Traversal in Tar File")
249
269
 
250
270
  tar.extractall(path)
251
271
 
252
272
  safe_extract(archive_file, source_code_extract_path)
253
273
 
254
274
 
255
- def build_from_source_code(identifier):
275
+ def build_from_source_code(identifier: str) -> None:
256
276
  if not is_go_available():
257
- raise OSError(
277
+ raise PyGethOSError(
258
278
  "The `go` runtime was not found but is required to build geth. If "
259
279
  "the `go` executable is not in your $PATH you can specify the path "
260
280
  "using the environment variable GO_BINARY to specify the path."
@@ -271,7 +291,7 @@ def build_from_source_code(identifier):
271
291
 
272
292
  built_executable_path = get_built_executable_path(identifier)
273
293
  if not os.path.exists(built_executable_path):
274
- raise OSError(
294
+ raise PyGethOSError(
275
295
  "Built executable not found in expected location: "
276
296
  f"{built_executable_path}"
277
297
  )
@@ -284,12 +304,14 @@ def build_from_source_code(identifier):
284
304
  if os.path.islink(executable_path):
285
305
  os.remove(executable_path)
286
306
  else:
287
- 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
+ )
288
310
  os.symlink(built_executable_path, executable_path)
289
311
  chmod_plus_x(executable_path)
290
312
 
291
313
 
292
- def install_from_source_code_release(identifier):
314
+ def install_from_source_code_release(identifier: str) -> None:
293
315
  download_source_code_release(identifier)
294
316
  extract_source_code_release(identifier)
295
317
  build_from_source_code(identifier)
@@ -307,91 +329,63 @@ def install_from_source_code_release(identifier):
307
329
  print(f"geth successfully installed at: {executable_path}\n\n{version_output}\n\n")
308
330
 
309
331
 
310
- install_v1_11_0 = functools.partial(install_from_source_code_release, V1_11_0)
311
- install_v1_11_1 = functools.partial(install_from_source_code_release, V1_11_1)
312
- install_v1_11_2 = functools.partial(install_from_source_code_release, V1_11_2)
313
- install_v1_11_3 = functools.partial(install_from_source_code_release, V1_11_3)
314
- install_v1_11_4 = functools.partial(install_from_source_code_release, V1_11_4)
315
- install_v1_11_5 = functools.partial(install_from_source_code_release, V1_11_5)
316
- install_v1_11_6 = functools.partial(install_from_source_code_release, V1_11_6)
317
- install_v1_12_0 = functools.partial(install_from_source_code_release, V1_12_0)
318
- install_v1_12_1 = functools.partial(install_from_source_code_release, V1_12_1)
319
- install_v1_12_2 = functools.partial(install_from_source_code_release, V1_12_2)
320
- install_v1_13_0 = functools.partial(install_from_source_code_release, V1_13_0)
321
- install_v1_13_1 = functools.partial(install_from_source_code_release, V1_13_1)
322
- install_v1_13_2 = functools.partial(install_from_source_code_release, V1_13_2)
323
- install_v1_13_3 = functools.partial(install_from_source_code_release, V1_13_3)
324
- install_v1_13_4 = functools.partial(install_from_source_code_release, V1_13_4)
325
- install_v1_13_5 = functools.partial(install_from_source_code_release, V1_13_5)
326
- install_v1_13_6 = functools.partial(install_from_source_code_release, V1_13_6)
327
- install_v1_13_7 = functools.partial(install_from_source_code_release, V1_13_7)
328
- install_v1_13_8 = functools.partial(install_from_source_code_release, V1_13_8)
329
- install_v1_13_9 = functools.partial(install_from_source_code_release, V1_13_9)
330
- install_v1_13_10 = functools.partial(install_from_source_code_release, V1_13_10)
331
-
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)
332
344
 
333
345
  INSTALL_FUNCTIONS = {
334
346
  LINUX: {
335
- V1_11_0: install_v1_11_0,
336
- V1_11_1: install_v1_11_1,
337
- V1_11_2: install_v1_11_2,
338
- V1_11_3: install_v1_11_3,
339
- V1_11_4: install_v1_11_4,
340
- V1_11_5: install_v1_11_5,
341
- V1_11_6: install_v1_11_6,
342
- V1_12_0: install_v1_12_0,
343
- V1_12_1: install_v1_12_1,
344
- V1_12_2: install_v1_12_2,
345
- V1_13_0: install_v1_13_0,
346
- V1_13_1: install_v1_13_1,
347
- V1_13_2: install_v1_13_2,
348
- V1_13_3: install_v1_13_3,
349
- V1_13_4: install_v1_13_4,
350
- V1_13_5: install_v1_13_5,
351
- V1_13_6: install_v1_13_6,
352
- V1_13_7: install_v1_13_7,
353
- V1_13_8: install_v1_13_8,
354
- V1_13_9: install_v1_13_9,
355
- V1_13_10: install_v1_13_10,
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,
356
359
  },
357
360
  OSX: {
358
- V1_11_0: install_v1_11_0,
359
- V1_11_1: install_v1_11_1,
360
- V1_11_2: install_v1_11_2,
361
- V1_11_3: install_v1_11_3,
362
- V1_11_4: install_v1_11_4,
363
- V1_11_5: install_v1_11_5,
364
- V1_11_6: install_v1_11_6,
365
- V1_12_0: install_v1_12_0,
366
- V1_12_1: install_v1_12_1,
367
- V1_12_2: install_v1_12_2,
368
- V1_13_0: install_v1_13_0,
369
- V1_13_1: install_v1_13_1,
370
- V1_13_2: install_v1_13_2,
371
- V1_13_3: install_v1_13_3,
372
- V1_13_4: install_v1_13_4,
373
- V1_13_5: install_v1_13_5,
374
- V1_13_6: install_v1_13_6,
375
- V1_13_7: install_v1_13_7,
376
- V1_13_8: install_v1_13_8,
377
- V1_13_9: install_v1_13_9,
378
- V1_13_10: install_v1_13_10,
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,
379
373
  },
380
374
  }
381
375
 
382
376
 
383
- def install_geth(identifier, platform=None):
377
+ def install_geth(identifier: str, platform: str | None = None) -> None:
384
378
  if platform is None:
385
379
  platform = get_platform()
386
380
 
387
381
  if platform not in INSTALL_FUNCTIONS:
388
- raise ValueError(
382
+ raise PyGethValueError(
389
383
  "Installation of go-ethereum is not supported on your platform "
390
384
  f"({platform}). Supported platforms are: "
391
385
  f"{', '.join(sorted(INSTALL_FUNCTIONS.keys()))}"
392
386
  )
393
387
  elif identifier not in INSTALL_FUNCTIONS[platform]:
394
- raise ValueError(
388
+ raise PyGethValueError(
395
389
  f"Installation of geth=={identifier} is not supported. Must be one of "
396
390
  f"{', '.join(sorted(INSTALL_FUNCTIONS[platform].keys()))}"
397
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]