4242 "--verbose" , "-v" , count = True , default = False , help = "Increase logging verbosity (-v = INFO, -vv = DEBUG)"
4343)
4444FILES_ARGUMENT = click .argument ("files" , nargs = - 1 )
45-
46-
47- @click .group ()
48- @click .option (
45+ # TODO(phuongfi91): Project option is made available globally in an ugly way. Refactor it.
46+ PROJECT_OPTION = click .option (
4947 "--project" ,
5048 "-p" ,
5149 type = click .Path (exists = True , dir_okay = True , file_okay = False , resolve_path = True ),
5250 help = "Path to project root" ,
5351)
52+
53+
54+ @click .group ()
55+ @PROJECT_OPTION
5456@click .option (
5557 f"--{ Flake8OptionEnum .OFFLINE .name .lower ()} " , # pylint: disable=no-member
5658 is_flag = True ,
@@ -62,18 +64,19 @@ def nitpick_cli(project: Path | None = None, offline=False): # pylint: disable=
6264 """Enforce the same settings across multiple language-independent projects."""
6365
6466
65- def get_nitpick (context : click .Context ) -> Nitpick :
67+ def get_nitpick (context : click .Context , project : Path | None = None ) -> Nitpick :
6668 """Create a Nitpick instance from the click context parameters."""
67- project = None
6869 offline = False
6970 if context .parent :
70- project = context .parent .params ["project" ]
71+ project = (
72+ project or context .parent .params ["project" ]
73+ ) # prioritize 'project' from the current command over the one from context
7174 offline = context .parent .params ["offline" ]
7275 project_root : Path | None = Path (project ) if project else None
7376 return Nitpick .singleton ().init (project_root , offline )
7477
7578
76- def common_fix_or_check (context , verbose : int , files , check_only : bool ) -> None :
79+ def common_fix_or_check (context , project : Path | None , verbose : int , files , check_only : bool ) -> None :
7780 """Common CLI code for both "fix" and "check" commands."""
7881 if verbose :
7982 level = logging .INFO if verbose == 1 else logging .DEBUG
@@ -85,7 +88,7 @@ def common_fix_or_check(context, verbose: int, files, check_only: bool) -> None:
8588
8689 logger .enable (PROJECT_NAME )
8790
88- nit = get_nitpick (context )
91+ nit = get_nitpick (context , project )
8992 try :
9093 for fuss in nit .run (* files , autofix = not check_only ):
9194 nit .echo (fuss .pretty )
@@ -101,39 +104,42 @@ def common_fix_or_check(context, verbose: int, files, check_only: bool) -> None:
101104
102105@nitpick_cli .command ()
103106@click .pass_context
107+ @PROJECT_OPTION
104108@VERBOSE_OPTION
105109@FILES_ARGUMENT
106- def fix (context , verbose , files ):
110+ def fix (context , project : Path | None , verbose , files ):
107111 """Fix files, modifying them directly.
108112
109113 You can use partial and multiple file names in the FILES argument.
110114 """
111- common_fix_or_check (context , verbose , files , False )
115+ common_fix_or_check (context , project , verbose , files , False )
112116
113117
114118@nitpick_cli .command ()
115119@click .pass_context
120+ @PROJECT_OPTION
116121@VERBOSE_OPTION
117122@FILES_ARGUMENT
118- def check (context , verbose , files ):
123+ def check (context , project : Path | None , verbose , files ):
119124 """Don't modify files, just print the differences.
120125
121126 Return code 0 means nothing would change. Return code 1 means some files would be modified.
122127 You can use partial and multiple file names in the FILES argument.
123128 """
124- common_fix_or_check (context , verbose , files , True )
129+ common_fix_or_check (context , project , verbose , files , True )
125130
126131
127132@nitpick_cli .command ()
128133@click .pass_context
134+ @PROJECT_OPTION
129135@FILES_ARGUMENT
130- def ls (context , files ): # pylint: disable=invalid-name
136+ def ls (context , project : Path | None , files ): # pylint: disable=invalid-name
131137 """List of files configured in the Nitpick style.
132138
133139 Display existing files in green and absent files in red.
134140 You can use partial and multiple file names in the FILES argument.
135141 """
136- nit = get_nitpick (context )
142+ nit = get_nitpick (context , project )
137143 try :
138144 violations = list (nit .project .merge_styles (nit .offline ))
139145 error_exit_code = 1
@@ -152,6 +158,7 @@ def ls(context, files): # pylint: disable=invalid-name
152158
153159@nitpick_cli .command ()
154160@click .pass_context
161+ @PROJECT_OPTION
155162@click .option (
156163 "--fix" ,
157164 "-f" ,
@@ -173,8 +180,9 @@ def ls(context, files): # pylint: disable=invalid-name
173180 help = "Library dir to scan for style files (implies --suggest); if not provided, uses the built-in style library" ,
174181)
175182@click .argument ("style_urls" , nargs = - 1 )
176- def init (
183+ def init ( # noqa: PLR0913, pylint: disable=too-many-arguments
177184 context ,
185+ project : Path | None ,
178186 fix : bool , # pylint: disable=redefined-outer-name
179187 suggest : bool ,
180188 library : str | None ,
@@ -194,7 +202,7 @@ def init(
194202 )
195203 return
196204
197- nit = get_nitpick (context )
205+ nit = get_nitpick (context , project )
198206 config = nit .project .read_configuration ()
199207
200208 # Convert tuple to list, so we can add styles to it
0 commit comments