• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

lbryio / lbry-sdk / 4599645360

pending completion
4599645360

push

github

GitHub
Bump cryptography from 2.5 to 39.0.1

2807 of 6557 branches covered (42.81%)

Branch coverage included in aggregate %.

12289 of 19915 relevant lines covered (61.71%)

0.97 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/lbry/error/generate.py
1
import re
×
2
import sys
×
3
import argparse
×
4
from pathlib import Path
×
5
from textwrap import fill, indent
×
6

7

8
INDENT = ' ' * 4
×
9

10
CLASS = """
×
11

12
class {name}({parents}):{doc}
13
"""
14

15
INIT = """
×
16
    def __init__({args}):{fields}
17
        super().__init__({format}"{message}")
18
"""
19

20
FUNCTIONS = ['claim_id']
×
21

22

23
class ErrorClass:
×
24

25
    def __init__(self, hierarchy, name, message):
×
26
        self.hierarchy = hierarchy.replace('**', '')
×
27
        self.other_parents = []
×
28
        if '(' in name:
×
29
            assert ')' in name, f"Missing closing parenthesis in '{name}'."
×
30
            self.other_parents = name[name.find('(')+1:name.find(')')].split(',')
×
31
            name = name[:name.find('(')]
×
32
        self.name = name
×
33
        self.class_name = name+'Error'
×
34
        self.message = message
×
35
        self.comment = ""
×
36
        if '--' in message:
×
37
            self.message, self.comment = message.split('--')
×
38
        self.message = self.message.strip()
×
39
        self.comment = self.comment.strip()
×
40

41
    @property
×
42
    def is_leaf(self):
×
43
        return 'x' not in self.hierarchy
×
44

45
    @property
×
46
    def code(self):
×
47
        return self.hierarchy.replace('x', '')
×
48

49
    @property
×
50
    def parent_codes(self):
×
51
        return self.hierarchy[0:2], self.hierarchy[0]
×
52

53
    def get_arguments(self):
×
54
        args = ['self']
×
55
        for arg in re.findall('{([a-z0-1_()]+)}', self.message):
×
56
            for func in FUNCTIONS:
×
57
                if arg.startswith(f'{func}('):
×
58
                    arg = arg[len(f'{func}('):-1]
×
59
                    break
×
60
            args.append(arg)
×
61
        return args
×
62

63
    @staticmethod
×
64
    def get_fields(args):
×
65
        if len(args) > 1:
×
66
            return ''.join(f'\n{INDENT*2}self.{field} = {field}' for field in args[1:])
×
67
        return ''
×
68

69
    @staticmethod
×
70
    def get_doc_string(doc):
×
71
        if doc:
×
72
            return f'\n{INDENT}"""\n{indent(fill(doc, 100), INDENT)}\n{INDENT}"""'
×
73
        return ""
×
74

75
    def render(self, out, parent):
×
76
        if not parent:
×
77
            parents = ['BaseError']
×
78
        else:
79
            parents = [parent.class_name]
×
80
        parents += self.other_parents
×
81
        args = self.get_arguments()
×
82
        if self.is_leaf:
×
83
            out.write((CLASS + INIT).format(
×
84
                name=self.class_name, parents=', '.join(parents),
85
                args=', '.join(args), fields=self.get_fields(args),
86
                message=self.message, doc=self.get_doc_string(self.comment), format='f' if len(args) > 1 else ''
87
            ))
88
        else:
89
            out.write(CLASS.format(
×
90
                name=self.class_name, parents=', '.join(parents),
91
                doc=self.get_doc_string(self.comment or self.message)
92
            ))
93

94

95
def get_errors():
×
96
    with open('README.md', 'r') as readme:
×
97
        lines = iter(readme.readlines())
×
98
        for line in lines:
×
99
            if line.startswith('## Exceptions Table'):
×
100
                break
×
101
        for line in lines:
×
102
            if line.startswith('---:|'):
×
103
                break
×
104
        for line in lines:
×
105
            if not line:
×
106
                break
×
107
            yield ErrorClass(*[c.strip() for c in line.split('|')])
×
108

109

110
def find_parent(stack, child):
×
111
    for parent_code in child.parent_codes:
×
112
        parent = stack.get(parent_code)
×
113
        if parent:
×
114
            return parent
×
115

116

117
def generate(out):
×
118
    out.write(f"from .base import BaseError, {', '.join(FUNCTIONS)}\n")
×
119
    stack = {}
×
120
    for error in get_errors():
×
121
        error.render(out, find_parent(stack, error))
×
122
        if not error.is_leaf:
×
123
            assert error.code not in stack, f"Duplicate code: {error.code}"
×
124
            stack[error.code] = error
×
125

126

127
def analyze():
×
128
    errors = {e.class_name: [] for e in get_errors() if e.is_leaf}
×
129
    here = Path(__file__).absolute().parents[0]
×
130
    module = here.parent
×
131
    for file_path in module.glob('**/*.py'):
×
132
        if here in file_path.parents:
×
133
            continue
×
134
        with open(file_path) as src_file:
×
135
            src = src_file.read()
×
136
            for error in errors.keys():
×
137
                found = src.count(error)
×
138
                if found > 0:
×
139
                    errors[error].append((file_path, found))
×
140

141
    print('Unused Errors:\n')
×
142
    for error, used in errors.items():
×
143
        if used:
×
144
            print(f' - {error}')
×
145
            for use in used:
×
146
                print(f'   {use[0].relative_to(module.parent)} {use[1]}')
×
147
            print('')
×
148

149
    print('')
×
150
    print('Unused Errors:')
×
151
    for error, used in errors.items():
×
152
        if not used:
×
153
            print(f' - {error}')
×
154

155

156
def main():
×
157
    parser = argparse.ArgumentParser()
×
158
    parser.add_argument("action", choices=['generate', 'analyze'])
×
159
    args = parser.parse_args()
×
160
    if args.action == "analyze":
×
161
        analyze()
×
162
    elif args.action == "generate":
×
163
        generate(sys.stdout)
×
164

165

166
if __name__ == "__main__":
×
167
    main()
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc