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

avanov / typeit / 4368003898

pending completion
4368003898

push

github

GitHub
Release 3.11.0.0 (#80)

43 of 43 new or added lines in 3 files covered. (100.0%)

1234 of 1344 relevant lines covered (91.82%)

0.92 hits per line

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

93.48
/typeit/utils.py
1
import re
1✔
2
import keyword
1✔
3
import string
1✔
4
import inspect as ins
1✔
5
from typing import Any, Type, TypeVar, Callable, Optional
1✔
6

7
from colander import TupleSchema, SequenceSchema
1✔
8

9
from typeit import flags
1✔
10
from typeit.definitions import OverridesT
1✔
11
from typeit.parser import get_type_attribute_info
1✔
12
from typeit.schema.nodes import SchemaNode
1✔
13

14
NORMALIZATION_PREFIX = 'overridden__'
1✔
15
SUPPORTED_CHARS = string.ascii_letters + string.digits
1✔
16

17

18
T = TypeVar('T', SchemaNode, TupleSchema, SequenceSchema)
1✔
19
A = TypeVar('A')
1✔
20
B = TypeVar('B')
1✔
21

22
def normalize_name(name: str,
1✔
23
                   pattern=re.compile('^([_0-9]+).*$')) -> str:
24
    """ Some field name patterns are not allowed in NamedTuples
25
    https://docs.python.org/3.7/library/collections.html#collections.namedtuple
26
    """
27
    being_normalized = name
1✔
28
    if not being_normalized.isidentifier():
1✔
29
        being_normalized = ''.join([
×
30
            c if c in SUPPORTED_CHARS else '_' for c in being_normalized
31
        ])
32
    being_normalized = being_normalized.strip('_')
1✔
33

34
    if keyword.iskeyword(being_normalized) or pattern.match(being_normalized):
1✔
35
        return f'{NORMALIZATION_PREFIX}{being_normalized}'
1✔
36
    return being_normalized
1✔
37

38

39
def is_named_tuple(typ: Type[Any]) -> bool:
1✔
40
    return hasattr(typ, '_fields')
1✔
41

42

43
def clone_schema_node(node: T) -> T:
1✔
44
    """ Clonning the node and reassigning the same children,
45
    because clonning is recursive, but we are only interested
46
    in a new version of the outermost schema node, the children nodes
47
    should be shared to avoid unnecessary duplicates.
48
    """
49
    new_node = node.clone()
1✔
50
    # a list comprehension to place the same nodes into
51
    # a new wrapping list object, so that extending
52
    # the cloned node with new children doesn't affect the original node
53
    new_node.children = [x for x in node.children]
1✔
54
    return new_node
1✔
55

56

57
def get_global_name_overrider(overrides: OverridesT) -> Callable[[str], str]:
1✔
58
    return overrides.get(flags.GlobalNameOverride, flags.Identity)
1✔
59

60

61
def new(t: Type[A], scope: Optional[B] = None) -> A:
1✔
62
    """Experimental: Init a type instance from the values of the provided scope, as long as the scope variables
63
    have the same names and their types match the types of the attributes being initialised.
64
    """
65
    if scope is None:
1✔
66
        f = ins.currentframe().f_back.f_locals
1✔
67
    else:
68
        f_ = scope.__annotations__
1✔
69
        f = {x: getattr(scope, x) for x in f_}
1✔
70

71
    tattrs = get_type_attribute_info(t)
1✔
72
    constr = {}
1✔
73
    for attr in tattrs:
1✔
74
        if attr.name not in f:
1✔
75
            raise AttributeError(f"Could not find attribute {attr.name} for type {t.__class__} in the provided context")
×
76
        ctxval = f[attr.name]
1✔
77
        if not isinstance(ctxval, attr.resolved_type):
1✔
78
            raise AttributeError(f"Types do not match: '{attr.name}' has to be {attr.resolved_type} but got {type(ctxval)} instead.")
×
79
        constr[attr.name] = ctxval
1✔
80
    return t(**constr)
1✔
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

© 2026 Coveralls, Inc