commit fd92068427394448d5343f7c152a6d908e5e4ec8 Author: brettlangdon Date: Sun Feb 1 15:55:34 2015 -0500 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..11041c7 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.egg-info diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..4a4abd2 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Brett Langdon + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..365c383 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,3 @@ +include README.* setup.py setup.cfg golab.py requirements.txt LICENSE +global-exclude *.pyc +global-exclude *.pyo diff --git a/README.md b/README.md new file mode 100644 index 0000000..f853a21 --- /dev/null +++ b/README.md @@ -0,0 +1,4 @@ +GoLab Python +============ + +Python client for GoLab diff --git a/golab.py b/golab.py new file mode 100644 index 0000000..058478b --- /dev/null +++ b/golab.py @@ -0,0 +1,89 @@ +__all__ = ["__version__", "Client"] +__version__ = "0.1.0" + +import collections +import json + +import memcache + + +class Client(object): + __slots__ = ["connection"] + + def __init__(self, host="127.0.0.1", port=11222): + self.connection = memcache.Client(["%s:%s" % (host, port)]) + + def get_user_variants(self, exp_ids, user_id): + keys = ['%s:%s' % (exp_id, user_id) for exp_id in exp_ids] + data = self.connection.get_multi(keys) + results = {} + + for key, value in data.iteritems(): + exp_id, _, _ = key.partition(":") + results[exp_id] = value + + return results + + def get_user_variant(self, exp_id, user_id): + key = '%s:%s' % (exp_id, user_id) + return self.connection.get(key) + + def convert_user(self, exp_id, user_id): + key = '%s:%s' % (exp_id, user_id) + return self.connection.incr(key) + + def add_new_experiment(self, data): + data = json.dumps(data) + return self.connection.add("1", data) + + def update_experiment(self, exp_id, data): + data = json.dumps(data) + return self.connection.replace(exp_id, data) + + def get_experiment(self, exp_id): + data = self.connection.get("experiment:%s" % (exp_id, )) + if data: + return json.loads(data) + return None + + def get_active_experiments(self): + data = self.connection.get("experiment:active") + results = {} + if data: + data = json.loads(data) + for exp in data: + results[int(exp['id'])] = exp + return results + + def get_all_experiments(self): + data = self.connection.get("experiment:*") + results = {} + if data: + data = json.loads(data) + for exp in data: + results[int(exp['id'])] = exp + return results + + def deactivate_experiment(self, exp_id): + return self.connection.delete(exp_id) + + def activate_experiment(self, exp_id): + return self.connection.touch(exp_id) + + def get_active_experiment_stats(self): + data = self.connection.get_stats() + results = collections.defaultdict(lambda: collections.defaultdict(dict)) + for server, stats in data: + for key, value in stats.iteritems(): + key, exp_id, bucket_id = key.split(".") + results[int(exp_id)][int(bucket_id)][key] = value + return results + + def get_experiment_stats(self, exp_id): + data = self.connection.get_stats(str(exp_id)) + results = collections.defaultdict(dict) + for server, stats in data: + for key, value in stats.iteritems(): + key, exp_id, bucket_id = key.split(".") + results[int(bucket_id)][int(key)] = value + return results diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..cc8f48f --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +python-memcached==1.53 diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..b88034e --- /dev/null +++ b/setup.cfg @@ -0,0 +1,2 @@ +[metadata] +description-file = README.md diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..9305462 --- /dev/null +++ b/setup.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python + +from setuptools import setup, find_packages + +from golab import __version__ + +requirements = [] +with open("./requirements.txt") as fp: + requirements = [l.strip() for l in fp] + +setup( + name="golab", + version=__version__, + description="Python client for GoLab", + author="Brett Langdon", + author_email="brett@blangdon.com", + url="https://github.com/brettlangdon/golab-python", + packages=find_packages(), + license="MIT", + install_requires=requirements, + classifiers=[ + "Intended Audience :: Developers", + "Programming Language :: Python", + "Programming Language :: Python :: 2.6", + "Programming Language :: Python :: 2.7", + "License :: OSI Approved :: MIT License", + ] +)