From f6e0e297eb2099af14f7758af6a48e3af9b3ca1e Mon Sep 17 00:00:00 2001 From: Tomasz Prus Date: Thu, 1 Feb 2018 10:26:38 +0100 Subject: [PATCH] [python-asyncio] tests and fixes (#7235) * fix: creating ssl context and passing args/files/forms * feat: python-async add tests * chore: rebuild petstore sample for python, tornado and asyncio * feat: add python asyncio to travis * feat: print coverage (python-asyncio) --- .../resources/python/asyncio/rest.mustache | 32 ++- .../python/test-requirements.mustache | 6 + .../src/main/resources/python/tox.mustache | 14 +- pom.xml | 1 + .../client/petstore/python-asyncio/Makefile | 18 ++ .../python-asyncio/dev-requirements.txt | 4 + .../petstore/python-asyncio/docs/FakeApi.md | 4 +- .../petstore/python-asyncio/git_push.sh | 2 +- .../python-asyncio/petstore_api/rest.py | 32 ++- .../client/petstore/python-asyncio/pom.xml | 46 ++++ .../python-asyncio/test-requirements.txt | 4 +- .../petstore/python-asyncio/test_python3.sh | 32 +++ .../petstore/python-asyncio/testfiles/foo.png | Bin 0 -> 43280 bytes .../petstore/python-asyncio/tests/__init__.py | 0 .../python-asyncio/tests/test_pet_api.py | 208 ++++++++++++++++++ .../petstore/python-asyncio/tests/util.py | 11 + .../client/petstore/python-asyncio/tox.ini | 7 +- .../client/petstore/python-tornado/tox.ini | 4 +- .../client/petstore/python/docs/FakeApi.md | 4 +- samples/client/petstore/python/tox.ini | 4 +- 20 files changed, 394 insertions(+), 39 deletions(-) create mode 100644 samples/client/petstore/python-asyncio/Makefile create mode 100644 samples/client/petstore/python-asyncio/dev-requirements.txt create mode 100644 samples/client/petstore/python-asyncio/pom.xml create mode 100755 samples/client/petstore/python-asyncio/test_python3.sh create mode 100644 samples/client/petstore/python-asyncio/testfiles/foo.png create mode 100644 samples/client/petstore/python-asyncio/tests/__init__.py create mode 100644 samples/client/petstore/python-asyncio/tests/test_pet_api.py create mode 100644 samples/client/petstore/python-asyncio/tests/util.py diff --git a/modules/swagger-codegen/src/main/resources/python/asyncio/rest.mustache b/modules/swagger-codegen/src/main/resources/python/asyncio/rest.mustache index 986902f56d0..39003abfbfd 100644 --- a/modules/swagger-codegen/src/main/resources/python/asyncio/rest.mustache +++ b/modules/swagger-codegen/src/main/resources/python/asyncio/rest.mustache @@ -47,8 +47,7 @@ class RESTClientObject(object): # if not set certificate file, use Mozilla's root certificates. ca_certs = certifi.where() - ssl_context = ssl.SSLContext() - ssl_context.load_verify_locations(cafile=ca_certs) + ssl_context = ssl.create_default_context(cafile=ca_certs) if configuration.cert_file: ssl_context.load_cert_chain( configuration.cert_file, keyfile=configuration.key_file @@ -113,21 +112,34 @@ class RESTClientObject(object): "timeout": timeout, "headers": headers } + + if query_params: + args["url"] += '?' + urlencode(query_params) + # For `POST`, `PUT`, `PATCH`, `OPTIONS`, `DELETE` if method in ['POST', 'PUT', 'PATCH', 'OPTIONS', 'DELETE']: - if query_params: - url += '?' + urlencode(query_params) if re.search('json', headers['Content-Type'], re.IGNORECASE): if body is not None: body = json.dumps(body) args["data"] = body elif headers['Content-Type'] == 'application/x-www-form-urlencoded': # noqa: E501 - data = aiohttp.FormData() - for k, v in post_params.items(): - data.add_field(k, v) - args["data"] = data + args["data"] = aiohttp.FormData(post_params) elif headers['Content-Type'] == 'multipart/form-data': - args["data"] = post_params + # must del headers['Content-Type'], or the correct + # Content-Type which generated by aiohttp + del headers['Content-Type'] + data = aiohttp.FormData() + for param in post_params: + k, v = param + if isinstance(v, tuple) and len(v) == 3: + data.add_field(k, + value=v[1], + filename=v[0], + content_type=v[2]) + else: + data.add_field(k, v) + args["data"] = data + # Pass a `bytes` parameter directly in the body to support # other content types than Json when `body` argument is provided # in serialized form @@ -139,8 +151,6 @@ class RESTClientObject(object): arguments. Please check that your arguments match declared content type.""" raise ApiException(status=0, reason=msg) - else: - args["data"] = query_params async with self.pool_manager.request(**args) as r: data = await r.text() diff --git a/modules/swagger-codegen/src/main/resources/python/test-requirements.mustache b/modules/swagger-codegen/src/main/resources/python/test-requirements.mustache index 2702246c0e6..31f8d94d99f 100644 --- a/modules/swagger-codegen/src/main/resources/python/test-requirements.mustache +++ b/modules/swagger-codegen/src/main/resources/python/test-requirements.mustache @@ -1,5 +1,11 @@ +{{^asyncio}} coverage>=4.0.3 nose>=1.3.7 +{{/asyncio}} +{{#asyncio}} +pytest>=3.3.1 +pytest-cov>=2.5.1 +{{/asyncio}} pluggy>=0.3.1 py>=1.4.31 randomize>=0.13 diff --git a/modules/swagger-codegen/src/main/resources/python/tox.mustache b/modules/swagger-codegen/src/main/resources/python/tox.mustache index 1cf0829dc93..63d12fdeaea 100644 --- a/modules/swagger-codegen/src/main/resources/python/tox.mustache +++ b/modules/swagger-codegen/src/main/resources/python/tox.mustache @@ -1,10 +1,20 @@ [tox] +{{^asyncio}} envlist = py27, py3 +{{/asyncio}} +{{#asyncio}} +envlist = py3 +{{/asyncio}} [testenv] deps=-r{toxinidir}/requirements.txt -r{toxinidir}/test-requirements.txt - + commands= +{{^asyncio}} nosetests \ - [] \ No newline at end of file + [] +{{/asyncio}} +{{#asyncio}} + pytest -v --cov petstore_api +{{/asyncio}} diff --git a/pom.xml b/pom.xml index f9d861bbf9d..ee1488a3b67 100644 --- a/pom.xml +++ b/pom.xml @@ -846,6 +846,7 @@ samples/client/petstore/javascript samples/client/petstore/python samples/client/petstore/python-tornado + samples/client/petstore/python-asyncio samples/client/petstore/typescript-fetch/builds/default samples/client/petstore/typescript-fetch/builds/es6-target samples/client/petstore/typescript-fetch/builds/with-npm-version diff --git a/samples/client/petstore/python-asyncio/Makefile b/samples/client/petstore/python-asyncio/Makefile new file mode 100644 index 00000000000..8d0afd4974d --- /dev/null +++ b/samples/client/petstore/python-asyncio/Makefile @@ -0,0 +1,18 @@ + #!/bin/bash + +REQUIREMENTS_FILE=dev-requirements.txt +REQUIREMENTS_OUT=dev-requirements.txt.log +SETUP_OUT=*.egg-info +VENV=.venv + +clean: + rm -rf $(REQUIREMENTS_OUT) + rm -rf $(SETUP_OUT) + rm -rf $(VENV) + rm -rf .tox + rm -rf .coverage + find . -name "*.py[oc]" -delete + find . -name "__pycache__" -delete + +test-all: clean + bash ./test_python3.sh diff --git a/samples/client/petstore/python-asyncio/dev-requirements.txt b/samples/client/petstore/python-asyncio/dev-requirements.txt new file mode 100644 index 00000000000..49182426e20 --- /dev/null +++ b/samples/client/petstore/python-asyncio/dev-requirements.txt @@ -0,0 +1,4 @@ +tox +coverage +randomize +flake8 diff --git a/samples/client/petstore/python-asyncio/docs/FakeApi.md b/samples/client/petstore/python-asyncio/docs/FakeApi.md index 1da84500bfe..b910ba2b464 100644 --- a/samples/client/petstore/python-asyncio/docs/FakeApi.md +++ b/samples/client/petstore/python-asyncio/docs/FakeApi.md @@ -273,10 +273,10 @@ configuration.password = 'YOUR_PASSWORD' # create an instance of the API class api_instance = petstore_api.FakeApi(petstore_api.ApiClient(configuration)) -number = 8.14 # float | None +number = 3.4 # float | None double = 1.2 # float | None pattern_without_delimiter = 'pattern_without_delimiter_example' # str | None -byte = 'B' # str | None +byte = 'byte_example' # str | None integer = 56 # int | None (optional) int32 = 56 # int | None (optional) int64 = 789 # int | None (optional) diff --git a/samples/client/petstore/python-asyncio/git_push.sh b/samples/client/petstore/python-asyncio/git_push.sh index ed374619b13..ae01b182ae9 100644 --- a/samples/client/petstore/python-asyncio/git_push.sh +++ b/samples/client/petstore/python-asyncio/git_push.sh @@ -36,7 +36,7 @@ git_remote=`git remote` if [ "$git_remote" = "" ]; then # git remote not defined if [ "$GIT_TOKEN" = "" ]; then - echo "[INFO] \$GIT_TOKEN (environment variable) is not set. Using the git crediential in your environment." + echo "[INFO] \$GIT_TOKEN (environment variable) is not set. Using the git credential in your environment." git remote add origin https://github.com/${git_user_id}/${git_repo_id}.git else git remote add origin https://${git_user_id}:${GIT_TOKEN}@github.com/${git_user_id}/${git_repo_id}.git diff --git a/samples/client/petstore/python-asyncio/petstore_api/rest.py b/samples/client/petstore/python-asyncio/petstore_api/rest.py index 497882aaa9f..69d87b282c6 100644 --- a/samples/client/petstore/python-asyncio/petstore_api/rest.py +++ b/samples/client/petstore/python-asyncio/petstore_api/rest.py @@ -56,8 +56,7 @@ class RESTClientObject(object): # if not set certificate file, use Mozilla's root certificates. ca_certs = certifi.where() - ssl_context = ssl.SSLContext() - ssl_context.load_verify_locations(cafile=ca_certs) + ssl_context = ssl.create_default_context(cafile=ca_certs) if configuration.cert_file: ssl_context.load_cert_chain( configuration.cert_file, keyfile=configuration.key_file @@ -122,21 +121,34 @@ class RESTClientObject(object): "timeout": timeout, "headers": headers } + + if query_params: + args["url"] += '?' + urlencode(query_params) + # For `POST`, `PUT`, `PATCH`, `OPTIONS`, `DELETE` if method in ['POST', 'PUT', 'PATCH', 'OPTIONS', 'DELETE']: - if query_params: - url += '?' + urlencode(query_params) if re.search('json', headers['Content-Type'], re.IGNORECASE): if body is not None: body = json.dumps(body) args["data"] = body elif headers['Content-Type'] == 'application/x-www-form-urlencoded': # noqa: E501 - data = aiohttp.FormData() - for k, v in post_params.items(): - data.add_field(k, v) - args["data"] = data + args["data"] = aiohttp.FormData(post_params) elif headers['Content-Type'] == 'multipart/form-data': - args["data"] = post_params + # must del headers['Content-Type'], or the correct + # Content-Type which generated by aiohttp + del headers['Content-Type'] + data = aiohttp.FormData() + for param in post_params: + k, v = param + if isinstance(v, tuple) and len(v) == 3: + data.add_field(k, + value=v[1], + filename=v[0], + content_type=v[2]) + else: + data.add_field(k, v) + args["data"] = data + # Pass a `bytes` parameter directly in the body to support # other content types than Json when `body` argument is provided # in serialized form @@ -148,8 +160,6 @@ class RESTClientObject(object): arguments. Please check that your arguments match declared content type.""" raise ApiException(status=0, reason=msg) - else: - args["data"] = query_params async with self.pool_manager.request(**args) as r: data = await r.text() diff --git a/samples/client/petstore/python-asyncio/pom.xml b/samples/client/petstore/python-asyncio/pom.xml new file mode 100644 index 00000000000..b370bd02469 --- /dev/null +++ b/samples/client/petstore/python-asyncio/pom.xml @@ -0,0 +1,46 @@ + + 4.0.0 + io.swagger + PythonAsyncioClientTests + pom + 1.0-SNAPSHOT + Python Asyncio Petstore Client + + + + maven-dependency-plugin + + + package + + copy-dependencies + + + ${project.build.directory} + + + + + + org.codehaus.mojo + exec-maven-plugin + 1.2.1 + + + pytest-test + integration-test + + exec + + + make + + test-all + + + + + + + + diff --git a/samples/client/petstore/python-asyncio/test-requirements.txt b/samples/client/petstore/python-asyncio/test-requirements.txt index 2702246c0e6..1c20b09b865 100644 --- a/samples/client/petstore/python-asyncio/test-requirements.txt +++ b/samples/client/petstore/python-asyncio/test-requirements.txt @@ -1,5 +1,5 @@ -coverage>=4.0.3 -nose>=1.3.7 +pytest>=3.3.1 +pytest-cov>=2.5.1 pluggy>=0.3.1 py>=1.4.31 randomize>=0.13 diff --git a/samples/client/petstore/python-asyncio/test_python3.sh b/samples/client/petstore/python-asyncio/test_python3.sh new file mode 100755 index 00000000000..01abf0b35b1 --- /dev/null +++ b/samples/client/petstore/python-asyncio/test_python3.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +REQUIREMENTS_FILE=dev-requirements.txt +REQUIREMENTS_OUT=dev-requirements.txt.log +SETUP_OUT=*.egg-info +VENV=.venv +DEACTIVE=false + +export LC_ALL=en_US.UTF-8 +export LANG=en_US.UTF-8 + +### set virtualenv +if [ -z "$VIRTUAL_ENV" ]; then + virtualenv $VENV --no-site-packages --always-copy --python python3 + source $VENV/bin/activate + DEACTIVE=true +fi + +### install dependencies +pip install -r $REQUIREMENTS_FILE | tee -a $REQUIREMENTS_OUT +python setup.py develop + +### run tests +tox || exit 1 + +### static analysis of code +flake8 --show-source petstore_api/ + +### deactivate virtualenv +#if [ $DEACTIVE == true ]; then +# deactivate +#fi diff --git a/samples/client/petstore/python-asyncio/testfiles/foo.png b/samples/client/petstore/python-asyncio/testfiles/foo.png new file mode 100644 index 0000000000000000000000000000000000000000..a9b12cf5927ac757b054dd875ee137c2581f69bb GIT binary patch literal 43280 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 literal 0 HcmV?d00001 diff --git a/samples/client/petstore/python-asyncio/tests/__init__.py b/samples/client/petstore/python-asyncio/tests/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/samples/client/petstore/python-asyncio/tests/test_pet_api.py b/samples/client/petstore/python-asyncio/tests/test_pet_api.py new file mode 100644 index 00000000000..ad143e246fa --- /dev/null +++ b/samples/client/petstore/python-asyncio/tests/test_pet_api.py @@ -0,0 +1,208 @@ +# coding: utf-8 + +# flake8: noqa + +""" +Run the tests. +$ docker pull swaggerapi/petstore +$ docker run -d -e SWAGGER_HOST=http://petstore.swagger.io -e SWAGGER_BASE_PATH=/v2 -p 80:8080 swaggerapi/petstore +$ pytest -vv +""" + +import os +import unittest +import asyncio +import pytest + +import petstore_api +from petstore_api import Configuration +from petstore_api.rest import ApiException + +from .util import id_gen + +import json + +import urllib3 + +HOST = 'http://localhost:80/v2' + + +def async_test(f): + def wrapper(*args, **kwargs): + coro = asyncio.coroutine(f) + future = coro(*args, **kwargs) + loop = asyncio.get_event_loop() + loop.run_until_complete(future) + return wrapper + + +class TestPetApiTests(unittest.TestCase): + + def setUp(self): + config = Configuration() + config.host = HOST + + self.api_client = petstore_api.ApiClient(config) + self.pet_api = petstore_api.PetApi(self.api_client) + self.setUpModels() + self.setUpFiles() + + def setUpModels(self): + self.category = petstore_api.Category() + self.category.id = id_gen() + self.category.name = "dog" + self.tag = petstore_api.Tag() + self.tag.id = id_gen() + self.tag.name = "swagger-codegen-python-pet-tag" + self.pet = petstore_api.Pet(name="hello kity", photo_urls=["http://foo.bar.com/1", "http://foo.bar.com/2"]) + self.pet.id = id_gen() + self.pet.status = "sold" + self.pet.category = self.category + self.pet.tags = [self.tag] + + def setUpFiles(self): + self.test_file_dir = os.path.join(os.path.dirname(__file__), "..", "testfiles") + self.test_file_dir = os.path.realpath(self.test_file_dir) + self.foo = os.path.join(self.test_file_dir, "foo.png") + + def test_separate_default_client_instances(self): + pet_api = petstore_api.PetApi() + pet_api2 = petstore_api.PetApi() + self.assertNotEqual(pet_api.api_client, pet_api2.api_client) + + pet_api.api_client.user_agent = 'api client 3' + pet_api2.api_client.user_agent = 'api client 4' + + self.assertNotEqual(pet_api.api_client.user_agent, pet_api2.api_client.user_agent) + + def test_separate_default_config_instances(self): + pet_api = petstore_api.PetApi() + pet_api2 = petstore_api.PetApi() + self.assertNotEqual(pet_api.api_client.configuration, pet_api2.api_client.configuration) + + pet_api.api_client.configuration.host = 'somehost' + pet_api2.api_client.configuration.host = 'someotherhost' + self.assertNotEqual(pet_api.api_client.configuration.host, pet_api2.api_client.configuration.host) + + @async_test + async def test_async_with_result(self): + await self.pet_api.add_pet(body=self.pet) + + calls = [self.pet_api.get_pet_by_id(self.pet.id), + self.pet_api.get_pet_by_id(self.pet.id)] + + responses, _ = await asyncio.wait(calls) + for response in responses: + self.assertEqual(response.result().id, self.pet.id) + self.assertEqual(len(responses), 2) + + @async_test + async def test_exception(self): + await self.pet_api.add_pet(body=self.pet) + + try: + await self.pet_api.get_pet_by_id("-9999999999999") + except ApiException as e: + exception = e + + self.assertIsInstance(exception, ApiException) + self.assertEqual(exception.status, 404) + + @async_test + async def test_add_pet_and_get_pet_by_id(self): + await self.pet_api.add_pet(body=self.pet) + + fetched = await self.pet_api.get_pet_by_id(pet_id=self.pet.id) + self.assertIsNotNone(fetched) + self.assertEqual(self.pet.id, fetched.id) + self.assertIsNotNone(fetched.category) + self.assertEqual(self.pet.category.name, fetched.category.name) + + @async_test + async def test_add_pet_and_get_pet_by_id_with_http_info(self): + await self.pet_api.add_pet(body=self.pet) + + fetched = await self.pet_api.get_pet_by_id_with_http_info(pet_id=self.pet.id) + self.assertIsNotNone(fetched) + self.assertEqual(self.pet.id, fetched[0].id) + self.assertIsNotNone(fetched[0].category) + self.assertEqual(self.pet.category.name, fetched[0].category.name) + + @async_test + async def test_update_pet(self): + self.pet.name = "hello kity with updated" + await self.pet_api.update_pet(body=self.pet) + + fetched = await self.pet_api.get_pet_by_id(pet_id=self.pet.id) + self.assertIsNotNone(fetched) + self.assertEqual(self.pet.id, fetched.id) + self.assertEqual(self.pet.name, fetched.name) + self.assertIsNotNone(fetched.category) + self.assertEqual(fetched.category.name, self.pet.category.name) + + @async_test + async def test_find_pets_by_status(self): + await self.pet_api.add_pet(body=self.pet) + pets = await self.pet_api.find_pets_by_status(status=[self.pet.status]) + self.assertIn( + self.pet.id, + list(map(lambda x: getattr(x, 'id'), pets)) + ) + + @async_test + async def test_find_pets_by_tags(self): + await self.pet_api.add_pet(body=self.pet) + pets = await self.pet_api.find_pets_by_tags(tags=[self.tag.name]) + self.assertIn( + self.pet.id, + list(map(lambda x: getattr(x, 'id'), pets)) + ) + + @async_test + async def test_update_pet_with_form(self): + await self.pet_api.add_pet(body=self.pet) + + name = "hello kity with form updated" + status = "pending" + await self.pet_api.update_pet_with_form(pet_id=self.pet.id, name=name, status=status) + + fetched = await self.pet_api.get_pet_by_id(pet_id=self.pet.id) + self.assertEqual(self.pet.id, fetched.id) + self.assertEqual(name, fetched.name) + self.assertEqual(status, fetched.status) + + @async_test + async def test_upload_file(self): + # upload file with form parameter + try: + additional_metadata = "special" + await self.pet_api.upload_file( + pet_id=self.pet.id, + additional_metadata=additional_metadata, + file=self.foo + ) + except ApiException as e: + self.fail("upload_file() raised {0} unexpectedly".format(type(e))) + + # upload only file + try: + await self.pet_api.upload_file(pet_id=self.pet.id, file=self.foo) + except ApiException as e: + self.fail("upload_file() raised {0} unexpectedly".format(type(e))) + + @async_test + async def test_delete_pet(self): + await self.pet_api.add_pet(body=self.pet) + await self.pet_api.delete_pet(pet_id=self.pet.id, api_key="special-key") + + try: + await self.pet_api.get_pet_by_id(pet_id=self.pet.id) + raise Exception("expected an error") + except ApiException as e: + self.assertEqual(404, e.status) + + +if __name__ == '__main__': + import logging + logging.basicConfig(level=logging.DEBUG) + unittest.main() diff --git a/samples/client/petstore/python-asyncio/tests/util.py b/samples/client/petstore/python-asyncio/tests/util.py new file mode 100644 index 00000000000..39fba1514b3 --- /dev/null +++ b/samples/client/petstore/python-asyncio/tests/util.py @@ -0,0 +1,11 @@ +# flake8: noqa + +import random + + +def id_gen(bits=32): + """ Returns a n-bit randomly generated int """ + return int(random.getrandbits(bits)) + + + diff --git a/samples/client/petstore/python-asyncio/tox.ini b/samples/client/petstore/python-asyncio/tox.ini index 1cf0829dc93..65f5351ddcc 100644 --- a/samples/client/petstore/python-asyncio/tox.ini +++ b/samples/client/petstore/python-asyncio/tox.ini @@ -1,10 +1,9 @@ [tox] -envlist = py27, py3 +envlist = py3 [testenv] deps=-r{toxinidir}/requirements.txt -r{toxinidir}/test-requirements.txt - + commands= - nosetests \ - [] \ No newline at end of file + pytest -v --cov petstore_api diff --git a/samples/client/petstore/python-tornado/tox.ini b/samples/client/petstore/python-tornado/tox.ini index 1cf0829dc93..3d0be613cfc 100644 --- a/samples/client/petstore/python-tornado/tox.ini +++ b/samples/client/petstore/python-tornado/tox.ini @@ -4,7 +4,7 @@ envlist = py27, py3 [testenv] deps=-r{toxinidir}/requirements.txt -r{toxinidir}/test-requirements.txt - + commands= nosetests \ - [] \ No newline at end of file + [] diff --git a/samples/client/petstore/python/docs/FakeApi.md b/samples/client/petstore/python/docs/FakeApi.md index 1da84500bfe..b910ba2b464 100644 --- a/samples/client/petstore/python/docs/FakeApi.md +++ b/samples/client/petstore/python/docs/FakeApi.md @@ -273,10 +273,10 @@ configuration.password = 'YOUR_PASSWORD' # create an instance of the API class api_instance = petstore_api.FakeApi(petstore_api.ApiClient(configuration)) -number = 8.14 # float | None +number = 3.4 # float | None double = 1.2 # float | None pattern_without_delimiter = 'pattern_without_delimiter_example' # str | None -byte = 'B' # str | None +byte = 'byte_example' # str | None integer = 56 # int | None (optional) int32 = 56 # int | None (optional) int64 = 789 # int | None (optional) diff --git a/samples/client/petstore/python/tox.ini b/samples/client/petstore/python/tox.ini index 1cf0829dc93..3d0be613cfc 100644 --- a/samples/client/petstore/python/tox.ini +++ b/samples/client/petstore/python/tox.ini @@ -4,7 +4,7 @@ envlist = py27, py3 [testenv] deps=-r{toxinidir}/requirements.txt -r{toxinidir}/test-requirements.txt - + commands= nosetests \ - [] \ No newline at end of file + []