11#!/usr/bin/env python3
22"""
3- Pre-commit hook to ensure optional imports are wrapped in try...except blocks .
3+ Pre-commit hook to ensure optional dependencies are always imported from .options module .
44This ensures that the connector can operate in environments where these optional libraries are not available.
55"""
66import argparse
@@ -27,17 +27,12 @@ def __str__(self):
2727
2828
2929class ImportChecker (ast .NodeVisitor ):
30- """Checks for unwrapped optional imports."""
30+ """Checks that optional imports are only imported from .options module ."""
3131
3232 def __init__ (self , filename : str ):
3333 self .filename = filename
3434 self .violations : List [ImportViolation ] = []
3535
36- def visit_Try (self , node : ast .Try ):
37- """Track entry/exit of try blocks."""
38- # do not visit blocks inside try..except blocks
39- pass
40-
4136 def visit_Import (self , node : ast .Import ):
4237 """Check import statements."""
4338 for alias in node .names :
@@ -47,27 +42,41 @@ def visit_Import(self, node: ast.Import):
4742 def visit_ImportFrom (self , node : ast .ImportFrom ):
4843 """Check from...import statements."""
4944 if node .module :
50- self ._check_import (node .module , node .lineno , node .col_offset )
45+ # Check if importing from a checked module directly
46+ for module in CHECKED_MODULES :
47+ if node .module .startswith (module ):
48+ self .violations .append (
49+ ImportViolation (
50+ self .filename ,
51+ node .lineno ,
52+ node .col_offset ,
53+ f"Import from '{ node .module } ' is not allowed. Use 'from .options import { module } ' instead" ,
54+ )
55+ )
56+
57+ # Check if importing checked modules from .options (this is allowed)
58+ if node .module == ".options" :
59+ # This is the correct way to import these modules
60+ pass
5161 self .generic_visit (node )
5262
5363 def _check_import (self , module_name : str , line : int , col : int ):
54- """Check if a module import is boto-related and unwrapped."""
55-
64+ """Check if a module import is for checked modules and not from .options."""
5665 for module in CHECKED_MODULES :
5766 if module_name .startswith (module ):
5867 self .violations .append (
5968 ImportViolation (
6069 self .filename ,
6170 line ,
6271 col ,
63- f"Import of '{ module_name } ' must be wrapped in try...except block to handle cases where { module } is not available " ,
72+ f"Direct import of '{ module_name } ' is not allowed. Use 'from .options import { module } ' instead " ,
6473 )
6574 )
6675 break
6776
6877
6978def check_file (filename : str ) -> List [ImportViolation ]:
70- """Check a file for boto import violations."""
79+ """Check a file for optional import violations."""
7180 try :
7281 tree = ast .parse (Path (filename ).read_text ())
7382 except SyntaxError :
@@ -80,9 +89,8 @@ def check_file(filename: str) -> List[ImportViolation]:
8089
8190def main ():
8291 """Main function for pre-commit hook."""
83- return 0 # temporarily skip the check
8492 parser = argparse .ArgumentParser (
85- description = "Check for unwrapped boto3/botocore imports"
93+ description = "Check that optional imports are only imported from .options module "
8694 )
8795 parser .add_argument ("filenames" , nargs = "*" , help = "Filenames to check" )
8896 parser .add_argument (
@@ -98,7 +106,7 @@ def main():
98106
99107 # Show violations
100108 if all_violations :
101- print ("Unwrapped boto3/botocore import violations found:" )
109+ print ("Optional import violations found:" )
102110 print ()
103111
104112 for violation in all_violations :
@@ -107,18 +115,19 @@ def main():
107115 if args .show_fixes :
108116 print ()
109117 print ("How to fix:" )
110- print (" - Wrap boto3/botocore imports in try...except blocks " )
118+ print (" - Import optional modules only from .options module " )
111119 print (" - Example:" )
112- print (" try:" )
113- print (" import boto3" )
114- print (" from botocore.config import Config" )
115- print (" except ImportError:" )
116- print (" # Handle the case where boto3/botocore is not available" )
117- print (" boto3 = None" )
118- print (" Config = None" )
120+ print (" # CORRECT:" )
121+ print (" from .options import boto3, botocore, installed_boto" )
122+ print (" if installed_boto:" )
123+ print (" SigV4Auth = botocore.auth.SigV4Auth" )
124+ print ()
125+ print (" # INCORRECT:" )
126+ print (" import boto3" )
127+ print (" from botocore.auth import SigV4Auth" )
119128 print ()
120129 print (
121- " - This ensures the connector works in environments where AWS libraries are not installed"
130+ " - This ensures the connector works in environments where optional libraries are not installed"
122131 )
123132
124133 print ()
0 commit comments