Skip to content

Commit a97d406

Browse files
committed
Enhancement: Update test environment and dependencies
- Enhancement: Update the dependencies to the latest supported versions. - Note: See Issue TestInABox#80 related to updating HTTPretty - Enhancement: Moved generic infrastructure to generic Py3 support so that it should always run. - Bug: Added a note regarding HTTPretty support - Enhancement: Refactored how the thread local object is accessed; this should improve parallel processing support. - Enhancement: Various Py3 support enhancements - Enhancement: Moved general tests that utilize a util module to requests_mock from HTTPretty due to the issues with HTTPretty - Enhancement: Added a Pypy3 test environment
1 parent 81e7bce commit a97d406

23 files changed

+157
-80
lines changed

.travis.yml

+21-17
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,36 @@
11
language: python
22
matrix:
33
include:
4-
- python: "2.7"
5-
env: TEST_SUITE=suite_2_7 TOX_ENV=py27
6-
- python: "pypy"
7-
env: TEST_SUITE=suite_pypy TOX_ENV=pypy
8-
- python: "3.4"
9-
env: TEST_SUITE=suite_3_4 TOX_ENV=py34
4+
- python: "pypy3"
5+
env: TEST_SUITE=suite_pypy3 TOX_ENV=pypy3
6+
- python: "3.6"
7+
env: TEST_SUITE=suite_3_6 TOX_ENV=pep8
8+
- python: "3.6"
9+
env: TEST_SUITE=suite_3_6 TOX_ENV=docs
1010
- python: "3.5"
11-
env: TEST_SUITE=suite_3_4 TOX_ENV=py35
11+
env: TEST_SUITE=suite_3_5 TOX_ENV=py35
12+
- python: "3.7"
13+
env: TEST_SUITE=suite_3_7 TOX_ENV=py37
14+
- python: "3.8"
15+
env: TEST_SUITE=suite_3_8 TOX_ENV=py38
16+
- python: "3.6"
17+
env: TEST_SUITE=suite_3_6 TOX_ENV=py36
18+
- python: "3.6"
19+
env: TEST_SUITE=suite_3_6 TOX_ENV=py36-httpretty
20+
- python: "3.6"
21+
env: TEST_SUITE=suite_3_6 TOX_ENV=py36-requests-mock
1222
- python: "3.6"
13-
env: TEST_SUITE=suite_3_4 TOX_ENV=py36
14-
- python: "3.4"
15-
env: TEST_SUITE=suite_3_4 TOX_ENV=pep8
23+
env: TEST_SUITE=suite_3_6 TOX_ENV=py36-responses
1624
- python: "2.7"
17-
env: TEST_SUITE=suite_2_7 TOX_ENV=docs
25+
env: TEST_SUITE=suite_2_7 TOX_ENV=py27
1826
- python: "2.7"
1927
env: TEST_SUITE=suite_2_7 TOX_ENV=py27-httpretty
20-
- python: "3.6"
21-
env: TEST_SUITE=suite_3_6 TOX_ENV=py36-httpretty
2228
- python: "2.7"
2329
env: TEST_SUITE=suite_2_7 TOX_ENV=py27-requests-mock
24-
- python: "3.6"
25-
env: TEST_SUITE=suite_3_6 TOX_ENV=py36-requests-mock
2630
- python: "2.7"
2731
env: TEST_SUITE=suite_2_7 TOX_ENV=py27-responses
28-
- python: "3.6"
29-
env: TEST_SUITE=suite_3_6 TOX_ENV=py36-responses
32+
- python: "pypy"
33+
env: TEST_SUITE=suite_pypy TOX_ENV=pypy
3034

3135
sudo: required
3236
before_install:

README.rst

+5
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,11 @@ Out-of-the-box it supports the following frameworks:
8989

9090
You can use any of them, and you must pull them in via your own test requirements.
9191

92+
.. note:: HTTPretty has some version and Python limitations. Version 0.8.6 works fine; however, version 0.9.x which supports
93+
Python3 seems to have a breaking change that is causing problems. Only 0.8.6 is supported by StackInABox under Python2
94+
for the time being. That is not to say you may not get it to work; just that the StackInABox Unit Tests cannot verify it
95+
will work. PRs are welcome to help resolve this.
96+
9297
-----------
9398
Error Codes
9499
-----------

setup.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
REQUIRES = ['six']
55
EXTRA_REQUIRES = {
6-
'httpretty': ['httpretty==0.8.6'],
6+
'httpretty': ['httpretty'],
77
'requests-mock': ['requests-mock'],
88
'responses': ['responses>=0.4.0']
99
}

stackinabox/services/service.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -383,7 +383,7 @@ def request(self, method, request, uri, headers):
383383
return self.try_handle_route(uri, method, request, uri, headers)
384384

385385
def sub_request(self, method, request, uri, headers):
386-
"""Handle the supplied sub-service request on the specified routing URI.
386+
"""Handle the supplied sub-service request on the specified routing URI
387387
388388
:param method: string - HTTP Verb
389389
:param request: request object describing the HTTP request

stackinabox/stack.py

+37-7
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,42 @@ class StackInABox(object):
3535
3636
"""
3737

38+
@classmethod
39+
def get_thread_instance(cls):
40+
"""
41+
Interface to the thread storage to ensure the instance properly exists
42+
"""
43+
create = False
44+
45+
# if the `instance` property doesn't exist
46+
if not hasattr(local_store, 'instance'):
47+
local_store.instance = None
48+
create = True
49+
50+
# if the instance doesn't exist at all
51+
elif local_store.instance is None:
52+
create = True
53+
54+
# if it's something else entirely...
55+
elif not isinstance(local_store.instance, cls):
56+
local_store.instance = None
57+
create = True
58+
59+
# if the above conditions are met, create it
60+
if create:
61+
logger.debug('Creating new StackInABox instance...')
62+
local_store.instance = cls()
63+
logger.debug(
64+
'Created StackInABox({0})'.format(local_store.instance.__id)
65+
)
66+
67+
return local_store.instance
68+
3869
@classmethod
3970
def reset_services(cls):
4071
"""Reset the thread's StackInABox instance."""
4172
logger.debug('Resetting services')
42-
return local_store.instance.reset()
73+
return cls.get_thread_instance().reset()
4374

4475
@classmethod
4576
def register_service(cls, service):
@@ -51,7 +82,7 @@ def register_service(cls, service):
5182
5283
"""
5384
logger.debug('Registering service {0}'.format(service.name))
54-
return local_store.instance.register(service)
85+
return cls.get_thread_instance().register(service)
5586

5687
@classmethod
5788
def call_into(cls, method, request, uri, headers):
@@ -66,7 +97,7 @@ def call_into(cls, method, request, uri, headers):
6697
6798
"""
6899
logger.debug('Request: {0} - {1}'.format(method, uri))
69-
return local_store.instance.call(method,
100+
return cls.get_thread_instance().call(method,
70101
request,
71102
uri,
72103
headers)
@@ -85,7 +116,7 @@ def hold_onto(cls, name, obj):
85116
"""
86117
logger.debug('Holding on {0} of type {1} with id {2}'
87118
.format(name, type(obj), id(obj)))
88-
local_store.instance.into_hold(name, obj)
119+
cls.get_thread_instance().into_hold(name, obj)
89120

90121
@classmethod
91122
def hold_out(cls, name):
@@ -102,7 +133,7 @@ def hold_out(cls, name):
102133
"""
103134
logger.debug('Retreiving {0} from hold'
104135
.format(name))
105-
obj = local_store.instance.from_hold(name)
136+
obj = cls.get_thread_instance().from_hold(name)
106137
logger.debug('Retrieved {0} of type {1} with id {2} from hold'
107138
.format(name, type(obj), id(obj)))
108139
return obj
@@ -115,7 +146,7 @@ def update_uri(cls, uri):
115146
116147
"""
117148
logger.debug('Request: Update URI to {0}'.format(uri))
118-
local_store.instance.base_url = uri
149+
cls.get_thread_instance().base_url = uri
119150

120151
def __init__(self):
121152
"""Initialize the StackInABox instance.
@@ -307,4 +338,3 @@ def from_hold(self, name):
307338

308339
# Thread local instance of StackInABox
309340
local_store = threading.local()
310-
local_store.instance = StackInABox()

stackinabox/util/httpretty/core.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ def registration(uri):
7979

8080
# build the regex for the uri and register all http verbs
8181
# with httpretty
82-
regex = re.compile('(http)?s?(://)?{0}:?(\d+)?/'.format(uri),
82+
regex = re.compile(r'(http)?s?(://)?{0}:?(\d+)?/'.format(uri),
8383
re.I)
8484
for method in HttpBaseClass.METHODS:
8585
register_uri(method, regex, body=httpretty_callback)

stackinabox/util/httpretty/decorator.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
"""
22
Stack-In-A-Box: HTTPretty Support via decorator
33
"""
4-
import collections
4+
try:
5+
import collections.abc as collections
6+
except ImportError:
7+
# Py2.7 Support
8+
import collections
59
import functools
610
import logging
711
import re

stackinabox/util/requests_mock/core.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ def __init__(self, uri):
4141
:param uri: URI to match against
4242
"""
4343
self.regex = re.compile(
44-
'(http)?s?(://)?{0}:?(\d+)?/'.format(uri), re.I)
44+
r'(http)?s?(://)?{0}:?(\d+)?/'.format(uri), re.I)
4545

4646
def __call__(self, request):
4747
"""object callable interface.

stackinabox/util/requests_mock/decorator.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
"""
22
Stack-In-A-Box: Requests-Mock Support via Decorator
33
"""
4-
import collections
4+
try:
5+
import collections.abc as collections
6+
except ImportError:
7+
# Py2.7 Support
8+
import collections
59
import functools
610
import logging
711
import re

stackinabox/util/responses/core.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ def registration(uri):
6161

6262
# Build the regex for the URI and register all HTTP verbs
6363
# with Responses
64-
regex = re.compile('(http)?s?(://)?{0}:?(\d+)?/'.format(uri),
64+
regex = re.compile(r'(http)?s?(://)?{0}:?(\d+)?/'.format(uri),
6565
re.I)
6666
METHODS = [
6767
responses.DELETE,

stackinabox/util/responses/decorator.py

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
"""
22
Stack-In-A-Box: Responses Support via decorator
33
"""
4-
import collections
4+
try:
5+
import collections.abc as collections
6+
except ImportError:
7+
# Py2.7 Support
8+
import collections
9+
510
import functools
611
import logging
712
import re

stackinabox/util/tools/caseinsensitivedict.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,11 @@
1414
# See the License for the specific language governing permissions and
1515
# limitations under the License.
1616

17-
import collections
17+
try:
18+
import collections.abc as collections
19+
except ImportError:
20+
# Py2.7 Support
21+
import collections
1822

1923

2024
# Compliments of Requests

tests/test_service.py

+8-9
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
import re
22
import unittest
33

4-
import httpretty
54
import requests
65

76
from stackinabox.stack import StackInABox
87
from stackinabox.services.service import *
9-
import stackinabox.util.httpretty
8+
import stackinabox.util.requests_mock
109

1110

1211
class TestServiceRegex(unittest.TestCase):
@@ -112,7 +111,6 @@ def test_bad_registration(self):
112111
service.register(StackInABoxService.GET, '/',
113112
AnotherAdvancedService.second_handler)
114113

115-
@httpretty.activate
116114
def test_subservice_registration(self):
117115
service = AnotherAdvancedService()
118116
subservice = YetAnotherService()
@@ -121,10 +119,11 @@ def test_subservice_registration(self):
121119

122120
StackInABox.register_service(service)
123121

124-
stackinabox.util.httpretty.registration('localhost')
122+
with stackinabox.util.requests_mock.activate():
123+
stackinabox.util.requests_mock.registration('localhost')
125124

126-
res = requests.get('http://localhost/aas/french')
127-
self.assertEqual(res.status_code,
128-
200)
129-
self.assertEqual(res.text,
130-
'bonjour')
125+
res = requests.get('http://localhost/aas/french')
126+
self.assertEqual(res.status_code,
127+
200)
128+
self.assertEqual(res.text,
129+
'bonjour')

tests/test_stack.py

+5-6
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,9 @@
22
import unittest
33

44
import ddt
5-
import httpretty
65
import requests
76

8-
import stackinabox.util.httpretty
7+
import stackinabox.util.requests_mock
98
from stackinabox.stack import (
109
StackInABox, ServiceAlreadyRegisteredError)
1110
from stackinabox.services.service import *
@@ -52,12 +51,12 @@ def test_get_services_url(self, url, base, value):
5251
result = StackInABox.get_services_url(url, base)
5352
self.assertEqual(result, value)
5453

55-
@httpretty.activate
5654
def test_service_exception(self):
5755
exceptional = ExceptionalServices()
5856
StackInABox.register_service(exceptional)
5957

60-
stackinabox.util.httpretty.registration('localhost')
58+
with stackinabox.util.requests_mock.activate():
59+
stackinabox.util.requests_mock.registration('localhost')
6160

62-
res = requests.get('http://localhost/except/')
63-
self.assertEqual(res.status_code, 596)
61+
res = requests.get('http://localhost/except/')
62+
self.assertEqual(res.status_code, 596)

tests/util/httpretty/test_core.py

+3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
Stack-In-A-Box: Basic Test
33
"""
44
import logging
5+
import sys
56
import unittest
67

78
import httpretty
@@ -18,6 +19,7 @@
1819
logger = logging.getLogger(__name__)
1920

2021

22+
@unittest.skipIf(sys.version_info >= (3, 0), "Httpretty not supported by Py3")
2123
@httpretty.activate
2224
class TestHttprettyBasic(unittest.TestCase):
2325

@@ -37,6 +39,7 @@ def test_basic(self):
3739
self.assertEqual(res.text, 'Hello')
3840

3941

42+
@unittest.skipIf(sys.version_info >= (3, 0), "Httpretty not supported by Py3")
4043
@httpretty.activate
4144
class TestHttprettyAdvanced(unittest.TestCase):
4245

tests/util/httpretty/test_decorator.py

+5
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
Stack-In-A-Box: Basic Test
33
"""
44
import collections
5+
import sys
56
import types
67
import unittest
78

@@ -13,6 +14,7 @@
1314
from tests.utils.services import AdvancedService
1415

1516

17+
@unittest.skipIf(sys.version_info >= (3, 0), "Httpretty not supported by Py3")
1618
class TestHttprettyBasicWithDecorator(unittest.TestCase):
1719

1820
@decorator.activate('localhost', HelloService())
@@ -41,6 +43,7 @@ def test_basic_with_stack_acccess(self, response_code, value='alpha',
4143
self.assertIsInstance(stack[list(stack.keys())[0]], HelloService)
4244

4345

46+
@unittest.skipIf(sys.version_info >= (3, 0), "Httpretty not supported by Py3")
4447
class TestHttprettyAdvancedWithDecorator(unittest.TestCase):
4548

4649
@decorator.activate('localhost', AdvancedService())
@@ -81,6 +84,7 @@ def httpretty_generator():
8184
yield HelloService()
8285

8386

87+
@unittest.skipIf(sys.version_info >= (3, 0), "Httpretty not supported by Py3")
8488
class TestHttprettyBasicWithDecoratorAndGenerator(unittest.TestCase):
8589

8690
def test_verify_generator(self):
@@ -127,6 +131,7 @@ def httpretty_list():
127131
]
128132

129133

134+
@unittest.skipIf(sys.version_info >= (3, 0), "Httpretty not supported by Py3")
130135
class TestHttprettyBasicWithDecoratorAndList(unittest.TestCase):
131136

132137
def test_verify_list(self):

tests/utils/services.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ def __init__(self):
3333
self.register(StackInABoxService.GET, '/g',
3434
AdvancedService.query_handler)
3535
self.register(StackInABoxService.GET,
36-
re.compile('^/\d+$'),
36+
re.compile(r'^/\d+$'),
3737
AdvancedService.regex_handler)
3838

3939
for key in self.POTENTIAL_RESPONSES.keys():

0 commit comments

Comments
 (0)