Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migration to Python 3 #56

Merged
merged 5 commits into from
May 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/python_actions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
with:
python-version: 2.7
python-version: 3.8

- name: Install dependencies
run: |
python -m pip install --upgrade wheel setuptools pip
python -m pip install --upgrade setuptools pip
pip install -U -r requirements.txt
pip install -U -r dev-requirements.txt

Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
*pyc
.idea
python
venv
3 changes: 2 additions & 1 deletion alembic/env.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from __future__ import with_statement
from __future__ import print_function
from alembic import context
from sqlalchemy import engine_from_config, pool
from logging.config import fileConfig
Expand Down Expand Up @@ -51,7 +52,7 @@ def get_app_config(key):
app = application.create_app()

with app.app_context() as c:
print 'Getting actual config for', key, app.config.get(key)
print('Getting actual config for', key, app.config.get(key))
return app.config.get(key)

def run_migrations_online():
Expand Down
8 changes: 4 additions & 4 deletions dev-requirements.txt
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
flask-cors==2.0.0
flask-testing==0.6.2
httpretty==0.8.10
Flask-Testing==0.8.1
httpretty==0.9.5
pep257==0.5.0
pytest==2.8.2
pytest==6.2.4
pytest-cache==1.0
pytest-cov==2.2.0
pytest-cov==2.12.0
pytest-pep8==1.0.6
mock==2.0.0
coverage==5.2.1
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
git+https://github.com/adsabs/ADSMicroserviceUtils.git@v1.1.9
git+https://github.com/adsabs/ADSMicroserviceUtils.git@v1.2.0
alembic==0.8.1
future==0.18.2
5 changes: 3 additions & 2 deletions solr/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
import app
from app import create_app
from __future__ import absolute_import
from . import app
from .app import create_app
10 changes: 6 additions & 4 deletions solr/app.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
from __future__ import absolute_import
from past.builtins import basestring
from flask import Flask, make_response, jsonify
from flask.ext.restful import Api
from flask.ext.discoverer import Discoverer
from flask.ext.sqlalchemy import SQLAlchemy
from views import StatusView, Tvrh, Search, Qtree, BigQuery
from flask_restful import Api
from flask_discoverer import Discoverer
from flask_sqlalchemy import SQLAlchemy
from .views import StatusView, Tvrh, Search, Qtree, BigQuery
from adsmutils import ADSFlask

def create_app(**config):
Expand Down
35 changes: 17 additions & 18 deletions solr/tests/unittests/test_solr.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
import sys, os
PROJECT_HOME = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../'))
sys.path.append(PROJECT_HOME)
from flask.ext.testing import TestCase
from flask_testing import TestCase
from flask import url_for
import unittest
import httpretty
import json
import app
from solr import app
from werkzeug.security import gen_salt
from werkzeug.datastructures import MultiDict
from StringIO import StringIO
from io import BytesIO
from solr.tests.mocks import MockSolrResponse
from views import SolrInterface
from solr import views
from solr.views import SolrInterface
from models import Limits, Base
import mock
from StringIO import StringIO

class TestSolrInterface(TestCase):

Expand Down Expand Up @@ -248,11 +247,11 @@ def request_callback(request, uri, headers):
r = c.get(url_for('search'), query_string={'q': 'star'})

# Two cookies (session and sroute)
self.assertEqual(len(r.data.split(';')), len(self.app.config.get("SOLR_SERVICE_FORWARDED_COOKIES")))
self.assertEqual(len(r.data.decode('utf-8').split(';')), len(self.app.config.get("SOLR_SERVICE_FORWARDED_COOKIES")))

# This forwarded cookie should match the one we gave originally
n_found_cookies_with_good_value = 0
for cookie in r.data.split(';'):
for cookie in r.data.decode('utf-8').split(';'):
key, value = cookie.split('=')
if key in self.app.config.get("SOLR_SERVICE_FORWARDED_COOKIES"):
self.assertEqual(value.strip(), cookie_value)
Expand Down Expand Up @@ -417,7 +416,7 @@ def test_docs_subquery(self):
data={
'q': '*:*',
'fq': 'docs(hHGU1Ef-TpacAhicI3J8kQ)',
'big': (StringIO('foo\nbar'), 'bigname', 'big-query/csv')
'big': (BytesIO('foo\nbar'.encode('utf-8')), 'bigname', 'big-query/csv')
},
headers={'Authorization': 'Bearer foo'})
# it made a request to retrieve library
Expand Down Expand Up @@ -568,7 +567,7 @@ def request_callback(request, uri, headers):
'q': '*:*',
'fl': 'bibcode',
'fq': '{!bitset}',
'file_field': (StringIO(bibcodes), 'file', 'big-query/csv')
'file_field': (BytesIO(bibcodes.encode('utf-8')), 'file', 'big-query/csv')
}
)

Expand All @@ -581,13 +580,13 @@ def request_callback(request, uri, headers):
data={
'q': '*:*',
'fl': 'bibcode',
'file_field': (StringIO(bibcodes), 'filename', 'big-query/csv'),
'file_field': (BytesIO(bibcodes.encode('utf-8')), 'filename', 'big-query/csv'),
}
)

self.assertEqual(resp.status_code, 200)
self.assertTrue('bitset' not in resp.data)
self.assertTrue("Content-Disposition: form-data; name=\"file_field\"; filename=\"file_field\"\r\nContent-Type: big-query/csv" in resp.data)
self.assertTrue('bitset' not in resp.data.decode('utf-8'))
self.assertTrue("Content-Disposition: form-data; name=\"file_field\"; filename=\"file_field\"\\r\\nContent-Type: big-query/csv" in resp.data.decode('utf-8'))


# Missing 'fq' parameter is filled in - but only when data (request.post(data=...)
Expand All @@ -599,8 +598,8 @@ def request_callback(request, uri, headers):
)

self.assertEqual(resp.status_code, 200)
self.assertTrue('fq=%7B%21bitset%7D' in resp.data)
self.assertTrue("Content-Disposition: form-data; name=\"old-bad-behaviour\"; filename=\"old-bad-behaviour\"\r\nContent-Type: big-query/csv" in resp.data)
self.assertTrue('fq=%7B%21bitset%7D' in resp.data.decode('utf-8'))
self.assertTrue("Content-Disposition: form-data; name=\"old-bad-behaviour\"; filename=\"old-bad-behaviour\"\\r\\nContent-Type: big-query/csv" in resp.data.decode('utf-8'))



Expand All @@ -612,20 +611,20 @@ def request_callback(request, uri, headers):
'q': '*:*',
'fl': 'bibcode',
'fq': '{!bitset compression = true}',
'file_field': (StringIO(bibcodes), 'filename', 'big-query/csv'),
'file_field': (BytesIO(bibcodes.encode('utf-8')), 'filename', 'big-query/csv'),
}
)

self.assertEqual(resp.status_code, 200)
self.assertTrue('fq=%7B%21bitset+compression+%3D+true%7D' in resp.data)
self.assertTrue('fq=%7B%21bitset+compression+%3D+true%7D' in resp.data.decode('utf-8'))

# We now allow more content streams to be sent
data = MultiDict([
('q', '*:*'),
('fl', 'bibcode'),
('fq', '{!bitset}'),
('file_field', (StringIO(bibcodes), 'filename', 'big-query/csv')),
('file_field', (StringIO(bibcodes), 'filename', 'big-query/csv')),
('file_field', (BytesIO(bibcodes.encode('utf-8')), 'filename', 'big-query/csv')),
('file_field', (BytesIO(bibcodes.encode('utf-8')), 'filename', 'big-query/csv')),
])

resp = self.client.post(
Expand Down
7 changes: 4 additions & 3 deletions solr/tests/unittests/test_webservices.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from flask.ext.testing import TestCase
from flask_testing import TestCase
from past.builtins import basestring
import unittest
import app
from solr import app


class TestWebservices(TestCase):
Expand All @@ -23,7 +24,7 @@ def test_ResourcesRoute(self):
'methods': list,
'description': basestring,
'rate_limit': list,
}.iteritems():
}.items():
# Assert each resource is described has the expected_field
[self.assertIn(expected_field, v) for v in r.json.values()]

Expand Down
34 changes: 19 additions & 15 deletions solr/views.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
from __future__ import absolute_import
from future import standard_library
standard_library.install_aliases()
from builtins import str
from past.builtins import basestring
from flask import current_app, request
from flask.ext.restful import Resource
from flask.ext.discoverer import advertise
from flask_restful import Resource
from flask_discoverer import advertise
try:
from flask_login import current_user
except:
# If solr service is not shipped with adsws, this will fail and it is ok
pass
import json
from models import Limits
from .models import Limits
from sqlalchemy import or_
from werkzeug.datastructures import MultiDict
try:
from cStringIO import StringIO
except:
from StringIO import StringIO
from io import StringIO
from io import BytesIO
from urlparse import parse_qs
from urllib.parse import parse_qs

import requests # Do not use current_app.client but requests, to avoid re-using
# connections from a pool which would make solr ingress nginx
Expand Down Expand Up @@ -145,7 +147,7 @@ def apply_protective_filters(self, payload, user_id, protected_fields, key):
for f in session.query(Limits).filter(Limits.uid==user_id, or_(Limits.field==x for x in protected_fields)).all():
if f.filter:
fl = u'{0},{1}'.format(fl, f.field)
fq.append(unicode(f.filter))
fq.append(str(f.filter))
payload['fl'] = fl
session.commit()

Expand Down Expand Up @@ -173,7 +175,7 @@ def cleanup_solr_request(self, payload, user_id=None, handler_class="default"):
handler = self.handler.get(handler_class, self.handler.get("default", "-"))
headers['Host'] = self.get_host(current_app.config.get(handler))
internal_logging = []
for internal_param, default in self.internal_logging_params.iteritems():
for internal_param, default in self.internal_logging_params.items():
if internal_param in request.headers:
internal_logging.append("{}={}".format(internal_param, request.headers[internal_param]))
headers[internal_param] = request.headers[internal_param]
Expand Down Expand Up @@ -208,7 +210,7 @@ def cleanup_solr_request(self, payload, user_id=None, handler_class="default"):

max_hl = current_app.config.get('SOLR_SERVICE_MAX_SNIPPETS', 4)
max_frag = current_app.config.get('SOLR_SERVICE_MAX_FRAGSIZE', 100)
for k,v in payload.items():
for k,v in list(payload.items()):
if 'hl.' in k:
if '.snippets' in k:
payload[k] = max(0, min(_safe_int(v, default=max_hl), max_hl))
Expand Down Expand Up @@ -242,7 +244,7 @@ def _cleanup_fields(self, payload, key, allowed_fields):
fields.extend([i.strip().lower() for i in y.split(',')])

if allowed_fields:
fields = filter(lambda x: x in allowed_fields, fields)
fields = [x for x in fields if x in allowed_fields]

payload[key] = ','.join(fields)

Expand Down Expand Up @@ -271,8 +273,8 @@ def _cleanup_fl(self, payload, user_id, key):

protected_fields = []
if disallowed:
protected_fields = filter(lambda x: x in disallowed, fields)
fields = filter(lambda x: x not in disallowed, fields)
protected_fields = [x for x in fields if x in disallowed]
fields = [x for x in fields if x not in disallowed]

if len(fields) == 0:
fields.append('id')
Expand Down Expand Up @@ -340,7 +342,9 @@ def check_for_embedded_bigquery(self, params, request, headers, handler_class="d
if request.data and isinstance(request.data, basestring) and len(request.data) > 0:
if 'fq' not in params:
params['fq'] = [u'{!bitset}']
elif len(filter(lambda x: '!bitset' in x, params['fq'])) == 0:
elif isinstance(params['fq'], str) and '{!bitset}' not in params['fq']:
params['fq'] += u' {!bitset}'
elif isinstance(params['fq'], list) and len([x for x in params['fq'] if '!bitset' in x]) == 0:
params['fq'].append(u'{!bitset}')

# we'll package request.data into files
Expand Down
2 changes: 1 addition & 1 deletion wsgi.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from werkzeug.serving import run_simple
from werkzeug.wsgi import DispatcherMiddleware
from werkzeug.middleware.dispatcher import DispatcherMiddleware
from solr import app

application = app.create_app()
Expand Down