We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN 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.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `setuptools/__init__.py`
Content:
```
1 """Extensions to the 'distutils' for large or complex distributions"""
2 
3 import os
4 import functools
5 import distutils.core
6 import distutils.filelist
7 from distutils.util import convert_path
8 from fnmatch import fnmatchcase
9 
10 from setuptools.extern.six.moves import filter, filterfalse, map
11 
12 import setuptools.version
13 from setuptools.extension import Extension
14 from setuptools.dist import Distribution, Feature
15 from setuptools.depends import Require
16 from . import monkey
17 
18 __all__ = [
19     'setup', 'Distribution', 'Feature', 'Command', 'Extension', 'Require',
20     'find_packages',
21 ]
22 
23 __version__ = setuptools.version.__version__
24 
25 bootstrap_install_from = None
26 
27 # If we run 2to3 on .py files, should we also convert docstrings?
28 # Default: yes; assume that we can detect doctests reliably
29 run_2to3_on_doctests = True
30 # Standard package names for fixer packages
31 lib2to3_fixer_packages = ['lib2to3.fixes']
32 
33 
34 class PackageFinder(object):
35     """
36     Generate a list of all Python packages found within a directory
37     """
38 
39     @classmethod
40     def find(cls, where='.', exclude=(), include=('*',)):
41         """Return a list all Python packages found within directory 'where'
42 
43         'where' is the root directory which will be searched for packages.  It
44         should be supplied as a "cross-platform" (i.e. URL-style) path; it will
45         be converted to the appropriate local path syntax.
46 
47         'exclude' is a sequence of package names to exclude; '*' can be used
48         as a wildcard in the names, such that 'foo.*' will exclude all
49         subpackages of 'foo' (but not 'foo' itself).
50 
51         'include' is a sequence of package names to include.  If it's
52         specified, only the named packages will be included.  If it's not
53         specified, all found packages will be included.  'include' can contain
54         shell style wildcard patterns just like 'exclude'.
55         """
56 
57         return list(cls._find_packages_iter(
58             convert_path(where),
59             cls._build_filter('ez_setup', '*__pycache__', *exclude),
60             cls._build_filter(*include)))
61 
62     @classmethod
63     def _find_packages_iter(cls, where, exclude, include):
64         """
65         All the packages found in 'where' that pass the 'include' filter, but
66         not the 'exclude' filter.
67         """
68         for root, dirs, files in os.walk(where, followlinks=True):
69             # Copy dirs to iterate over it, then empty dirs.
70             all_dirs = dirs[:]
71             dirs[:] = []
72 
73             for dir in all_dirs:
74                 full_path = os.path.join(root, dir)
75                 rel_path = os.path.relpath(full_path, where)
76                 package = rel_path.replace(os.path.sep, '.')
77 
78                 # Check if the directory is a package and passes the filters
79                 if ('.' not in dir
80                         and include(package)
81                         and not exclude(package)
82                         and cls._looks_like_package(full_path)):
83                     yield package
84                     dirs.append(dir)
85 
86     @staticmethod
87     def _looks_like_package(path):
88         """Does a directory look like a package?"""
89         return os.path.isfile(os.path.join(path, '__init__.py'))
90 
91     @staticmethod
92     def _build_filter(*patterns):
93         """
94         Given a list of patterns, return a callable that will be true only if
95         the input matches at least one of the patterns.
96         """
97         return lambda name: any(fnmatchcase(name, pat=pat) for pat in patterns)
98 
99 
100 class PEP420PackageFinder(PackageFinder):
101 
102     @staticmethod
103     def _looks_like_package(path):
104         return True
105 
106 
107 find_packages = PackageFinder.find
108 
109 setup = distutils.core.setup
110 
111 _Command = monkey.get_unpatched(distutils.core.Command)
112 
113 
114 class Command(_Command):
115     __doc__ = _Command.__doc__
116 
117     command_consumes_arguments = False
118 
119     def __init__(self, dist, **kw):
120         """
121         Construct the command for dist, updating
122         vars(self) with any keyword parameters.
123         """
124         _Command.__init__(self, dist)
125         vars(self).update(kw)
126 
127     def reinitialize_command(self, command, reinit_subcommands=0, **kw):
128         cmd = _Command.reinitialize_command(self, command, reinit_subcommands)
129         vars(cmd).update(kw)
130         return cmd
131 
132 
133 def _find_all_simple(path):
134     """
135     Find all files under 'path'
136     """
137     results = (
138         os.path.join(base, file)
139         for base, dirs, files in os.walk(path, followlinks=True)
140         for file in files
141     )
142     return filter(os.path.isfile, results)
143 
144 
145 def findall(dir=os.curdir):
146     """
147     Find all files under 'dir' and return the list of full filenames.
148     Unless dir is '.', return full filenames with dir prepended.
149     """
150     files = _find_all_simple(dir)
151     if dir == os.curdir:
152         make_rel = functools.partial(os.path.relpath, start=dir)
153         files = map(make_rel, files)
154     return list(files)
155 
156 
157 monkey.patch_all()
158
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/setuptools/__init__.py b/setuptools/__init__.py
--- a/setuptools/__init__.py
+++ b/setuptools/__init__.py
@@ -75,13 +75,17 @@
                 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):

{"golden_diff": "diff --git a/setuptools/__init__.py b/setuptools/__init__.py\n--- a/setuptools/__init__.py\n+++ b/setuptools/__init__.py\n@@ -75,13 +75,17 @@\n                 rel_path = os.path.relpath(full_path, where)\n                 package = rel_path.replace(os.path.sep, '.')\n \n-                # Check if the directory is a package and passes the filters\n-                if ('.' not in dir\n-                        and include(package)\n-                        and not exclude(package)\n-                        and cls._looks_like_package(full_path)):\n+                # Skip directory trees that are not valid packages\n+                if ('.' in dir or not cls._looks_like_package(full_path)):\n+                    continue\n+\n+                # Should this package be included?\n+                if include(package) and not exclude(package):\n                     yield package\n-                    dirs.append(dir)\n+\n+                # Keep searching subdirectories, as there may be more packages\n+                # down there, even if the parent was excluded.\n+                dirs.append(dir)\n \n     @staticmethod\n     def _looks_like_package(path):\n", "issue": "find_packages() include does not allow inclusion of subpackages without super packages\nHello! 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.\n\nI 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).\n\nTo be a little more concrete, here are examples of different behavior. With setuptools-18.0.1, I get this with my project:\n\n```\n$ python -c \"from setuptools import find_packages; print find_packages(include=['bodhi.server', 'bodhi.server.*'])\"\n['bodhi.server', 'bodhi.server.static', 'bodhi.server.services', 'bodhi.server.models', 'bodhi.server.views', 'bodhi.server.consumers', 'bodhi.server.scripts']\n```\n\nThat's the results I want (note that 'bodhi' is not included). With setuptools-28.2.0, I get this with my project:\n\n```\n$ python -c \"from setuptools import find_packages; print find_packages(include=['bodhi.server', 'bodhi.server.*'])\"\n[]\n```\n\nIf I add `'bodhi'` (which I do not want), the `bodhi.server` packages get included.\n\n", "before_files": [{"content": "\"\"\"Extensions to the 'distutils' for large or complex distributions\"\"\"\n\nimport os\nimport functools\nimport distutils.core\nimport distutils.filelist\nfrom distutils.util import convert_path\nfrom fnmatch import fnmatchcase\n\nfrom setuptools.extern.six.moves import filter, filterfalse, map\n\nimport setuptools.version\nfrom setuptools.extension import Extension\nfrom setuptools.dist import Distribution, Feature\nfrom setuptools.depends import Require\nfrom . import monkey\n\n__all__ = [\n    'setup', 'Distribution', 'Feature', 'Command', 'Extension', 'Require',\n    'find_packages',\n]\n\n__version__ = setuptools.version.__version__\n\nbootstrap_install_from = None\n\n# If we run 2to3 on .py files, should we also convert docstrings?\n# Default: yes; assume that we can detect doctests reliably\nrun_2to3_on_doctests = True\n# Standard package names for fixer packages\nlib2to3_fixer_packages = ['lib2to3.fixes']\n\n\nclass PackageFinder(object):\n    \"\"\"\n    Generate a list of all Python packages found within a directory\n    \"\"\"\n\n    @classmethod\n    def find(cls, where='.', exclude=(), include=('*',)):\n        \"\"\"Return a list all Python packages found within directory 'where'\n\n        'where' is the root directory which will be searched for packages.  It\n        should be supplied as a \"cross-platform\" (i.e. URL-style) path; it will\n        be converted to the appropriate local path syntax.\n\n        'exclude' is a sequence of package names to exclude; '*' can be used\n        as a wildcard in the names, such that 'foo.*' will exclude all\n        subpackages of 'foo' (but not 'foo' itself).\n\n        'include' is a sequence of package names to include.  If it's\n        specified, only the named packages will be included.  If it's not\n        specified, all found packages will be included.  'include' can contain\n        shell style wildcard patterns just like 'exclude'.\n        \"\"\"\n\n        return list(cls._find_packages_iter(\n            convert_path(where),\n            cls._build_filter('ez_setup', '*__pycache__', *exclude),\n            cls._build_filter(*include)))\n\n    @classmethod\n    def _find_packages_iter(cls, where, exclude, include):\n        \"\"\"\n        All the packages found in 'where' that pass the 'include' filter, but\n        not the 'exclude' filter.\n        \"\"\"\n        for root, dirs, files in os.walk(where, followlinks=True):\n            # Copy dirs to iterate over it, then empty dirs.\n            all_dirs = dirs[:]\n            dirs[:] = []\n\n            for dir in all_dirs:\n                full_path = os.path.join(root, dir)\n                rel_path = os.path.relpath(full_path, where)\n                package = rel_path.replace(os.path.sep, '.')\n\n                # Check if the directory is a package and passes the filters\n                if ('.' not in dir\n                        and include(package)\n                        and not exclude(package)\n                        and cls._looks_like_package(full_path)):\n                    yield package\n                    dirs.append(dir)\n\n    @staticmethod\n    def _looks_like_package(path):\n        \"\"\"Does a directory look like a package?\"\"\"\n        return os.path.isfile(os.path.join(path, '__init__.py'))\n\n    @staticmethod\n    def _build_filter(*patterns):\n        \"\"\"\n        Given a list of patterns, return a callable that will be true only if\n        the input matches at least one of the patterns.\n        \"\"\"\n        return lambda name: any(fnmatchcase(name, pat=pat) for pat in patterns)\n\n\nclass PEP420PackageFinder(PackageFinder):\n\n    @staticmethod\n    def _looks_like_package(path):\n        return True\n\n\nfind_packages = PackageFinder.find\n\nsetup = distutils.core.setup\n\n_Command = monkey.get_unpatched(distutils.core.Command)\n\n\nclass Command(_Command):\n    __doc__ = _Command.__doc__\n\n    command_consumes_arguments = False\n\n    def __init__(self, dist, **kw):\n        \"\"\"\n        Construct the command for dist, updating\n        vars(self) with any keyword parameters.\n        \"\"\"\n        _Command.__init__(self, dist)\n        vars(self).update(kw)\n\n    def reinitialize_command(self, command, reinit_subcommands=0, **kw):\n        cmd = _Command.reinitialize_command(self, command, reinit_subcommands)\n        vars(cmd).update(kw)\n        return cmd\n\n\ndef _find_all_simple(path):\n    \"\"\"\n    Find all files under 'path'\n    \"\"\"\n    results = (\n        os.path.join(base, file)\n        for base, dirs, files in os.walk(path, followlinks=True)\n        for file in files\n    )\n    return filter(os.path.isfile, results)\n\n\ndef findall(dir=os.curdir):\n    \"\"\"\n    Find all files under 'dir' and return the list of full filenames.\n    Unless dir is '.', return full filenames with dir prepended.\n    \"\"\"\n    files = _find_all_simple(dir)\n    if dir == os.curdir:\n        make_rel = functools.partial(os.path.relpath, start=dir)\n        files = map(make_rel, files)\n    return list(files)\n\n\nmonkey.patch_all()\n", "path": "setuptools/__init__.py"}], "after_files": [{"content": "\"\"\"Extensions to the 'distutils' for large or complex distributions\"\"\"\n\nimport os\nimport functools\nimport distutils.core\nimport distutils.filelist\nfrom distutils.util import convert_path\nfrom fnmatch import fnmatchcase\n\nfrom setuptools.extern.six.moves import filter, filterfalse, map\n\nimport setuptools.version\nfrom setuptools.extension import Extension\nfrom setuptools.dist import Distribution, Feature\nfrom setuptools.depends import Require\nfrom . import monkey\n\n__all__ = [\n    'setup', 'Distribution', 'Feature', 'Command', 'Extension', 'Require',\n    'find_packages',\n]\n\n__version__ = setuptools.version.__version__\n\nbootstrap_install_from = None\n\n# If we run 2to3 on .py files, should we also convert docstrings?\n# Default: yes; assume that we can detect doctests reliably\nrun_2to3_on_doctests = True\n# Standard package names for fixer packages\nlib2to3_fixer_packages = ['lib2to3.fixes']\n\n\nclass PackageFinder(object):\n    \"\"\"\n    Generate a list of all Python packages found within a directory\n    \"\"\"\n\n    @classmethod\n    def find(cls, where='.', exclude=(), include=('*',)):\n        \"\"\"Return a list all Python packages found within directory 'where'\n\n        'where' is the root directory which will be searched for packages.  It\n        should be supplied as a \"cross-platform\" (i.e. URL-style) path; it will\n        be converted to the appropriate local path syntax.\n\n        'exclude' is a sequence of package names to exclude; '*' can be used\n        as a wildcard in the names, such that 'foo.*' will exclude all\n        subpackages of 'foo' (but not 'foo' itself).\n\n        'include' is a sequence of package names to include.  If it's\n        specified, only the named packages will be included.  If it's not\n        specified, all found packages will be included.  'include' can contain\n        shell style wildcard patterns just like 'exclude'.\n        \"\"\"\n\n        return list(cls._find_packages_iter(\n            convert_path(where),\n            cls._build_filter('ez_setup', '*__pycache__', *exclude),\n            cls._build_filter(*include)))\n\n    @classmethod\n    def _find_packages_iter(cls, where, exclude, include):\n        \"\"\"\n        All the packages found in 'where' that pass the 'include' filter, but\n        not the 'exclude' filter.\n        \"\"\"\n        for root, dirs, files in os.walk(where, followlinks=True):\n            # Copy dirs to iterate over it, then empty dirs.\n            all_dirs = dirs[:]\n            dirs[:] = []\n\n            for dir in all_dirs:\n                full_path = os.path.join(root, dir)\n                rel_path = os.path.relpath(full_path, where)\n                package = rel_path.replace(os.path.sep, '.')\n\n                # Skip directory trees that are not valid packages\n                if ('.' in dir or not cls._looks_like_package(full_path)):\n                    continue\n\n                # Should this package be included?\n                if include(package) and not exclude(package):\n                    yield package\n\n                # Keep searching subdirectories, as there may be more packages\n                # down there, even if the parent was excluded.\n                dirs.append(dir)\n\n    @staticmethod\n    def _looks_like_package(path):\n        \"\"\"Does a directory look like a package?\"\"\"\n        return os.path.isfile(os.path.join(path, '__init__.py'))\n\n    @staticmethod\n    def _build_filter(*patterns):\n        \"\"\"\n        Given a list of patterns, return a callable that will be true only if\n        the input matches at least one of the patterns.\n        \"\"\"\n        return lambda name: any(fnmatchcase(name, pat=pat) for pat in patterns)\n\n\nclass PEP420PackageFinder(PackageFinder):\n\n    @staticmethod\n    def _looks_like_package(path):\n        return True\n\n\nfind_packages = PackageFinder.find\n\nsetup = distutils.core.setup\n\n_Command = monkey.get_unpatched(distutils.core.Command)\n\n\nclass Command(_Command):\n    __doc__ = _Command.__doc__\n\n    command_consumes_arguments = False\n\n    def __init__(self, dist, **kw):\n        \"\"\"\n        Construct the command for dist, updating\n        vars(self) with any keyword parameters.\n        \"\"\"\n        _Command.__init__(self, dist)\n        vars(self).update(kw)\n\n    def reinitialize_command(self, command, reinit_subcommands=0, **kw):\n        cmd = _Command.reinitialize_command(self, command, reinit_subcommands)\n        vars(cmd).update(kw)\n        return cmd\n\n\ndef _find_all_simple(path):\n    \"\"\"\n    Find all files under 'path'\n    \"\"\"\n    results = (\n        os.path.join(base, file)\n        for base, dirs, files in os.walk(path, followlinks=True)\n        for file in files\n    )\n    return filter(os.path.isfile, results)\n\n\ndef findall(dir=os.curdir):\n    \"\"\"\n    Find all files under 'dir' and return the list of full filenames.\n    Unless dir is '.', return full filenames with dir prepended.\n    \"\"\"\n    files = _find_all_simple(dir)\n    if dir == os.curdir:\n        make_rel = functools.partial(os.path.relpath, start=dir)\n        files = map(make_rel, files)\n    return list(files)\n\n\nmonkey.patch_all()\n", "path": "setuptools/__init__.py"}]}