Skip to content

Commit 7726fb3

Browse files
authored
Merge pull request #33 from cehbrecht/fix-tests
fixed tests
2 parents 1edfcb6 + 539133b commit 7726fb3

10 files changed

+83
-65
lines changed

.travis.yml

+7-8
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
1+
dist: xenial # required for Python >= 3.7
12
language: python
23
python:
34
- 2.7
4-
- 3.3
5-
- 3.4
65
- 3.5
7-
8-
addons:
9-
apt:
10-
packages:
11-
- cython
6+
- 3.6
7+
- 3.7
8+
os:
9+
- linux
10+
sudo: false
1211
install:
1312
- pip install -e .[testing]
1413

1514
script:
16-
- py.test
15+
- pytest
1716
- flake8

README.rst

+12
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,15 @@
1+
.. image:: https://img.shields.io/badge/docs-latest-brightgreen.svg
2+
:target: https://esgf-pyclient.readthedocs.io/en/latest/?badge=latest
3+
:alt: Documentation Status
4+
5+
.. image:: https://travis-ci.org/ESGF/esgf-pyclient.svg?branch=master
6+
:target: https://travis-ci.org/ESGF/esgf-pyclient
7+
:alt: Travis Build
8+
9+
.. image:: https://img.shields.io/github/license/ESGF/esgf-pyclient.svg
10+
:target: https://github.com/ESGF/esgf-pyclient/blob/master/LICENSE
11+
:alt: GitHub license
12+
113
This package contains API code for calling the `ESGF Search API`_ within
214
client code. The initial implementation is in Python.
315

pyesgf/multidict.py

+2
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,8 @@ def __nonzero__(self):
362362
return True
363363
return False
364364

365+
__bool__ = __nonzero__
366+
365367
def iteritems(self):
366368
for d in self.dicts:
367369
for item in iteritems_(d):

pyesgf/search/connection.py

+7-9
Original file line numberDiff line numberDiff line change
@@ -93,14 +93,13 @@ def __init__(self, url, distrib=True, cache=None, timeout=120,
9393
self._isopen = False
9494

9595
def open(self):
96-
if (isinstance(self._passed_session, requests.Session) or
97-
isinstance(self._passed_session,
98-
requests_cache.core.CachedSession)):
96+
if (isinstance(self._passed_session, requests.Session) or isinstance(
97+
self._passed_session, requests_cache.core.CachedSession)):
9998
self.session = self._passed_session
10099
else:
101100
self.session = create_single_session(
102-
cache=self.cache,
103-
expire_after=self.expire_after)
101+
cache=self.cache,
102+
expire_after=self.expire_after)
104103
self._isopen = True
105104
return
106105

@@ -114,9 +113,8 @@ def __exit__(self, type, value, traceback):
114113

115114
def close(self):
116115
# Close the session
117-
if not (isinstance(self._passed_session, requests.Session) or
118-
isinstance(self._passed_session,
119-
requests_cache.core.CachedSession)):
116+
if not (isinstance(self._passed_session, requests.Session) or isinstance(
117+
self._passed_session, requests_cache.core.CachedSession)):
120118
self.session.close()
121119
self._isopen = False
122120
return
@@ -202,7 +200,7 @@ def _send_query(self, endpoint, full_query):
202200
timeout=self.timeout)
203201
if response.status_code == 400:
204202
# If error code 400, use urllib to find the errors:
205-
errors = set(re.findall("Invalid HTTP query parameter=(\w+)",
203+
errors = set(re.findall(r"Invalid HTTP query parameter=(\w+)",
206204
response.text))
207205
content = "; ".join([e for e in list(errors)])
208206
raise Exception("Invalid query parameter(s): %s" % content)

pyesgf/test/test_ats.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,16 @@
88
from pyesgf.security.ats import AttributeService
99
from pyesgf.node import ESGFNode
1010
from unittest import TestCase
11+
import pytest
1112

1213
ESGF_NODE = ESGFNode('https://esgf-node.llnl.gov')
1314
TEST_OPENID = os.environ.get('LLNL_OPENID')
14-
TEST_USER_DETAILS = os.environ.get('LLNL_NAME').split()
15+
TEST_USER_DETAILS = os.environ.get('LLNL_NAME', '').split()
1516

1617

1718
class TestATS(TestCase):
1819

20+
@pytest.mark.skip(reason="needs test openid")
1921
def test_ceda_ats(self):
2022
service = AttributeService(ESGF_NODE.ats_url, 'esgf-pyclient')
2123
fn, ln = TEST_USER_DETAILS
@@ -37,6 +39,7 @@ def test_unknown_principal(self):
3739
assert resp.get_status() == ('urn:oasis:names:tc:SAML:2.0:'
3840
'status:UnknownPrincipal')
3941

42+
@pytest.mark.skip(reason="needs test openid")
4043
def test_multi_attribute(self):
4144
service = AttributeService(ESGF_NODE.ats_url, 'esgf-pyclient')
4245
CMIP5_RESEARCH = 'CMIP5 Research'

pyesgf/test/test_context.py

+30-24
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
class TestContext(TestCase):
1212
def setUp(self):
13-
self.test_service = 'http://esgf-index1.ceda.ac.uk/esg-search'
13+
self.test_service = 'http://esgf-data.dkrz.de/esg-search'
1414
self.cache = os.path.join(os.path.dirname(__file__), 'url_cache')
1515

1616
def test_context_freetext(self):
@@ -35,8 +35,7 @@ def test_context_facets_multivalue(self):
3535
self.assertTrue(context2.hit_count > 0)
3636

3737
self.assertTrue(context2.facet_constraints['project'] == 'CMIP5')
38-
self.assertTrue(sorted(context2.facet_constraints.getall('model'))
39-
== ['IPSL-CM5A-LR', 'IPSL-CM5A-MR'])
38+
self.assertTrue(sorted(context2.facet_constraints.getall('model')) == ['IPSL-CM5A-LR', 'IPSL-CM5A-MR'])
4039

4140
def test_context_facet_multivalue2(self):
4241
conn = SearchConnection(self.test_service, cache=self.cache)
@@ -45,8 +44,7 @@ def test_context_facet_multivalue2(self):
4544
context.facet_constraints.getall('model') == ['IPSL-CM5A-MR'])
4645

4746
context2 = context.constrain(model=['IPSL-CM5A-MR', 'IPSL-CM5A-LR'])
48-
self.assertTrue(sorted(context2.facet_constraints.getall('model'))
49-
== ['IPSL-CM5A-LR', 'IPSL-CM5A-MR'])
47+
self.assertTrue(sorted(context2.facet_constraints.getall('model')) == ['IPSL-CM5A-LR', 'IPSL-CM5A-MR'])
5048

5149
def test_context_facet_multivalue3(self):
5250
conn = SearchConnection(self.test_service, cache=self.cache)
@@ -94,18 +92,29 @@ def test_facet_count(self):
9492
self.assertTrue(list(counts['project'].keys()) == ['CMIP5'])
9593

9694
def test_distrib(self):
97-
conn = SearchConnection(self.test_service, cache=self.cache,
98-
distrib=False)
95+
conn = SearchConnection(self.test_service, distrib=False)
9996

10097
context = conn.new_context(project='CMIP5')
10198
count1 = context.hit_count
10299

103-
conn2 = SearchConnection(self.test_service, cache=self.cache,
104-
distrib=True)
100+
conn2 = SearchConnection(self.test_service, distrib=True)
105101
context = conn2.new_context(project='CMIP5')
106102
count2 = context.hit_count
107103

108-
self.assertTrue(count1 < count2)
104+
assert count1 < count2
105+
106+
# @pytest.mark.skip(reason="cache fails on python 3.7")
107+
def test_distrib_with_cache(self):
108+
conn = SearchConnection(self.test_service, cache=self.cache, distrib=False)
109+
110+
context = conn.new_context(project='CMIP5')
111+
count1 = context.hit_count
112+
113+
conn2 = SearchConnection(self.test_service, cache=self.cache, distrib=True)
114+
context = conn2.new_context(project='CMIP5')
115+
count2 = context.hit_count
116+
117+
assert count1 < count2
109118

110119
def test_constrain(self):
111120
conn = SearchConnection(self.test_service, cache=self.cache)
@@ -149,24 +158,24 @@ def test_negative_facet(self):
149158
context3 = context.constrain(experiment=not_equals('historical'))
150159
hits3 = context3.hit_count
151160

152-
self.assertTrue(hits1 == hits2 + hits3)
161+
assert hits1 == hits2 + hits3
153162

154163
def test_replica(self):
155164
# Test that we can exclude replicas
156165
# This tests assumes the test dataset is replicated
157-
conn = SearchConnection(self.test_service, cache=self.cache)
166+
conn = SearchConnection(self.test_service)
158167
qry = 'id:cmip5.output1.MOHC.HadGEM2-ES.rcp45.mon.atmos.Amon.r1i1p1.*'
159168
version = '20111128'
160169

161170
# Search for all replicas
162171
context = conn.new_context(query=qry, version=version)
163-
self.assertTrue(context.hit_count > 2,
164-
'Expecting more than 2 search hits for replicas')
172+
# Expecting more than 2 search hits for replicas
173+
assert context.hit_count > 2
165174

166175
# Search for only one replicant
167176
context = conn.new_context(query=qry, replica=False, version=version)
168-
self.assertTrue(context.hit_count == 1,
169-
'Expecting one search replica')
177+
# Expecting one search replica
178+
assert context.hit_count == 1
170179

171180
def test_response_from_bad_parameter(self):
172181
# Test that a bad parameter name raises a useful exception
@@ -186,21 +195,18 @@ def test_response_from_bad_parameter(self):
186195
"No JSON object could be decoded"))
187196

188197
def test_context_project_cmip6(self):
189-
test_service = 'https://esgf-node.ipsl.upmc.fr/esg-search'
198+
test_service = 'https://esgf-node.llnl.gov/esg-search'
190199
conn = SearchConnection(test_service)
191200

192-
context = conn.new_context(project='CMIP6')
193-
self.assertEqual(context.hit_count, 1973)
194-
195-
context2 = context.constrain(realm="atmosChem")
196-
self.assertEqual(context2.hit_count, 10)
201+
context = conn.new_context(project='CMIP6', institution_id='AWI', distrib=False)
202+
self.assertTrue(context.hit_count > 100)
197203

204+
context2 = context.constrain(variable='tas')
205+
self.assertTrue(context2.hit_count > 10)
198206

199207
def test_context_project_c3s_cmip5(self):
200208
test_service = 'https://cp4cds-index1.ceda.ac.uk/esg-search'
201209
conn = SearchConnection(test_service)
202210

203211
context = conn.new_context(project='c3s-cmip5')
204212
self.assertTrue(context.hit_count > 20000)
205-
206-

pyesgf/test/test_results.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ def test_result1(self):
2323
results = ctx.search()
2424

2525
r1 = results[0]
26-
assert re.match(r'cmip5\.output1\.MOHC\..+\|esgf-data1.ceda.ac.uk',
26+
assert re.match(r'cmip5\.output1\..+\|esgf-data1.ceda.ac.uk',
2727
r1.dataset_id)
2828

2929
def test_file_context(self):

pyesgf/test/test_shard_regex.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
import re
66
from unittest import TestCase
77

8-
R = re.compile("^(?P<prefix>https?://)?(?P<host>.+?)"
9-
":?(?P<port>\d+)?/(?P<suffix>.+)$")
8+
R = re.compile(r"^(?P<prefix>https?://)?(?P<host>.+?)"
9+
r":?(?P<port>\d+)?/(?P<suffix>.+)$")
1010

1111

1212
class TestShardRegex(TestCase):

setup.cfg

+10-10
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
1-
[egg_info]
2-
#tag_build = p3
3-
4-
[nosetests]
5-
verbosity=2
6-
with-doctest=1
7-
doctest-extension=.txt
8-
tests=test
9-
#nologcapture=1
1+
[tool:pytest]
2+
addopts =
3+
--strict
4+
--tb=native
5+
python_files = test_*.py
6+
markers =
7+
online: mark test to need internet connection
8+
slow: mark test to be slow
109

1110
[flake8]
12-
exclude =
11+
max-line-length = 120
12+
exclude =
1313
.git,
1414
__pycache__,
1515
docs/conf.py,

setup.py

+8-10
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,14 @@
1919
description="A library interacting with ESGF services within Python",
2020
long_description=long_description,
2121
classifiers=[
22-
'Development Status :: 4 - Beta',
23-
'License :: OSI Approved :: BSD License',
24-
'Topic :: Scientific/Engineering',
25-
'Programming Language :: Python :: 2.6',
26-
'Programming Language :: Python :: 2.7',
27-
'Programming Language :: Python :: 3.3',
28-
'Programming Language :: Python :: 3.4',
29-
'Programming Language :: Python :: 3.5',
30-
'Programming Language :: Python :: 3.6'
31-
],
22+
'Development Status :: 4 - Beta',
23+
'License :: OSI Approved :: BSD License',
24+
'Topic :: Scientific/Engineering',
25+
'Programming Language :: Python :: 2.7',
26+
'Programming Language :: Python :: 3.5',
27+
'Programming Language :: Python :: 3.6',
28+
'Programming Language :: Python :: 3.7',
29+
],
3230
# Get strings from http://pypi.python.org/pypi?%3Aaction=list_classifiers
3331
keywords='',
3432
author='Ag Stephens',

0 commit comments

Comments
 (0)