Repository: pypa/setuptools (python)

Issue:
find_packages() include does not allow inclusion of subpackages without super packages
Hello! I'm trying to solve [an issue](https://github.com/fedora-infra/bodhi/issues/994) I've got in my project with [the change in setuptools 28.0 that made exclude also exclude all subpackages](https://github.com/pypa/setuptools/pull/733). I had been relying on that behavior to exclude my package's top level package so that I could distribute one of the subpackages as its own add-on package.

I decided to try to include just the subpackage and its subpackages instead, but this also does not seem to work on 28.0 unless I include the top level package (which I am trying to avoid).

To be a little more concrete, here are examples of different behavior. With setuptools-18.0.1, I get this with my project:

```
$ python -c "from setuptools import find_packages; print find_packages(include=['bodhi.server', 'bodhi.server.*'])"
['bodhi.server', 'bodhi.server.static', 'bodhi.server.services', 'bodhi.server.models', 'bodhi.server.views', 'bodhi.server.consumers', 'bodhi.server.scripts']
```

That's the results I want (note that 'bodhi' is not included). With setuptools-28.2.0, I get this with my project:

```
$ python -c "from setuptools import find_packages; print find_packages(include=['bodhi.server', 'bodhi.server.*'])"
[]
```

If I add ```'bodhi'``` (which I do not want), the ```bodhi.server``` packages get included.

Pull request:
Find nested packages with excluded parent
`find_packages(exclude=['pkg'])` should still find and include the `pkg.subpkg` package.

Fixes #808

Patch:
diff --git a/setuptools/__init__.py b/setuptools/__init__.py
index 892626e6a..baec38849 100644
--- a/setuptools/__init__.py
+++ b/setuptools/__init__.py
@@ -75,13 +75,17 @@ class PackageFinder(object):
                 rel_path = os.path.relpath(full_path, where)
                 package = rel_path.replace(os.path.sep, '.')
 
-                # Check if the directory is a package and passes the filters
-                if ('.' not in dir
-                        and include(package)
-                        and not exclude(package)
-                        and cls._looks_like_package(full_path)):
+                # Skip directory trees that are not valid packages
+                if ('.' in dir or not cls._looks_like_package(full_path)):
+                    continue
+
+                # Should this package be included?
+                if include(package) and not exclude(package):
                     yield package
-                    dirs.append(dir)
+
+                # Keep searching subdirectories, as there may be more packages
+                # down there, even if the parent was excluded.
+                dirs.append(dir)
 
     @staticmethod
     def _looks_like_package(path):


Test patch:
diff --git a/setuptools/tests/test_find_packages.py b/setuptools/tests/test_find_packages.py
index 9d31ccd7a..6dc1b3ac7 100644
--- a/setuptools/tests/test_find_packages.py
+++ b/setuptools/tests/test_find_packages.py
@@ -100,12 +100,12 @@ class TestFindPackages:
 
     def test_exclude_recursive(self):
         """
-        Excluding a parent package should exclude all child packages as well.
+        Excluding a parent package should not exclude child packages as well.
         """
         self._touch('__init__.py', self.pkg_dir)
         self._touch('__init__.py', self.sub_pkg_dir)
         packages = find_packages(self.dist_dir, exclude=('pkg',))
-        assert packages == []
+        assert packages == ['pkg.subpkg']
 
     def test_include_excludes_other(self):
         """