Coverage for sources/absence/objects.py: 100%
35 statements
« prev ^ index » next coverage.py v7.9.2, created at 2025-07-03 18:01 +0000
« prev ^ index » next coverage.py v7.9.2, created at 2025-07-03 18:01 +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. '''
24from __future__ import annotations
26import falsifier as _falsifier
28from . import __
31class AbsenceFactory( _falsifier.Falsifier ):
32 ''' Produces arbitrary absence sentinels. '''
34 def __init__(
35 self,
36 repr_function: __.typx.Annotated[
37 __.typx.Optional[ __.cabc.Callable[ [ __.typx.Self ], str ] ],
38 __.dynadoc.Doc( ''' Function for __repr__. ''' )
39 ] = None,
40 str_function: __.typx.Annotated[
41 __.typx.Optional[ __.cabc.Callable[ [ __.typx.Self ], str ] ],
42 __.dynadoc.Doc( ''' Function for __str__. ''' )
43 ] = None,
44 ) -> None:
45 self._repr_function = repr_function
46 self._str_function = str_function
47 super( ).__init__( )
49 def __repr__( self ) -> str:
50 if self._repr_function is not None:
51 return self._repr_function( self )
52 return 'absence.AbsenceFactory( )'
54 def __str__( self ) -> str:
55 if self._str_function is not None:
56 return self._str_function( self )
57 return 'absence'
59 def __reduce__( self ) -> __.typx.Never:
60 from .exceptions import OperationValidityError
61 raise OperationValidityError( 'pickle' )
64class AbsentSingleton( AbsenceFactory ):
65 ''' Produces global absence sentinel. '''
66 # TODO: Instance immutability after initialization.
68 def __new__( selfclass ) -> __.typx.Self:
69 absent_ = globals( ).get( 'absent' )
70 if isinstance( absent_, selfclass ): return absent_
71 return super( ).__new__( selfclass )
73 def __repr__( self ) -> str:
74 return 'absence.absent'
76 def __str__( self ) -> str:
77 return 'absent'
80absent: __.typx.Annotated[
81 AbsentSingleton, __.dynadoc.Doc( ''' Global absence sentinel. ''' )
82] = AbsentSingleton( )
85def is_absence( value: object ) -> __.typx.TypeIs[ AbsenceFactory ]:
86 ''' Checks if value is an absence sentinel. '''
87 return isinstance( value, AbsenceFactory )
90def is_absent( value: object ) -> __.typx.TypeIs[ AbsentSingleton ]:
91 ''' Checks if value is the global absence sentinel. '''
92 return absent is value
95# Note: Separate typevar definition because it is less confusing to Pyright.
96_V = __.typx.TypeVar( '_V' )
97Absential: __.typx.TypeAlias = _V | AbsentSingleton
100def _typecheck_me( arg: Absential[ int ] = absent ): # pragma: no cover
101 # Note: Not part of public interface.
102 # Exists to help identify type issues
103 # since test code is exempt from type checking at this time.
104 if is_absent( arg ): return 'absent'
105 return arg