From 8e35e33da89323b8f49d026d7035dac172997cf1 Mon Sep 17 00:00:00 2001 From: Shinsuke Sugaya Date: Sun, 10 Sep 2017 10:35:50 +0900 Subject: [PATCH 01/11] Add travis test and Refactoring Closes #22 --- .travis.yml | 34 ++ README.txt | 122 +++--- predictionio/__init__.py | 14 +- tests-obsolete/conversion_test.py | 16 - tests-obsolete/import_testdata.py | 46 --- tests-obsolete/import_testdata_id_mismatch.py | 46 --- .../import_testdata_special_char.py | 46 --- tests-obsolete/predictionio_itemrec_test.py | 336 ---------------- .../predictionio_itemrec_test_special_char.py | 366 ------------------ tests-obsolete/predictionio_itemsim_test.py | 200 ---------- tests-obsolete/predictionio_test.py | 257 ------------ tests/.keep | 0 tests/after_script.travis.sh | 5 + tests/before_script.travis.sh | 27 ++ tests/engineclient_test.py | 48 +++ tests/eventclient_test.py | 251 ++++++++++++ tests/fileexport_test.py | 74 ++++ tox.ini | 7 +- 18 files changed, 511 insertions(+), 1384 deletions(-) create mode 100644 .travis.yml delete mode 100644 tests-obsolete/conversion_test.py delete mode 100644 tests-obsolete/import_testdata.py delete mode 100644 tests-obsolete/import_testdata_id_mismatch.py delete mode 100644 tests-obsolete/import_testdata_special_char.py delete mode 100644 tests-obsolete/predictionio_itemrec_test.py delete mode 100644 tests-obsolete/predictionio_itemrec_test_special_char.py delete mode 100644 tests-obsolete/predictionio_itemsim_test.py delete mode 100644 tests-obsolete/predictionio_test.py delete mode 100644 tests/.keep create mode 100755 tests/after_script.travis.sh create mode 100755 tests/before_script.travis.sh create mode 100644 tests/engineclient_test.py create mode 100644 tests/eventclient_test.py create mode 100644 tests/fileexport_test.py diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..50d98a9 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,34 @@ +sudo: required + +language: python + +jdk: + - oraclejdk8 + +python: + - 2.7 + - 3.4 + - 3.5 + - 3.6 + +cache: + directories: + - $HOME/.ivy2/cache + - $HOME/.sbt/boot + - $HOME/.sbt/launchers + +install: + - pip install tox tox-travis + - pip install coverage coveralls + +before_script: + - java -version + - ./tests/before_script.travis.sh + - export PATH=$PATH:$PWD/predictionio-setup/predictionio/bin + +script: + - pio status + - tox -r + +after_script: + - ./tests/after_script.travis.sh diff --git a/README.txt b/README.txt index 2a542a0..4740ff5 100644 --- a/README.txt +++ b/README.txt @@ -1,63 +1,59 @@ -PredictionIO Python SDK -======================= - - -Installation -============ - -To install the module from PyPI, you may - - $ pip install predictionio - -or - - $ easy_install predictionio - -If you have cloned the repository and want to install directly from there, -do the following in the root directory of the repository: - - $ python setup.py install - -This will install the "predictionio" module to your Python distribution. - - -Usage -===== - -To use predictionio in your Python script, - - >>> import predictionio - - -Documentation -============= - -The latest documentation is located at http://pythonhosted.org/PredictionIO/ - -If you want to build a local copy, please install Sphinx -(http://sphinx-doc.org/install.html). - -To generate documentation, - - % cd docs - % make html - -To view the generated documentation, go to docs/build/html/index.html. - - -SUPPORT -======= - - -Forum ------ - -https://groups.google.com/group/predictionio-user - - -Issue Tracker -------------- - -https://predictionio.atlassian.net - -If you are unsure whether a behavior is an issue, bringing it up in the forum is highly encouraged. +PredictionIO Python SDK +======================= + + +Installation +============ + +To install the module from PyPI, you may + + $ pip install predictionio + +or + + $ easy_install predictionio + +If you have cloned the repository and want to install directly from there, +do the following in the root directory of the repository: + + $ python setup.py install + +This will install the "predictionio" module to your Python distribution. + + +Usage +===== + +To use predictionio in your Python script, + + >>> import predictionio + + +Documentation +============= + +The latest documentation is located at http://pythonhosted.org/PredictionIO/ + +If you want to build a local copy, please install Sphinx +(http://sphinx-doc.org/install.html). + +To generate documentation, + + % cd docs + % make html + +To view the generated documentation, go to docs/build/html/index.html. + + +SUPPORT +======= + +http://predictionio.incubator.apache.org/support/ + + +Issue Tracker +------------- + +https://issues.apache.org/jira/projects/PIO + +If you are unsure whether a behavior is an issue, bringing it up in the forum is highly encouraged. diff --git a/predictionio/__init__.py b/predictionio/__init__.py index b429b4e..01ac045 100644 --- a/predictionio/__init__.py +++ b/predictionio/__init__.py @@ -21,6 +21,12 @@ # pylint: disable=F0401,E0611 from urllib.parse import urlencode +try: + from urllib import quote +except ImportError: + # pylint: disable=F0401,E0611 + from urllib.parse import quote + import json import urllib @@ -260,7 +266,7 @@ def aget_event(self, event_id): if self.channel is not None: qparam["channel"] = self.channel - enc_event_id = urllib.quote(event_id, "") # replace special char with %xx + enc_event_id = quote(event_id, "") # replace special char with %xx path = "/events/%s.json" % (enc_event_id, ) request = AsyncRequest("GET", path, **qparam) request.set_rfunc(self._aget_resp) @@ -335,7 +341,7 @@ def adelete_event(self, event_id): if self.channel is not None: qparam["channel"] = self.channel - enc_event_id = urllib.quote(event_id, "") # replace special char with %xx + enc_event_id = quote(event_id, "") # replace special char with %xx path = "/events/%s.json" % (enc_event_id, ) request = AsyncRequest("DELETE", path, **qparam) request.set_rfunc(self._adelete_resp) @@ -519,7 +525,7 @@ def __init__(self, file_name): def create_event(self, event, entity_type, entity_id, target_entity_type=None, target_entity_id=None, properties=None, - event_time=None): + event_time=None, ensure_ascii=True): """Create an event and write to the file. (please refer to EventClient's create_event()) """ @@ -544,7 +550,7 @@ def create_event(self, event, entity_type, entity_id, et_str = et.strftime("%Y-%m-%dT%H:%M:%S.%f")[:-3] + et.strftime("%z") data["eventTime"] = et_str - j = json.dumps(data) + j = json.dumps(data, ensure_ascii=ensure_ascii) self._file.write(j+"\n") def close(self): diff --git a/tests-obsolete/conversion_test.py b/tests-obsolete/conversion_test.py deleted file mode 100644 index b9dca97..0000000 --- a/tests-obsolete/conversion_test.py +++ /dev/null @@ -1,16 +0,0 @@ -import timeit - -if __name__ == "__main__": - a = True - - t = timeit.Timer("json.dumps(True)", "import json") - - t_bool2json = t.timeit(1000) / 1000 - print("bool 2 json") - print(t_bool2json) - - t = timeit.Timer("str(True).lower()", "") - - t_bool2string = t.timeit(1000) / 1000 - print("bool 2 string") - print(t_bool2string) diff --git a/tests-obsolete/import_testdata.py b/tests-obsolete/import_testdata.py deleted file mode 100644 index e5338c0..0000000 --- a/tests-obsolete/import_testdata.py +++ /dev/null @@ -1,46 +0,0 @@ -""" -Import simple test data for testing getting itemrec -""" -import predictionio - -APP_KEY = "gDx1XuMUC9vu1YWWPRZkLRTftoq7m73mlj2MtnZEjncPlZ1JxUS2s7oajwP9xrZQ" -API_URL = "http://localhost:7070" - -MIN_VERSION = '0.5.0' -if predictionio.__version__ < MIN_VERSION: - err = "Require PredictionIO Python SDK version >= %s" % MIN_VERSION - raise Exception(err) - -if __name__ == "__main__": - client = predictionio.Client(APP_KEY, 1, API_URL) - - client.create_user("u0") - client.create_user("u1") - client.create_user("u2") - client.create_user("u3") - - client.create_item("i0", ("t1",), {"custom1": "i0c1"}) - client.create_item("i1", ("t1", "t2"), {"custom1": "i1c1", "custom2": "i1c2"}) - client.create_item("i2", ("t1", "t2"), {"custom2": "i2c2"}) - client.create_item("i3", ("t1",)) - - client.identify("u0") - client.record_action_on_item("rate", "i0", {"pio_rate": 2}) - client.record_action_on_item("rate", "i1", {"pio_rate": 3}) - client.record_action_on_item("rate", "i2", {"pio_rate": 4}) - - client.identify("u1") - client.record_action_on_item("rate", "i2", {"pio_rate": 4}) - client.record_action_on_item("rate", "i3", {"pio_rate": 1}) - - client.identify("u2") - client.record_action_on_item("rate", "i1", {"pio_rate": 2}) - client.record_action_on_item("rate", "i2", {"pio_rate": 1}) - client.record_action_on_item("rate", "i3", {"pio_rate": 3}) - - client.identify("u3") - client.record_action_on_item("rate", "i0", {"pio_rate": 5}) - client.record_action_on_item("rate", "i1", {"pio_rate": 3}) - client.record_action_on_item("rate", "i3", {"pio_rate": 2}) - - client.close() diff --git a/tests-obsolete/import_testdata_id_mismatch.py b/tests-obsolete/import_testdata_id_mismatch.py deleted file mode 100644 index 104f75c..0000000 --- a/tests-obsolete/import_testdata_id_mismatch.py +++ /dev/null @@ -1,46 +0,0 @@ -""" -Import simple test data for testing getting itemrec -""" -import predictionio - -APP_KEY = "gDx1XuMUC9vu1YWWPRZkLRTftoq7m73mlj2MtnZEjncPlZ1JxUS2s7oajwP9xrZQ" -API_URL = "http://localhost:8000" - -MIN_VERSION = '0.5.0' -if predictionio.__version__ < MIN_VERSION: - err = "Require PredictionIO Python SDK version >= %s" % MIN_VERSION - raise Exception(err) - -if __name__ == "__main__": - client = predictionio.Client(APP_KEY, 1, API_URL) - - client.create_user("u0") - client.create_user("u1") - client.create_user("u2") - client.create_user("u3") - - client.create_item("i0", ("t1",), {"custom1": "i0c1"}) - client.create_item("i1", ("t1", "t2"), {"custom1": "i1c1", "custom2": "i1c2"}) - client.create_item("i2", ("t1", "t2"), {"custom2": "i2c2"}) - client.create_item("i3", ("t1",)) - - client.identify("u0x") - client.record_action_on_item("rate", "i0", {"pio_rate": 2}) - client.record_action_on_item("rate", "i1", {"pio_rate": 3}) - client.record_action_on_item("rate", "i2", {"pio_rate": 4}) - - client.identify("u1x") - client.record_action_on_item("rate", "i2", {"pio_rate": 4}) - client.record_action_on_item("rate", "i3", {"pio_rate": 1}) - - client.identify("u2x") - client.record_action_on_item("rate", "i1", {"pio_rate": 2}) - client.record_action_on_item("rate", "i2", {"pio_rate": 1}) - client.record_action_on_item("rate", "i3", {"pio_rate": 3}) - - client.identify("u3x") - client.record_action_on_item("rate", "i0", {"pio_rate": 5}) - client.record_action_on_item("rate", "i1", {"pio_rate": 3}) - client.record_action_on_item("rate", "i3", {"pio_rate": 2}) - - client.close() diff --git a/tests-obsolete/import_testdata_special_char.py b/tests-obsolete/import_testdata_special_char.py deleted file mode 100644 index c047b6a..0000000 --- a/tests-obsolete/import_testdata_special_char.py +++ /dev/null @@ -1,46 +0,0 @@ -""" -Import simple test data (id with special characters) for testing getting itemrec -""" -import predictionio - -APP_KEY = "gDx1XuMUC9vu1YWWPRZkLRTftoq7m73mlj2MtnZEjncPlZ1JxUS2s7oajwP9xrZQ" -API_URL = "http://localhost:8000" - -MIN_VERSION = '0.5.0' -if predictionio.__version__ < MIN_VERSION: - err = "Require PredictionIO Python SDK version >= %s" % MIN_VERSION - raise Exception(err) - -if __name__ == "__main__": - client = predictionio.Client(APP_KEY, 1, API_URL) - - client.create_user("u0@u.n") - client.create_user("u1@u.n") - client.create_user("http://u2.com") - client.create_user("u3@u.n") - - client.create_item("http://i0.com", ("t1",), {"custom1": "i0c1"}) - client.create_item("i1@i1", ("t1", "t2"), {"custom1": "i1c1", "custom2": "i1c2"}) - client.create_item("i2.org", ("t1", "t2"), {"custom2": "i2c2"}) - client.create_item("i3", ("t1",)) - - client.identify("u0@u.n") - client.record_action_on_item("rate", "http://i0.com", {"pio_rate": 2}) - client.record_action_on_item("rate", "i1@i1", {"pio_rate": 3}) - client.record_action_on_item("rate", "i2.org", {"pio_rate": 4}) - - client.identify("u1@u.n") - client.record_action_on_item("rate", "i2.org", {"pio_rate": 4}) - client.record_action_on_item("rate", "i3", {"pio_rate": 1}) - - client.identify("http://u2.com") - client.record_action_on_item("rate", "i1@i1", {"pio_rate": 2}) - client.record_action_on_item("rate", "i2.org", {"pio_rate": 1}) - client.record_action_on_item("rate", "i3", {"pio_rate": 3}) - - client.identify("u3@u.n") - client.record_action_on_item("rate", "http://i0.com", {"pio_rate": 5}) - client.record_action_on_item("rate", "i1@i1", {"pio_rate": 3}) - client.record_action_on_item("rate", "i3", {"pio_rate": 2}) - - client.close() diff --git a/tests-obsolete/predictionio_itemrec_test.py b/tests-obsolete/predictionio_itemrec_test.py deleted file mode 100644 index 3105f0f..0000000 --- a/tests-obsolete/predictionio_itemrec_test.py +++ /dev/null @@ -1,336 +0,0 @@ -""" -Test getting itemrec after algo training completes. -""" - -from __future__ import print_function - -import unittest - -import predictionio - - -APP_KEY = "gDx1XuMUC9vu1YWWPRZkLRTftoq7m73mlj2MtnZEjncPlZ1JxUS2s7oajwP9xrZQ" # replace this with your AppKey -API_URL = "http://localhost:8000" # PredictoinIO Server - -DEBUG = True - -MIN_VERSION = '0.6.0' -if predictionio.__version__ < MIN_VERSION: - err = "Require PredictionIO Python SDK version >= %s" % MIN_VERSION - raise Exception(err) - - -class TestPredictionIO(unittest.TestCase): - def setUp(self): - pass - - def tearDown(self): - pass - - def test_get_itemrec_exception_deprecated(self): - client = predictionio.Client(APP_KEY, 1, API_URL) - - try: - client.get_itemrec("uidwithoutrec", 10, "python-itemrec-engine") - except predictionio.ItemRecNotFoundError as e: # noqa - pass # expected exception - except: - raise - - client.close() - - def test_get_itemrec_exception(self): - client = predictionio.Client(APP_KEY, 1, API_URL) - - client.identify("uidwithoutrec") - - try: - client.get_itemrec_topn("python-itemrec-engine", 10) - except predictionio.ItemRecNotFoundError as e: # noqa - pass # expected exception - except: - raise - - try: - client.get_itemrec_topn("python-itemrec-engine", 10, - {"pio_itypes": ("t1",), "pio_latlng": [1.34, 5.67], "pio_within": 5.0, - "pio_unit": "km", "pio_attributes": ["custom1", "custom2"]}) - except predictionio.ItemRecNotFoundError as e: # noqa - pass # expected exception - except: - raise - - client.close() - - def test_get_itemrec_deprecated(self): - client = predictionio.Client(APP_KEY, 1, API_URL) - - # request more - try: - itemrec = client.get_itemrec("u0", 10, "python-itemrec-engine") - except predictionio.ItemRecNotFoundError as e: - print("ERROR: have you run import_testdata.py and then wait for the algorithm training completion?") - raise - except: - raise - if DEBUG: - print(itemrec) - self.assertEqual(itemrec, {"pio_iids": ["i2", "i3", "i1", "i0"]}) - - try: - itemrec = client.get_itemrec("u1", 10, "python-itemrec-engine") - except predictionio.ItemRecNotFoundError as e: - print("ERROR: have you run import_testdata.py and then wait for the algorithm training completion?") - raise - except: - raise - if DEBUG: - print(itemrec) - - self.assertTrue((itemrec == {"pio_iids": ["i2", "i1", "i0", "i3"]}) or - (itemrec == {"pio_iids": ["i2", "i0", "i1", "i3"]})) - - try: - itemrec = client.get_itemrec("u2", 10, "python-itemrec-engine") - except predictionio.ItemRecNotFoundError as e: - print("ERROR: have you run import_testdata.py and then wait for the algorithm training completion?") - raise - except: - raise - if DEBUG: - print(itemrec) - self.assertTrue((itemrec == {"pio_iids": ["i3", "i0", "i1", "i2"]}) or - (itemrec == {"pio_iids": ["i3", "i1", "i0", "i2"]})) - - try: - itemrec = client.get_itemrec("u3", 6, "python-itemrec-engine") - except predictionio.ItemRecNotFoundError as e: - print("ERROR: have you run import_testdata.py and then wait for the algorithm training completion?") - raise - except: - raise - if DEBUG: - print(itemrec) - self.assertTrue((itemrec == {"pio_iids": ["i0", "i1", "i2", "i3"]}) or - (itemrec == {"pio_iids": ["i0", "i2", "i1", "i3"]})) - - # request less - try: - itemrec = client.get_itemrec("u0", 1, "python-itemrec-engine") - except predictionio.ItemRecNotFoundError as e: - print("ERROR: have you run import_testdata.py and then wait for the algorithm training completion?") - raise - except: - raise - if DEBUG: - print(itemrec) - self.assertEqual(itemrec, {"pio_iids": ["i2"]}) - - try: - itemrec = client.get_itemrec("u0", 2, "python-itemrec-engine") - except predictionio.ItemRecNotFoundError as e: - print("ERROR: have you run import_testdata.py and then wait for the algorithm training completion?") - raise - except: - raise - if DEBUG: - print(itemrec) - self.assertEqual(itemrec, {"pio_iids": ["i2", "i3"]}) - - # request with optional attributes - - # pio_itypes - try: - itemrec = client.get_itemrec("u0", 10, "python-itemrec-engine", pio_itypes=("t1", "t2")) - except predictionio.ItemRecNotFoundError as e: - print("ERROR: have you run import_testdata.py and then wait for the algorithm training completion?") - raise - except: - raise - if DEBUG: - print(itemrec) - self.assertEqual(itemrec, {"pio_iids": ["i2", "i3", "i1", "i0"]}) - - # subset itypes - try: - itemrec = client.get_itemrec("u0", 10, "python-itemrec-engine", pio_itypes=("t2",)) - except predictionio.ItemRecNotFoundError as e: - print("ERROR: have you run import_testdata.py and then wait for the algorithm training completion?") - raise - except: - raise - if DEBUG: - print(itemrec) - self.assertEqual(itemrec, {"pio_iids": ["i2", "i1"]}) - - # nonexisting itypes - try: - itemrec = client.get_itemrec("u0", 10, "python-itemrec-engine", pio_itypes=("other-itype",)) - except predictionio.ItemRecNotFoundError as e: - pass # expected no recommendation - except: - raise - - # pio_attributes - try: - itemrec = client.get_itemrec("u0", 10, "python-itemrec-engine", pio_itypes=("t1",), - pio_attributes=["custom1", "custom2"]) - except predictionio.ItemRecNotFoundError as e: # noqa - print("ERROR: have you run import_testdata.py and then wait for the algorithm training completion?") - raise - except: - raise - - if DEBUG: - print(itemrec) - - self.assertEqual(itemrec, {"pio_iids": ["i2", "i3", "i1", "i0"], "custom1": [None, None, "i1c1", "i0c1"], - "custom2": ["i2c2", None, "i1c2", None]}) - - client.close() - - def test_get_itemrec(self): - client = predictionio.Client(APP_KEY, 1, API_URL) - - # request more - client.identify("u0") - try: - itemrec = client.get_itemrec_topn("python-itemrec-engine", 10) - except predictionio.ItemRecNotFoundError as e: - print("ERROR: have you run import_testdata.py and then wait for the algorithm training completion?") - raise - except: - raise - - if DEBUG: - print(itemrec) - - self.assertEqual(itemrec, {"pio_iids": ["i2", "i3", "i1", "i0"]}) - - client.identify("u1") - try: - itemrec = client.get_itemrec_topn("python-itemrec-engine", 10) - except predictionio.ItemRecNotFoundError as e: - print("ERROR: have you run import_testdata.py and then wait for the algorithm training completion?") - raise - except: - raise - if DEBUG: - print(itemrec) - self.assertTrue((itemrec == {"pio_iids": ["i2", "i1", "i0", "i3"]}) or - (itemrec == {"pio_iids": ["i2", "i0", "i1", "i3"]})) - - client.identify("u2") - try: - itemrec = client.get_itemrec_topn("python-itemrec-engine", 10) - except predictionio.ItemRecNotFoundError as e: - print("ERROR: have you run import_testdata.py and then wait for the algorithm training completion?") - raise - except: - raise - if DEBUG: - print(itemrec) - self.assertTrue((itemrec == {"pio_iids": ["i3", "i0", "i1", "i2"]}) or - (itemrec == {"pio_iids": ["i3", "i1", "i0", "i2"]})) - - client.identify("u3") - try: - itemrec = client.get_itemrec_topn("python-itemrec-engine", 6) - except predictionio.ItemRecNotFoundError as e: - print("ERROR: have you run import_testdata.py and then wait for the algorithm training completion?") - raise - except: - raise - if DEBUG: - print(itemrec) - self.assertTrue((itemrec == {"pio_iids": ["i0", "i1", "i2", "i3"]}) or - (itemrec == {"pio_iids": ["i0", "i2", "i1", "i3"]})) - - # request less - client.identify("u0") - try: - itemrec = client.get_itemrec_topn("python-itemrec-engine", 1) - except predictionio.ItemRecNotFoundError as e: - print("ERROR: have you run import_testdata.py and then wait for the algorithm training completion?") - raise - except: - raise - if DEBUG: - print(itemrec) - self.assertEqual(itemrec, {"pio_iids": ["i2"]}) - - client.identify("u0") - try: - itemrec = client.get_itemrec_topn("python-itemrec-engine", 2) - except predictionio.ItemRecNotFoundError as e: - print("ERROR: have you run import_testdata.py and then wait for the algorithm training completion?") - raise - except: - raise - if DEBUG: - print(itemrec) - self.assertEqual(itemrec, {"pio_iids": ["i2", "i3"]}) - - # request with optional attributes - - # pio_itypes - client.identify("u0") - try: - itemrec = client.get_itemrec_topn("python-itemrec-engine", 10, {"pio_itypes": ("t1", "t2")}) - except predictionio.ItemRecNotFoundError as e: - print("ERROR: have you run import_testdata.py and then wait for the algorithm training completion?") - raise - except: - raise - if DEBUG: - print(itemrec) - self.assertEqual(itemrec, {"pio_iids": ["i2", "i3", "i1", "i0"]}) - - # subset itypes - client.identify("u0") - try: - itemrec = client.get_itemrec_topn("python-itemrec-engine", 10, {"pio_itypes": ("t2",)}) - except predictionio.ItemRecNotFoundError as e: - print("ERROR: have you run import_testdata.py and then wait for the algorithm training completion?") - raise - except: - raise - if DEBUG: - print(itemrec) - self.assertEqual(itemrec, {"pio_iids": ["i2", "i1"]}) - - # nonexisting itypes - client.identify("u0") - try: - itemrec = client.get_itemrec_topn("python-itemrec-engine", 10, {"pio_itypes": ("other-itype",)}) - except predictionio.ItemRecNotFoundError as e: - pass # expected no recommendation - except: - raise - - # pio_attributes - client.identify("u0") - try: - itemrec = client.get_itemrec_topn("python-itemrec-engine", 10, - {"pio_itypes": ("t1",), "pio_attributes": ["custom1", "custom2"]}) - except predictionio.ItemRecNotFoundError as e: # noqa - print("ERROR: have you run import_testdata.py and then wait for the algorithm training completion?") - raise - except: - raise - - if DEBUG: - print(itemrec) - - self.assertEqual(itemrec, {"pio_iids": ["i2", "i3", "i1", "i0"], "custom1": [None, None, "i1c1", "i0c1"], - "custom2": ["i2c2", None, "i1c2", None]}) - - # TODO pio_latlng - # TODO pio_within - # TODO pio_unit - - client.close() - - -if __name__ == "__main__": - unittest.main() diff --git a/tests-obsolete/predictionio_itemrec_test_special_char.py b/tests-obsolete/predictionio_itemrec_test_special_char.py deleted file mode 100644 index a622800..0000000 --- a/tests-obsolete/predictionio_itemrec_test_special_char.py +++ /dev/null @@ -1,366 +0,0 @@ -""" -Test getting itemrec after algo training completes. -""" -import unittest - -import predictionio - - -APP_KEY = "gDx1XuMUC9vu1YWWPRZkLRTftoq7m73mlj2MtnZEjncPlZ1JxUS2s7oajwP9xrZQ" # replace this with your AppKey -API_URL = "http://localhost:8000" # PredictoinIO Server - -DEBUG = True - -MIN_VERSION = '0.6.0' -if predictionio.__version__ < MIN_VERSION: - err = "Require PredictionIO Python SDK version >= %s" % MIN_VERSION - raise Exception(err) - - -class TestPredictionIO(unittest.TestCase): - def setUp(self): - pass - - def tearDown(self): - pass - - def test_get_itemrec_deprecated(self): - client = predictionio.Client(APP_KEY, 1, API_URL) - - uid0 = "u0@u.n" - uid1 = "u1@u.n" - uid2 = "http://u2.com" - uid3 = "u3@u.n" - - iid0 = "http://i0.com" - iid1 = "i1@i1" - iid2 = "i2.org" - iid3 = "i3" - - engine_name = "itemrec" - - # request more - try: - itemrec = client.get_itemrec(uid0, 10, engine_name) - except predictionio.ItemRecNotFoundError as e: - print(e) - print("ERROR: have you run import_testdata.py and then wait for the algorithm training completion?") - raise - except: - raise - - if DEBUG: - print(itemrec) - - self.assertEqual(itemrec, {"pio_iids": [iid2, iid3, iid1, iid0]}) - - try: - itemrec = client.get_itemrec(uid1, 10, engine_name) - except predictionio.ItemRecNotFoundError as e: - print(e) - print("ERROR: have you run import_testdata.py and then wait for the algorithm training completion?") - raise - except: - raise - - if DEBUG: - print(itemrec) - - self.assertTrue((itemrec == {"pio_iids": [iid2, iid1, iid0, iid3]}) or - (itemrec == {"pio_iids": [iid2, iid0, iid1, iid3]})) - - try: - itemrec = client.get_itemrec(uid2, 10, engine_name) - except predictionio.ItemRecNotFoundError as e: - print(e) - print("ERROR: have you run import_testdata.py and then wait for the algorithm training completion?") - raise - except: - raise - - if DEBUG: - print(itemrec) - - self.assertTrue((itemrec == {"pio_iids": [iid3, iid0, iid1, iid2]}) or - (itemrec == {"pio_iids": [iid3, iid1, iid0, iid2]})) - - try: - itemrec = client.get_itemrec(uid3, 6, engine_name) - except predictionio.ItemRecNotFoundError as e: - print(e) - print("ERROR: have you run import_testdata.py and then wait for the algorithm training completion?") - raise - except: - raise - - if DEBUG: - print(itemrec) - - self.assertTrue((itemrec == {"pio_iids": [iid0, iid1, iid2, iid3]}) or - (itemrec == {"pio_iids": [iid0, iid2, iid1, iid3]})) - - # request less - try: - itemrec = client.get_itemrec(uid0, 1, engine_name) - except predictionio.ItemRecNotFoundError as e: - print("ERROR: have you run import_testdata.py and then wait for the algorithm training completion?") - raise - except: - raise - - if DEBUG: - print(itemrec) - - self.assertEqual(itemrec, {"pio_iids": [iid2]}) - - try: - itemrec = client.get_itemrec(uid0, 2, engine_name) - except predictionio.ItemRecNotFoundError as e: - print("ERROR: have you run import_testdata.py and then wait for the algorithm training completion?") - raise - except: - raise - - if DEBUG: - print(itemrec) - - self.assertEqual(itemrec, {"pio_iids": [iid2, iid3]}) - - # request with optional attributes - - # pio_itypes - try: - itemrec = client.get_itemrec(uid0, 10, engine_name, pio_itypes=("t1", "t2")) - except predictionio.ItemRecNotFoundError as e: - print("ERROR: have you run import_testdata.py and then wait for the algorithm training completion?") - raise - except: - raise - - if DEBUG: - print(itemrec) - - self.assertEqual(itemrec, {"pio_iids": [iid2, iid3, iid1, iid0]}) - - # subset itypes - try: - itemrec = client.get_itemrec(uid0, 10, engine_name, pio_itypes=("t2",)) - except predictionio.ItemRecNotFoundError as e: - print("ERROR: have you run import_testdata.py and then wait for the algorithm training completion?") - raise - except: - raise - - if DEBUG: - print(itemrec) - - self.assertEqual(itemrec, {"pio_iids": [iid2, iid1]}) - - # nonexisting itypes - try: - client.get_itemrec(uid0, 10, engine_name, pio_itypes=("other-itype",)) - except predictionio.ItemRecNotFoundError as e: - print(e) - pass # expected no recommendation - except: - raise - - # pio_attributes - try: - itemrec = client.get_itemrec(uid0, 10, engine_name, pio_itypes=("t1",), - pio_attributes=["custom1", "custom2"]) - except predictionio.ItemRecNotFoundError as e: - print(e) - print("ERROR: have you run import_testdata.py and then wait for the algorithm training completion?") - raise - except: - raise - - if DEBUG: - print(itemrec) - - self.assertEqual(itemrec, {"pio_iids": [iid2, iid3, iid1, iid0], "custom1": [None, None, "i1c1", "i0c1"], - "custom2": ["i2c2", None, "i1c2", None]}) - - client.close() - - def test_get_itemrec(self): - client = predictionio.Client(APP_KEY, 1, API_URL) - - uid0 = "u0@u.n" - uid1 = "u1@u.n" - uid2 = "http://u2.com" - uid3 = "u3@u.n" - - iid0 = "http://i0.com" - iid1 = "i1@i1" - iid2 = "i2.org" - iid3 = "i3" - - engine_name = "itemrec" - - # request more - client.identify(uid0) - try: - itemrec = client.get_itemrec_topn(engine_name, 10) - except predictionio.ItemRecNotFoundError as e: - print(e) - print("ERROR: have you run import_testdata.py and then wait for the algorithm training completion?") - raise - except: - raise - - if DEBUG: - print(itemrec) - - self.assertEqual(itemrec, {"pio_iids": [iid2, iid3, iid1, iid0]}) - - client.identify(uid1) - try: - itemrec = client.get_itemrec_topn(engine_name, 10) - except predictionio.ItemRecNotFoundError as e: - print(e) - print("ERROR: have you run import_testdata.py and then wait for the algorithm training completion?") - raise - except: - raise - - if DEBUG: - print(itemrec) - - self.assertTrue((itemrec == {"pio_iids": [iid2, iid1, iid0, iid3]}) or - (itemrec == {"pio_iids": [iid2, iid0, iid1, iid3]})) - - client.identify(uid2) - try: - itemrec = client.get_itemrec_topn(engine_name, 10) - except predictionio.ItemRecNotFoundError as e: - print("ERROR: have you run import_testdata.py and then wait for the algorithm training completion?") - raise - except: - raise - - if DEBUG: - print(itemrec) - - self.assertTrue((itemrec == {"pio_iids": [iid3, iid0, iid1, iid2]}) or - (itemrec == {"pio_iids": [iid3, iid1, iid0, iid2]})) - - client.identify(uid3) - try: - itemrec = client.get_itemrec_topn(engine_name, 6) - except predictionio.ItemRecNotFoundError as e: - print(e) - print("ERROR: have you run import_testdata.py and then wait for the algorithm training completion?") - raise - except: - raise - - if DEBUG: - print(itemrec) - - self.assertTrue((itemrec == {"pio_iids": [iid0, iid1, iid2, iid3]}) or - (itemrec == {"pio_iids": [iid0, iid2, iid1, iid3]})) - - # request less - client.identify(uid0) - try: - itemrec = client.get_itemrec_topn(engine_name, 1) - except predictionio.ItemRecNotFoundError as e: - print(e) - print("ERROR: have you run import_testdata.py and then wait for the algorithm training completion?") - raise - except: - raise - - if DEBUG: - print(itemrec) - - self.assertEqual(itemrec, {"pio_iids": [iid2]}) - - client.identify(uid0) - try: - itemrec = client.get_itemrec_topn(engine_name, 2) - except predictionio.ItemRecNotFoundError as e: - print(e) - print("ERROR: have you run import_testdata.py and then wait for the algorithm training completion?") - raise - except: - raise - - if DEBUG: - print(itemrec) - - self.assertEqual(itemrec, {"pio_iids": [iid2, iid3]}) - - # request with optional attributes - - # pio_itypes - client.identify(uid0) - try: - itemrec = client.get_itemrec_topn(engine_name, 10, {"pio_itypes": ("t1", "t2")}) - except predictionio.ItemRecNotFoundError as e: - print(e) - print("ERROR: have you run import_testdata.py and then wait for the algorithm training completion?") - raise - except: - raise - - if DEBUG: - print(itemrec) - - self.assertEqual(itemrec, {"pio_iids": [iid2, iid3, iid1, iid0]}) - - # subset itypes - client.identify(uid0) - try: - itemrec = client.get_itemrec_topn(engine_name, 10, {"pio_itypes": ("t2",)}) - except predictionio.ItemRecNotFoundError as e: - print(e) - print("ERROR: have you run import_testdata.py and then wait for the algorithm training completion?") - raise - except: - raise - - if DEBUG: - print(itemrec) - - self.assertEqual(itemrec, {"pio_iids": [iid2, iid1]}) - - # nonexisting itypes - client.identify(uid0) - try: - client.get_itemrec_topn(engine_name, 10, {"pio_itypes": ("other-itype",)}) - except predictionio.ItemRecNotFoundError as e: - print(e) - pass # expected no recommendation - except: - raise - - # pio_attributes - client.identify(uid0) - try: - itemrec = client.get_itemrec_topn(engine_name, 10, - {"pio_itypes": ("t1",), "pio_attributes": ["custom1", "custom2"]}) - except predictionio.ItemRecNotFoundError as e: - print(e) - print("ERROR: have you run import_testdata.py and then wait for the algorithm training completion?") - raise - except: - raise - - if DEBUG: - print(itemrec) - - self.assertEqual(itemrec, {"pio_iids": [iid2, iid3, iid1, iid0], "custom1": [None, None, "i1c1", "i0c1"], - "custom2": ["i2c2", None, "i1c2", None]}) - - # TODO pio_latlng - # TODO pio_within - # TODO pio_unit - - client.close() - - -if __name__ == "__main__": - unittest.main() diff --git a/tests-obsolete/predictionio_itemsim_test.py b/tests-obsolete/predictionio_itemsim_test.py deleted file mode 100644 index 45fa151..0000000 --- a/tests-obsolete/predictionio_itemsim_test.py +++ /dev/null @@ -1,200 +0,0 @@ -""" -Test getting itemsim after algo training completes (pdio-itemsimcf with cosine sim). -""" -import unittest - -import predictionio - - -APP_KEY = "gDx1XuMUC9vu1YWWPRZkLRTftoq7m73mlj2MtnZEjncPlZ1JxUS2s7oajwP9xrZQ" # replace this with your AppKey -API_URL = "http://localhost:8000" # PredictoinIO Server - -DEBUG = True - -MIN_VERSION = '0.6.0' -if predictionio.__version__ < MIN_VERSION: - err = "Require PredictionIO Python SDK version >= %s" % MIN_VERSION - raise Exception(err) - - -class TestPredictionIO(unittest.TestCase): - def setUp(self): - pass - - def tearDown(self): - pass - - def test_get_itemsim_exception(self): - client = predictionio.Client(APP_KEY, 1, API_URL) - - try: - client.get_itemsim_topn("python-itemsim-engine", "iidwithoutsim", 10) - except predictionio.ItemSimNotFoundError as e: - pass # expected exception - except: - raise - - try: - client.get_itemsim_topn("python-itemsim-engine", "iidwithoutsim", 10, - {"pio_itypes": ("t1",), "pio_latlng": [1.34, 5.67], "pio_within": 5.0, - "pio_unit": "km", "pio_attributes": ["custom1", "custom2"]}) - except predictionio.ItemSimNotFoundError as e: - if DEBUG: - print(e) - pass # expected exception - except: - raise - - client.close() - - def test_get_itemsim(self): - client = predictionio.Client(APP_KEY, 1, API_URL) - - # request more than what is available - try: - itemsim = client.get_itemsim_topn("python-itemsim-engine", "i0", 10) - except predictionio.ItemSimNotFoundError as e: - print - "ERROR: have you run import_testdata.py and then wait for the algorithm training completion?" - raise - except: - raise - - if DEBUG: - print(itemsim) - - self.assertTrue((itemsim == {"pio_iids": ["i1", "i2", "i3"]}) or - (itemsim == {"pio_iids": ["i1", "i3", "i2"]})) - - try: - itemsim = client.get_itemsim_topn("python-itemsim-engine", "i1", 10) - except predictionio.ItemSimNotFoundError as e: - print("ERROR: have you run import_testdata.py and then wait for the algorithm training completion?") - raise - except: - raise - - if DEBUG: - print(itemsim) - - self.assertTrue((itemsim == {"pio_iids": ["i2", "i3", "i0"]})) - - try: - itemsim = client.get_itemsim_topn("python-itemsim-engine", "i2", 10) - except predictionio.ItemSimNotFoundError as e: - print("ERROR: have you run import_testdata.py and then wait for the algorithm training completion?") - raise - except: - raise - - if DEBUG: - print(itemsim) - - self.assertTrue((itemsim == {"pio_iids": ["i1", "i3", "i0"]})) - - try: - itemsim = client.get_itemsim_topn("python-itemsim-engine", "i3", 10) - except predictionio.ItemSimNotFoundError as e: - print("ERROR: have you run import_testdata.py and then wait for the algorithm training completion?") - raise - except: - raise - - if DEBUG: - print(itemsim) - - self.assertTrue((itemsim == {"pio_iids": ["i1", "i2", "i0"]})) - - # request less - try: - itemsim = client.get_itemsim_topn("python-itemsim-engine", "i1", 1) - except predictionio.ItemSimNotFoundError as e: - print - "ERROR: have you run import_testdata.py and then wait for the algorithm training completion?" - raise - except: - raise - - if DEBUG: - print(itemsim) - - self.assertEqual(itemsim, {"pio_iids": ["i2"]}) - - try: - itemsim = client.get_itemsim_topn("python-itemsim-engine", "i1", 2) - except predictionio.ItemSimNotFoundError as e: - print - "ERROR: have you run import_testdata.py and then wait for the algorithm training completion?" - raise - except: - raise - - if DEBUG: - print(itemsim) - - self.assertEqual(itemsim, {"pio_iids": ["i2", "i3"]}) - - # request with optional attributes - - # pio_itypes - try: - itemsim = client.get_itemsim_topn("python-itemsim-engine", "i1", 10, {"pio_itypes": ("t1", "t2")}) - except predictionio.ItemSimNotFoundError as e: - print("ERROR: have you run import_testdata.py and then wait for the algorithm training completion?") - raise - except: - raise - - if DEBUG: - print(itemsim) - - self.assertEqual(itemsim, {"pio_iids": ["i2", "i3", "i0"]}) - - # subset itypes - try: - itemsim = client.get_itemsim_topn("python-itemsim-engine", "i1", 10, {"pio_itypes": ("t2",)}) - except predictionio.ItemSimNotFoundError as e: - print("ERROR: have you run import_testdata.py and then wait for the algorithm training completion?") - raise - except: - raise - - if DEBUG: - print(itemsim) - - self.assertEqual(itemsim, {"pio_iids": ["i2"]}) - - # nonexisting itypes - try: - itemsim = client.get_itemsim_topn("python-itemsim-engine", "i0", 10, {"pio_itypes": ("other-itype",)}) - except predictionio.ItemSimNotFoundError as e: - pass # expected no recommendation - except: - raise - - # pio_attributes - try: - itemsim = client.get_itemsim_topn("python-itemsim-engine", "i1", 10, - {"pio_itypes": ("t1",), "pio_attributes": ["custom1", "custom2"]}) - except predictionio.ItemSimNotFoundError as e: - print(e) - print("ERROR: have you run import_testdata.py and then wait for the algorithm training completion?") - raise - except: - raise - - if DEBUG: - print(itemsim) - - self.assertEqual(itemsim, {"pio_iids": ["i2", "i3", "i0"], "custom1": [None, None, "i0c1"], - "custom2": ["i2c2", None, None]}) - - # TODO pio_latlng - # TODO pio_within - # TODO pio_unit - - client.close() - - -if __name__ == "__main__": - unittest.main() diff --git a/tests-obsolete/predictionio_test.py b/tests-obsolete/predictionio_test.py deleted file mode 100644 index 696718c..0000000 --- a/tests-obsolete/predictionio_test.py +++ /dev/null @@ -1,257 +0,0 @@ -""" -Test Python SDK -""" -import unittest - -import predictionio -import time - - -APP_KEY = "gDx1XuMUC9vu1YWWPRZkLRTftoq7m73mlj2MtnZEjncPlZ1JxUS2s7oajwP9xrZQ" # replace this with your AppKey -API_URL = "http://localhost:8000" # PredictoinIO Server - -MIN_VERSION = '0.6.0' -if predictionio.__version__ < MIN_VERSION: - err = "Require PredictionIO Python SDK version >= %s" % MIN_VERSION - raise Exception(err) - -# print predictionio.__version__ -# predictionio.connection.enable_log() - - -class TestPredictionIO(unittest.TestCase): - def setUp(self): - pass - - def tearDown(self): - pass - - def test_status(self): - client = predictionio.Client(APP_KEY, 1, API_URL) - status = client.get_status() - self.assertEqual(status, "PredictionIO Output API is online.") - client.close() - - def _test_user(self, uids): - client = predictionio.Client(APP_KEY, 1, API_URL) - - uid1 = uids[0] - uid2 = uids[1] - uid3 = uids[2] - uid4 = uids[3] - uid5 = uids[4] - - # create users and get them back - client.create_user(uid1) - # create user with optional attributes - client.create_user(uid2, {"pio_latlng": [1.2, 33.3]}) - client.create_user(uid3, {"pio_latlng": [4.5, 67.8], "pio_inactive": True}) - # create user with custom attributes - client.create_user(uid4, {"pio_latlng": [1.2, 33.3], "custom1": "value1", "custom2": "value2"}) - client.create_user(uid5, {"custom1": "u5c1", "custom2": "u5c2"}) - - user1 = client.get_user(uid1) - user2 = client.get_user(uid2) - user3 = client.get_user(uid3) - user4 = client.get_user(uid4) - user5 = client.get_user(uid5) - - self.assertEqual(user1, {"pio_uid": uid1}) - self.assertEqual(user2, {"pio_uid": uid2, "pio_latlng": [1.2, 33.3]}) - self.assertEqual(user3, {"pio_uid": uid3, "pio_latlng": [4.5, 67.8], "pio_inactive": True}) - self.assertEqual(user4, {"pio_uid": uid4, "pio_latlng": [1.2, 33.3], "custom1": "value1", "custom2": "value2"}) - self.assertEqual(user5, {"pio_uid": uid5, "custom1": "u5c1", "custom2": "u5c2"}) - - # delete user and then try to get it - client.delete_user(uid1) - - try: - client.get_user(uid1) - except predictionio.UserNotFoundError as e: # noqa - pass # expected exception - except: - raise - - # other users still exist - user2 = client.get_user(uid2) - self.assertEqual(user2, {"pio_uid": uid2, "pio_latlng": [1.2, 33.3]}) - - # read, modify, write - user3 = client.get_user(uid3) - self.assertEqual(user3, {"pio_uid": uid3, "pio_latlng": [4.5, 67.8], "pio_inactive": True}) - del user3["pio_uid"] - user3["pio_latlng"] = [5.6, 10.11] - user3["pio_inactive"] = False - user3["custom1"] = "food" - client.create_user(uid3, user3) - updated_user3 = client.get_user(uid3) - self.assertEqual(updated_user3, - {"pio_uid": uid3, "pio_latlng": [5.6, 10.11], "pio_inactive": False, "custom1": "food"}) - - user4 = client.get_user(uid4) - self.assertEqual(user4, {"pio_uid": uid4, "pio_latlng": [1.2, 33.3], "custom1": "value1", "custom2": "value2"}) - del user4["pio_uid"] - user4["custom1"] = "new value" - client.create_user(uid4, user4) - updated_user4 = client.get_user(uid4) - self.assertEqual(updated_user4, - {"pio_uid": uid4, "pio_latlng": [1.2, 33.3], "custom1": "new value", "custom2": "value2"}) - - client.close() - - def test_user(self): - self._test_user(["u1", "u2", "u3", "u4", "u5"]) - # test special characters in uid - self._test_user(["u1@a.com", "u2@ap/ple", "u3@foo.bar", "u4/a/b", "&^%$()u5"]) - - def _test_item(self, iids): - client = predictionio.Client(APP_KEY, 1, API_URL) - - iid1 = iids[0] - iid2 = iids[1] - iid3 = iids[2] - iid4 = iids[3] - iid5 = iids[4] - - # create items and read back - client.create_item(iid1, ("t1", "t2", "t3")) - client.create_item(iid2, ("t1",)) - client.create_item(iid3, ("t2",), - {"pio_price": 4.99, "pio_profit": 2.0, "pio_startT": 12345667, "pio_endT": 4567788, - "pio_latlng": [1.345, 9.876], "pio_inactive": True}) - client.create_item(iid4, ("t2",), {"pio_latlng": [1.2345, 10.11], "custom1": "value1"}) - client.create_item(iid5, ("t1", "t2"), {"custom1": "i5value1", "custom2": "i5value2"}) - - item1 = client.get_item(iid1) - item2 = client.get_item(iid2) - item3 = client.get_item(iid3) - item4 = client.get_item(iid4) - item5 = client.get_item(iid5) - - del item1["pio_startT"] # pio_startT is automatically inserted, don't compare - self.assertEqual(item1, {"pio_iid": iid1, "pio_itypes": ("t1", "t2", "t3")}) - del item2["pio_startT"] - self.assertEqual(item2, {"pio_iid": iid2, "pio_itypes": ("t1",)}) - self.assertEqual(item3, {"pio_iid": iid3, "pio_itypes": ("t2",), "pio_price": 4.99, "pio_profit": 2.0, - "pio_startT": 12345667, "pio_endT": 4567788, "pio_latlng": [1.345, 9.876], - "pio_inactive": True}) - del item4["pio_startT"] - self.assertEqual(item4, - {"pio_iid": iid4, "pio_itypes": ("t2",), "pio_latlng": [1.2345, 10.11], "custom1": "value1"}) - del item5["pio_startT"] - self.assertEqual(item5, - {"pio_iid": iid5, "pio_itypes": ("t1", "t2"), "custom1": "i5value1", "custom2": "i5value2"}) - - # delete and then try to get it - client.delete_item(iid2) - - try: - item2 = client.get_item(iid2) - except predictionio.ItemNotFoundError as e: # noqa - pass # expected exception - except: - raise - - # others still exist - item3 = client.get_item(iid3) - self.assertEqual(item3, {"pio_iid": iid3, "pio_itypes": ("t2",), "pio_price": 4.99, "pio_profit": 2.0, - "pio_startT": 12345667, "pio_endT": 4567788, "pio_latlng": [1.345, 9.876], - "pio_inactive": True}) - - # read, modify, write - del item3["pio_iid"] - item3_itypes = item3.pop("pio_itypes") - item3["pio_price"] = 6.99 - item3["custom1"] = "some value" - client.create_item(iid3, item3_itypes, item3) - updated_item3 = client.get_item(iid3) - self.assertEqual(updated_item3, {"pio_iid": iid3, "pio_itypes": ("t2",), "pio_price": 6.99, "pio_profit": 2.0, - "pio_startT": 12345667, "pio_endT": 4567788, "pio_latlng": [1.345, 9.876], - "pio_inactive": True, "custom1": "some value"}) - - client.close() - - def test_item(self): - self._test_item(["i1", "i2", "i3", "i4", "i5"]) - # test special characters in iid - self._test_item(["i1@abc.com", "i2/f/bar//@@foo", "$$i3%%$~~", "http://www.i4.com", "``i5/apple/"]) - - def test_u2iAction_deprecated(self): - client = predictionio.Client(APP_KEY, 1, API_URL) - - client.user_like_item("u1", "i1") - client.user_dislike_item("u2", "i2") - client.user_view_item("u3", "i3") - client.user_rate_item("u4", "i4", 4) - client.user_conversion_item("u5", "i5") - - client.close() - - def test_u2iAction(self): - client = predictionio.Client(APP_KEY, 1, API_URL) - - client.identify("u101") - - # required param - client.record_action_on_item("like", "i1") - client.record_action_on_item("dislike", "i2") - client.record_action_on_item("view", "i3") - client.record_action_on_item("rate", "i4", {"pio_rate": 1}) - client.record_action_on_item("conversion", "i5") - - client.identify("u102") - - # with optional param - client.record_action_on_item("like", "i1", {"pio_latlng": [1.23, 4.56]}) - client.record_action_on_item("dislike", "i2", {"pio_t": 1234567689}) - client.record_action_on_item("view", "i3", {"pio_latlng": [4.67, 1.44], "pio_t": 3445566778}) - client.record_action_on_item("rate", "i4", {"pio_rate": 1, "pio_latlng": [66.78, 9.10]}) - client.record_action_on_item("conversion", "i5", {"pio_price": 12.5}) - - # uid and iid with special characters - client.identify("u1@a.com") - client.record_action_on_item("view", "i3@bb.com") - client.record_action_on_item("view", "http://www.yahoo.com") - - client.close() - - def test_pending_requests(self): - client = predictionio.Client(APP_KEY, 1, API_URL) - - client.identify("u111") - for i in range(100): - client.arecord_action_on_item("like", str(i)) - - n = 1 - while n > 0: - n = client.pending_requests() - time.sleep(0.1) - # print n - - client.close() - - def test_qsize(self): - client = predictionio.Client(APP_KEY, 1, API_URL, qsize=10) - - client.identify("u222") - for i in range(100): - client.arecord_action_on_item("like", str(i)) - - n = 1 - while n > 0: - n = client.pending_requests() - time.sleep(0.1) - # print n - - client.close() - - -""" -to run individual test: -$ python -m unittest predictionio_test.TestPredictionIO.test_user - -to run ALL tests: -% python predictionio_test.py -""" -if __name__ == "__main__": - unittest.main() diff --git a/tests/.keep b/tests/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/tests/after_script.travis.sh b/tests/after_script.travis.sh new file mode 100755 index 0000000..e2ea03f --- /dev/null +++ b/tests/after_script.travis.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +cd predictionio-setup +./bin/pio-setup stop + diff --git a/tests/before_script.travis.sh b/tests/before_script.travis.sh new file mode 100755 index 0000000..a38a6ee --- /dev/null +++ b/tests/before_script.travis.sh @@ -0,0 +1,27 @@ +#!/bin/sh + +mkdir -p predictionio-setup/bin +cd predictionio-setup +curl -o bin/pio-setup https://raw.githubusercontent.com/jpioug/predictionio-setup/master/bin/pio-setup +chmod +x bin/pio-setup + +PIO_GIT_USER=apache PIO_GIT_BRANCH=develop PIO_EVENTDATA_REFRESH=true ./bin/pio-setup deploy +touch target/pio-setup.log +tail -f target/pio-setup.log & + +counter=1 +ret=7 +while [ $ret = 7 -a $counter != 10 ] ; do + ./bin/pio-setup start + sleep 5 + curl -v 127.0.0.1:7070/events.json + ret=$? + echo "Checking Java processes..." + ps aux | grep java + echo "Checking 7070 port..." + netstat | grep 7070 + counter=`expr $counter + 1` +done + +./bin/pio-setup status +tail -f ~/pio.log & diff --git a/tests/engineclient_test.py b/tests/engineclient_test.py new file mode 100644 index 0000000..276328b --- /dev/null +++ b/tests/engineclient_test.py @@ -0,0 +1,48 @@ +import random +import subprocess +import unittest + +from predictionio import EventClient + +app_name ='EngineClientApp' +access_key = 'FILE_EXPORT_TEST' + +class EngineClientTest(unittest.TestCase): + + def setUp(self): + subprocess.call(['pio', 'app', 'new', '--access-key', access_key, app_name]) + + def tearDown(self): + subprocess.call(['pio', 'app', 'delete', '-f', app_name]) + + def test_query(self): + random.seed() + + client = EventClient(access_key=access_key, url="http://127.0.0.1:7070") + + # Check status + print("Check status") + print(client.get_status()) + self.assertEqual(client.get_status(), {'status': 'alive'}) + + user_ids = [str(i) for i in range(1, 3)] + for user_id in user_ids: + print("Set user", user_id) + client.set_user(user_id) + # TODO assert + + item_ids = [str(i) for i in range(1, 5)] + for item_id in item_ids: + print("Set item", item_id) + client.set_item(item_id, {"itypes": ['1']}) + # TODO assert + + # each user randomly views 10 items + for user_id in user_ids: + for viewed_item in random.sample(item_ids, 2): + print("User", user_id, "views item", viewed_item) + client.record_user_action_on_item("view", user_id, viewed_item) + # TODO assert + + client.close() + diff --git a/tests/eventclient_test.py b/tests/eventclient_test.py new file mode 100644 index 0000000..900c48b --- /dev/null +++ b/tests/eventclient_test.py @@ -0,0 +1,251 @@ +import pytz +import subprocess +import unittest + +from datetime import datetime +from predictionio import EventClient +from predictionio import NotFoundError + +app_name ='EventClientApp' +access_key = 'EVENT_CLIENT_TEST' +channel = 'Test' + +class EventClientTest(unittest.TestCase): + + def setUp(self): + subprocess.call(['pio', 'app', 'new', '--access-key', access_key, app_name]) + subprocess.call(['pio', 'app', 'show', app_name]) + + def tearDown(self): + subprocess.call(['pio', 'app', 'delete', '-f', app_name]) + + def test_eventclient(self): + client = EventClient(access_key=access_key, url="http://127.0.0.1:7070") + + # Check status + print("Check status") + print(client.get_status()) + self.assertEqual(client.get_status(), {'status': 'alive'}) + + # First event + first_event_properties = { + "prop1": 1, + "prop2": "value2", + "prop3": [1, 2, 3], + "prop4": True, + "prop5": ["a", "b", "c"], + "prop6": 4.56, + } + first_event_time = datetime( + 2004, 12, 13, 21, 39, 45, 618000, pytz.timezone('US/Mountain')) + first_event_response = client.create_event( + event="my_event", + entity_type="user", + entity_id="uid", + properties=first_event_properties, + event_time=first_event_time, + ) + print("First Event response") + print(first_event_response) + self.assertEqual(first_event_response.status, 201) + + # Second event + second_event_properties = { + "someProperty": "value1", + "anotherProperty": "value2", + } + second_event_response = client.create_event( + event="my_event", + entity_type="user", + entity_id="uid", + target_entity_type="item", + target_entity_id="iid", + properties=second_event_properties, + event_time=datetime(2014, 12, 13, 21, 38, 45, 618000, pytz.utc)) + print("Second Event response") + print(second_event_response) + self.assertEqual(second_event_response.status, 201) + + + # Get the first event from Event Server + first_event_id = first_event_response.json_body["eventId"] + print("Get Event") + event = client.get_event(first_event_id) + print(event) + self.assertEqual(event.get('eventId'), first_event_id) + + + # Delete the first event from Event Server + print("Delete Event") + delete_response = client.delete_event(first_event_id) + print(delete_response) + self.assertEqual(delete_response.decode('utf-8'), '{"message":"Found"}') + + + # Delete the first event from Event Server again should yield exception. + print("Delete Event Again") + try: + delete_response = client.delete_event(first_event_id) + self.fail() + except NotFoundError as ex: + print("The expected error: {0}".format(ex)) + + + # "user"-helper methods + + # Set user properties implicitly create a user + # This call creates a user "foo", and set the properties of "foo". + print("Create user foo") + foo_properties = {"city": "sunnyvale", "car": "honda fit"} + response = client.set_user("foo", properties=foo_properties) + print(response) + self.assertEqual(response.status, 201) + + # This call overrides the existing properties for user "foo", setting "car" to + # a new "honda odyssey" and create a new property "food" to "seafood". + print("Set new properties") + foo_properties = {"car": "honda odyssey", "food": "seafood"} + response = client.set_user("foo", properties=foo_properties) + print(response) + self.assertEqual(response.status, 201) + + # This call removes the specified properties. It ignores the value of the dict. + # After this call, the "city" will become an unset field. + print("Unset properties") + foo_properties = {"city": "x"} + response = client.unset_user("foo", properties=foo_properties) + print(response) + self.assertEqual(response.status, 201) + + # This call deletes a user + print("Delete user") + response = client.delete_user("foo") + print(response) + self.assertEqual(response.status, 201) + + # The SDK also support specifying the eventTime. It is useful for importing + # events happened in the past. + foo_time = datetime(2014, 8, 31, 4, 56, tzinfo=pytz.timezone('US/Pacific')) + print("Create user at " + str(foo_time)) + response = client.set_user("Jarvis", {}, foo_time) + print(response) + self.assertEqual(response.status, 201) + + # "item"-helper methods + + # Set item properties implicitly create a item + # This call creates a item "bar", and set the properties of "bar". + print("Create item bar") + bar_properties = {"city": "santa clara", "weight": 6.9} + response = client.set_item("bar", properties=bar_properties) + print(response) + self.assertEqual(response.status, 201) + + # Similar to user-methods, we can do the same thing with item + print("Set new properties") + bar_properties = {"weight": 6.2} + response = client.set_item("bar", properties=bar_properties) + print(response) + self.assertEqual(response.status, 201) + + # This call removes the specified properties. It ignores the value of the dict. + # After this call, the "city" will become an unset field. + print("Unset properties") + bar_properties = {"city": None} + response = client.unset_item("bar", properties=bar_properties) + print(response) + self.assertEqual(response.status, 201) + + # This call deletes a item + print("Delete item") + response = client.delete_item("bar") + print(response) + self.assertEqual(response.status, 201) + + + # "record" action helper functions + + # This call creates a event between a user and an item. In particular, this set + # the price of the action + print("Record user action") + action_properties = {"price": 10.0} + response = client.record_user_action_on_item("buy", "foo", "bar", action_properties) + print(response) + self.assertEqual(response.status, 201) + + + def test_eventclient_channel(self): + subprocess.call(['pio', 'app', 'channel-new', app_name, channel]) + + client = EventClient(access_key=access_key, url="http://127.0.0.1:7070", + channel=channel) + + # Check status + print("Check status") + print(client.get_status()) + self.assertEqual(client.get_status(), {'status': 'alive'}) + + # First event + first_event_properties = { + "prop1" : 1, + "prop2" : "value2", + "prop3" : [1, 2, 3], + "prop4" : True, + "prop5" : ["a", "b", "c"], + "prop6" : 4.56 , + } + first_event_time = datetime( + 2004, 12, 13, 21, 39, 45, 618000, pytz.timezone('US/Mountain')) + first_event_response = client.create_event( + event="my_event", + entity_type="user", + entity_id="uid", + properties=first_event_properties, + event_time=first_event_time, + ) + print("First Event response") + print(first_event_response) + self.assertEqual(first_event_response.status, 201) + + # Second event + second_event_properties = { + "someProperty" : "value1", + "anotherProperty" : "value2", + } + second_event_response = client.create_event( + event="my_event", + entity_type="user", + entity_id="uid", + target_entity_type="item", + target_entity_id="iid", + properties=second_event_properties, + event_time=datetime(2014, 12, 13, 21, 38, 45, 618000, pytz.utc)) + print("Second Event response") + print(second_event_response) + self.assertEqual(second_event_response.status, 201) + + + # Get the first event from Event Server + first_event_id = first_event_response.json_body["eventId"] + print("Get Event") + event = client.get_event(first_event_id) + print(event) + self.assertEqual(event.get('eventId'), first_event_id) + + # Delete the first event from Event Server + print("Delete Event") + delete_response = client.delete_event(first_event_id) + print(delete_response) + self.assertEqual(delete_response.decode('utf-8'), '{"message":"Found"}') + + # Delete the first event from Event Server again should yield exception. + print("Delete Event Again") + try: + delete_response = client.delete_event(first_event_id) + self.fail() + except NotFoundError as ex: + print("The expected error: {0}".format(ex)) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/fileexport_test.py b/tests/fileexport_test.py new file mode 100644 index 0000000..0fad97e --- /dev/null +++ b/tests/fileexport_test.py @@ -0,0 +1,74 @@ +import pytz +import re +import subprocess +import unittest + +from datetime import datetime +import predictionio +from predictionio import EventClient + +app_name ='FileExporterApp' +access_key = 'FILE_EXPORT_TEST' +filename = 'export_events.json' + +class FileExporterTest(unittest.TestCase): + + def setUp(self): + subprocess.call(['pio', 'app', 'new', '--access-key', access_key, app_name]) + + def tearDown(self): + subprocess.call(['pio', 'app', 'delete', '-f', app_name]) + + def test_export(self): + app_info = subprocess.check_output(['pio', 'app', 'show', app_name]) + app_id = re.search('App ID: ([0-9]+)', app_info.decode('utf-8')).group(1) + print(app_id) + + exporter = predictionio.FileExporter(file_name=filename) + + first_event_properties = { + "prop1" : 1, + "prop2" : "value2", + "prop3" : [1, 2, 3], + "prop4" : True, + "prop5" : ["a", "b", "c"], + "prop6" : 4.56 , + } + first_event_time = datetime( + 2004, 12, 13, 21, 39, 45, 618000, pytz.timezone('US/Mountain')) + exporter.create_event( + event="my_event", + entity_type="user", + entity_id="uid", + properties=first_event_properties, + event_time=first_event_time, + ) + + # Second event + second_event_properties = { + "someProperty" : "value1", + "anotherProperty" : "value2", + } + exporter.create_event( + event="my_event", + entity_type="user", + entity_id="uid", + target_entity_type="item", + target_entity_id="iid", + properties=second_event_properties, + event_time=datetime(2014, 12, 13, 21, 38, 45, 618000, pytz.utc)) + + exporter.close() + + subprocess.call(['pio', 'import', '--appid', app_id, '--input ', filename]) + + # TODO + # client = EventClient(access_key=access_key, url="http://127.0.0.1:7070") + # + # print("Get Event") + # event = client.get_event(event_id) + # print(event) + # self.assertEqual(event.get('eventId'), event_id) + +if __name__ == "__main__": + unittest.main() diff --git a/tox.ini b/tox.ini index 87b57e9..6f5cd20 100644 --- a/tox.ini +++ b/tox.ini @@ -1,13 +1,12 @@ [tox] -envlist = py27,py34 +envlist = py27,py34,py35,py36 [testenv] deps = flake8 - pandas +passenv = HOME TRAVIS* +commands = python -m unittest discover --pattern=*.py tests [flake8] ignore = E111 - commands = flake8 --ignore=E501 --filename=*.py --exclude=doc,setup.py,*/tests/* - python -m unittest discover --pattern=*.py tests From a151e0cdfc9f84334cb29c6bb429a829606f5c4b Mon Sep 17 00:00:00 2001 From: goodspeed Date: Sun, 10 Sep 2017 23:12:50 +0900 Subject: [PATCH 02/11] fix InvalidArgumentError is not defined Closes #19 --- predictionio/__init__.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/predictionio/__init__.py b/predictionio/__init__.py index 01ac045..d70c85c 100644 --- a/predictionio/__init__.py +++ b/predictionio/__init__.py @@ -47,6 +47,10 @@ class NotFoundError(PredictionIOAPIError): pass +class InvalidArgumentError(PredictionIOAPIError): + pass + + def event_time_validation(t): """ Validate event_time according to EventAPI Specification. """ From 88a11a84eac281c06b9a29fa90323ff4c706401e Mon Sep 17 00:00:00 2001 From: Shinsuke Sugaya Date: Sun, 10 Sep 2017 23:16:45 +0900 Subject: [PATCH 03/11] add test case and remove unused imports --- predictionio/__init__.py | 2 -- tests/eventclient_test.py | 8 ++++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/predictionio/__init__.py b/predictionio/__init__.py index d70c85c..c067689 100644 --- a/predictionio/__init__.py +++ b/predictionio/__init__.py @@ -28,14 +28,12 @@ from urllib.parse import quote import json -import urllib from datetime import datetime import pytz from predictionio.connection import Connection from predictionio.connection import AsyncRequest -from predictionio.connection import AsyncResponse from predictionio.connection import PredictionIOAPIError diff --git a/tests/eventclient_test.py b/tests/eventclient_test.py index 900c48b..ac8a72d 100644 --- a/tests/eventclient_test.py +++ b/tests/eventclient_test.py @@ -5,6 +5,7 @@ from datetime import datetime from predictionio import EventClient from predictionio import NotFoundError +from predictionio import InvalidArgumentError app_name ='EventClientApp' access_key = 'EVENT_CLIENT_TEST' @@ -246,6 +247,13 @@ def test_eventclient_channel(self): except NotFoundError as ex: print("The expected error: {0}".format(ex)) + def test_invalidurl(self): + try: + EventClient(access_key=access_key, url="invalid") + self.fail() + except InvalidArgumentError as ex: + print("The expected error: {0}".format(ex)) + if __name__ == "__main__": unittest.main() From 55109536075352a555ab7f56f7ba4b8e0ea539af Mon Sep 17 00:00:00 2001 From: thomas-idmt Date: Sun, 10 Sep 2017 23:19:12 +0900 Subject: [PATCH 04/11] Update __init__.py (Updated Deprecation Error Message) Closes #15 --- predictionio/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/predictionio/__init__.py b/predictionio/__init__.py index c067689..3ef8d96 100644 --- a/predictionio/__init__.py +++ b/predictionio/__init__.py @@ -183,8 +183,8 @@ def __init__(self, access_key, if len(access_key) <= 8: raise DeprecationWarning( - "It seems like you are specifying an app_id. It is deprecated in " - "Prediction.IO 0.8.2. Please use access_key instead. Or, " + "The entered access key is very short, it seems like you are specifying an app_id." + "This is deprecated in Prediction.IO 0.8.2. Please use (a longer) access_key instead. Or, " "you may use an earlier version of this sdk.") self.access_key = access_key From 4b51a300e95c123de67742f7679d55f8045e07d7 Mon Sep 17 00:00:00 2001 From: Shinsuke Sugaya Date: Sun, 10 Sep 2017 23:20:52 +0900 Subject: [PATCH 05/11] Closes #21 From 579ab327d3ef8685f7e98bd97c4320e331d4272a Mon Sep 17 00:00:00 2001 From: Shinsuke Sugaya Date: Wed, 13 Sep 2017 15:15:37 +0900 Subject: [PATCH 06/11] ignore .DS_Store --- .DS_Store | Bin 6148 -> 0 bytes .gitignore | 1 + 2 files changed, 1 insertion(+) delete mode 100644 .DS_Store diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index af48d0a74eed77eb15d165e4a60516f93535f3c1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHK%}N6?5T3MEcd6(Kf_lr%OAnQb;>o4flNX_44=TFr7P?S2rQOm)E$l_`_c=tL zNbqHxNkXAi!IOxcfthbInaPqbkn8|}sP>~R01p5hRKlE#<_n>D(kaQ=h(JWeHDb7i z6s>|}Dw_j;kpVipMd&~mnh;H#AD&`3=yk%j3Nhy+?6l)vS}wnfT)r?jzu>rT(Jd}5 z7cc59HK?aS+V53^?ir1agR~V||3sf$(RV#;|VP9im^ zs(upn&g&-Fh@-Tn7qtP$aUJ*4TN@55+j}Lsw=*iq;qGp^B)50Uqmg&(Ivbmn{i9Ib z+}%GsK0Uv@8r}tMm1M=h*uITDc9;QXfEkz(2JD6C6lY|=yiI0+8TdH^bU#Q`Lf>L$ zP+uKrbPIr3z_1qdsh6M{Y0b_y3bcJYoizfq%t-DAek;DsIWXty7z$w^pKF rp^{KuW^i1Bj(& Date: Mon, 18 Sep 2017 09:42:22 +0900 Subject: [PATCH 07/11] Update project info Closes #23 --- LICENSE.txt | 209 +++++++++++++++++++++++++++++++++++++++++++++++++--- setup.py | 10 +-- 2 files changed, 204 insertions(+), 15 deletions(-) diff --git a/LICENSE.txt b/LICENSE.txt index 11c8530..d645695 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,13 +1,202 @@ -Copyright 2013 TappingStone Inc. -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ - http://www.apache.org/licenses/LICENSE-2.0 + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/setup.py b/setup.py index eeafe17..f34003f 100644 --- a/setup.py +++ b/setup.py @@ -3,9 +3,9 @@ except ImportError: from distutils.core import setup -__author__ = "The PredictionIO Team" -__email__ = "help@tappingstone.com" -__copyright__ = "Copyright 2014, TappingStone, Inc." +__author__ = "Apache PredictionIO" +__email__ = "user@predictionio.incubator.apache.org" +__copyright__ = "Copyright 2017 The Apache Software Foundation" __license__ = "Apache License, Version 2.0" setup( @@ -14,7 +14,7 @@ author=__author__, author_email=__email__, packages=['predictionio'], - url='http://prediction.io', + url='http://predictionio.incubator.apache.org/', license='LICENSE.txt', description='PredictionIO Python SDK', classifiers=[ @@ -44,7 +44,7 @@ - without worrying about scalability Detailed documentation is available on our - `documentation site `_. + `documentation site `_. This module provides convenient access of the PredictionIO API to Python programmers so that they From 72a509296d355328bdfaa7a4125ff65496d0d937 Mon Sep 17 00:00:00 2001 From: Shinsuke Sugaya Date: Thu, 19 Oct 2017 17:50:19 +0900 Subject: [PATCH 08/11] Prepare 0.9.9rc1 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index f34003f..fd735a0 100644 --- a/setup.py +++ b/setup.py @@ -10,7 +10,7 @@ setup( name='PredictionIO', - version="0.9.8", + version="0.9.9", author=__author__, author_email=__email__, packages=['predictionio'], From 4d8c843e3f7d940c8df01b2295d086857391ae40 Mon Sep 17 00:00:00 2001 From: Shinsuke Sugaya Date: Fri, 20 Oct 2017 22:12:44 +0900 Subject: [PATCH 09/11] update to 0.9.9 in __init__.py and remove incubator --- README.txt | 2 +- predictionio/__init__.py | 2 +- setup.py | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.txt b/README.txt index 4740ff5..9a7da1d 100644 --- a/README.txt +++ b/README.txt @@ -48,7 +48,7 @@ To view the generated documentation, go to docs/build/html/index.html. SUPPORT ======= -http://predictionio.incubator.apache.org/support/ +http://predictionio.apache.org/support/ Issue Tracker diff --git a/predictionio/__init__.py b/predictionio/__init__.py index 3ef8d96..a20f4cc 100644 --- a/predictionio/__init__.py +++ b/predictionio/__init__.py @@ -4,7 +4,7 @@ """ -__version__ = "0.9.8" +__version__ = "0.9.9" # import packages import re diff --git a/setup.py b/setup.py index fd735a0..968a9e5 100644 --- a/setup.py +++ b/setup.py @@ -4,7 +4,7 @@ from distutils.core import setup __author__ = "Apache PredictionIO" -__email__ = "user@predictionio.incubator.apache.org" +__email__ = "user@predictionio.apache.org" __copyright__ = "Copyright 2017 The Apache Software Foundation" __license__ = "Apache License, Version 2.0" @@ -14,7 +14,7 @@ author=__author__, author_email=__email__, packages=['predictionio'], - url='http://predictionio.incubator.apache.org/', + url='http://predictionio.apache.org/', license='LICENSE.txt', description='PredictionIO Python SDK', classifiers=[ @@ -44,7 +44,7 @@ - without worrying about scalability Detailed documentation is available on our - `documentation site `_. + `documentation site `_. This module provides convenient access of the PredictionIO API to Python programmers so that they From 766fd9e7b72e7916a57c5d7f3bd4632758293e5f Mon Sep 17 00:00:00 2001 From: Shinsuke Sugaya Date: Wed, 25 Oct 2017 22:33:46 +0900 Subject: [PATCH 10/11] bump up version to 0.9.10.dev1 --- predictionio/__init__.py | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/predictionio/__init__.py b/predictionio/__init__.py index a20f4cc..fcb649c 100644 --- a/predictionio/__init__.py +++ b/predictionio/__init__.py @@ -4,7 +4,7 @@ """ -__version__ = "0.9.9" +__version__ = "0.9.10.dev1" # import packages import re diff --git a/setup.py b/setup.py index 968a9e5..f697be5 100644 --- a/setup.py +++ b/setup.py @@ -10,7 +10,7 @@ setup( name='PredictionIO', - version="0.9.9", + version="0.9.10.dev1", author=__author__, author_email=__email__, packages=['predictionio'], From 0de59e3d72afd2ba30121c2ab033715eb63e879f Mon Sep 17 00:00:00 2001 From: Shinsuke Sugaya Date: Wed, 25 Oct 2017 22:54:37 +0900 Subject: [PATCH 11/11] add release procedure --- PMC.md | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 PMC.md diff --git a/PMC.md b/PMC.md new file mode 100644 index 0000000..6e71c45 --- /dev/null +++ b/PMC.md @@ -0,0 +1,94 @@ + + +# Project Management Committee Documentation + +## Release Procedure + +1. Generate code signing key if you do not already have one for Apache. Refer to +http://apache.org/dev/openpgp.html#generate-key on how to generate a strong code +signing key. +2. Add your public key to the `KEYS` file at the root of the source code tree. +3. Create a new release branch, with version bumped to the next release version. + 1. `git checkout -b release/0.9.9` + 2. Replace all `0.9.9.dev0` in the code tree to `0.9.9`. + 3. `git commit -am "Prepare 0.9.9rc1"` + 4. `git tag -am "Apache PredictionIO Python SDK 0.9.9rc1" v0.9.9rc1` +4. Package a binary/source files. + 1. `python setup.py sdist bdist_wheel` +5. Generate MD5 and SHA512 checksums for the release candidates in dist directory. + 1. `gpg --print-md MD5 PredictionIO-0.9.9-py3-none-any.whl > + PredictionIO-0.9.9-py3-none-any.whl.md5` + 2. `gpg --print-md SHA512 PredictionIO-0.9.9-py3-none-any.whl > + PredictionIO-0.9.9-py3-none-any.whl.sha512` + 3. `gpg --print-md MD5 PredictionIO-0.9.9.tar.gz > + PredictionIO-0.9.9.tar.gz.md5` + 4. `gpg --print-md SHA512 PredictionIO-0.9.9.tar.gz > + PredictionIO-0.9.9.tar.gz.sha512` +6. Generate detached signature for the release candidate. +(http://apache.org/dev/release-signing.html#openpgp-ascii-detach-sig) + 1. `gpg --armor --output PredictionIO-0.9.9-py3-none-any.whl.asc + --detach-sig PredictionIO-0.9.9-py3-none-any.whl` + 2. `gpg --armor --output PredictionIO-0.9.9.tar.gz.asc + --detach-sig PredictionIO-0.9.9.tar.gz` +7. If you have not done so, use SVN to checkout + https://dist.apache.org/repos/dist/dev/incubator/predictionio/sdk-python. + This is the area for staging release candidates for voting. + 1. `svn co https://dist.apache.org/repos/dist/dev/incubator/predictionio/sdk-python` +8. Create a subdirectory at the SVN staging area. The area should have a `KEYS` file. + 1. `mkdir 0.9.9rc1` + 2. `cp PredictionIO-0.9.9* 0.9.9rc1` +9. If you have updated the `KEYS` file, also copy that to the staging area. +10. `svn commit` +13. Wait for Travis to pass build on the release branch. +14. Tag the release branch with a rc tag, e.g. `0.9.9rc1`. +15. Send out e-mail for voting on PredictionIO dev mailing list. + + ``` + Subject: [VOTE] Apache PredictionIO SDK Python 0.9.9 Release (RC1) + + This is the vote for 0.9.9 of Apache PredictionIO. + + The vote will run for at least 72 hours and will close on Apr 7th, 2017. + + The release candidate artifacts can be downloaded here: + https://dist.apache.org/repos/dist/dev/incubator/predictionio/sdk-python/0.9.9rc1/ + + Test results can be found here: + https://travis-ci.org/apache/incubator-predictionio-sdk-python/builds/XXXXXX + + To install this python module: + $ pip install PredictionIO-0.9.9.tar.gz + or + $ pip3 install PredictionIO-0.9.9-py3-none-any.whl + + The artifacts have been signed with Key : YOUR_KEY_ID + + Please vote accordingly: + + [ ] +1, accept RC as the official 0.9.9 release + [ ] 0, neutral because... + [ ] -1, do not accept RC as the official 0.9.9 release because... + ``` +16. Publish files to PyPI if the vote is passed. + 1. `twine upload dist/PredictionIO-0.9.9.tar.gz dist/PredictionIO-0.9.9.tar.gz.asc \ + dist/PredictionIO-0.9.9-py3-none-any.whl dist/PredictionIO-0.9.9-py3-none-any.whl.asc` +17. Create release tag + 1. `git tag -am "Apache PredictionIO Python SDK 0.9.9" v0.9.9` +18. Merge release/0.9.9 into master and develop branch +19. Bump up version in setup.py on develop branch +