We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Use the latest EDM version (3.0.1)
A new major version of EDM is available and it would be good to update to the latest version - https://assets.enthought.com/downloads/edm/. This should be as simple as updating the environment variables in travis and appveyor config files.

https://github.com/enthought/chaco/blob/3de7780561fa29e79c887432d3ce408ea82d1614/.travis.yml#L23
https://github.com/enthought/chaco/blob/3de7780561fa29e79c887432d3ce408ea82d1614/appveyor.yml#L8

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `ci/edmtool.py`
Content:
```
1 #
2 #  Copyright (c) 2017, Enthought, Inc.
3 #  All rights reserved.
4 #
5 #  This software is provided without warranty under the terms of the BSD
6 #  license included in enthought/LICENSE.txt and may be redistributed only
7 #  under the conditions described in the aforementioned license.  The license
8 #  is also available online at http://www.enthought.com/licenses/BSD.txt
9 #
10 #  Thanks for using Enthought open source!
11 #
12 """
13 Tasks for Test Runs
14 ===================
15 This file is intended to be used with a python environment with the
16 click library to automate the process of setting up test environments
17 and running the test within them.  This improves repeatability and
18 reliability of tests be removing many of the variables around the
19 developer's particular Python environment.  Test environment setup and
20 package management is performed using `EDM http://docs.enthought.com/edm/`_
21 
22 To use this to run you tests, you will need to install EDM and click
23 into your working environment.  You will also need to have git
24 installed to access required source code from github repositories.
25 
26 You can then do::
27     python edmtool.py install --runtime=... --toolkit=...
28 to create a test environment from the current codebase and::
29     python edmtool.py test --runtime=... --toolkit=...
30 to run tests in that environment.  You can remove the environment with::
31     python edmtool.py cleanup --runtime=... --toolkit=...
32 
33 If you make changes you will either need to remove and re-install the
34 environment or manually update the environment using ``edm``, as
35 the install performs a ``python setup.py install`` rather than a ``develop``,
36 so changes in your code will not be automatically mirrored in the test
37 environment.  You can update with a command like::
38     edm run --environment ... -- python setup.py install
39 You can run all three tasks at once with::
40     python edmtool.py test_clean --runtime=... --toolkit=...
41 which will create, install, run tests, and then clean-up the environment.  And
42 you can run tests in all supported runtimes and toolkits (with cleanup)
43 using::
44     python edmtool.py test_all
45 
46 Currently supported runtime values are ``3.6``, and currently
47 supported toolkits are ``null``, ``pyqt``, ``pyqt5`` and ``pyside2``.  Not all
48 combinations of toolkits and runtimes will work, but the tasks will fail with
49 a clear error if that is the case. Tests can still be run via the usual means
50 in other environments if that suits a developer's purpose.
51 
52 Changing This File
53 ------------------
54 To change the packages installed during a test run, change the dependencies
55 variable below.  To install a package from github, or one which is not yet
56 available via EDM, add it to the `ci/requirements.txt` file (these will be
57 installed by `pip`).
58 
59 Other changes to commands should be a straightforward change to the listed
60 commands for each task. See the EDM documentation for more information about
61 how to run commands within an EDM enviornment.
62 """
63 import glob
64 import os
65 import subprocess
66 import sys
67 from shutil import rmtree, copy as copyfile
68 from tempfile import mkdtemp
69 from contextlib import contextmanager
70 
71 import click
72 
73 supported_combinations = {
74     '3.6': {'pyside2', 'pyqt', 'pyqt5', 'null'},
75 }
76 
77 dependencies = {
78     "six",
79     "mock",
80     "numpy",
81     "pandas",
82     "pyface",
83     "pygments",
84     "pyparsing",
85     "traits",
86     "traitsui",
87     "cython",
88     "enable",
89     # Needed to install enable from source
90     "swig",
91 }
92 
93 # Dependencies we install from source for cron tests
94 source_dependencies = {
95     "enable",
96     "pyface",
97     "traits",
98     "traitsui",
99 }
100 
101 github_url_fmt = "git+http://github.com/enthought/{0}.git#egg={0}"
102 
103 extra_dependencies = {
104     'pyside2': set(),  # pyside2 is pip-installed during the install step
105     'pyqt': {'pyqt'},
106     'pyqt5': {'pyqt5'},
107     'null': set()
108 }
109 
110 environment_vars = {
111     'pyside2': {'ETS_TOOLKIT': 'qt4', 'QT_API': 'pyside2'},
112     'pyqt': {'ETS_TOOLKIT': 'qt4', 'QT_API': 'pyqt'},
113     'pyqt5': {'ETS_TOOLKIT': 'qt4', 'QT_API': 'pyqt5'},
114     'null': {'ETS_TOOLKIT': 'null.image'},
115 }
116 
117 
118 def normalize(name):
119     return name.replace("_", "-")
120 
121 
122 @click.group(context_settings={"token_normalize_func": normalize})
123 def cli():
124     pass
125 
126 
127 @cli.command()
128 @click.option('--runtime', default='3.6')
129 @click.option('--toolkit', default='null')
130 @click.option('--environment', default=None)
131 @click.option(
132     "--source/--no-source",
133     default=False,
134     help="Install ETS packages from source",
135 )
136 def install(runtime, toolkit, environment, source):
137     """ Install project and dependencies into a clean EDM environment.
138     """
139     parameters = get_parameters(runtime, toolkit, environment)
140     parameters['packages'] = ' '.join(
141         dependencies | extra_dependencies.get(toolkit, set()))
142     # edm commands to setup the development environment
143     commands = [
144         "edm environments create {environment} --force --version={runtime}",
145         "edm install -y -e {environment} {packages}",
146         ("edm run -e {environment} -- pip install -r ci/requirements.txt"
147          " --no-dependencies"),
148         "edm run -e {environment} -- pip install . --no-deps",
149     ]
150     # pip install pyside2, because we don't have it in EDM yet
151     if toolkit == 'pyside2':
152         commands.append(
153             "edm run -e {environment} -- pip install pyside2==5.11"
154         )
155     
156     click.echo("Creating environment '{environment}'".format(**parameters))
157     execute(commands, parameters)
158 
159     if source:
160         # Remove EDM ETS packages and install them from source
161         cmd_fmt = (
162             "edm plumbing remove-package "
163             "--environment {environment} --force "
164         )
165         commands = [cmd_fmt + source_pkg for source_pkg in source_dependencies]
166         execute(commands, parameters)
167         source_pkgs = [
168             github_url_fmt.format(pkg) for pkg in source_dependencies
169         ]
170         commands = [
171             "python -m pip install {pkg} --no-deps".format(pkg=pkg)
172             for pkg in source_pkgs
173         ]
174         commands = [
175             "edm run -e {environment} -- " + command for command in commands
176         ]
177         execute(commands, parameters)
178     click.echo('Done install')
179 
180 
181 @cli.command()
182 @click.option('--runtime', default='3.6')
183 @click.option('--toolkit', default='null')
184 @click.option('--environment', default=None)
185 def test(runtime, toolkit, environment):
186     """ Run the test suite in a given environment with the specified toolkit.
187     """
188     parameters = get_parameters(runtime, toolkit, environment)
189     environ = environment_vars.get(toolkit, {}).copy()
190 
191     environ['PYTHONUNBUFFERED'] = "1"
192     commands = [
193         "edm run -e {environment} -- coverage run -m unittest discover -v chaco"
194     ]
195 
196     cwd = os.getcwd()
197 
198     # We run in a tempdir to avoid accidentally picking up wrong traitsui
199     # code from a local dir.  We need to ensure a good .coveragerc is in
200     # that directory, plus coverage has a bug that means a non-local coverage
201     # file doesn't get populated correctly.
202     click.echo("Running tests in '{environment}'".format(**parameters))
203     with do_in_tempdir(files=['.coveragerc'], capture_files=['./.coverage*']):
204         os.environ.update(environ)
205         execute(commands, parameters)
206 
207     click.echo('Done test')
208 
209 
210 @cli.command()
211 @click.option('--runtime', default='3.6')
212 @click.option('--toolkit', default='null')
213 @click.option('--environment', default=None)
214 def cleanup(runtime, toolkit, environment):
215     """ Remove a development environment.
216     """
217     parameters = get_parameters(runtime, toolkit, environment)
218     commands = [
219         "edm run -e {environment} -- python setup.py clean",
220         "edm environments remove {environment} --purge -y",
221     ]
222     click.echo("Cleaning up environment '{environment}'".format(**parameters))
223     execute(commands, parameters)
224     click.echo('Done cleanup')
225 
226 
227 @cli.command()
228 @click.option('--runtime', default='3.6')
229 @click.option('--toolkit', default='null')
230 def test_clean(runtime, toolkit):
231     """ Run tests in a clean environment, cleaning up afterwards
232     """
233     args = ['--toolkit={}'.format(toolkit),
234             '--runtime={}'.format(runtime)]
235     try:
236         install(args=args, standalone_mode=False)
237         test(args=args, standalone_mode=False)
238     finally:
239         cleanup(args=args, standalone_mode=False)
240 
241 
242 @cli.command()
243 @click.option('--runtime', default='3.6')
244 @click.option('--toolkit', default='null')
245 @click.option('--environment', default=None)
246 def update(runtime, toolkit, environment):
247     """ Update/Reinstall package into environment.
248     """
249     parameters = get_parameters(runtime, toolkit, environment)
250     commands = [
251         "edm run -e {environment} -- python setup.py install"]
252     click.echo("Re-installing in  '{environment}'".format(**parameters))
253     execute(commands, parameters)
254     click.echo('Done update')
255 
256 
257 @cli.command()
258 def test_all():
259     """ Run test_clean across all supported environment combinations.
260     """
261     for runtime, toolkits in supported_combinations.items():
262         for toolkit in toolkits:
263             args = ['--toolkit={}'.format(toolkit),
264                     '--runtime={}'.format(runtime)]
265             test_clean(args, standalone_mode=True)
266 
267 
268 # ----------------------------------------------------------------------------
269 # Utility routines
270 # ----------------------------------------------------------------------------
271 
272 def get_parameters(runtime, toolkit, environment):
273     """Set up parameters dictionary for format() substitution
274     """
275     parameters = {'runtime': runtime, 'toolkit': toolkit,
276                   'environment': environment}
277     if toolkit not in supported_combinations[runtime]:
278         msg = ("Python {runtime!r}, toolkit {toolkit!r}, "
279                "not supported by test environments ({available})")
280         available = ", ".join(
281             repr(tk) for tk in sorted(supported_combinations[runtime])
282         )
283         raise RuntimeError(msg.format(available=available, **parameters))
284     if environment is None:
285         tmpl = 'chaco-test-{runtime}-{toolkit}'
286         environment = tmpl.format(**parameters)
287         parameters['environment'] = environment
288     return parameters
289 
290 
291 @contextmanager
292 def do_in_tempdir(files=(), capture_files=()):
293     """ Create a temporary directory, cleaning up after done.
294     Creates the temporary directory, and changes into it.  On exit returns to
295     original directory and removes temporary dir.
296     Parameters
297     ----------
298     files : sequence of filenames
299         Files to be copied across to temporary directory.
300     capture_files : sequence of filenames
301         Files to be copied back from temporary directory.
302     """
303     path = mkdtemp()
304     old_path = os.getcwd()
305 
306     # send across any files we need
307     for filepath in files:
308         click.echo('copying file to tempdir: {}'.format(filepath))
309         copyfile(filepath, path)
310 
311     os.chdir(path)
312     try:
313         yield path
314         # retrieve any result files we want
315         for pattern in capture_files:
316             for filepath in glob.iglob(pattern):
317                 click.echo('copying file back: {}'.format(filepath))
318                 copyfile(filepath, old_path)
319     finally:
320         os.chdir(old_path)
321         rmtree(path)
322 
323 
324 def execute(commands, parameters):
325     for command in commands:
326         print("[EXECUTING]", command.format(**parameters))
327         try:
328             subprocess.check_call(command.format(**parameters).split())
329         except subprocess.CalledProcessError:
330             sys.exit(1)
331 
332 
333 if __name__ == '__main__':
334     cli()
335
```
--- 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/ci/edmtool.py b/ci/edmtool.py
--- a/ci/edmtool.py
+++ b/ci/edmtool.py
@@ -101,7 +101,7 @@
 github_url_fmt = "git+http://github.com/enthought/{0}.git#egg={0}"
 
 extra_dependencies = {
-    'pyside2': set(),  # pyside2 is pip-installed during the install step
+    'pyside2': {'pyside2'},
     'pyqt': {'pyqt'},
     'pyqt5': {'pyqt5'},
     'null': set()
@@ -139,19 +139,20 @@
     parameters = get_parameters(runtime, toolkit, environment)
     parameters['packages'] = ' '.join(
         dependencies | extra_dependencies.get(toolkit, set()))
+
+    if toolkit == "pyside2":
+        additional_repositories = "--add-repository enthought/lgpl"
+    else:
+        additional_repositories = ""
+
     # edm commands to setup the development environment
     commands = [
         "edm environments create {environment} --force --version={runtime}",
-        "edm install -y -e {environment} {packages}",
+        "edm install -y -e {environment} {packages} " + additional_repositories,
         ("edm run -e {environment} -- pip install -r ci/requirements.txt"
          " --no-dependencies"),
         "edm run -e {environment} -- pip install . --no-deps",
     ]
-    # pip install pyside2, because we don't have it in EDM yet
-    if toolkit == 'pyside2':
-        commands.append(
-            "edm run -e {environment} -- pip install pyside2==5.11"
-        )
     
     click.echo("Creating environment '{environment}'".format(**parameters))
     execute(commands, parameters)

{"golden_diff": "diff --git a/ci/edmtool.py b/ci/edmtool.py\n--- a/ci/edmtool.py\n+++ b/ci/edmtool.py\n@@ -101,7 +101,7 @@\n github_url_fmt = \"git+http://github.com/enthought/{0}.git#egg={0}\"\n \n extra_dependencies = {\n-    'pyside2': set(),  # pyside2 is pip-installed during the install step\n+    'pyside2': {'pyside2'},\n     'pyqt': {'pyqt'},\n     'pyqt5': {'pyqt5'},\n     'null': set()\n@@ -139,19 +139,20 @@\n     parameters = get_parameters(runtime, toolkit, environment)\n     parameters['packages'] = ' '.join(\n         dependencies | extra_dependencies.get(toolkit, set()))\n+\n+    if toolkit == \"pyside2\":\n+        additional_repositories = \"--add-repository enthought/lgpl\"\n+    else:\n+        additional_repositories = \"\"\n+\n     # edm commands to setup the development environment\n     commands = [\n         \"edm environments create {environment} --force --version={runtime}\",\n-        \"edm install -y -e {environment} {packages}\",\n+        \"edm install -y -e {environment} {packages} \" + additional_repositories,\n         (\"edm run -e {environment} -- pip install -r ci/requirements.txt\"\n          \" --no-dependencies\"),\n         \"edm run -e {environment} -- pip install . --no-deps\",\n     ]\n-    # pip install pyside2, because we don't have it in EDM yet\n-    if toolkit == 'pyside2':\n-        commands.append(\n-            \"edm run -e {environment} -- pip install pyside2==5.11\"\n-        )\n     \n     click.echo(\"Creating environment '{environment}'\".format(**parameters))\n     execute(commands, parameters)\n", "issue": "Use the latest EDM version (3.0.1)\nA new major version of EDM is available and it would be good to update to the latest version - https://assets.enthought.com/downloads/edm/. This should be as simple as updating the environment variables in travis and appveyor config files.\r\n\r\nhttps://github.com/enthought/chaco/blob/3de7780561fa29e79c887432d3ce408ea82d1614/.travis.yml#L23\r\nhttps://github.com/enthought/chaco/blob/3de7780561fa29e79c887432d3ce408ea82d1614/appveyor.yml#L8\n", "before_files": [{"content": "#\n#  Copyright (c) 2017, Enthought, Inc.\n#  All rights reserved.\n#\n#  This software is provided without warranty under the terms of the BSD\n#  license included in enthought/LICENSE.txt and may be redistributed only\n#  under the conditions described in the aforementioned license.  The license\n#  is also available online at http://www.enthought.com/licenses/BSD.txt\n#\n#  Thanks for using Enthought open source!\n#\n\"\"\"\nTasks for Test Runs\n===================\nThis file is intended to be used with a python environment with the\nclick library to automate the process of setting up test environments\nand running the test within them.  This improves repeatability and\nreliability of tests be removing many of the variables around the\ndeveloper's particular Python environment.  Test environment setup and\npackage management is performed using `EDM http://docs.enthought.com/edm/`_\n\nTo use this to run you tests, you will need to install EDM and click\ninto your working environment.  You will also need to have git\ninstalled to access required source code from github repositories.\n\nYou can then do::\n    python edmtool.py install --runtime=... --toolkit=...\nto create a test environment from the current codebase and::\n    python edmtool.py test --runtime=... --toolkit=...\nto run tests in that environment.  You can remove the environment with::\n    python edmtool.py cleanup --runtime=... --toolkit=...\n\nIf you make changes you will either need to remove and re-install the\nenvironment or manually update the environment using ``edm``, as\nthe install performs a ``python setup.py install`` rather than a ``develop``,\nso changes in your code will not be automatically mirrored in the test\nenvironment.  You can update with a command like::\n    edm run --environment ... -- python setup.py install\nYou can run all three tasks at once with::\n    python edmtool.py test_clean --runtime=... --toolkit=...\nwhich will create, install, run tests, and then clean-up the environment.  And\nyou can run tests in all supported runtimes and toolkits (with cleanup)\nusing::\n    python edmtool.py test_all\n\nCurrently supported runtime values are ``3.6``, and currently\nsupported toolkits are ``null``, ``pyqt``, ``pyqt5`` and ``pyside2``.  Not all\ncombinations of toolkits and runtimes will work, but the tasks will fail with\na clear error if that is the case. Tests can still be run via the usual means\nin other environments if that suits a developer's purpose.\n\nChanging This File\n------------------\nTo change the packages installed during a test run, change the dependencies\nvariable below.  To install a package from github, or one which is not yet\navailable via EDM, add it to the `ci/requirements.txt` file (these will be\ninstalled by `pip`).\n\nOther changes to commands should be a straightforward change to the listed\ncommands for each task. See the EDM documentation for more information about\nhow to run commands within an EDM enviornment.\n\"\"\"\nimport glob\nimport os\nimport subprocess\nimport sys\nfrom shutil import rmtree, copy as copyfile\nfrom tempfile import mkdtemp\nfrom contextlib import contextmanager\n\nimport click\n\nsupported_combinations = {\n    '3.6': {'pyside2', 'pyqt', 'pyqt5', 'null'},\n}\n\ndependencies = {\n    \"six\",\n    \"mock\",\n    \"numpy\",\n    \"pandas\",\n    \"pyface\",\n    \"pygments\",\n    \"pyparsing\",\n    \"traits\",\n    \"traitsui\",\n    \"cython\",\n    \"enable\",\n    # Needed to install enable from source\n    \"swig\",\n}\n\n# Dependencies we install from source for cron tests\nsource_dependencies = {\n    \"enable\",\n    \"pyface\",\n    \"traits\",\n    \"traitsui\",\n}\n\ngithub_url_fmt = \"git+http://github.com/enthought/{0}.git#egg={0}\"\n\nextra_dependencies = {\n    'pyside2': set(),  # pyside2 is pip-installed during the install step\n    'pyqt': {'pyqt'},\n    'pyqt5': {'pyqt5'},\n    'null': set()\n}\n\nenvironment_vars = {\n    'pyside2': {'ETS_TOOLKIT': 'qt4', 'QT_API': 'pyside2'},\n    'pyqt': {'ETS_TOOLKIT': 'qt4', 'QT_API': 'pyqt'},\n    'pyqt5': {'ETS_TOOLKIT': 'qt4', 'QT_API': 'pyqt5'},\n    'null': {'ETS_TOOLKIT': 'null.image'},\n}\n\n\ndef normalize(name):\n    return name.replace(\"_\", \"-\")\n\n\n@click.group(context_settings={\"token_normalize_func\": normalize})\ndef cli():\n    pass\n\n\n@cli.command()\n@click.option('--runtime', default='3.6')\n@click.option('--toolkit', default='null')\n@click.option('--environment', default=None)\n@click.option(\n    \"--source/--no-source\",\n    default=False,\n    help=\"Install ETS packages from source\",\n)\ndef install(runtime, toolkit, environment, source):\n    \"\"\" Install project and dependencies into a clean EDM environment.\n    \"\"\"\n    parameters = get_parameters(runtime, toolkit, environment)\n    parameters['packages'] = ' '.join(\n        dependencies | extra_dependencies.get(toolkit, set()))\n    # edm commands to setup the development environment\n    commands = [\n        \"edm environments create {environment} --force --version={runtime}\",\n        \"edm install -y -e {environment} {packages}\",\n        (\"edm run -e {environment} -- pip install -r ci/requirements.txt\"\n         \" --no-dependencies\"),\n        \"edm run -e {environment} -- pip install . --no-deps\",\n    ]\n    # pip install pyside2, because we don't have it in EDM yet\n    if toolkit == 'pyside2':\n        commands.append(\n            \"edm run -e {environment} -- pip install pyside2==5.11\"\n        )\n    \n    click.echo(\"Creating environment '{environment}'\".format(**parameters))\n    execute(commands, parameters)\n\n    if source:\n        # Remove EDM ETS packages and install them from source\n        cmd_fmt = (\n            \"edm plumbing remove-package \"\n            \"--environment {environment} --force \"\n        )\n        commands = [cmd_fmt + source_pkg for source_pkg in source_dependencies]\n        execute(commands, parameters)\n        source_pkgs = [\n            github_url_fmt.format(pkg) for pkg in source_dependencies\n        ]\n        commands = [\n            \"python -m pip install {pkg} --no-deps\".format(pkg=pkg)\n            for pkg in source_pkgs\n        ]\n        commands = [\n            \"edm run -e {environment} -- \" + command for command in commands\n        ]\n        execute(commands, parameters)\n    click.echo('Done install')\n\n\n@cli.command()\n@click.option('--runtime', default='3.6')\n@click.option('--toolkit', default='null')\n@click.option('--environment', default=None)\ndef test(runtime, toolkit, environment):\n    \"\"\" Run the test suite in a given environment with the specified toolkit.\n    \"\"\"\n    parameters = get_parameters(runtime, toolkit, environment)\n    environ = environment_vars.get(toolkit, {}).copy()\n\n    environ['PYTHONUNBUFFERED'] = \"1\"\n    commands = [\n        \"edm run -e {environment} -- coverage run -m unittest discover -v chaco\"\n    ]\n\n    cwd = os.getcwd()\n\n    # We run in a tempdir to avoid accidentally picking up wrong traitsui\n    # code from a local dir.  We need to ensure a good .coveragerc is in\n    # that directory, plus coverage has a bug that means a non-local coverage\n    # file doesn't get populated correctly.\n    click.echo(\"Running tests in '{environment}'\".format(**parameters))\n    with do_in_tempdir(files=['.coveragerc'], capture_files=['./.coverage*']):\n        os.environ.update(environ)\n        execute(commands, parameters)\n\n    click.echo('Done test')\n\n\n@cli.command()\n@click.option('--runtime', default='3.6')\n@click.option('--toolkit', default='null')\n@click.option('--environment', default=None)\ndef cleanup(runtime, toolkit, environment):\n    \"\"\" Remove a development environment.\n    \"\"\"\n    parameters = get_parameters(runtime, toolkit, environment)\n    commands = [\n        \"edm run -e {environment} -- python setup.py clean\",\n        \"edm environments remove {environment} --purge -y\",\n    ]\n    click.echo(\"Cleaning up environment '{environment}'\".format(**parameters))\n    execute(commands, parameters)\n    click.echo('Done cleanup')\n\n\n@cli.command()\n@click.option('--runtime', default='3.6')\n@click.option('--toolkit', default='null')\ndef test_clean(runtime, toolkit):\n    \"\"\" Run tests in a clean environment, cleaning up afterwards\n    \"\"\"\n    args = ['--toolkit={}'.format(toolkit),\n            '--runtime={}'.format(runtime)]\n    try:\n        install(args=args, standalone_mode=False)\n        test(args=args, standalone_mode=False)\n    finally:\n        cleanup(args=args, standalone_mode=False)\n\n\n@cli.command()\n@click.option('--runtime', default='3.6')\n@click.option('--toolkit', default='null')\n@click.option('--environment', default=None)\ndef update(runtime, toolkit, environment):\n    \"\"\" Update/Reinstall package into environment.\n    \"\"\"\n    parameters = get_parameters(runtime, toolkit, environment)\n    commands = [\n        \"edm run -e {environment} -- python setup.py install\"]\n    click.echo(\"Re-installing in  '{environment}'\".format(**parameters))\n    execute(commands, parameters)\n    click.echo('Done update')\n\n\n@cli.command()\ndef test_all():\n    \"\"\" Run test_clean across all supported environment combinations.\n    \"\"\"\n    for runtime, toolkits in supported_combinations.items():\n        for toolkit in toolkits:\n            args = ['--toolkit={}'.format(toolkit),\n                    '--runtime={}'.format(runtime)]\n            test_clean(args, standalone_mode=True)\n\n\n# ----------------------------------------------------------------------------\n# Utility routines\n# ----------------------------------------------------------------------------\n\ndef get_parameters(runtime, toolkit, environment):\n    \"\"\"Set up parameters dictionary for format() substitution\n    \"\"\"\n    parameters = {'runtime': runtime, 'toolkit': toolkit,\n                  'environment': environment}\n    if toolkit not in supported_combinations[runtime]:\n        msg = (\"Python {runtime!r}, toolkit {toolkit!r}, \"\n               \"not supported by test environments ({available})\")\n        available = \", \".join(\n            repr(tk) for tk in sorted(supported_combinations[runtime])\n        )\n        raise RuntimeError(msg.format(available=available, **parameters))\n    if environment is None:\n        tmpl = 'chaco-test-{runtime}-{toolkit}'\n        environment = tmpl.format(**parameters)\n        parameters['environment'] = environment\n    return parameters\n\n\n@contextmanager\ndef do_in_tempdir(files=(), capture_files=()):\n    \"\"\" Create a temporary directory, cleaning up after done.\n    Creates the temporary directory, and changes into it.  On exit returns to\n    original directory and removes temporary dir.\n    Parameters\n    ----------\n    files : sequence of filenames\n        Files to be copied across to temporary directory.\n    capture_files : sequence of filenames\n        Files to be copied back from temporary directory.\n    \"\"\"\n    path = mkdtemp()\n    old_path = os.getcwd()\n\n    # send across any files we need\n    for filepath in files:\n        click.echo('copying file to tempdir: {}'.format(filepath))\n        copyfile(filepath, path)\n\n    os.chdir(path)\n    try:\n        yield path\n        # retrieve any result files we want\n        for pattern in capture_files:\n            for filepath in glob.iglob(pattern):\n                click.echo('copying file back: {}'.format(filepath))\n                copyfile(filepath, old_path)\n    finally:\n        os.chdir(old_path)\n        rmtree(path)\n\n\ndef execute(commands, parameters):\n    for command in commands:\n        print(\"[EXECUTING]\", command.format(**parameters))\n        try:\n            subprocess.check_call(command.format(**parameters).split())\n        except subprocess.CalledProcessError:\n            sys.exit(1)\n\n\nif __name__ == '__main__':\n    cli()\n", "path": "ci/edmtool.py"}], "after_files": [{"content": "#\n#  Copyright (c) 2017, Enthought, Inc.\n#  All rights reserved.\n#\n#  This software is provided without warranty under the terms of the BSD\n#  license included in enthought/LICENSE.txt and may be redistributed only\n#  under the conditions described in the aforementioned license.  The license\n#  is also available online at http://www.enthought.com/licenses/BSD.txt\n#\n#  Thanks for using Enthought open source!\n#\n\"\"\"\nTasks for Test Runs\n===================\nThis file is intended to be used with a python environment with the\nclick library to automate the process of setting up test environments\nand running the test within them.  This improves repeatability and\nreliability of tests be removing many of the variables around the\ndeveloper's particular Python environment.  Test environment setup and\npackage management is performed using `EDM http://docs.enthought.com/edm/`_\n\nTo use this to run you tests, you will need to install EDM and click\ninto your working environment.  You will also need to have git\ninstalled to access required source code from github repositories.\n\nYou can then do::\n    python edmtool.py install --runtime=... --toolkit=...\nto create a test environment from the current codebase and::\n    python edmtool.py test --runtime=... --toolkit=...\nto run tests in that environment.  You can remove the environment with::\n    python edmtool.py cleanup --runtime=... --toolkit=...\n\nIf you make changes you will either need to remove and re-install the\nenvironment or manually update the environment using ``edm``, as\nthe install performs a ``python setup.py install`` rather than a ``develop``,\nso changes in your code will not be automatically mirrored in the test\nenvironment.  You can update with a command like::\n    edm run --environment ... -- python setup.py install\nYou can run all three tasks at once with::\n    python edmtool.py test_clean --runtime=... --toolkit=...\nwhich will create, install, run tests, and then clean-up the environment.  And\nyou can run tests in all supported runtimes and toolkits (with cleanup)\nusing::\n    python edmtool.py test_all\n\nCurrently supported runtime values are ``3.6``, and currently\nsupported toolkits are ``null``, ``pyqt``, ``pyqt5`` and ``pyside2``.  Not all\ncombinations of toolkits and runtimes will work, but the tasks will fail with\na clear error if that is the case. Tests can still be run via the usual means\nin other environments if that suits a developer's purpose.\n\nChanging This File\n------------------\nTo change the packages installed during a test run, change the dependencies\nvariable below.  To install a package from github, or one which is not yet\navailable via EDM, add it to the `ci/requirements.txt` file (these will be\ninstalled by `pip`).\n\nOther changes to commands should be a straightforward change to the listed\ncommands for each task. See the EDM documentation for more information about\nhow to run commands within an EDM enviornment.\n\"\"\"\nimport glob\nimport os\nimport subprocess\nimport sys\nfrom shutil import rmtree, copy as copyfile\nfrom tempfile import mkdtemp\nfrom contextlib import contextmanager\n\nimport click\n\nsupported_combinations = {\n    '3.6': {'pyside2', 'pyqt', 'pyqt5', 'null'},\n}\n\ndependencies = {\n    \"six\",\n    \"mock\",\n    \"numpy\",\n    \"pandas\",\n    \"pyface\",\n    \"pygments\",\n    \"pyparsing\",\n    \"traits\",\n    \"traitsui\",\n    \"cython\",\n    \"enable\",\n    # Needed to install enable from source\n    \"swig\",\n}\n\n# Dependencies we install from source for cron tests\nsource_dependencies = {\n    \"enable\",\n    \"pyface\",\n    \"traits\",\n    \"traitsui\",\n}\n\ngithub_url_fmt = \"git+http://github.com/enthought/{0}.git#egg={0}\"\n\nextra_dependencies = {\n    'pyside2': {'pyside2'},\n    'pyqt': {'pyqt'},\n    'pyqt5': {'pyqt5'},\n    'null': set()\n}\n\nenvironment_vars = {\n    'pyside2': {'ETS_TOOLKIT': 'qt4', 'QT_API': 'pyside2'},\n    'pyqt': {'ETS_TOOLKIT': 'qt4', 'QT_API': 'pyqt'},\n    'pyqt5': {'ETS_TOOLKIT': 'qt4', 'QT_API': 'pyqt5'},\n    'null': {'ETS_TOOLKIT': 'null.image'},\n}\n\n\ndef normalize(name):\n    return name.replace(\"_\", \"-\")\n\n\n@click.group(context_settings={\"token_normalize_func\": normalize})\ndef cli():\n    pass\n\n\n@cli.command()\n@click.option('--runtime', default='3.6')\n@click.option('--toolkit', default='null')\n@click.option('--environment', default=None)\n@click.option(\n    \"--source/--no-source\",\n    default=False,\n    help=\"Install ETS packages from source\",\n)\ndef install(runtime, toolkit, environment, source):\n    \"\"\" Install project and dependencies into a clean EDM environment.\n    \"\"\"\n    parameters = get_parameters(runtime, toolkit, environment)\n    parameters['packages'] = ' '.join(\n        dependencies | extra_dependencies.get(toolkit, set()))\n\n    if toolkit == \"pyside2\":\n        additional_repositories = \"--add-repository enthought/lgpl\"\n    else:\n        additional_repositories = \"\"\n\n    # edm commands to setup the development environment\n    commands = [\n        \"edm environments create {environment} --force --version={runtime}\",\n        \"edm install -y -e {environment} {packages} \" + additional_repositories,\n        (\"edm run -e {environment} -- pip install -r ci/requirements.txt\"\n         \" --no-dependencies\"),\n        \"edm run -e {environment} -- pip install . --no-deps\",\n    ]\n    \n    click.echo(\"Creating environment '{environment}'\".format(**parameters))\n    execute(commands, parameters)\n\n    if source:\n        # Remove EDM ETS packages and install them from source\n        cmd_fmt = (\n            \"edm plumbing remove-package \"\n            \"--environment {environment} --force \"\n        )\n        commands = [cmd_fmt + source_pkg for source_pkg in source_dependencies]\n        execute(commands, parameters)\n        source_pkgs = [\n            github_url_fmt.format(pkg) for pkg in source_dependencies\n        ]\n        commands = [\n            \"python -m pip install {pkg} --no-deps\".format(pkg=pkg)\n            for pkg in source_pkgs\n        ]\n        commands = [\n            \"edm run -e {environment} -- \" + command for command in commands\n        ]\n        execute(commands, parameters)\n    click.echo('Done install')\n\n\n@cli.command()\n@click.option('--runtime', default='3.6')\n@click.option('--toolkit', default='null')\n@click.option('--environment', default=None)\ndef test(runtime, toolkit, environment):\n    \"\"\" Run the test suite in a given environment with the specified toolkit.\n    \"\"\"\n    parameters = get_parameters(runtime, toolkit, environment)\n    environ = environment_vars.get(toolkit, {}).copy()\n\n    environ['PYTHONUNBUFFERED'] = \"1\"\n    commands = [\n        \"edm run -e {environment} -- coverage run -m unittest discover -v chaco\"\n    ]\n\n    cwd = os.getcwd()\n\n    # We run in a tempdir to avoid accidentally picking up wrong traitsui\n    # code from a local dir.  We need to ensure a good .coveragerc is in\n    # that directory, plus coverage has a bug that means a non-local coverage\n    # file doesn't get populated correctly.\n    click.echo(\"Running tests in '{environment}'\".format(**parameters))\n    with do_in_tempdir(files=['.coveragerc'], capture_files=['./.coverage*']):\n        os.environ.update(environ)\n        execute(commands, parameters)\n\n    click.echo('Done test')\n\n\n@cli.command()\n@click.option('--runtime', default='3.6')\n@click.option('--toolkit', default='null')\n@click.option('--environment', default=None)\ndef cleanup(runtime, toolkit, environment):\n    \"\"\" Remove a development environment.\n    \"\"\"\n    parameters = get_parameters(runtime, toolkit, environment)\n    commands = [\n        \"edm run -e {environment} -- python setup.py clean\",\n        \"edm environments remove {environment} --purge -y\",\n    ]\n    click.echo(\"Cleaning up environment '{environment}'\".format(**parameters))\n    execute(commands, parameters)\n    click.echo('Done cleanup')\n\n\n@cli.command()\n@click.option('--runtime', default='3.6')\n@click.option('--toolkit', default='null')\ndef test_clean(runtime, toolkit):\n    \"\"\" Run tests in a clean environment, cleaning up afterwards\n    \"\"\"\n    args = ['--toolkit={}'.format(toolkit),\n            '--runtime={}'.format(runtime)]\n    try:\n        install(args=args, standalone_mode=False)\n        test(args=args, standalone_mode=False)\n    finally:\n        cleanup(args=args, standalone_mode=False)\n\n\n@cli.command()\n@click.option('--runtime', default='3.6')\n@click.option('--toolkit', default='null')\n@click.option('--environment', default=None)\ndef update(runtime, toolkit, environment):\n    \"\"\" Update/Reinstall package into environment.\n    \"\"\"\n    parameters = get_parameters(runtime, toolkit, environment)\n    commands = [\n        \"edm run -e {environment} -- python setup.py install\"]\n    click.echo(\"Re-installing in  '{environment}'\".format(**parameters))\n    execute(commands, parameters)\n    click.echo('Done update')\n\n\n@cli.command()\ndef test_all():\n    \"\"\" Run test_clean across all supported environment combinations.\n    \"\"\"\n    for runtime, toolkits in supported_combinations.items():\n        for toolkit in toolkits:\n            args = ['--toolkit={}'.format(toolkit),\n                    '--runtime={}'.format(runtime)]\n            test_clean(args, standalone_mode=True)\n\n\n# ----------------------------------------------------------------------------\n# Utility routines\n# ----------------------------------------------------------------------------\n\ndef get_parameters(runtime, toolkit, environment):\n    \"\"\"Set up parameters dictionary for format() substitution\n    \"\"\"\n    parameters = {'runtime': runtime, 'toolkit': toolkit,\n                  'environment': environment}\n    if toolkit not in supported_combinations[runtime]:\n        msg = (\"Python {runtime!r}, toolkit {toolkit!r}, \"\n               \"not supported by test environments ({available})\")\n        available = \", \".join(\n            repr(tk) for tk in sorted(supported_combinations[runtime])\n        )\n        raise RuntimeError(msg.format(available=available, **parameters))\n    if environment is None:\n        tmpl = 'chaco-test-{runtime}-{toolkit}'\n        environment = tmpl.format(**parameters)\n        parameters['environment'] = environment\n    return parameters\n\n\n@contextmanager\ndef do_in_tempdir(files=(), capture_files=()):\n    \"\"\" Create a temporary directory, cleaning up after done.\n    Creates the temporary directory, and changes into it.  On exit returns to\n    original directory and removes temporary dir.\n    Parameters\n    ----------\n    files : sequence of filenames\n        Files to be copied across to temporary directory.\n    capture_files : sequence of filenames\n        Files to be copied back from temporary directory.\n    \"\"\"\n    path = mkdtemp()\n    old_path = os.getcwd()\n\n    # send across any files we need\n    for filepath in files:\n        click.echo('copying file to tempdir: {}'.format(filepath))\n        copyfile(filepath, path)\n\n    os.chdir(path)\n    try:\n        yield path\n        # retrieve any result files we want\n        for pattern in capture_files:\n            for filepath in glob.iglob(pattern):\n                click.echo('copying file back: {}'.format(filepath))\n                copyfile(filepath, old_path)\n    finally:\n        os.chdir(old_path)\n        rmtree(path)\n\n\ndef execute(commands, parameters):\n    for command in commands:\n        print(\"[EXECUTING]\", command.format(**parameters))\n        try:\n            subprocess.check_call(command.format(**parameters).split())\n        except subprocess.CalledProcessError:\n            sys.exit(1)\n\n\nif __name__ == '__main__':\n    cli()\n", "path": "ci/edmtool.py"}]}