Skip to content

Commit

Permalink
Merge a08fd18 into 097578c
Browse files Browse the repository at this point in the history
  • Loading branch information
crankycoder committed Aug 8, 2018
2 parents 097578c + a08fd18 commit dd4a708
Show file tree
Hide file tree
Showing 39 changed files with 1,744 additions and 984 deletions.
6 changes: 2 additions & 4 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ language: python

matrix:
include:
- python: "2.7"
env: REQUIREMENTS="latest"
- python: "3.5"
env: REQUIREMENTS="latest"
- python: "2.7"
Expand Down Expand Up @@ -37,10 +35,10 @@ install:
else
exit 1;
fi
- pip install -r test_requirements.txt
- pip install -r requirements.txt

script:
- flake8 taar tests || exit 1 # Fail if flake8 fails
- if [[ $TRAVIS_PYTHON_VERSION == 3.5 ]]; then flake8 taar tests || exit 1; fi
- py.test --cov taar tests

after_success:
Expand Down
4 changes: 3 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,6 @@ test:
python setup.py test
flake8 taar tests


# Updating pip hashes is awful
freeze:
bin/hashfreeze
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,12 @@ Alternately, if you've got GNUMake installed, you can just run `make test` which
There are additional integration tests and a microbenchmark available
in `tests/test_integration.py`. See the source code for more
information.


## Pinning dependencies

TAAR uses hashin (https://pypi.org/project/hashin/) to pin SHA256
hashes for each dependency. To update the hashes, you will need to
remove the run `make freeze` which forces all packages in the current
virtualenv to be written out to requirement.txt with versions and SHA
hashes.
7 changes: 7 additions & 0 deletions bin/hashfreeze
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/bin/bash
touch requirements.txt
for package_ver in `pip freeze |grep -v hashin`
do
echo "Processing "$package_ver
hashin $package_ver
done
1 change: 1 addition & 0 deletions environment_emr.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ dependencies:
- expat=2.1.0=0
- fastcache=1.0.2=py27_1
- filelock=2.0.6=py27_0
- flake8==3.5.0=py27_0
- flask=0.11.1=py27_0
- flask-cors=2.1.2=py27_0
- fontconfig=2.11.1=6
Expand Down
609 changes: 609 additions & 0 deletions requirements.txt

Large diffs are not rendered by default.

6 changes: 5 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
setup(
name='mozilla-taar3',
use_scm_version=False,
version='0.0.28',
version='0.1.1',
setup_requires=['setuptools_scm', 'pytest-runner'],
tests_require=['pytest'],
include_package_data = True,
Expand Down Expand Up @@ -33,5 +33,9 @@
'Topic :: Internet :: WWW/HTTP',
'Topic :: Scientific/Engineering :: Information Analysis'
],
entry_points="""
[taarapi_app]
app=taar.plugin:configure_plugin
""",
zip_safe=False,
)
1 change: 0 additions & 1 deletion taar/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
from .profile_fetcher import ProfileFetcher # noqa
from .adapters.dynamo import ProfileController # noqa
import pkg_resources

__version__ = pkg_resources.require("mozilla-taar3")[0].version
41 changes: 0 additions & 41 deletions taar/adapters/dynamo.py

This file was deleted.

65 changes: 0 additions & 65 deletions taar/cache.py

This file was deleted.

62 changes: 4 additions & 58 deletions taar/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,77 +13,23 @@
chain.
"""

from taar.recommenders import utils


class Context:
def __init__(self, delegate=None):
if delegate is None:
delegate = {}

self._local_dict = {}
self._delegate = delegate

def __contains__(self, key):
try:
self[key]
return True
except KeyError:
return False

def __getitem__(self, key):
# This is a little tricky, we want to lookup items in our
# local namespace before we hit the delegate
try:
result = self._local_dict[key]
except KeyError:
result = self._delegate[key]
return result

def get(self, key, default):
try:
result = self[key]
except KeyError:
result = default
return result

def __setitem__(self, key, value):
self._local_dict[key] = value

def __delitem__(self, key):
del self._local_dict[key]

def wrap(self, ctx):
ctx_child = ctx.child()
this_child = self.child()
this_child._delegate = ctx_child
return this_child

def child(self):
""" In general, you should call this immediately in any
constructor that receives a context """

return Context(self)
# Clobber the Context name to prevent messy name collisions
from srgutil.context import Context as _Context


def default_context():
ctx = Context()
from taar.recommenders import LegacyRecommender
ctx = _Context()
from taar.recommenders import CollaborativeRecommender
from taar.recommenders import SimilarityRecommender
from taar.recommenders import LocaleRecommender
from taar.cache import Clock
from taar.cache import JSONCache

# Note that the EnsembleRecommender is *not* in this map as it
# needs to ensure that the recommender_map key is installed in the
# context
ctx['recommender_factory_map'] = {'legacy': lambda: LegacyRecommender(ctx.child()),
'collaborative': lambda: CollaborativeRecommender(ctx.child()),
ctx['recommender_factory_map'] = {'collaborative': lambda: CollaborativeRecommender(ctx.child()),
'similarity': lambda: SimilarityRecommender(ctx.child()),
'locale': lambda: LocaleRecommender(ctx.child())}

ctx['utils'] = utils
ctx['clock'] = Clock()
ctx['cache'] = JSONCache(ctx)
return ctx
106 changes: 106 additions & 0 deletions taar/plugin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

from decouple import config
from flask import request
import json

# TAAR specific libraries
from taar.context import default_context
from taar.profile_fetcher import ProfileFetcher
from taar import recommenders

# These are configurations that are specific to the TAAR library
VALID_BRANCHES = set(['linear', 'ensemble', 'control'])
TAAR_MAX_RESULTS = config('TAAR_MAX_RESULTS', default=10, cast=int)


class ResourceProxy(object):
def __init__(self):
self._resource = None

def setResource(self, rsrc):
self._resource = rsrc

def getResource(self):
return self._resource


PROXY_MANAGER = ResourceProxy()


def configure_plugin(app):
"""
This is a factory function that configures all the routes for
flask given a particular library.
"""
@app.route('/api/recommendations/<uuid:uuid_client_id>/')
def recommendations(uuid_client_id):
"""Return a list of recommendations provided a telemetry client_id."""
# Use the module global PROXY_MANAGER
global PROXY_MANAGER

# Coerce the uuid.UUID type into a string
client_id = str(uuid_client_id)

branch = request.args.get('branch', '')

if branch.endswith('-taar'):
branch = branch.replace("-taar", "")

if branch not in VALID_BRANCHES:
# Force branch to be a control branch if an invalid request
# comes in.
branch = 'control'

extra_data = {'branch': branch}

locale = request.args.get('locale', None)
if locale is not None:
extra_data['locale'] = locale

platform = request.args.get('platform', None)
if platform is not None:
extra_data['platform'] = platform

if PROXY_MANAGER.getResource() is None:
ctx = default_context()
profile_fetcher = ProfileFetcher(ctx)

ctx['profile_fetcher'] = profile_fetcher

# Lock the context down after we've got basic bits installed
root_ctx = ctx.child()
r_factory = recommenders.RecommenderFactory(root_ctx)
root_ctx['recommender_factory'] = r_factory
instance = recommenders.RecommendationManager(root_ctx.child())
PROXY_MANAGER.setResource(instance)

instance = PROXY_MANAGER.getResource()
recommendations = instance.recommend(client_id=client_id,
limit=TAAR_MAX_RESULTS,
extra_data=extra_data)
# Strip out weights from TAAR results to maintain compatibility
# with TAAR 1.0
jdata = {"results": [x[0] for x in recommendations]}

response = app.response_class(response=json.dumps(jdata),
status=200,
mimetype='application/json')
return response

class MyPlugin:
def set(self, config_options):
"""
This setter is primarily so that we can instrument the
cached RecommendationManager implementation under test.
All plugins should implement this set method to enable
overwriting configuration options with a TAAR library.
"""
global PROXY_MANAGER
if 'PROXY_RESOURCE' in config_options:
PROXY_MANAGER._resource = config_options['PROXY_RESOURCE']

return MyPlugin()

0 comments on commit dd4a708

Please sign in to comment.