mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 05:31:20 +00:00 
			
		
		
		
	gh-122903: Honor directories in zipfile.Path.glob. (#122908)
This commit is contained in:
		
							parent
							
								
									9cd0326310
								
							
						
					
					
						commit
						6aa35f3002
					
				
					 4 changed files with 40 additions and 9 deletions
				
			
		|  | @ -101,7 +101,7 @@ def zipfile_ondisk(self, alpharep): | ||||||
|     def test_iterdir_and_types(self, alpharep): |     def test_iterdir_and_types(self, alpharep): | ||||||
|         root = zipfile.Path(alpharep) |         root = zipfile.Path(alpharep) | ||||||
|         assert root.is_dir() |         assert root.is_dir() | ||||||
|         a, k, b, g, j = root.iterdir() |         a, n, b, g, j = root.iterdir() | ||||||
|         assert a.is_file() |         assert a.is_file() | ||||||
|         assert b.is_dir() |         assert b.is_dir() | ||||||
|         assert g.is_dir() |         assert g.is_dir() | ||||||
|  | @ -121,7 +121,7 @@ def test_is_file_missing(self, alpharep): | ||||||
|     @pass_alpharep |     @pass_alpharep | ||||||
|     def test_iterdir_on_file(self, alpharep): |     def test_iterdir_on_file(self, alpharep): | ||||||
|         root = zipfile.Path(alpharep) |         root = zipfile.Path(alpharep) | ||||||
|         a, k, b, g, j = root.iterdir() |         a, n, b, g, j = root.iterdir() | ||||||
|         with self.assertRaises(ValueError): |         with self.assertRaises(ValueError): | ||||||
|             a.iterdir() |             a.iterdir() | ||||||
| 
 | 
 | ||||||
|  | @ -136,7 +136,7 @@ def test_subdir_is_dir(self, alpharep): | ||||||
|     @pass_alpharep |     @pass_alpharep | ||||||
|     def test_open(self, alpharep): |     def test_open(self, alpharep): | ||||||
|         root = zipfile.Path(alpharep) |         root = zipfile.Path(alpharep) | ||||||
|         a, k, b, g, j = root.iterdir() |         a, n, b, g, j = root.iterdir() | ||||||
|         with a.open(encoding="utf-8") as strm: |         with a.open(encoding="utf-8") as strm: | ||||||
|             data = strm.read() |             data = strm.read() | ||||||
|         self.assertEqual(data, "content of a") |         self.assertEqual(data, "content of a") | ||||||
|  | @ -240,7 +240,7 @@ def test_open_missing_directory(self, alpharep): | ||||||
|     @pass_alpharep |     @pass_alpharep | ||||||
|     def test_read(self, alpharep): |     def test_read(self, alpharep): | ||||||
|         root = zipfile.Path(alpharep) |         root = zipfile.Path(alpharep) | ||||||
|         a, k, b, g, j = root.iterdir() |         a, n, b, g, j = root.iterdir() | ||||||
|         assert a.read_text(encoding="utf-8") == "content of a" |         assert a.read_text(encoding="utf-8") == "content of a" | ||||||
|         # Also check positional encoding arg (gh-101144). |         # Also check positional encoding arg (gh-101144). | ||||||
|         assert a.read_text("utf-8") == "content of a" |         assert a.read_text("utf-8") == "content of a" | ||||||
|  | @ -306,7 +306,7 @@ def test_mutability(self, alpharep): | ||||||
|         reflect that change. |         reflect that change. | ||||||
|         """ |         """ | ||||||
|         root = zipfile.Path(alpharep) |         root = zipfile.Path(alpharep) | ||||||
|         a, k, b, g, j = root.iterdir() |         a, n, b, g, j = root.iterdir() | ||||||
|         alpharep.writestr('foo.txt', 'foo') |         alpharep.writestr('foo.txt', 'foo') | ||||||
|         alpharep.writestr('bar/baz.txt', 'baz') |         alpharep.writestr('bar/baz.txt', 'baz') | ||||||
|         assert any(child.name == 'foo.txt' for child in root.iterdir()) |         assert any(child.name == 'foo.txt' for child in root.iterdir()) | ||||||
|  | @ -475,6 +475,18 @@ def test_glob_recursive(self, alpharep): | ||||||
| 
 | 
 | ||||||
|         assert list(root.glob("**/*.txt")) == list(root.rglob("*.txt")) |         assert list(root.glob("**/*.txt")) == list(root.rglob("*.txt")) | ||||||
| 
 | 
 | ||||||
|  |     @pass_alpharep | ||||||
|  |     def test_glob_dirs(self, alpharep): | ||||||
|  |         root = zipfile.Path(alpharep) | ||||||
|  |         assert list(root.glob('b')) == [zipfile.Path(alpharep, "b/")] | ||||||
|  |         assert list(root.glob('b*')) == [zipfile.Path(alpharep, "b/")] | ||||||
|  | 
 | ||||||
|  |     @pass_alpharep | ||||||
|  |     def test_glob_subdir(self, alpharep): | ||||||
|  |         root = zipfile.Path(alpharep) | ||||||
|  |         assert list(root.glob('g/h')) == [zipfile.Path(alpharep, "g/h/")] | ||||||
|  |         assert list(root.glob('g*/h*')) == [zipfile.Path(alpharep, "g/h/")] | ||||||
|  | 
 | ||||||
|     @pass_alpharep |     @pass_alpharep | ||||||
|     def test_glob_subdirs(self, alpharep): |     def test_glob_subdirs(self, alpharep): | ||||||
|         root = zipfile.Path(alpharep) |         root = zipfile.Path(alpharep) | ||||||
|  | @ -594,3 +606,10 @@ def test_malformed_paths(self): | ||||||
|             'two-slash.txt', |             'two-slash.txt', | ||||||
|             'parent.txt', |             'parent.txt', | ||||||
|         ] |         ] | ||||||
|  | 
 | ||||||
|  |     @pass_alpharep | ||||||
|  |     def test_interface(self, alpharep): | ||||||
|  |         from importlib.resources.abc import Traversable | ||||||
|  | 
 | ||||||
|  |         zf = zipfile.Path(alpharep) | ||||||
|  |         assert isinstance(zf, Traversable) | ||||||
|  |  | ||||||
|  | @ -250,7 +250,10 @@ def _extract_text_encoding(encoding=None, *args, **kwargs): | ||||||
| 
 | 
 | ||||||
| class Path: | class Path: | ||||||
|     """ |     """ | ||||||
|     A pathlib-compatible interface for zip files. |     A :class:`importlib.resources.abc.Traversable` interface for zip files. | ||||||
|  | 
 | ||||||
|  |     Implements many of the features users enjoy from | ||||||
|  |     :class:`pathlib.Path`. | ||||||
| 
 | 
 | ||||||
|     Consider a zip file with this structure:: |     Consider a zip file with this structure:: | ||||||
| 
 | 
 | ||||||
|  | @ -466,8 +469,7 @@ def glob(self, pattern): | ||||||
|         prefix = re.escape(self.at) |         prefix = re.escape(self.at) | ||||||
|         tr = Translator(seps='/') |         tr = Translator(seps='/') | ||||||
|         matches = re.compile(prefix + tr.translate(pattern)).fullmatch |         matches = re.compile(prefix + tr.translate(pattern)).fullmatch | ||||||
|         names = (data.filename for data in self.root.filelist) |         return map(self._next, filter(matches, self.root.namelist())) | ||||||
|         return map(self._next, filter(matches, names)) |  | ||||||
| 
 | 
 | ||||||
|     def rglob(self, pattern): |     def rglob(self, pattern): | ||||||
|         return self.glob(f'**/{pattern}') |         return self.glob(f'**/{pattern}') | ||||||
|  |  | ||||||
|  | @ -28,7 +28,7 @@ def translate(self, pattern): | ||||||
|         """ |         """ | ||||||
|         Given a glob pattern, produce a regex that matches it. |         Given a glob pattern, produce a regex that matches it. | ||||||
|         """ |         """ | ||||||
|         return self.extend(self.translate_core(pattern)) |         return self.extend(self.match_dirs(self.translate_core(pattern))) | ||||||
| 
 | 
 | ||||||
|     def extend(self, pattern): |     def extend(self, pattern): | ||||||
|         r""" |         r""" | ||||||
|  | @ -41,6 +41,14 @@ def extend(self, pattern): | ||||||
|         """ |         """ | ||||||
|         return rf'(?s:{pattern})\Z' |         return rf'(?s:{pattern})\Z' | ||||||
| 
 | 
 | ||||||
|  |     def match_dirs(self, pattern): | ||||||
|  |         """ | ||||||
|  |         Ensure that zipfile.Path directory names are matched. | ||||||
|  | 
 | ||||||
|  |         zipfile.Path directory names always end in a slash. | ||||||
|  |         """ | ||||||
|  |         return rf'{pattern}[/]?' | ||||||
|  | 
 | ||||||
|     def translate_core(self, pattern): |     def translate_core(self, pattern): | ||||||
|         r""" |         r""" | ||||||
|         Given a glob pattern, produce a regex that matches it. |         Given a glob pattern, produce a regex that matches it. | ||||||
|  |  | ||||||
|  | @ -0,0 +1,2 @@ | ||||||
|  | ``zipfile.Path.glob`` now correctly matches directories instead of | ||||||
|  | silently omitting them. | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Jason R. Coombs
						Jason R. Coombs