Coverage for sources/absence/objects.py: 100%

36 statements  

« prev     ^ index     » next       coverage.py v7.15.4, created at 2026-08-08 06:42 +0000

1# vim: set filetype=python fileencoding=utf-8: 

2# -*- coding: utf-8 -*- 

3 

4#============================================================================# 

5# # 

6# Licensed under the Apache License, Version 2.0 (the "License"); # 

7# you may not use this file except in compliance with the License. # 

8# You may obtain a copy of the License at # 

9# # 

10# http://www.apache.org/licenses/LICENSE-2.0 # 

11# # 

12# Unless required by applicable law or agreed to in writing, software # 

13# distributed under the License is distributed on an "AS IS" BASIS, # 

14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # 

15# See the License for the specific language governing permissions and # 

16# limitations under the License. # 

17# # 

18#============================================================================# 

19 

20 

21''' Absence sentinel factory, global singleton, and helper functions. ''' 

22 

23 

24import falsifier as _falsifier 

25 

26from . import __ 

27 

28 

29class AbsenceFactory( _falsifier.Falsifier ): 

30 ''' Produces arbitrary absence sentinels. ''' 

31 

32 def __init__( 

33 self, 

34 repr_function: __.typx.Annotated[ 

35 __.typx.Optional[ __.cabc.Callable[ [ __.typx.Self ], str ] ], 

36 __.ddoc.Doc( ''' Function for __repr__. ''' ) 

37 ] = None, 

38 str_function: __.typx.Annotated[ 

39 __.typx.Optional[ __.cabc.Callable[ [ __.typx.Self ], str ] ], 

40 __.ddoc.Doc( ''' Function for __str__. ''' ) 

41 ] = None, 

42 ) -> None: 

43 self._repr_function = repr_function 

44 self._str_function = str_function 

45 super( ).__init__( ) 

46 

47 def __repr__( self ) -> str: 

48 if self._repr_function is not None: 

49 return self._repr_function( self ) 

50 return 'absence.AbsenceFactory( )' 

51 

52 def __str__( self ) -> str: 

53 if self._str_function is not None: 

54 return self._str_function( self ) 

55 return 'absence' 

56 

57 def __reduce__( self ) -> __.typx.Never: 

58 from .exceptions import OperationValidityError 

59 raise OperationValidityError( 'pickle' ) 

60 

61 

62class AbsentSingleton( AbsenceFactory ): 

63 ''' Produces global absence sentinel. ''' 

64 # TODO: Instance immutability after initialization. 

65 

66 def __new__( selfclass ) -> __.typx.Self: 

67 absent_ = globals( ).get( 'absent' ) 

68 if isinstance( absent_, selfclass ): return absent_ 

69 return super( ).__new__( selfclass ) 

70 

71 def __repr__( self ) -> str: 

72 return 'absence.absent' 

73 

74 def __str__( self ) -> str: 

75 return 'absent' 

76 

77 

78absent: __.typx.Annotated[ 

79 AbsentSingleton, __.ddoc.Doc( ''' Global absence sentinel. ''' ) 

80] = AbsentSingleton( ) 

81 

82 

83def is_absence( value: object ) -> __.typx.TypeIs[ AbsenceFactory ]: 

84 ''' Checks if value is an absence sentinel. ''' 

85 return isinstance( value, AbsenceFactory ) 

86 

87 

88def is_absent( value: object ) -> __.typx.TypeIs[ AbsentSingleton ]: 

89 ''' Checks if value is the global absence sentinel. ''' 

90 return absent is value 

91 

92 

93# Note: Separate typevar definition because it is less confusing to Pyright. 

94_V = __.typx.TypeVar( '_V' ) 

95Absential: __.typx.TypeAlias = _V | AbsentSingleton 

96 

97 

98def is_present( value: Absential[ _V ] ) -> __.typx.TypeIs[ _V ]: 

99 ''' Checks if value is present (not the global absent sentinel). ''' 

100 return value is not absent 

101 

102 

103def _typecheck_me( arg: Absential[ int ] = absent ): # pragma: no cover 

104 # Note: Not part of public interface. 

105 # Exists to help identify type issues 

106 # since test code is exempt from type checking at this time. 

107 if is_present( arg ): return arg 

108 return 'absent'