Coverage for sources/copiertv/exceptions.py: 100%
46 statements
« prev ^ index » next coverage.py v7.14.1, created at 2026-06-14 02:11 +0000
« prev ^ index » next coverage.py v7.14.1, created at 2026-06-14 02:11 +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''' Family of exceptions for package API. '''
24from . import __
27class Omniexception( __.immut.exceptions.Omniexception ):
28 ''' Base for all exceptions raised by package API. '''
31class Omnierror( Omniexception, Exception ):
32 ''' Base for error exceptions raised by package API. '''
35class ConfigurationAbsence( Omnierror, FileNotFoundError ):
36 ''' Required configuration resource not found. '''
38 def __init__(
39 self, location: __.Absential[ __.Path ] = __.absent
40 ) -> None:
41 message = 'Could not locate configuration'
42 if not __.is_absent( location ):
43 message = f"{message} at '{location}'"
44 super( ).__init__( f"{message}." )
46 def render_as_markdown( self ) -> tuple[ str, ... ]:
47 return (
48 f"\u274c {self}",
49 '',
50 'Ensure the answers directory and copier.yaml exist.',
51 )
54class ConfigurationInvalidity( Omnierror, ValueError ):
55 ''' Configuration data is invalid or a dependency is missing. '''
57 def __init__(
58 self, reason: __.Absential[ str | Exception ] = __.absent
59 ) -> None:
60 if __.is_absent( reason ): message = 'Invalid configuration.'
61 else: message = f"Invalid configuration: {reason}"
62 super( ).__init__( message )
64 def render_as_markdown( self ) -> tuple[ str, ... ]:
65 return ( f"\u274c {self}", )
68class DataInvalidity( ConfigurationInvalidity ):
69 ''' Data file content is invalid. '''
71 def __init__( self, path: __.Path, cause: str ) -> None:
72 super( ).__init__( f"{cause}: {path}" )
75class FileOperationFailure( Omnierror, OSError ):
76 ''' File or directory operation failure. '''
78 def __init__( self, path: __.Path, operation: str = 'access file' ):
79 message = f"Failed to {operation}: {path}"
80 super( ).__init__( message )
82 def render_as_markdown( self ) -> tuple[ str, ... ]:
83 return ( f"\u274c {self}", )
86class ValidationCommandFailure( Omnierror ):
87 ''' Validation command exited with non-zero status. '''
89 def __init__(
90 self,
91 command: tuple[ str, ... ],
92 returncode: int,
93 temp_directory: __.Absential[ __.Path ] = __.absent,
94 stderr: __.Absential[ str ] = __.absent,
95 ) -> None:
96 self.command = command
97 self.returncode = returncode
98 self._temp_directory = temp_directory
99 self._stderr = stderr
100 message = (
101 f"Validation command failed with exit code "
102 f"{returncode}: {' '.join( command )}"
103 )
104 if not __.is_absent( temp_directory ):
105 message = (
106 f"{message}\nTemporary directory preserved at: "
107 f"{temp_directory}"
108 )
109 if not __.is_absent( stderr ) and stderr:
110 message = f"{message}\n{stderr}"
111 super( ).__init__( message )
113 def render_as_markdown( self ) -> tuple[ str, ... ]:
114 lines = [
115 f"\u274c Validation command failed "
116 f"(exit code {self.returncode}): "
117 f"{' '.join( self.command )}",
118 ]
119 if not __.is_absent( self._stderr ) and self._stderr:
120 lines.append( self._stderr )
121 if not __.is_absent( self._temp_directory ):
122 lines.append(
123 f"\U0001f4c1 Temporary directory preserved at: "
124 f"{self._temp_directory}"
125 )
126 return tuple( lines )