We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
jupyterhub update-db fails
When I run it, I get:

```
    FileNotFoundError: [Errno 2] No such file or directory: '/home/yuvipanda/code/jupyterhub-kubernetes-spawner/lib/python3.5/site-packages/jupyterhub/alembic.ini'
```

I didn't capture the full stack trace though.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `setup.py`
Content:
```
1 #!/usr/bin/env python3
2 # coding: utf-8
3 
4 # Copyright (c) Juptyer Development Team.
5 # Distributed under the terms of the Modified BSD License.
6 
7 #-----------------------------------------------------------------------------
8 # Minimal Python version sanity check (from IPython)
9 #-----------------------------------------------------------------------------
10 
11 from __future__ import print_function
12 
13 import os
14 import shutil
15 import sys
16 
17 v = sys.version_info
18 if v[:2] < (3,3):
19     error = "ERROR: JupyterHub requires Python version 3.3 or above."
20     print(error, file=sys.stderr)
21     sys.exit(1)
22 
23 
24 if os.name in ('nt', 'dos'):
25     error = "ERROR: Windows is not supported"
26     print(error, file=sys.stderr)
27 
28 # At least we're on the python version we need, move on.
29 
30 import os
31 from glob import glob
32 from subprocess import check_call
33 
34 from setuptools import setup
35 from setuptools.command.bdist_egg import bdist_egg
36 
37 pjoin = os.path.join
38 
39 here = os.path.abspath(os.path.dirname(__file__))
40 share_jupyter = pjoin(here, 'share', 'jupyter', 'hub')
41 static = pjoin(share_jupyter, 'static')
42 
43 is_repo = os.path.exists(pjoin(here, '.git'))
44 
45 #---------------------------------------------------------------------------
46 # Build basic package data, etc.
47 #---------------------------------------------------------------------------
48 
49 def get_data_files():
50     """Get data files in share/jupyter"""
51     
52     data_files = []
53     ntrim = len(here + os.path.sep)
54     
55     for (d, dirs, filenames) in os.walk(share_jupyter):
56         data_files.append((
57             d[ntrim:],
58             [ pjoin(d, f) for f in filenames ]
59         ))
60     return data_files
61 
62 def get_package_data():
63     """Get package data
64 
65     (mostly alembic config)
66     """
67     package_data = {}
68     package_data['jupyterhub'] = [
69         'alembic/*',
70         'alembic/versions/*',
71     ]
72     return package_data
73 
74 ns = {}
75 with open(pjoin(here, 'jupyterhub', 'version.py')) as f:
76     exec(f.read(), {}, ns)
77 
78 
79 packages = []
80 for d, _, _ in os.walk('jupyterhub'):
81     if os.path.exists(pjoin(d, '__init__.py')):
82         packages.append(d.replace(os.path.sep, '.'))
83 
84 setup_args = dict(
85     name                = 'jupyterhub',
86     scripts             = glob(pjoin('scripts', '*')),
87     packages            = packages,
88                         # dummy, so that install_data doesn't get skipped
89                         # this will be overridden when bower is run anyway
90     data_files          = get_data_files() or ['dummy'],
91     package_data        = get_package_data(),
92     version             = ns['__version__'],
93     description         = "JupyterHub: A multi-user server for Jupyter notebooks",
94     long_description    = "See https://jupyterhub.readthedocs.io for more info.",
95     author              = "Jupyter Development Team",
96     author_email        = "jupyter@googlegroups.com",
97     url                 = "http://jupyter.org",
98     license             = "BSD",
99     platforms           = "Linux, Mac OS X",
100     keywords            = ['Interactive', 'Interpreter', 'Shell', 'Web'],
101     classifiers         = [
102         'Intended Audience :: Developers',
103         'Intended Audience :: System Administrators',
104         'Intended Audience :: Science/Research',
105         'License :: OSI Approved :: BSD License',
106         'Programming Language :: Python',
107         'Programming Language :: Python :: 3',
108     ],
109 )
110 
111 #---------------------------------------------------------------------------
112 # custom distutils commands
113 #---------------------------------------------------------------------------
114 
115 # imports here, so they are after setuptools import if there was one
116 from distutils.cmd import Command
117 from distutils.command.build_py import build_py
118 from distutils.command.sdist import sdist
119 
120 
121 npm_path = ':'.join([
122     pjoin(here, 'node_modules', '.bin'),
123     os.environ.get("PATH", os.defpath),
124 ])
125 
126 
127 def mtime(path):
128     """shorthand for mtime"""
129     return os.stat(path).st_mtime
130 
131 
132 class BaseCommand(Command):
133     """Dumb empty command because Command needs subclasses to override too much"""
134     user_options = []
135     
136     def initialize_options(self):
137         pass
138     
139     def finalize_options(self):
140         pass
141     
142     def get_inputs(self):
143         return []
144     
145     def get_outputs(self):
146         return []
147 
148 
149 class Bower(BaseCommand):
150     description = "fetch static client-side components with bower"
151     
152     user_options = []
153     bower_dir = pjoin(static, 'components')
154     node_modules = pjoin(here, 'node_modules')
155     
156     def should_run(self):
157         if not os.path.exists(self.bower_dir):
158             return True
159         return mtime(self.bower_dir) < mtime(pjoin(here, 'bower.json'))
160 
161     def should_run_npm(self):
162         if not shutil.which('npm'):
163             print("npm unavailable", file=sys.stderr)
164             return False
165         if not os.path.exists(self.node_modules):
166             return True
167         return mtime(self.node_modules) < mtime(pjoin(here, 'package.json'))
168     
169     def run(self):
170         if not self.should_run():
171             print("bower dependencies up to date")
172             return
173         
174         if self.should_run_npm():
175             print("installing build dependencies with npm")
176             check_call(['npm', 'install', '--progress=false'], cwd=here)
177             os.utime(self.node_modules)
178         
179         env = os.environ.copy()
180         env['PATH'] = npm_path
181         
182         try:
183             check_call(
184                 ['bower', 'install', '--allow-root', '--config.interactive=false'],
185                 cwd=here,
186                 env=env,
187             )
188         except OSError as e:
189             print("Failed to run bower: %s" % e, file=sys.stderr)
190             print("You can install js dependencies with `npm install`", file=sys.stderr)
191             raise
192         os.utime(self.bower_dir)
193         # update data-files in case this created new files
194         self.distribution.data_files = get_data_files()
195 
196 
197 class CSS(BaseCommand):
198     description = "compile CSS from LESS"
199     
200     def should_run(self):
201         """Does less need to run?"""
202         # from IPython.html.tasks.py
203         
204         css_targets = [pjoin(static, 'css', 'style.min.css')]
205         css_maps = [t + '.map' for t in css_targets]
206         targets = css_targets + css_maps
207         if not all(os.path.exists(t) for t in targets):
208             # some generated files don't exist
209             return True
210         earliest_target = sorted(mtime(t) for t in targets)[0]
211     
212         # check if any .less files are newer than the generated targets
213         for (dirpath, dirnames, filenames) in os.walk(static):
214             for f in filenames:
215                 if f.endswith('.less'):
216                     path = pjoin(static, dirpath, f)
217                     timestamp = mtime(path)
218                     if timestamp > earliest_target:
219                         return True
220     
221         return False
222     
223     def run(self):
224         if not self.should_run():
225             print("CSS up-to-date")
226             return
227         
228         self.run_command('js')
229         
230         style_less = pjoin(static, 'less', 'style.less')
231         style_css = pjoin(static, 'css', 'style.min.css')
232         sourcemap = style_css + '.map'
233         
234         env = os.environ.copy()
235         env['PATH'] = npm_path
236         try:
237             check_call([
238                 'lessc', '--clean-css',
239                 '--source-map-basepath={}'.format(static),
240                 '--source-map={}'.format(sourcemap),
241                 '--source-map-rootpath=../',
242                 style_less, style_css,
243             ], cwd=here, env=env)
244         except OSError as e:
245             print("Failed to run lessc: %s" % e, file=sys.stderr)
246             print("You can install js dependencies with `npm install`", file=sys.stderr)
247             raise
248         # update data-files in case this created new files
249         self.distribution.data_files = get_data_files()
250 
251 
252 def js_css_first(cls, strict=True):
253     class Command(cls):
254         def run(self):
255             try:
256                 self.run_command('js')
257                 self.run_command('css')
258             except Exception:
259                 if strict:
260                     raise
261                 else:
262                     pass
263             return super().run()
264     return Command
265 
266 
267 class bdist_egg_disabled(bdist_egg):
268     """Disabled version of bdist_egg
269 
270     Prevents setup.py install performing setuptools' default easy_install,
271     which it should never ever do.
272     """
273     def run(self):
274         sys.exit("Aborting implicit building of eggs. Use `pip install .` to install from source.")
275 
276 
277 setup_args['cmdclass'] = {
278     'js': Bower,
279     'css': CSS,
280     'build_py': js_css_first(build_py, strict=is_repo),
281     'sdist': js_css_first(sdist, strict=True),
282     'bdist_egg': bdist_egg if 'bdist_egg' in sys.argv else bdist_egg_disabled,
283 }
284 
285 
286 # setuptools requirements
287 
288 setup_args['zip_safe'] = False
289 from setuptools.command.develop import develop
290 class develop_js_css(develop):
291     def run(self):
292         if not self.uninstall:
293             self.distribution.run_command('js')
294             self.distribution.run_command('css')
295         develop.run(self)
296 setup_args['cmdclass']['develop'] = develop_js_css
297 setup_args['install_requires'] = install_requires = []
298 
299 with open('requirements.txt') as f:
300     for line in f.readlines():
301         req = line.strip()
302         if not req or req.startswith('#') or '://' in req:
303             continue
304         install_requires.append(req)
305 
306 #---------------------------------------------------------------------------
307 # setup
308 #---------------------------------------------------------------------------
309 
310 def main():
311     setup(**setup_args)
312 
313 if __name__ == '__main__':
314     main()
315
```
--- 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/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -66,6 +66,7 @@
     """
     package_data = {}
     package_data['jupyterhub'] = [
+        'alembic.ini',
         'alembic/*',
         'alembic/versions/*',
     ]

{"golden_diff": "diff --git a/setup.py b/setup.py\n--- a/setup.py\n+++ b/setup.py\n@@ -66,6 +66,7 @@\n     \"\"\"\n     package_data = {}\n     package_data['jupyterhub'] = [\n+        'alembic.ini',\n         'alembic/*',\n         'alembic/versions/*',\n     ]\n", "issue": "jupyterhub update-db fails\nWhen I run it, I get:\n\n```\n    FileNotFoundError: [Errno 2] No such file or directory: '/home/yuvipanda/code/jupyterhub-kubernetes-spawner/lib/python3.5/site-packages/jupyterhub/alembic.ini'\n```\n\nI didn't capture the full stack trace though.\n\n", "before_files": [{"content": "#!/usr/bin/env python3\n# coding: utf-8\n\n# Copyright (c) Juptyer Development Team.\n# Distributed under the terms of the Modified BSD License.\n\n#-----------------------------------------------------------------------------\n# Minimal Python version sanity check (from IPython)\n#-----------------------------------------------------------------------------\n\nfrom __future__ import print_function\n\nimport os\nimport shutil\nimport sys\n\nv = sys.version_info\nif v[:2] < (3,3):\n    error = \"ERROR: JupyterHub requires Python version 3.3 or above.\"\n    print(error, file=sys.stderr)\n    sys.exit(1)\n\n\nif os.name in ('nt', 'dos'):\n    error = \"ERROR: Windows is not supported\"\n    print(error, file=sys.stderr)\n\n# At least we're on the python version we need, move on.\n\nimport os\nfrom glob import glob\nfrom subprocess import check_call\n\nfrom setuptools import setup\nfrom setuptools.command.bdist_egg import bdist_egg\n\npjoin = os.path.join\n\nhere = os.path.abspath(os.path.dirname(__file__))\nshare_jupyter = pjoin(here, 'share', 'jupyter', 'hub')\nstatic = pjoin(share_jupyter, 'static')\n\nis_repo = os.path.exists(pjoin(here, '.git'))\n\n#---------------------------------------------------------------------------\n# Build basic package data, etc.\n#---------------------------------------------------------------------------\n\ndef get_data_files():\n    \"\"\"Get data files in share/jupyter\"\"\"\n    \n    data_files = []\n    ntrim = len(here + os.path.sep)\n    \n    for (d, dirs, filenames) in os.walk(share_jupyter):\n        data_files.append((\n            d[ntrim:],\n            [ pjoin(d, f) for f in filenames ]\n        ))\n    return data_files\n\ndef get_package_data():\n    \"\"\"Get package data\n\n    (mostly alembic config)\n    \"\"\"\n    package_data = {}\n    package_data['jupyterhub'] = [\n        'alembic/*',\n        'alembic/versions/*',\n    ]\n    return package_data\n\nns = {}\nwith open(pjoin(here, 'jupyterhub', 'version.py')) as f:\n    exec(f.read(), {}, ns)\n\n\npackages = []\nfor d, _, _ in os.walk('jupyterhub'):\n    if os.path.exists(pjoin(d, '__init__.py')):\n        packages.append(d.replace(os.path.sep, '.'))\n\nsetup_args = dict(\n    name                = 'jupyterhub',\n    scripts             = glob(pjoin('scripts', '*')),\n    packages            = packages,\n                        # dummy, so that install_data doesn't get skipped\n                        # this will be overridden when bower is run anyway\n    data_files          = get_data_files() or ['dummy'],\n    package_data        = get_package_data(),\n    version             = ns['__version__'],\n    description         = \"JupyterHub: A multi-user server for Jupyter notebooks\",\n    long_description    = \"See https://jupyterhub.readthedocs.io for more info.\",\n    author              = \"Jupyter Development Team\",\n    author_email        = \"jupyter@googlegroups.com\",\n    url                 = \"http://jupyter.org\",\n    license             = \"BSD\",\n    platforms           = \"Linux, Mac OS X\",\n    keywords            = ['Interactive', 'Interpreter', 'Shell', 'Web'],\n    classifiers         = [\n        'Intended Audience :: Developers',\n        'Intended Audience :: System Administrators',\n        'Intended Audience :: Science/Research',\n        'License :: OSI Approved :: BSD License',\n        'Programming Language :: Python',\n        'Programming Language :: Python :: 3',\n    ],\n)\n\n#---------------------------------------------------------------------------\n# custom distutils commands\n#---------------------------------------------------------------------------\n\n# imports here, so they are after setuptools import if there was one\nfrom distutils.cmd import Command\nfrom distutils.command.build_py import build_py\nfrom distutils.command.sdist import sdist\n\n\nnpm_path = ':'.join([\n    pjoin(here, 'node_modules', '.bin'),\n    os.environ.get(\"PATH\", os.defpath),\n])\n\n\ndef mtime(path):\n    \"\"\"shorthand for mtime\"\"\"\n    return os.stat(path).st_mtime\n\n\nclass BaseCommand(Command):\n    \"\"\"Dumb empty command because Command needs subclasses to override too much\"\"\"\n    user_options = []\n    \n    def initialize_options(self):\n        pass\n    \n    def finalize_options(self):\n        pass\n    \n    def get_inputs(self):\n        return []\n    \n    def get_outputs(self):\n        return []\n\n\nclass Bower(BaseCommand):\n    description = \"fetch static client-side components with bower\"\n    \n    user_options = []\n    bower_dir = pjoin(static, 'components')\n    node_modules = pjoin(here, 'node_modules')\n    \n    def should_run(self):\n        if not os.path.exists(self.bower_dir):\n            return True\n        return mtime(self.bower_dir) < mtime(pjoin(here, 'bower.json'))\n\n    def should_run_npm(self):\n        if not shutil.which('npm'):\n            print(\"npm unavailable\", file=sys.stderr)\n            return False\n        if not os.path.exists(self.node_modules):\n            return True\n        return mtime(self.node_modules) < mtime(pjoin(here, 'package.json'))\n    \n    def run(self):\n        if not self.should_run():\n            print(\"bower dependencies up to date\")\n            return\n        \n        if self.should_run_npm():\n            print(\"installing build dependencies with npm\")\n            check_call(['npm', 'install', '--progress=false'], cwd=here)\n            os.utime(self.node_modules)\n        \n        env = os.environ.copy()\n        env['PATH'] = npm_path\n        \n        try:\n            check_call(\n                ['bower', 'install', '--allow-root', '--config.interactive=false'],\n                cwd=here,\n                env=env,\n            )\n        except OSError as e:\n            print(\"Failed to run bower: %s\" % e, file=sys.stderr)\n            print(\"You can install js dependencies with `npm install`\", file=sys.stderr)\n            raise\n        os.utime(self.bower_dir)\n        # update data-files in case this created new files\n        self.distribution.data_files = get_data_files()\n\n\nclass CSS(BaseCommand):\n    description = \"compile CSS from LESS\"\n    \n    def should_run(self):\n        \"\"\"Does less need to run?\"\"\"\n        # from IPython.html.tasks.py\n        \n        css_targets = [pjoin(static, 'css', 'style.min.css')]\n        css_maps = [t + '.map' for t in css_targets]\n        targets = css_targets + css_maps\n        if not all(os.path.exists(t) for t in targets):\n            # some generated files don't exist\n            return True\n        earliest_target = sorted(mtime(t) for t in targets)[0]\n    \n        # check if any .less files are newer than the generated targets\n        for (dirpath, dirnames, filenames) in os.walk(static):\n            for f in filenames:\n                if f.endswith('.less'):\n                    path = pjoin(static, dirpath, f)\n                    timestamp = mtime(path)\n                    if timestamp > earliest_target:\n                        return True\n    \n        return False\n    \n    def run(self):\n        if not self.should_run():\n            print(\"CSS up-to-date\")\n            return\n        \n        self.run_command('js')\n        \n        style_less = pjoin(static, 'less', 'style.less')\n        style_css = pjoin(static, 'css', 'style.min.css')\n        sourcemap = style_css + '.map'\n        \n        env = os.environ.copy()\n        env['PATH'] = npm_path\n        try:\n            check_call([\n                'lessc', '--clean-css',\n                '--source-map-basepath={}'.format(static),\n                '--source-map={}'.format(sourcemap),\n                '--source-map-rootpath=../',\n                style_less, style_css,\n            ], cwd=here, env=env)\n        except OSError as e:\n            print(\"Failed to run lessc: %s\" % e, file=sys.stderr)\n            print(\"You can install js dependencies with `npm install`\", file=sys.stderr)\n            raise\n        # update data-files in case this created new files\n        self.distribution.data_files = get_data_files()\n\n\ndef js_css_first(cls, strict=True):\n    class Command(cls):\n        def run(self):\n            try:\n                self.run_command('js')\n                self.run_command('css')\n            except Exception:\n                if strict:\n                    raise\n                else:\n                    pass\n            return super().run()\n    return Command\n\n\nclass bdist_egg_disabled(bdist_egg):\n    \"\"\"Disabled version of bdist_egg\n\n    Prevents setup.py install performing setuptools' default easy_install,\n    which it should never ever do.\n    \"\"\"\n    def run(self):\n        sys.exit(\"Aborting implicit building of eggs. Use `pip install .` to install from source.\")\n\n\nsetup_args['cmdclass'] = {\n    'js': Bower,\n    'css': CSS,\n    'build_py': js_css_first(build_py, strict=is_repo),\n    'sdist': js_css_first(sdist, strict=True),\n    'bdist_egg': bdist_egg if 'bdist_egg' in sys.argv else bdist_egg_disabled,\n}\n\n\n# setuptools requirements\n\nsetup_args['zip_safe'] = False\nfrom setuptools.command.develop import develop\nclass develop_js_css(develop):\n    def run(self):\n        if not self.uninstall:\n            self.distribution.run_command('js')\n            self.distribution.run_command('css')\n        develop.run(self)\nsetup_args['cmdclass']['develop'] = develop_js_css\nsetup_args['install_requires'] = install_requires = []\n\nwith open('requirements.txt') as f:\n    for line in f.readlines():\n        req = line.strip()\n        if not req or req.startswith('#') or '://' in req:\n            continue\n        install_requires.append(req)\n\n#---------------------------------------------------------------------------\n# setup\n#---------------------------------------------------------------------------\n\ndef main():\n    setup(**setup_args)\n\nif __name__ == '__main__':\n    main()\n", "path": "setup.py"}], "after_files": [{"content": "#!/usr/bin/env python3\n# coding: utf-8\n\n# Copyright (c) Juptyer Development Team.\n# Distributed under the terms of the Modified BSD License.\n\n#-----------------------------------------------------------------------------\n# Minimal Python version sanity check (from IPython)\n#-----------------------------------------------------------------------------\n\nfrom __future__ import print_function\n\nimport os\nimport shutil\nimport sys\n\nv = sys.version_info\nif v[:2] < (3,3):\n    error = \"ERROR: JupyterHub requires Python version 3.3 or above.\"\n    print(error, file=sys.stderr)\n    sys.exit(1)\n\n\nif os.name in ('nt', 'dos'):\n    error = \"ERROR: Windows is not supported\"\n    print(error, file=sys.stderr)\n\n# At least we're on the python version we need, move on.\n\nimport os\nfrom glob import glob\nfrom subprocess import check_call\n\nfrom setuptools import setup\nfrom setuptools.command.bdist_egg import bdist_egg\n\npjoin = os.path.join\n\nhere = os.path.abspath(os.path.dirname(__file__))\nshare_jupyter = pjoin(here, 'share', 'jupyter', 'hub')\nstatic = pjoin(share_jupyter, 'static')\n\nis_repo = os.path.exists(pjoin(here, '.git'))\n\n#---------------------------------------------------------------------------\n# Build basic package data, etc.\n#---------------------------------------------------------------------------\n\ndef get_data_files():\n    \"\"\"Get data files in share/jupyter\"\"\"\n    \n    data_files = []\n    ntrim = len(here + os.path.sep)\n    \n    for (d, dirs, filenames) in os.walk(share_jupyter):\n        data_files.append((\n            d[ntrim:],\n            [ pjoin(d, f) for f in filenames ]\n        ))\n    return data_files\n\ndef get_package_data():\n    \"\"\"Get package data\n\n    (mostly alembic config)\n    \"\"\"\n    package_data = {}\n    package_data['jupyterhub'] = [\n        'alembic.ini',\n        'alembic/*',\n        'alembic/versions/*',\n    ]\n    return package_data\n\nns = {}\nwith open(pjoin(here, 'jupyterhub', 'version.py')) as f:\n    exec(f.read(), {}, ns)\n\n\npackages = []\nfor d, _, _ in os.walk('jupyterhub'):\n    if os.path.exists(pjoin(d, '__init__.py')):\n        packages.append(d.replace(os.path.sep, '.'))\n\nsetup_args = dict(\n    name                = 'jupyterhub',\n    scripts             = glob(pjoin('scripts', '*')),\n    packages            = packages,\n                        # dummy, so that install_data doesn't get skipped\n                        # this will be overridden when bower is run anyway\n    data_files          = get_data_files() or ['dummy'],\n    package_data        = get_package_data(),\n    version             = ns['__version__'],\n    description         = \"JupyterHub: A multi-user server for Jupyter notebooks\",\n    long_description    = \"See https://jupyterhub.readthedocs.io for more info.\",\n    author              = \"Jupyter Development Team\",\n    author_email        = \"jupyter@googlegroups.com\",\n    url                 = \"http://jupyter.org\",\n    license             = \"BSD\",\n    platforms           = \"Linux, Mac OS X\",\n    keywords            = ['Interactive', 'Interpreter', 'Shell', 'Web'],\n    classifiers         = [\n        'Intended Audience :: Developers',\n        'Intended Audience :: System Administrators',\n        'Intended Audience :: Science/Research',\n        'License :: OSI Approved :: BSD License',\n        'Programming Language :: Python',\n        'Programming Language :: Python :: 3',\n    ],\n)\n\n#---------------------------------------------------------------------------\n# custom distutils commands\n#---------------------------------------------------------------------------\n\n# imports here, so they are after setuptools import if there was one\nfrom distutils.cmd import Command\nfrom distutils.command.build_py import build_py\nfrom distutils.command.sdist import sdist\n\n\nnpm_path = ':'.join([\n    pjoin(here, 'node_modules', '.bin'),\n    os.environ.get(\"PATH\", os.defpath),\n])\n\n\ndef mtime(path):\n    \"\"\"shorthand for mtime\"\"\"\n    return os.stat(path).st_mtime\n\n\nclass BaseCommand(Command):\n    \"\"\"Dumb empty command because Command needs subclasses to override too much\"\"\"\n    user_options = []\n    \n    def initialize_options(self):\n        pass\n    \n    def finalize_options(self):\n        pass\n    \n    def get_inputs(self):\n        return []\n    \n    def get_outputs(self):\n        return []\n\n\nclass Bower(BaseCommand):\n    description = \"fetch static client-side components with bower\"\n    \n    user_options = []\n    bower_dir = pjoin(static, 'components')\n    node_modules = pjoin(here, 'node_modules')\n    \n    def should_run(self):\n        if not os.path.exists(self.bower_dir):\n            return True\n        return mtime(self.bower_dir) < mtime(pjoin(here, 'bower.json'))\n\n    def should_run_npm(self):\n        if not shutil.which('npm'):\n            print(\"npm unavailable\", file=sys.stderr)\n            return False\n        if not os.path.exists(self.node_modules):\n            return True\n        return mtime(self.node_modules) < mtime(pjoin(here, 'package.json'))\n    \n    def run(self):\n        if not self.should_run():\n            print(\"bower dependencies up to date\")\n            return\n        \n        if self.should_run_npm():\n            print(\"installing build dependencies with npm\")\n            check_call(['npm', 'install', '--progress=false'], cwd=here)\n            os.utime(self.node_modules)\n        \n        env = os.environ.copy()\n        env['PATH'] = npm_path\n        \n        try:\n            check_call(\n                ['bower', 'install', '--allow-root', '--config.interactive=false'],\n                cwd=here,\n                env=env,\n            )\n        except OSError as e:\n            print(\"Failed to run bower: %s\" % e, file=sys.stderr)\n            print(\"You can install js dependencies with `npm install`\", file=sys.stderr)\n            raise\n        os.utime(self.bower_dir)\n        # update data-files in case this created new files\n        self.distribution.data_files = get_data_files()\n\n\nclass CSS(BaseCommand):\n    description = \"compile CSS from LESS\"\n    \n    def should_run(self):\n        \"\"\"Does less need to run?\"\"\"\n        # from IPython.html.tasks.py\n        \n        css_targets = [pjoin(static, 'css', 'style.min.css')]\n        css_maps = [t + '.map' for t in css_targets]\n        targets = css_targets + css_maps\n        if not all(os.path.exists(t) for t in targets):\n            # some generated files don't exist\n            return True\n        earliest_target = sorted(mtime(t) for t in targets)[0]\n    \n        # check if any .less files are newer than the generated targets\n        for (dirpath, dirnames, filenames) in os.walk(static):\n            for f in filenames:\n                if f.endswith('.less'):\n                    path = pjoin(static, dirpath, f)\n                    timestamp = mtime(path)\n                    if timestamp > earliest_target:\n                        return True\n    \n        return False\n    \n    def run(self):\n        if not self.should_run():\n            print(\"CSS up-to-date\")\n            return\n        \n        self.run_command('js')\n        \n        style_less = pjoin(static, 'less', 'style.less')\n        style_css = pjoin(static, 'css', 'style.min.css')\n        sourcemap = style_css + '.map'\n        \n        env = os.environ.copy()\n        env['PATH'] = npm_path\n        try:\n            check_call([\n                'lessc', '--clean-css',\n                '--source-map-basepath={}'.format(static),\n                '--source-map={}'.format(sourcemap),\n                '--source-map-rootpath=../',\n                style_less, style_css,\n            ], cwd=here, env=env)\n        except OSError as e:\n            print(\"Failed to run lessc: %s\" % e, file=sys.stderr)\n            print(\"You can install js dependencies with `npm install`\", file=sys.stderr)\n            raise\n        # update data-files in case this created new files\n        self.distribution.data_files = get_data_files()\n\n\ndef js_css_first(cls, strict=True):\n    class Command(cls):\n        def run(self):\n            try:\n                self.run_command('js')\n                self.run_command('css')\n            except Exception:\n                if strict:\n                    raise\n                else:\n                    pass\n            return super().run()\n    return Command\n\n\nclass bdist_egg_disabled(bdist_egg):\n    \"\"\"Disabled version of bdist_egg\n\n    Prevents setup.py install performing setuptools' default easy_install,\n    which it should never ever do.\n    \"\"\"\n    def run(self):\n        sys.exit(\"Aborting implicit building of eggs. Use `pip install .` to install from source.\")\n\n\nsetup_args['cmdclass'] = {\n    'js': Bower,\n    'css': CSS,\n    'build_py': js_css_first(build_py, strict=is_repo),\n    'sdist': js_css_first(sdist, strict=True),\n    'bdist_egg': bdist_egg if 'bdist_egg' in sys.argv else bdist_egg_disabled,\n}\n\n\n# setuptools requirements\n\nsetup_args['zip_safe'] = False\nfrom setuptools.command.develop import develop\nclass develop_js_css(develop):\n    def run(self):\n        if not self.uninstall:\n            self.distribution.run_command('js')\n            self.distribution.run_command('css')\n        develop.run(self)\nsetup_args['cmdclass']['develop'] = develop_js_css\nsetup_args['install_requires'] = install_requires = []\n\nwith open('requirements.txt') as f:\n    for line in f.readlines():\n        req = line.strip()\n        if not req or req.startswith('#') or '://' in req:\n            continue\n        install_requires.append(req)\n\n#---------------------------------------------------------------------------\n# setup\n#---------------------------------------------------------------------------\n\ndef main():\n    setup(**setup_args)\n\nif __name__ == '__main__':\n    main()\n", "path": "setup.py"}]}