Coverage for install/scipp/format/_parse.py: 23%

44 statements  

« prev     ^ index     » next       coverage.py v7.4.0, created at 2024-04-28 01:28 +0000

1# SPDX-License-Identifier: BSD-3-Clause 

2# Copyright (c) 2023 Scipp contributors (https://github.com/scipp) 

3# @author Jan-Lukas Wynen 

4 

5import dataclasses 

6import enum 

7import re 

8from typing import Optional 

9 

10 

11def _dataclass_with_slots(**kwargs): 

12 try: 

13 return dataclasses.dataclass(slots=True, **kwargs) 

14 except TypeError: 

15 # Fallback for Python < 3.10 

16 return dataclasses.dataclass(**kwargs) 

17 

18 

19class FormatType(enum.Enum): 

20 default = None 

21 compact = 'c' 

22 

23 

24@_dataclass_with_slots(frozen=True) 

25class FormatSpec: 

26 format_type: FormatType 

27 _selection: Optional[str] 

28 _length: Optional[int] 

29 _nested: Optional[str] 

30 

31 @property 

32 def selection(self) -> str: 

33 return '^' if self._selection is None else self._selection 

34 

35 @property 

36 def length(self) -> int: 

37 return 4 if self._length is None else int(self._length) 

38 

39 @property 

40 def nested(self) -> str: 

41 return '' if self._nested is None else self._nested 

42 

43 @property 

44 def has_selection(self) -> bool: 

45 return self._selection is not None 

46 

47 @property 

48 def has_length(self) -> bool: 

49 return self._length is not None 

50 

51 @property 

52 def has_nested(self) -> bool: 

53 return self._nested is not None 

54 

55 def __str__(self) -> str: 

56 return ( 

57 self.selection 

58 if self.has_selection 

59 else '' + f'#{self.length}' 

60 if self.has_length 

61 else '' + str(self.format_type) 

62 if self.format_type != FormatType.default 

63 else '' + f':{self.nested}' 

64 if self.has_nested 

65 else '' 

66 ) 

67 

68 

69_FORMAT_PATTERN = re.compile( 

70 '^(?P<selection>[><^])?' 

71 r'(?:#(?P<length>\d+))?' 

72 '(?P<type>[c])?' 

73 '(?::(?P<nested>.*))?$' 

74) 

75 

76 

77def parse(raw_spec: str, cls: type) -> FormatSpec: 

78 match = _FORMAT_PATTERN.match(raw_spec) 

79 if match is None: 

80 raise ValueError(f"Invalid format spec '{raw_spec}' for type '{cls}'") 

81 

82 return FormatSpec( 

83 format_type=FormatType(match['type']), 

84 _selection=match['selection'], 

85 _length=match['length'], 

86 _nested=match['nested'], 

87 )