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
« 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 -*-
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#============================================================================#
21''' Absence sentinel factory, global singleton, and helper functions. '''
24import falsifier as _falsifier
26from . import __
29class AbsenceFactory( _falsifier.Falsifier ):
30 ''' Produces arbitrary absence sentinels. '''
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__( )
47 def __repr__( self ) -> str:
48 if self._repr_function is not None:
49 return self._repr_function( self )
50 return 'absence.AbsenceFactory( )'
52 def __str__( self ) -> str:
53 if self._str_function is not None:
54 return self._str_function( self )
55 return 'absence'
57 def __reduce__( self ) -> __.typx.Never:
58 from .exceptions import OperationValidityError
59 raise OperationValidityError( 'pickle' )
62class AbsentSingleton( AbsenceFactory ):
63 ''' Produces global absence sentinel. '''
64 # TODO: Instance immutability after initialization.
66 def __new__( selfclass ) -> __.typx.Self:
67 absent_ = globals( ).get( 'absent' )
68 if isinstance( absent_, selfclass ): return absent_
69 return super( ).__new__( selfclass )
71 def __repr__( self ) -> str:
72 return 'absence.absent'
74 def __str__( self ) -> str:
75 return 'absent'
78absent: __.typx.Annotated[
79 AbsentSingleton, __.ddoc.Doc( ''' Global absence sentinel. ''' )
80] = AbsentSingleton( )
83def is_absence( value: object ) -> __.typx.TypeIs[ AbsenceFactory ]:
84 ''' Checks if value is an absence sentinel. '''
85 return isinstance( value, AbsenceFactory )
88def is_absent( value: object ) -> __.typx.TypeIs[ AbsentSingleton ]:
89 ''' Checks if value is the global absence sentinel. '''
90 return absent is value
93# Note: Separate typevar definition because it is less confusing to Pyright.
94_V = __.typx.TypeVar( '_V' )
95Absential: __.typx.TypeAlias = _V | AbsentSingleton
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
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'