40
40
41
41
log = logging .getLogger ('babel' )
42
42
43
- try :
44
- # See: https://setuptools.pypa.io/en/latest/deprecated/distutils-legacy.html
45
- from setuptools import Command as _Command
46
- distutils_log = log # "distutils.log → (no replacement yet)"
47
43
48
- try :
49
- from setuptools .errors import BaseError , OptionError , SetupError
50
- except ImportError : # Error aliases only added in setuptools 59 (2021-11).
51
- OptionError = SetupError = BaseError = Exception
44
+ class BaseError (Exception ):
45
+ pass
52
46
53
- except ImportError :
54
- from distutils import log as distutils_log
55
- from distutils .cmd import Command as _Command
56
- from distutils .errors import DistutilsError as BaseError
57
- from distutils .errors import DistutilsOptionError as OptionError
58
- from distutils .errors import DistutilsSetupError as SetupError
47
+
48
+ class OptionError (BaseError ):
49
+ pass
50
+
51
+
52
+ class SetupError (BaseError ):
53
+ pass
59
54
60
55
61
56
def listify_value (arg , split = None ):
@@ -100,7 +95,7 @@ def listify_value(arg, split=None):
100
95
return out
101
96
102
97
103
- class Command ( _Command ) :
98
+ class CommandMixin :
104
99
# This class is a small shim between Distutils commands and
105
100
# optparse option parsing in the frontend command line.
106
101
@@ -128,7 +123,7 @@ class Command(_Command):
128
123
option_choices = {}
129
124
130
125
#: Log object. To allow replacement in the script command line runner.
131
- log = distutils_log
126
+ log = log
132
127
133
128
def __init__ (self , dist = None ):
134
129
# A less strict version of distutils' `__init__`.
@@ -140,24 +135,21 @@ def __init__(self, dist=None):
140
135
self .help = 0
141
136
self .finalized = 0
142
137
138
+ def initialize_options (self ):
139
+ pass
143
140
144
- class compile_catalog (Command ):
145
- """Catalog compilation command for use in ``setup.py`` scripts.
146
-
147
- If correctly installed, this command is available to Setuptools-using
148
- setup scripts automatically. For projects using plain old ``distutils``,
149
- the command needs to be registered explicitly in ``setup.py``::
150
-
151
- from babel.messages.frontend import compile_catalog
141
+ def ensure_finalized (self ):
142
+ if not self .finalized :
143
+ self .finalize_options ()
144
+ self .finalized = 1
152
145
153
- setup(
154
- ...
155
- cmdclass = {'compile_catalog': compile_catalog}
146
+ def finalize_options ( self ):
147
+ raise RuntimeError (
148
+ f"abstract method -- subclass { self . __class__ } must override" ,
156
149
)
157
150
158
- .. versionadded:: 0.9
159
- """
160
151
152
+ class CompileCatalog (CommandMixin ):
161
153
description = 'compile message catalogs to binary MO files'
162
154
user_options = [
163
155
('domain=' , 'D' ,
@@ -280,31 +272,19 @@ def _make_directory_filter(ignore_patterns):
280
272
"""
281
273
Build a directory_filter function based on a list of ignore patterns.
282
274
"""
275
+
283
276
def cli_directory_filter (dirname ):
284
277
basename = os .path .basename (dirname )
285
278
return not any (
286
279
fnmatch .fnmatch (basename , ignore_pattern )
287
280
for ignore_pattern
288
281
in ignore_patterns
289
282
)
290
- return cli_directory_filter
291
-
292
283
293
- class extract_messages (Command ):
294
- """Message extraction command for use in ``setup.py`` scripts.
295
-
296
- If correctly installed, this command is available to Setuptools-using
297
- setup scripts automatically. For projects using plain old ``distutils``,
298
- the command needs to be registered explicitly in ``setup.py``::
299
-
300
- from babel.messages.frontend import extract_messages
284
+ return cli_directory_filter
301
285
302
- setup(
303
- ...
304
- cmdclass = {'extract_messages': extract_messages}
305
- )
306
- """
307
286
287
+ class ExtractMessages (CommandMixin ):
308
288
description = 'extract localizable strings from the project code'
309
289
user_options = [
310
290
('charset=' , None ,
@@ -497,6 +477,7 @@ def callback(filename: str, method: str, options: dict):
497
477
opt_values = ", " .join (f'{ k } ="{ v } "' for k , v in options .items ())
498
478
optstr = f" ({ opt_values } )"
499
479
self .log .info ('extracting messages from %s%s' , filepath , optstr )
480
+
500
481
return callback
501
482
502
483
def run (self ):
@@ -572,38 +553,7 @@ def _get_mappings(self):
572
553
return mappings
573
554
574
555
575
- def check_message_extractors (dist , name , value ):
576
- """Validate the ``message_extractors`` keyword argument to ``setup()``.
577
-
578
- :param dist: the distutils/setuptools ``Distribution`` object
579
- :param name: the name of the keyword argument (should always be
580
- "message_extractors")
581
- :param value: the value of the keyword argument
582
- :raise `DistutilsSetupError`: if the value is not valid
583
- """
584
- assert name == 'message_extractors'
585
- if not isinstance (value , dict ):
586
- raise SetupError (
587
- 'the value of the "message_extractors" '
588
- 'parameter must be a dictionary'
589
- )
590
-
591
-
592
- class init_catalog (Command ):
593
- """New catalog initialization command for use in ``setup.py`` scripts.
594
-
595
- If correctly installed, this command is available to Setuptools-using
596
- setup scripts automatically. For projects using plain old ``distutils``,
597
- the command needs to be registered explicitly in ``setup.py``::
598
-
599
- from babel.messages.frontend import init_catalog
600
-
601
- setup(
602
- ...
603
- cmdclass = {'init_catalog': init_catalog}
604
- )
605
- """
606
-
556
+ class InitCatalog (CommandMixin ):
607
557
description = 'create a new catalog based on a POT file'
608
558
user_options = [
609
559
('domain=' , 'D' ,
@@ -678,23 +628,7 @@ def run(self):
678
628
write_po (outfile , catalog , width = self .width )
679
629
680
630
681
- class update_catalog (Command ):
682
- """Catalog merging command for use in ``setup.py`` scripts.
683
-
684
- If correctly installed, this command is available to Setuptools-using
685
- setup scripts automatically. For projects using plain old ``distutils``,
686
- the command needs to be registered explicitly in ``setup.py``::
687
-
688
- from babel.messages.frontend import update_catalog
689
-
690
- setup(
691
- ...
692
- cmdclass = {'update_catalog': update_catalog}
693
- )
694
-
695
- .. versionadded:: 0.9
696
- """
697
-
631
+ class UpdateCatalog (CommandMixin ):
698
632
description = 'update message catalogs from a POT file'
699
633
user_options = [
700
634
('domain=' , 'D' ,
@@ -911,10 +845,10 @@ class CommandLineInterface:
911
845
}
912
846
913
847
command_classes = {
914
- 'compile' : compile_catalog ,
915
- 'extract' : extract_messages ,
916
- 'init' : init_catalog ,
917
- 'update' : update_catalog ,
848
+ 'compile' : CompileCatalog ,
849
+ 'extract' : ExtractMessages ,
850
+ 'init' : InitCatalog ,
851
+ 'update' : UpdateCatalog ,
918
852
}
919
853
920
854
log = None # Replaced on instance level
@@ -996,7 +930,7 @@ def _configure_command(self, cmdname, argv):
996
930
cmdinst = cmdclass ()
997
931
if self .log :
998
932
cmdinst .log = self .log # Use our logger, not distutils'.
999
- assert isinstance (cmdinst , Command )
933
+ assert isinstance (cmdinst , CommandMixin )
1000
934
cmdinst .initialize_options ()
1001
935
1002
936
parser = optparse .OptionParser (
@@ -1113,7 +1047,8 @@ def parse_mapping(fileobj, filename=None):
1113
1047
1114
1048
return method_map , options_map
1115
1049
1116
- def _parse_spec (s : str ) -> tuple [int | None , tuple [int | tuple [int , str ], ...]]:
1050
+
1051
+ def _parse_spec (s : str ) -> tuple [int | None , tuple [int | tuple [int , str ], ...]]:
1117
1052
inds = []
1118
1053
number = None
1119
1054
for x in s .split (',' ):
@@ -1125,6 +1060,7 @@ def _parse_spec(s: str) -> tuple[int | None, tuple[int|tuple[int, str], ...]]:
1125
1060
inds .append (int (x ))
1126
1061
return number , tuple (inds )
1127
1062
1063
+
1128
1064
def parse_keywords (strings : Iterable [str ] = ()):
1129
1065
"""Parse keywords specifications from the given list of strings.
1130
1066
@@ -1173,5 +1109,16 @@ def parse_keywords(strings: Iterable[str] = ()):
1173
1109
return keywords
1174
1110
1175
1111
1112
+ def __getattr__ (name : str ):
1113
+ # Re-exports for backwards compatibility;
1114
+ # `setuptools_frontend` is the canonical import location.
1115
+ if name in {'check_message_extractors' , 'compile_catalog' , 'extract_messages' , 'init_catalog' , 'update_catalog' }:
1116
+ from babel .messages import setuptools_frontend
1117
+
1118
+ return getattr (setuptools_frontend , name )
1119
+
1120
+ raise AttributeError (f"module { __name__ !r} has no attribute { name !r} " )
1121
+
1122
+
1176
1123
if __name__ == '__main__' :
1177
1124
main ()
0 commit comments