Repository: ethereum/consensus-specs

Issue:
add linter to CI
Add a new job to CI that uses `flake8` or something similar to lint the the pyspec after the python code is dumped to `spec.py`.

This will likely need a bit of configuration (`maxline=120`, etc) and some cleaning up.


Discussion:

Resolving patch:
diff --git a/scripts/phase0/build_spec.py b/scripts/phase0/build_spec.py
--- a/scripts/phase0/build_spec.py
+++ b/scripts/phase0/build_spec.py
@@ -12,8 +12,18 @@ def build_phase0_spec(sourcefile, outfile):
     NewType,
     Tuple,
 )
-from eth2spec.utils.minimal_ssz import *
-from eth2spec.utils.bls_stub import *
+from eth2spec.utils.minimal_ssz import (
+    SSZType,
+    hash_tree_root,
+    signing_root,
+)
+from eth2spec.utils.bls_stub import (
+    bls_aggregate_pubkeys,
+    bls_verify,
+    bls_verify_multiple,
+)
+from eth2spec.utils.hash_function import hash
+
 
 # stub, will get overwritten by real var
 SLOTS_PER_EPOCH = 64
@@ -61,6 +71,7 @@ def hash(x):
         hash_cache[x] = ret
         return ret
 
+
 # Access to overwrite spec constants based on configuration
 def apply_constants_preset(preset: Dict[str, Any]):
     global_vars = globals()
diff --git a/scripts/phase0/function_puller.py b/scripts/phase0/function_puller.py
--- a/scripts/phase0/function_puller.py
+++ b/scripts/phase0/function_puller.py
@@ -55,15 +55,19 @@ def get_spec(file_name: str) -> List[str]:
                     if eligible:
                         code_lines.append(row[0] + ' = ' + (row[1].replace('**TBD**', '0x1234567890123456789012345678901234567890')))
     # Build type-def re-initialization
-    code_lines.append('')
+    code_lines.append('\n')
     code_lines.append('def init_SSZ_types():')
     code_lines.append('    global_vars = globals()')
     for ssz_type_name, ssz_type in type_defs:
         code_lines.append('')
         for type_line in ssz_type:
-            code_lines.append('    ' + type_line)
+            if len(type_line) > 0:
+                code_lines.append('    ' + type_line)
     code_lines.append('\n')
-    code_lines.append('ssz_types = [' + ', '.join([f'\'{ssz_type_name}\'' for (ssz_type_name, _) in type_defs]) + ']')
+    code_lines.append('ssz_types = [\n')
+    for (ssz_type_name, _) in type_defs:
+        code_lines.append(f'    {ssz_type_name},\n')
+    code_lines.append(']')
     code_lines.append('\n')
     code_lines.append('def get_ssz_type_by_name(name: str) -> SSZType:')
     code_lines.append('    return globals()[name]')


Test patch:
diff --git a/test_libs/pyspec/eth2spec/debug/decode.py b/test_libs/pyspec/eth2spec/debug/decode.py
--- a/test_libs/pyspec/eth2spec/debug/decode.py
+++ b/test_libs/pyspec/eth2spec/debug/decode.py
@@ -16,11 +16,11 @@ def decode(json, typ):
         for field, subtype in typ.fields.items():
             temp[field] = decode(json[field], subtype)
             if field + "_hash_tree_root" in json:
-                assert(json[field + "_hash_tree_root"][2:] == 
+                assert(json[field + "_hash_tree_root"][2:] ==
                        hash_tree_root(temp[field], subtype).hex())
         ret = typ(**temp)
         if "hash_tree_root" in json:
-            assert(json["hash_tree_root"][2:] == 
+            assert(json["hash_tree_root"][2:] ==
                    hash_tree_root(ret, typ).hex())
         return ret
     else:
diff --git a/test_libs/pyspec/eth2spec/debug/encode.py b/test_libs/pyspec/eth2spec/debug/encode.py
--- a/test_libs/pyspec/eth2spec/debug/encode.py
+++ b/test_libs/pyspec/eth2spec/debug/encode.py
@@ -25,4 +25,3 @@ def encode(value, typ, include_hash_tree_roots=False):
     else:
         print(value, typ)
         raise Exception("Type not recognized")
-
diff --git a/test_libs/pyspec/eth2spec/debug/random_value.py b/test_libs/pyspec/eth2spec/debug/random_value.py
--- a/test_libs/pyspec/eth2spec/debug/random_value.py
+++ b/test_libs/pyspec/eth2spec/debug/random_value.py
@@ -31,7 +31,12 @@ def is_changing(self):
         return self.value in [0, 4, 5]
 
 
-def get_random_ssz_object(rng: Random, typ: Any, max_bytes_length: int, max_list_length: int, mode: RandomizationMode, chaos: bool) -> Any:
+def get_random_ssz_object(rng: Random,
+                          typ: Any,
+                          max_bytes_length: int,
+                          max_list_length: int,
+                          mode: RandomizationMode,
+                          chaos: bool) -> Any:
     """
     Create an object for a given type, filled with random data.
     :param rng: The random number generator to use.
@@ -77,7 +82,10 @@ def get_random_ssz_object(rng: Random, typ: Any, max_bytes_length: int, max_list
             return get_random_basic_value(rng, typ)
     # Vector:
     elif isinstance(typ, list) and len(typ) == 2:
-        return [get_random_ssz_object(rng, typ[0], max_bytes_length, max_list_length, mode, chaos) for _ in range(typ[1])]
+        return [
+            get_random_ssz_object(rng, typ[0], max_bytes_length, max_list_length, mode, chaos)
+            for _ in range(typ[1])
+        ]
     # List:
     elif isinstance(typ, list) and len(typ) == 1:
         length = rng.randint(0, max_list_length)
@@ -85,10 +93,17 @@ def get_random_ssz_object(rng: Random, typ: Any, max_bytes_length: int, max_list
             length = 1
         if mode == RandomizationMode.mode_max_count:
             length = max_list_length
-        return [get_random_ssz_object(rng, typ[0], max_bytes_length, max_list_length, mode, chaos) for _ in range(length)]
+        return [
+            get_random_ssz_object(rng, typ[0], max_bytes_length, max_list_length, mode, chaos)
+            for _ in range(length)
+        ]
     # Container:
     elif hasattr(typ, 'fields'):
-        return typ(**{field: get_random_ssz_object(rng, subtype, max_bytes_length, max_list_length, mode, chaos) for field, subtype in typ.fields.items()})
+        return typ(**{
+            field:
+                get_random_ssz_object(rng, subtype, max_bytes_length, max_list_length, mode, chaos)
+                for field, subtype in typ.fields.items()
+        })
     else:
         print(typ)
         raise Exception("Type not recognized")