From 4f964a9ff1bafa78b21d544bb04a2807f5f4ebe3 Mon Sep 17 00:00:00 2001 From: Jorge Moraleda Date: Thu, 12 Jun 2025 20:06:37 -0400 Subject: [PATCH 1/3] Add option extract_from_dir and frontend to follow symbolic links when traversing a directory --- babel/messages/extract.py | 5 ++++- babel/messages/frontend.py | 6 +++++- docs/cmdline.rst | 2 ++ tests/messages/test_frontend.py | 8 ++++++++ 4 files changed, 19 insertions(+), 2 deletions(-) diff --git a/babel/messages/extract.py b/babel/messages/extract.py index dcf62f24f..ff3ae83da 100644 --- a/babel/messages/extract.py +++ b/babel/messages/extract.py @@ -126,6 +126,7 @@ def extract_from_dir( callback: Callable[[str, str, dict[str, Any]], object] | None = None, strip_comment_tags: bool = False, directory_filter: Callable[[str], bool] | None = None, + follow_links: bool = False, ) -> Generator[_FileExtractionResult, None, None]: """Extract messages from any source files found in the given directory. @@ -194,6 +195,8 @@ def extract_from_dir( :param directory_filter: a callback to determine whether a directory should be recursed into. Receives the full directory path; should return True if the directory is valid. + :param follow_links: Whether symbolic links should be followed in OS's that + support them. By default they are not followed. :see: `pathmatch` """ if dirname is None: @@ -204,7 +207,7 @@ def extract_from_dir( directory_filter = default_directory_filter absname = os.path.abspath(dirname) - for root, dirnames, filenames in os.walk(absname): + for root, dirnames, filenames in os.walk(absname, followlinks=follow_links): dirnames[:] = [ subdir for subdir in dirnames if directory_filter(os.path.join(root, subdir)) diff --git a/babel/messages/frontend.py b/babel/messages/frontend.py index 29e5a2aa2..703e72b03 100644 --- a/babel/messages/frontend.py +++ b/babel/messages/frontend.py @@ -347,10 +347,12 @@ class ExtractMessages(CommandMixin): 'header comment for the catalog'), ('last-translator=', None, 'set the name and email of the last translator in output'), + ('follow-links', 'l', + 'follow symbolic links when traversing directories'), ] boolean_options = [ 'no-default-keywords', 'no-location', 'omit-header', 'no-wrap', - 'sort-output', 'sort-by-file', 'strip-comments', + 'sort-output', 'sort-by-file', 'strip-comments', 'follow-links' ] as_args = 'input-paths' multiple_value_options = ( @@ -390,6 +392,7 @@ def initialize_options(self): self.version = None self.add_comments = None self.strip_comments = False + self.follow_links = False self.include_lineno = True self.ignore_dirs = None self.header_comment = None @@ -518,6 +521,7 @@ def run(self): callback=callback, strip_comment_tags=self.strip_comments, directory_filter=self.directory_filter, + follow_links=self.follow_links, ) for filename, lineno, message, comments, context in extracted: if os.path.isfile(path): diff --git a/docs/cmdline.rst b/docs/cmdline.rst index e1328fe8f..ab5fe8865 100644 --- a/docs/cmdline.rst +++ b/docs/cmdline.rst @@ -129,6 +129,8 @@ a collection of source files:: Patterns for directories to ignore when scanning for messages. Separate multiple patterns with spaces (default ".* ._") + -f, --follow-links + follow symbolic links when traversing directories --header-comment=HEADER_COMMENT header comment for the catalog diff --git a/tests/messages/test_frontend.py b/tests/messages/test_frontend.py index c83948d28..94a622855 100644 --- a/tests/messages/test_frontend.py +++ b/tests/messages/test_frontend.py @@ -1608,6 +1608,14 @@ def test_extract_cli_knows_dash_s(): assert cmdinst.strip_comments + +def test_extract_cli_knows_follow_links(): + # This tests the follow-links command line argument + cmdinst = configure_cli_command("extract --follow-links -o foo babel") + assert isinstance(cmdinst, ExtractMessages) + assert cmdinst.follow_links + + def test_extract_cli_knows_dash_dash_last_dash_translator(): cmdinst = configure_cli_command('extract --last-translator "FULL NAME EMAIL@ADDRESS" -o foo babel') assert isinstance(cmdinst, ExtractMessages) From e1762b0bef9ba761f9891812b4a40f68ac0b6b10 Mon Sep 17 00:00:00 2001 From: Jorge Moraleda Date: Tue, 24 Jun 2025 17:36:42 -0400 Subject: [PATCH 2/3] Remove trailing whitespace --- docs/cmdline.rst | 2 +- tests/messages/test_frontend.py | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/cmdline.rst b/docs/cmdline.rst index ab5fe8865..7c95e4861 100644 --- a/docs/cmdline.rst +++ b/docs/cmdline.rst @@ -130,7 +130,7 @@ a collection of source files:: messages. Separate multiple patterns with spaces (default ".* ._") -f, --follow-links - follow symbolic links when traversing directories + follow symbolic links when traversing directories --header-comment=HEADER_COMMENT header comment for the catalog diff --git a/tests/messages/test_frontend.py b/tests/messages/test_frontend.py index 94a622855..b4b73478c 100644 --- a/tests/messages/test_frontend.py +++ b/tests/messages/test_frontend.py @@ -1608,13 +1608,12 @@ def test_extract_cli_knows_dash_s(): assert cmdinst.strip_comments - def test_extract_cli_knows_follow_links(): # This tests the follow-links command line argument cmdinst = configure_cli_command("extract --follow-links -o foo babel") assert isinstance(cmdinst, ExtractMessages) assert cmdinst.follow_links - + def test_extract_cli_knows_dash_dash_last_dash_translator(): cmdinst = configure_cli_command('extract --last-translator "FULL NAME EMAIL@ADDRESS" -o foo babel') From fa35e3f3b31c1133930932506bd584d19a619a11 Mon Sep 17 00:00:00 2001 From: Jorge Moraleda Date: Tue, 8 Jul 2025 08:04:22 -0400 Subject: [PATCH 3/3] Add trailing comma in list definition to complain with linter style requirements --- babel/messages/frontend.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/babel/messages/frontend.py b/babel/messages/frontend.py index 703e72b03..050ac287f 100644 --- a/babel/messages/frontend.py +++ b/babel/messages/frontend.py @@ -352,7 +352,7 @@ class ExtractMessages(CommandMixin): ] boolean_options = [ 'no-default-keywords', 'no-location', 'omit-header', 'no-wrap', - 'sort-output', 'sort-by-file', 'strip-comments', 'follow-links' + 'sort-output', 'sort-by-file', 'strip-comments', 'follow-links', ] as_args = 'input-paths' multiple_value_options = (