Repository: pypa/setuptools

Issue:
Since setuptools 28.5.0, a "global-exclude .pyc" no longer matches .pyc files
Since commit bb45468d27615c2ce9f9c9757a367c44d6ee80d2, if a project's MANIFEST.in contains ``global-exclude .py[co]``, the archive generated with ``python setup.py sdist`` will still contain all ``.pyc`` / ``.pyo`` files.

The test below shows that this line worked in setuptools 28.4.0, and broke in setuptools 28.5.0.

I'm not sure whether this can be considered a bug: the previous implementation looked up patterns without any anchoring, whereas the new one forces users to explicitly include wildcards in their ``MANIFEST.in``.
However, I think this change should have been mentioned in the version Changelog.

```patch
diff --cc setuptools/tests/test_manifest.py
index 6360270,ef4beda..0000000
--- a/setuptools/tests/test_manifest.py
+++ b/setuptools/tests/test_manifest.py
@@@ -425,12 -464,22 +425,19 @@@ class TestFileListTest(TempDirTestCase)
          assert file_list.files == ['b.txt']
          self.assertWarnings()
  
+         file_list = FileList()
+         file_list.files = ['a.py', 'b.txt', l('d/c.pyc'), 'e.pyo']
+         file_list.process_template_line('global-exclude .py[co]')
+         file_list.sort()
+         assert file_list.files == ['a.py', 'b.txt']
+         self.assertNoWarnings()
+ 
          # recursive-include
  ```
Since setuptools 28.5.0, a "global-exclude .pyc" no longer matches .pyc files
Since commit bb45468d27615c2ce9f9c9757a367c44d6ee80d2, if a project's MANIFEST.in contains ``global-exclude .py[co]``, the archive generated with ``python setup.py sdist`` will still contain all ``.pyc`` / ``.pyo`` files.

The test below shows that this line worked in setuptools 28.4.0, and broke in setuptools 28.5.0.

I'm not sure whether this can be considered a bug: the previous implementation looked up patterns without any anchoring, whereas the new one forces users to explicitly include wildcards in their ``MANIFEST.in``.
However, I think this change should have been mentioned in the version Changelog.

```patch
diff --cc setuptools/tests/test_manifest.py
index 6360270,ef4beda..0000000
--- a/setuptools/tests/test_manifest.py
+++ b/setuptools/tests/test_manifest.py
@@@ -425,12 -464,22 +425,19 @@@ class TestFileListTest(TempDirTestCase)
          assert file_list.files == ['b.txt']
          self.assertWarnings()
  
+         file_list = FileList()
+         file_list.files = ['a.py', 'b.txt', l('d/c.pyc'), 'e.pyo']
+         file_list.process_template_line('global-exclude .py[co]')
+         file_list.sort()
+         assert file_list.files == ['a.py', 'b.txt']
+         self.assertNoWarnings()
+ 
          # recursive-include
  ```


Discussion:
Thanks @rbarrois for tracing the issue and providing a unit test.

I agree this looks like an unintentional regression. 

According to the changelog, #764 is implicated in this change. Since the unit tests didn't capture this behavior before, it's no surprise that it was missed during the re-write.

@timheap How difficult would it be to restore this expectation?

Thanks @rbarrois for tracing the issue and providing a unit test.

I agree this looks like an unintentional regression. 

According to the changelog, #764 is implicated in this change. Since the unit tests didn't capture this behavior before, it's no surprise that it was missed during the re-write.

@timheap How difficult would it be to restore this expectation?


Resolving patch:
diff --git a/setuptools/command/egg_info.py b/setuptools/command/egg_info.py
--- a/setuptools/command/egg_info.py
+++ b/setuptools/command/egg_info.py
@@ -457,7 +457,7 @@ def global_include(self, pattern):
         """
         if self.allfiles is None:
             self.findall()
-        match = translate_pattern(os.path.join('**', pattern))
+        match = translate_pattern(os.path.join('**', '*' + pattern))
         found = [f for f in self.allfiles if match.match(f)]
         self.extend(found)
         return bool(found)
@@ -466,7 +466,7 @@ def global_exclude(self, pattern):
         """
         Exclude all files anywhere that match the pattern.
         """
-        match = translate_pattern(os.path.join('**', pattern))
+        match = translate_pattern(os.path.join('**', '*' + pattern))
         return self._remove_files(match.match)
 
     def append(self, item):


Test patch:
diff --git a/setuptools/tests/test_manifest.py b/setuptools/tests/test_manifest.py
--- a/setuptools/tests/test_manifest.py
+++ b/setuptools/tests/test_manifest.py
@@ -449,6 +449,11 @@ def test_global_include(self):
         assert file_list.files == ['a.py', l('d/c.py')]
         self.assertWarnings()
 
+        file_list.process_template_line('global-include .txt')
+        file_list.sort()
+        assert file_list.files == ['a.py', 'b.txt', l('d/c.py')]
+        self.assertNoWarnings()
+
     def test_global_exclude(self):
         l = make_local_path
         # global-exclude
@@ -465,6 +470,13 @@ def test_global_exclude(self):
         assert file_list.files == ['b.txt']
         self.assertWarnings()
 
+        file_list = FileList()
+        file_list.files = ['a.py', 'b.txt', l('d/c.pyc'), 'e.pyo']
+        file_list.process_template_line('global-exclude .py[co]')
+        file_list.sort()
+        assert file_list.files == ['a.py', 'b.txt']
+        self.assertNoWarnings()
+
     def test_recursive_include(self):
         l = make_local_path
         # recursive-include