From 360e53323c976d65e74323e963e573e028f4dba5 Mon Sep 17 00:00:00 2001 From: "Philip I. Thomas" Date: Sat, 2 Apr 2016 16:00:03 -0700 Subject: [PATCH 01/27] Prevent rate limiting --- README.md | 5 ++++- staffjoy/config.py | 1 + staffjoy/resource.py | 9 +++++++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e8be083..88077bb 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,10 @@ Authentication keys are currently tied to an individual user's account. To issue To get your organization ID, look at the URL path when you go to the Manager app while logged in. +## Rate Limits + +This client sleeps for .5 seconds after every request. Thus, in a single thread, requests are limited to 120 per minute. This is done to avoid rate limiting. Staffjoy's API currently rate limits to 300 requests per second across keys and IPs. Thus, by using this library, you should never encounter a rate limit (assuming one executing thread per IP address). + ## Updates If you use this library, please subscribe to the [Staffjoy API Updates Google Group](https://groups.google.com/forum/#!forum/staffjoy-api-updates) for important notifications about changes and deprecations. @@ -62,4 +66,3 @@ loc.delete() ``` - diff --git a/staffjoy/config.py b/staffjoy/config.py index 4b09018..514058f 100644 --- a/staffjoy/config.py +++ b/staffjoy/config.py @@ -5,6 +5,7 @@ class DefaultConfig: ENV = "prod" LOG_LEVEL = logging.INFO BASE = "https://www.staffjoy.com/api/v2/" + REQUEST_SLEEP = 0.5 class StageConfig(DefaultConfig): diff --git a/staffjoy/resource.py b/staffjoy/resource.py index 87438c5..e826036 100644 --- a/staffjoy/resource.py +++ b/staffjoy/resource.py @@ -1,4 +1,5 @@ import requests +import time from copy import copy from .config import config_from_env @@ -70,6 +71,7 @@ def get_all(cls, parent=None, **params): r = requests.get(base_obj._url(), auth=(base_obj.key, ""), params=params) + time.sleep(config.REQUEST_SLEEP) if r.status_code not in cls.TRUTHY_CODES: return base_obj._handle_request_exception(r) @@ -117,6 +119,8 @@ def _handle_request_exception(request): def fetch(self): """Perform a read request against the resource""" r = requests.get(self._url(), auth=(self.key, "")) + time.sleep(config.REQUEST_SLEEP) + if r.status_code not in self.TRUTHY_CODES: return self._handle_request_exception(r) @@ -138,12 +142,16 @@ def delete(self): """Delete the object""" r = requests.delete(self._url(), auth=(self.key, "")) + time.sleep(config.REQUEST_SLEEP) + if r.status_code not in self.TRUTHY_CODES: return self._handle_request_exception(r) def patch(self, **kwargs): """Change attributes of the item""" r = requests.patch(self._url(), auth=(self.key, ""), data=kwargs) + time.sleep(config.REQUEST_SLEEP) + if r.status_code not in self.TRUTHY_CODES: return self._handle_request_exception(r) @@ -165,6 +173,7 @@ def create(cls, parent=None, **kwargs): obj = cls(key=parent.key, route=route, config=parent.config) response = requests.post(obj._url(), auth=(obj.key, ""), data=kwargs) + time.sleep(config.REQUEST_SLEEP) if response.status_code not in cls.TRUTHY_CODES: return cls._handle_request_exception(response) From 4b197d3837fdd6639d1bf7341a311bc78f606063 Mon Sep 17 00:00:00 2001 From: "Philip I. Thomas" Date: Sat, 2 Apr 2016 16:06:25 -0700 Subject: [PATCH 02/27] This is why we have testing --- staffjoy/resource.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/staffjoy/resource.py b/staffjoy/resource.py index e826036..53a945e 100644 --- a/staffjoy/resource.py +++ b/staffjoy/resource.py @@ -71,7 +71,7 @@ def get_all(cls, parent=None, **params): r = requests.get(base_obj._url(), auth=(base_obj.key, ""), params=params) - time.sleep(config.REQUEST_SLEEP) + time.sleep(self.config.REQUEST_SLEEP) if r.status_code not in cls.TRUTHY_CODES: return base_obj._handle_request_exception(r) @@ -119,7 +119,7 @@ def _handle_request_exception(request): def fetch(self): """Perform a read request against the resource""" r = requests.get(self._url(), auth=(self.key, "")) - time.sleep(config.REQUEST_SLEEP) + time.sleep(self.config.REQUEST_SLEEP) if r.status_code not in self.TRUTHY_CODES: return self._handle_request_exception(r) @@ -142,7 +142,7 @@ def delete(self): """Delete the object""" r = requests.delete(self._url(), auth=(self.key, "")) - time.sleep(config.REQUEST_SLEEP) + time.sleep(self.config.REQUEST_SLEEP) if r.status_code not in self.TRUTHY_CODES: return self._handle_request_exception(r) @@ -150,7 +150,7 @@ def delete(self): def patch(self, **kwargs): """Change attributes of the item""" r = requests.patch(self._url(), auth=(self.key, ""), data=kwargs) - time.sleep(config.REQUEST_SLEEP) + time.sleep(self.config.REQUEST_SLEEP) if r.status_code not in self.TRUTHY_CODES: return self._handle_request_exception(r) @@ -173,7 +173,7 @@ def create(cls, parent=None, **kwargs): obj = cls(key=parent.key, route=route, config=parent.config) response = requests.post(obj._url(), auth=(obj.key, ""), data=kwargs) - time.sleep(config.REQUEST_SLEEP) + time.sleep(self.config.REQUEST_SLEEP) if response.status_code not in cls.TRUTHY_CODES: return cls._handle_request_exception(response) From a75fcbe6b822506fe7780c1c1857247d3eb92f10 Mon Sep 17 00:00:00 2001 From: "Philip I. Thomas" Date: Sat, 2 Apr 2016 16:07:30 -0700 Subject: [PATCH 03/27] version bump --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index d896206..2d44b61 100644 --- a/setup.py +++ b/setup.py @@ -1,6 +1,6 @@ from setuptools import setup, find_packages -version = "0.13" +version = "0.14" setup(name="staffjoy", packages=find_packages(), version=version, From db606c33054b6a038ed3fa922453d3139f3fb39e Mon Sep 17 00:00:00 2001 From: "Philip I. Thomas" Date: Sat, 2 Apr 2016 16:11:57 -0700 Subject: [PATCH 04/27] Fix for class methods --- staffjoy/resource.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/staffjoy/resource.py b/staffjoy/resource.py index 53a945e..80be980 100644 --- a/staffjoy/resource.py +++ b/staffjoy/resource.py @@ -7,6 +7,9 @@ class Resource: + # Seconds to sleep between requests (bc of rate limits) + REQUEST_SLEEP = 0.5 + PATH = "" # URL path added to base, including route variables ID_NAME = None # What is this ID called in the route of children? META_ENVELOPES = [] # Metadata keys for what to unpack from response @@ -71,7 +74,7 @@ def get_all(cls, parent=None, **params): r = requests.get(base_obj._url(), auth=(base_obj.key, ""), params=params) - time.sleep(self.config.REQUEST_SLEEP) + time.sleep(self.REQUEST_SLEEP) if r.status_code not in cls.TRUTHY_CODES: return base_obj._handle_request_exception(r) @@ -119,7 +122,7 @@ def _handle_request_exception(request): def fetch(self): """Perform a read request against the resource""" r = requests.get(self._url(), auth=(self.key, "")) - time.sleep(self.config.REQUEST_SLEEP) + time.sleep(self.REQUEST_SLEEP) if r.status_code not in self.TRUTHY_CODES: return self._handle_request_exception(r) @@ -142,7 +145,7 @@ def delete(self): """Delete the object""" r = requests.delete(self._url(), auth=(self.key, "")) - time.sleep(self.config.REQUEST_SLEEP) + time.sleep(self.REQUEST_SLEEP) if r.status_code not in self.TRUTHY_CODES: return self._handle_request_exception(r) @@ -150,7 +153,7 @@ def delete(self): def patch(self, **kwargs): """Change attributes of the item""" r = requests.patch(self._url(), auth=(self.key, ""), data=kwargs) - time.sleep(self.config.REQUEST_SLEEP) + time.sleep(self.REQUEST_SLEEP) if r.status_code not in self.TRUTHY_CODES: return self._handle_request_exception(r) @@ -173,7 +176,7 @@ def create(cls, parent=None, **kwargs): obj = cls(key=parent.key, route=route, config=parent.config) response = requests.post(obj._url(), auth=(obj.key, ""), data=kwargs) - time.sleep(self.config.REQUEST_SLEEP) + time.sleep(self.REQUEST_SLEEP) if response.status_code not in cls.TRUTHY_CODES: return cls._handle_request_exception(response) From 87f0e815c14ea187df82e4f343fdddf642f8be9b Mon Sep 17 00:00:00 2001 From: "Philip I. Thomas" Date: Sat, 2 Apr 2016 16:16:11 -0700 Subject: [PATCH 05/27] oops - some are instantiated --- staffjoy/resource.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/staffjoy/resource.py b/staffjoy/resource.py index 80be980..d66ac6e 100644 --- a/staffjoy/resource.py +++ b/staffjoy/resource.py @@ -74,7 +74,7 @@ def get_all(cls, parent=None, **params): r = requests.get(base_obj._url(), auth=(base_obj.key, ""), params=params) - time.sleep(self.REQUEST_SLEEP) + time.sleep(cls.REQUEST_SLEEP) if r.status_code not in cls.TRUTHY_CODES: return base_obj._handle_request_exception(r) @@ -176,7 +176,7 @@ def create(cls, parent=None, **kwargs): obj = cls(key=parent.key, route=route, config=parent.config) response = requests.post(obj._url(), auth=(obj.key, ""), data=kwargs) - time.sleep(self.REQUEST_SLEEP) + time.sleep(cls.REQUEST_SLEEP) if response.status_code not in cls.TRUTHY_CODES: return cls._handle_request_exception(response) From 4f68c0cdefb06c95f9e716325c9b7d3bce4b3a27 Mon Sep 17 00:00:00 2001 From: andhess Date: Thu, 14 Apr 2016 15:26:18 -0700 Subject: [PATCH 06/27] recurring shifts api --- setup.py | 2 +- staffjoy/resources/recurring_shift.py | 6 ++++++ staffjoy/resources/role.py | 10 ++++++++++ 3 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 staffjoy/resources/recurring_shift.py diff --git a/setup.py b/setup.py index 2d44b61..b122b11 100644 --- a/setup.py +++ b/setup.py @@ -1,6 +1,6 @@ from setuptools import setup, find_packages -version = "0.14" +version = "0.15" setup(name="staffjoy", packages=find_packages(), version=version, diff --git a/staffjoy/resources/recurring_shift.py b/staffjoy/resources/recurring_shift.py new file mode 100644 index 0000000..8298c98 --- /dev/null +++ b/staffjoy/resources/recurring_shift.py @@ -0,0 +1,6 @@ +from ..resource import Resource + + +class RecurringShift(Resource): + PATH = "organizations/{organization_id}/locations/{location_id}/roles/{role_id}/recurringshifts/{recurring_shift_id}" + ID_NAME = "recurring_shift_id" diff --git a/staffjoy/resources/role.py b/staffjoy/resources/role.py index 456aa68..43fd174 100644 --- a/staffjoy/resources/role.py +++ b/staffjoy/resources/role.py @@ -2,6 +2,7 @@ from .worker import Worker from .schedule import Schedule from .shift import Shift +from .recurring_shift import RecurringShift class Role(Resource): @@ -31,3 +32,12 @@ def get_shift(self, id): def create_shift(self, **kwargs): return Shift.create(parent=self, **kwargs) + + def get_recurring_shifts(self, **kwargs): + return RecurringShift.get_all(parent=self, **kwargs) + + def get_recurring_shift(self, id): + return RecurringShift.get(parent=self, id=id) + + def create_recurring_shift(self, **kwargs): + return RecurringShift.create(parent=self, **kwargs) From caebe99d7bd02623042345bcc2833318992c5a25 Mon Sep 17 00:00:00 2001 From: andhess Date: Mon, 18 Apr 2016 16:41:19 -0700 Subject: [PATCH 07/27] adding org workers --- staffjoy/resources/organization.py | 4 ++++ staffjoy/resources/organization_worker.py | 6 ++++++ 2 files changed, 10 insertions(+) create mode 100644 staffjoy/resources/organization_worker.py diff --git a/staffjoy/resources/organization.py b/staffjoy/resources/organization.py index bdf8ef2..5a7c82d 100644 --- a/staffjoy/resources/organization.py +++ b/staffjoy/resources/organization.py @@ -1,6 +1,7 @@ from ..resource import Resource from .location import Location from .admin import Admin +from .organization_worker import OrganizationWorker class Organization(Resource): @@ -25,3 +26,6 @@ def get_admin(self, id): def create_admin(self, **kwargs): """Typically just pass email""" return Admin.create(parent=self, **kwargs) + + def get_workers(self, **kwargs): + return OrganizationWorker.get_all(parent=self, **kwargs) diff --git a/staffjoy/resources/organization_worker.py b/staffjoy/resources/organization_worker.py new file mode 100644 index 0000000..19a2f1f --- /dev/null +++ b/staffjoy/resources/organization_worker.py @@ -0,0 +1,6 @@ +from ..resource import Resource + + +class OrganizationWorker(Resource): + """Organization workers - this endpoint is only a get collection""" + PATH = "organizations/{organization_id}/workers/" From 707a0cec14c78cf60893d6f3af7c7b22b169e4f7 Mon Sep 17 00:00:00 2001 From: andhess Date: Tue, 19 Apr 2016 14:02:18 -0700 Subject: [PATCH 08/27] version bump --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index b122b11..e168e68 100644 --- a/setup.py +++ b/setup.py @@ -1,6 +1,6 @@ from setuptools import setup, find_packages -version = "0.15" +version = "0.16" setup(name="staffjoy", packages=find_packages(), version=version, From 2e6ad308422d49228131f3155121edd7be980087 Mon Sep 17 00:00:00 2001 From: andhess Date: Thu, 28 Apr 2016 09:26:14 -0700 Subject: [PATCH 09/27] adding location manager --- setup.py | 2 +- staffjoy/resources/location.py | 11 +++++++++++ staffjoy/resources/manager.py | 7 +++++++ 3 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 staffjoy/resources/manager.py diff --git a/setup.py b/setup.py index e168e68..20e2206 100644 --- a/setup.py +++ b/setup.py @@ -1,6 +1,6 @@ from setuptools import setup, find_packages -version = "0.16" +version = "0.17" setup(name="staffjoy", packages=find_packages(), version=version, diff --git a/staffjoy/resources/location.py b/staffjoy/resources/location.py index 46da89c..67d7b83 100644 --- a/staffjoy/resources/location.py +++ b/staffjoy/resources/location.py @@ -1,5 +1,6 @@ from ..resource import Resource from .role import Role +from .manager import Manager class Location(Resource): @@ -14,3 +15,13 @@ def get_role(self, id): def create_role(self, **kwargs): return Role.create(parent=self, **kwargs) + + def get_managers(self): + return Manager.get_all(parent=self) + + def get_manager(self, id): + return Manager.get(parent=self, id=id) + + def create_manager(self, **kwargs): + """Typically just pass email""" + return Manager.create(parent=self, **kwargs) diff --git a/staffjoy/resources/manager.py b/staffjoy/resources/manager.py new file mode 100644 index 0000000..a51cc8d --- /dev/null +++ b/staffjoy/resources/manager.py @@ -0,0 +1,7 @@ +from ..resource import Resource + + +class Manager(Resource): + """Location managers""" + PATH = "organizations/{organization_id}/locations/{location_id}/managers/{user_id}" + ID_NAME = "user_id" From 2da9e73a6e976c95b8e4964cd8b466462dd8c820 Mon Sep 17 00:00:00 2001 From: andhess Date: Mon, 2 May 2016 13:29:45 -0700 Subject: [PATCH 10/27] adding some kwargs --- staffjoy/resources/location.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/staffjoy/resources/location.py b/staffjoy/resources/location.py index 67d7b83..9c67e63 100644 --- a/staffjoy/resources/location.py +++ b/staffjoy/resources/location.py @@ -7,8 +7,8 @@ class Location(Resource): PATH = "organizations/{organization_id}/locations/{location_id}" ID_NAME = "location_id" - def get_roles(self): - return Role.get_all(parent=self) + def get_roles(self, **kwargs): + return Role.get_all(parent=self, **kwargs) def get_role(self, id): return Role.get(parent=self, id=id) @@ -16,8 +16,8 @@ def get_role(self, id): def create_role(self, **kwargs): return Role.create(parent=self, **kwargs) - def get_managers(self): - return Manager.get_all(parent=self) + def get_managers(self, **kwargs): + return Manager.get_all(parent=self, **kwargs) def get_manager(self, id): return Manager.get(parent=self, id=id) From 6fdade6c952847a65280f2c9d259b84cdab15a3f Mon Sep 17 00:00:00 2001 From: andhess Date: Wed, 18 May 2016 11:58:57 -0700 Subject: [PATCH 11/27] adding location data endpoints --- setup.py | 2 +- staffjoy/resources/location.py | 12 ++++++++++++ staffjoy/resources/location_shift.py | 6 ++++++ staffjoy/resources/location_time_off_request.py | 6 ++++++ staffjoy/resources/location_timeclock.py | 6 ++++++ 5 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 staffjoy/resources/location_shift.py create mode 100644 staffjoy/resources/location_time_off_request.py create mode 100644 staffjoy/resources/location_timeclock.py diff --git a/setup.py b/setup.py index 20e2206..a6bd5b7 100644 --- a/setup.py +++ b/setup.py @@ -1,6 +1,6 @@ from setuptools import setup, find_packages -version = "0.17" +version = "0.18" setup(name="staffjoy", packages=find_packages(), version=version, diff --git a/staffjoy/resources/location.py b/staffjoy/resources/location.py index 9c67e63..23ad1e1 100644 --- a/staffjoy/resources/location.py +++ b/staffjoy/resources/location.py @@ -1,6 +1,9 @@ from ..resource import Resource from .role import Role from .manager import Manager +from .location_timeclock import LocationTimeclock +from .location_time_off_request import LocationTimeOffRequest +from .location_shift import LocationShift class Location(Resource): @@ -25,3 +28,12 @@ def get_manager(self, id): def create_manager(self, **kwargs): """Typically just pass email""" return Manager.create(parent=self, **kwargs) + + def get_timeclocks(self, **kwargs): + return LocationTimeclock.get_all(parent=self, **kwargs) + + def get_time_off_requests(self, **kwargs): + return LocationTimeOffRequest.get_all(parent=self, **kwargs) + + def get_shifts(self, **kwargs): + return LocationShift.get_all(parent=self, **kwargs) diff --git a/staffjoy/resources/location_shift.py b/staffjoy/resources/location_shift.py new file mode 100644 index 0000000..a618ef0 --- /dev/null +++ b/staffjoy/resources/location_shift.py @@ -0,0 +1,6 @@ +from ..resource import Resource + + +class LocationShift(Resource): + """this is only a get collection endpoint""" + PATH = "organizations/{organization_id}/locations/{location_id}/shifts/" diff --git a/staffjoy/resources/location_time_off_request.py b/staffjoy/resources/location_time_off_request.py new file mode 100644 index 0000000..5d702ed --- /dev/null +++ b/staffjoy/resources/location_time_off_request.py @@ -0,0 +1,6 @@ +from ..resource import Resource + + +class LocationTimeOffRequest(Resource): + """this is only a get collection endpoint""" + PATH = "organizations/{organization_id}/locations/{location_id}/timeoffrequests/" diff --git a/staffjoy/resources/location_timeclock.py b/staffjoy/resources/location_timeclock.py new file mode 100644 index 0000000..ae64014 --- /dev/null +++ b/staffjoy/resources/location_timeclock.py @@ -0,0 +1,6 @@ +from ..resource import Resource + + +class LocationTimeclock(Resource): + """this is only a get collection endpoint""" + PATH = "organizations/{organization_id}/locations/{location_id}/timeclocks/" From 7d65ca58c9cc4b4e1fb37eaba590d39d9fb7781d Mon Sep 17 00:00:00 2001 From: andhess Date: Wed, 18 May 2016 13:57:36 -0700 Subject: [PATCH 12/27] removed relative imports --- staffjoy/__init__.py | 6 +++--- staffjoy/client.py | 14 +++++++------- staffjoy/resource.py | 6 +++--- staffjoy/resources/admin.py | 2 +- staffjoy/resources/apikey.py | 2 +- staffjoy/resources/chomp_task.py | 2 +- staffjoy/resources/cron.py | 2 +- staffjoy/resources/location.py | 12 ++++++------ staffjoy/resources/location_shift.py | 2 +- staffjoy/resources/location_time_off_request.py | 2 +- staffjoy/resources/location_timeclock.py | 2 +- staffjoy/resources/manager.py | 2 +- staffjoy/resources/mobius_task.py | 2 +- staffjoy/resources/organization.py | 8 ++++---- staffjoy/resources/organization_worker.py | 2 +- staffjoy/resources/plan.py | 2 +- staffjoy/resources/preference.py | 2 +- staffjoy/resources/preferences.py | 6 ------ staffjoy/resources/recurring_shift.py | 2 +- staffjoy/resources/role.py | 10 +++++----- staffjoy/resources/schedule.py | 10 +++++----- staffjoy/resources/schedule_shift.py | 2 +- staffjoy/resources/schedule_time_off_request.py | 2 +- staffjoy/resources/schedule_timeclock.py | 2 +- staffjoy/resources/session.py | 2 +- staffjoy/resources/shift.py | 4 ++-- staffjoy/resources/shift_eligible_workers.py | 2 +- staffjoy/resources/time_off_request.py | 2 +- staffjoy/resources/timeclock.py | 2 +- staffjoy/resources/user.py | 6 +++--- staffjoy/resources/worker.py | 6 +++--- 31 files changed, 61 insertions(+), 67 deletions(-) delete mode 100644 staffjoy/resources/preferences.py diff --git a/staffjoy/__init__.py b/staffjoy/__init__.py index 031e957..e3392f3 100644 --- a/staffjoy/__init__.py +++ b/staffjoy/__init__.py @@ -1,3 +1,3 @@ -from .resource import Resource -from .exceptions import UnauthorizedException, NotFoundException, BadRequestException -from .client import Client +from staffjoy.resource import Resource +from staffjoy.exceptions import UnauthorizedException, NotFoundException, BadRequestException +from staffjoy.client import Client diff --git a/staffjoy/client.py b/staffjoy/client.py index 4051ef0..bbc7045 100644 --- a/staffjoy/client.py +++ b/staffjoy/client.py @@ -1,10 +1,10 @@ -from .resource import Resource -from .resources.organization import Organization -from .resources.cron import Cron -from .resources.user import User -from .resources.plan import Plan -from .resources.chomp_task import ChompTask -from .resources.mobius_task import MobiusTask +from staffjoy.resource import Resource +from staffjoy.resources.organization import Organization +from staffjoy.resources.cron import Cron +from staffjoy.resources.user import User +from staffjoy.resources.plan import Plan +from staffjoy.resources.chomp_task import ChompTask +from staffjoy.resources.mobius_task import MobiusTask class Client(Resource): diff --git a/staffjoy/resource.py b/staffjoy/resource.py index d66ac6e..2bfe5a6 100644 --- a/staffjoy/resource.py +++ b/staffjoy/resource.py @@ -1,9 +1,9 @@ -import requests import time from copy import copy +import requests -from .config import config_from_env -from .exceptions import UnauthorizedException, NotFoundException, BadRequestException +from staffjoy.config import config_from_env +from staffjoy.exceptions import UnauthorizedException, NotFoundException, BadRequestException class Resource: diff --git a/staffjoy/resources/admin.py b/staffjoy/resources/admin.py index 40e76a2..06b8f29 100644 --- a/staffjoy/resources/admin.py +++ b/staffjoy/resources/admin.py @@ -1,4 +1,4 @@ -from ..resource import Resource +from staffjoy.resource import Resource class Admin(Resource): diff --git a/staffjoy/resources/apikey.py b/staffjoy/resources/apikey.py index 6183b7d..37c066f 100644 --- a/staffjoy/resources/apikey.py +++ b/staffjoy/resources/apikey.py @@ -1,4 +1,4 @@ -from ..resource import Resource +from staffjoy.resource import Resource class ApiKey(Resource): diff --git a/staffjoy/resources/chomp_task.py b/staffjoy/resources/chomp_task.py index 175caad..4e7b162 100644 --- a/staffjoy/resources/chomp_task.py +++ b/staffjoy/resources/chomp_task.py @@ -1,4 +1,4 @@ -from ..resource import Resource +from staffjoy.resource import Resource class ChompTask(Resource): diff --git a/staffjoy/resources/cron.py b/staffjoy/resources/cron.py index 8837c31..00a04ac 100644 --- a/staffjoy/resources/cron.py +++ b/staffjoy/resources/cron.py @@ -1,4 +1,4 @@ -from ..resource import Resource +from staffjoy.resource import Resource class Cron(Resource): diff --git a/staffjoy/resources/location.py b/staffjoy/resources/location.py index 23ad1e1..3c4db3a 100644 --- a/staffjoy/resources/location.py +++ b/staffjoy/resources/location.py @@ -1,9 +1,9 @@ -from ..resource import Resource -from .role import Role -from .manager import Manager -from .location_timeclock import LocationTimeclock -from .location_time_off_request import LocationTimeOffRequest -from .location_shift import LocationShift +from staffjoy.resource import Resource +from staffjoy.resources.role import Role +from staffjoy.resources.manager import Manager +from staffjoy.resources.location_timeclock import LocationTimeclock +from staffjoy.resources.location_time_off_request import LocationTimeOffRequest +from staffjoy.resources.location_shift import LocationShift class Location(Resource): diff --git a/staffjoy/resources/location_shift.py b/staffjoy/resources/location_shift.py index a618ef0..3931024 100644 --- a/staffjoy/resources/location_shift.py +++ b/staffjoy/resources/location_shift.py @@ -1,4 +1,4 @@ -from ..resource import Resource +from staffjoy.resource import Resource class LocationShift(Resource): diff --git a/staffjoy/resources/location_time_off_request.py b/staffjoy/resources/location_time_off_request.py index 5d702ed..584b8eb 100644 --- a/staffjoy/resources/location_time_off_request.py +++ b/staffjoy/resources/location_time_off_request.py @@ -1,4 +1,4 @@ -from ..resource import Resource +from staffjoy.resource import Resource class LocationTimeOffRequest(Resource): diff --git a/staffjoy/resources/location_timeclock.py b/staffjoy/resources/location_timeclock.py index ae64014..89967df 100644 --- a/staffjoy/resources/location_timeclock.py +++ b/staffjoy/resources/location_timeclock.py @@ -1,4 +1,4 @@ -from ..resource import Resource +from staffjoy.resource import Resource class LocationTimeclock(Resource): diff --git a/staffjoy/resources/manager.py b/staffjoy/resources/manager.py index a51cc8d..7e58bb0 100644 --- a/staffjoy/resources/manager.py +++ b/staffjoy/resources/manager.py @@ -1,4 +1,4 @@ -from ..resource import Resource +from staffjoy.resource import Resource class Manager(Resource): diff --git a/staffjoy/resources/mobius_task.py b/staffjoy/resources/mobius_task.py index d1be395..a5c7586 100644 --- a/staffjoy/resources/mobius_task.py +++ b/staffjoy/resources/mobius_task.py @@ -1,4 +1,4 @@ -from ..resource import Resource +from staffjoy.resource import Resource class MobiusTask(Resource): diff --git a/staffjoy/resources/organization.py b/staffjoy/resources/organization.py index 5a7c82d..3801b76 100644 --- a/staffjoy/resources/organization.py +++ b/staffjoy/resources/organization.py @@ -1,7 +1,7 @@ -from ..resource import Resource -from .location import Location -from .admin import Admin -from .organization_worker import OrganizationWorker +from staffjoy.resource import Resource +from staffjoy.resources.location import Location +from staffjoy.resources.admin import Admin +from staffjoy.resources.organization_worker import OrganizationWorker class Organization(Resource): diff --git a/staffjoy/resources/organization_worker.py b/staffjoy/resources/organization_worker.py index 19a2f1f..a835730 100644 --- a/staffjoy/resources/organization_worker.py +++ b/staffjoy/resources/organization_worker.py @@ -1,4 +1,4 @@ -from ..resource import Resource +from staffjoy.resource import Resource class OrganizationWorker(Resource): diff --git a/staffjoy/resources/plan.py b/staffjoy/resources/plan.py index e997f1a..a4d1498 100644 --- a/staffjoy/resources/plan.py +++ b/staffjoy/resources/plan.py @@ -1,4 +1,4 @@ -from ..resource import Resource +from staffjoy.resource import Resource class Plan(Resource): diff --git a/staffjoy/resources/preference.py b/staffjoy/resources/preference.py index 5858431..b03c554 100644 --- a/staffjoy/resources/preference.py +++ b/staffjoy/resources/preference.py @@ -1,4 +1,4 @@ -from ..resource import Resource +from staffjoy.resource import Resource class Preference(Resource): diff --git a/staffjoy/resources/preferences.py b/staffjoy/resources/preferences.py deleted file mode 100644 index 5858431..0000000 --- a/staffjoy/resources/preferences.py +++ /dev/null @@ -1,6 +0,0 @@ -from ..resource import Resource - - -class Preference(Resource): - PATH = "organizations/{organization_id}/locations/{location_id}/roles/{role_id}/schedules/{schedule_id}/preferences/{user_id}" - ID_NAME = "user_id" diff --git a/staffjoy/resources/recurring_shift.py b/staffjoy/resources/recurring_shift.py index 8298c98..0956517 100644 --- a/staffjoy/resources/recurring_shift.py +++ b/staffjoy/resources/recurring_shift.py @@ -1,4 +1,4 @@ -from ..resource import Resource +from staffjoy.resource import Resource class RecurringShift(Resource): diff --git a/staffjoy/resources/role.py b/staffjoy/resources/role.py index 43fd174..b9db876 100644 --- a/staffjoy/resources/role.py +++ b/staffjoy/resources/role.py @@ -1,8 +1,8 @@ -from ..resource import Resource -from .worker import Worker -from .schedule import Schedule -from .shift import Shift -from .recurring_shift import RecurringShift +from staffjoy.resource import Resource +from staffjoy.resources.worker import Worker +from staffjoy.resources.schedule import Schedule +from staffjoy.resources.shift import Shift +from staffjoy.resources.recurring_shift import RecurringShift class Role(Resource): diff --git a/staffjoy/resources/schedule.py b/staffjoy/resources/schedule.py index d95f7d6..ec73278 100644 --- a/staffjoy/resources/schedule.py +++ b/staffjoy/resources/schedule.py @@ -1,8 +1,8 @@ -from ..resource import Resource -from .preference import Preference -from .schedule_shift import ScheduleShift -from .schedule_timeclock import ScheduleTimeclock -from .schedule_time_off_request import ScheduleTimeOffRequest +from staffjoy.resource import Resource +from staffjoy.resources.preference import Preference +from staffjoy.resources.schedule_shift import ScheduleShift +from staffjoy.resources.schedule_timeclock import ScheduleTimeclock +from staffjoy.resources.schedule_time_off_request import ScheduleTimeOffRequest class Schedule(Resource): diff --git a/staffjoy/resources/schedule_shift.py b/staffjoy/resources/schedule_shift.py index a269ee8..49415bb 100644 --- a/staffjoy/resources/schedule_shift.py +++ b/staffjoy/resources/schedule_shift.py @@ -1,4 +1,4 @@ -from ..resource import Resource +from staffjoy.resource import Resource class ScheduleShift(Resource): diff --git a/staffjoy/resources/schedule_time_off_request.py b/staffjoy/resources/schedule_time_off_request.py index 1ebb21c..78ae4ff 100644 --- a/staffjoy/resources/schedule_time_off_request.py +++ b/staffjoy/resources/schedule_time_off_request.py @@ -1,4 +1,4 @@ -from ..resource import Resource +from staffjoy.resource import Resource class ScheduleTimeOffRequest(Resource): diff --git a/staffjoy/resources/schedule_timeclock.py b/staffjoy/resources/schedule_timeclock.py index 6e4042b..00f5ecf 100644 --- a/staffjoy/resources/schedule_timeclock.py +++ b/staffjoy/resources/schedule_timeclock.py @@ -1,4 +1,4 @@ -from ..resource import Resource +from staffjoy.resource import Resource class ScheduleTimeclock(Resource): diff --git a/staffjoy/resources/session.py b/staffjoy/resources/session.py index 05f5d4c..671963f 100644 --- a/staffjoy/resources/session.py +++ b/staffjoy/resources/session.py @@ -1,4 +1,4 @@ -from ..resource import Resource +from staffjoy.resource import Resource class Session(Resource): diff --git a/staffjoy/resources/shift.py b/staffjoy/resources/shift.py index d83b981..9a215e8 100644 --- a/staffjoy/resources/shift.py +++ b/staffjoy/resources/shift.py @@ -1,5 +1,5 @@ -from ..resource import Resource -from .shift_eligible_workers import ShiftEligibleWorker +from staffjoy.resource import Resource +from staffjoy.resources.shift_eligible_workers import ShiftEligibleWorker class Shift(Resource): diff --git a/staffjoy/resources/shift_eligible_workers.py b/staffjoy/resources/shift_eligible_workers.py index 805ba26..762dad3 100644 --- a/staffjoy/resources/shift_eligible_workers.py +++ b/staffjoy/resources/shift_eligible_workers.py @@ -1,4 +1,4 @@ -from ..resource import Resource +from staffjoy.resource import Resource class ShiftEligibleWorker(Resource): diff --git a/staffjoy/resources/time_off_request.py b/staffjoy/resources/time_off_request.py index f983c23..ffb2c6d 100644 --- a/staffjoy/resources/time_off_request.py +++ b/staffjoy/resources/time_off_request.py @@ -1,4 +1,4 @@ -from ..resource import Resource +from staffjoy.resource import Resource class TimeOffRequest(Resource): diff --git a/staffjoy/resources/timeclock.py b/staffjoy/resources/timeclock.py index e93aae7..16cedc6 100644 --- a/staffjoy/resources/timeclock.py +++ b/staffjoy/resources/timeclock.py @@ -1,4 +1,4 @@ -from ..resource import Resource +from staffjoy.resource import Resource class Timeclock(Resource): diff --git a/staffjoy/resources/user.py b/staffjoy/resources/user.py index e756e8b..d0c0972 100644 --- a/staffjoy/resources/user.py +++ b/staffjoy/resources/user.py @@ -1,6 +1,6 @@ -from ..resource import Resource -from .session import Session -from .apikey import ApiKey +from staffjoy.resource import Resource +from staffjoy.resources.session import Session +from staffjoy.resources.apikey import ApiKey class User(Resource): diff --git a/staffjoy/resources/worker.py b/staffjoy/resources/worker.py index 9eea8d3..0ce8379 100644 --- a/staffjoy/resources/worker.py +++ b/staffjoy/resources/worker.py @@ -1,6 +1,6 @@ -from ..resource import Resource -from .timeclock import Timeclock -from .time_off_request import TimeOffRequest +from staffjoy.resource import Resource +from staffjoy.resources.timeclock import Timeclock +from staffjoy.resources.time_off_request import TimeOffRequest class Worker(Resource): From f7a29cd00190530623b1638534eb29816621e892 Mon Sep 17 00:00:00 2001 From: "Philip I. Thomas" Date: Tue, 24 May 2016 18:23:32 -0700 Subject: [PATCH 13/27] Misspelled parent --- staffjoy/resources/user.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/staffjoy/resources/user.py b/staffjoy/resources/user.py index d0c0972..173ebe9 100644 --- a/staffjoy/resources/user.py +++ b/staffjoy/resources/user.py @@ -11,7 +11,7 @@ def get_sessions(self): return Session.get_all(parent=self) def get_session(self, id): - return Session.get(parset=self, id=id) + return Session.get(parent=self, id=id) def get_apikeys(self): return ApiKey.get_all(parent=self) From d2ce40f8d0e71ad26adce311639fae2d8740dc7b Mon Sep 17 00:00:00 2001 From: andhess Date: Fri, 27 May 2016 15:05:22 -0700 Subject: [PATCH 14/27] need kwargs on schedules --- setup.py | 2 +- staffjoy/resources/role.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index a6bd5b7..3bab3cc 100644 --- a/setup.py +++ b/setup.py @@ -1,6 +1,6 @@ from setuptools import setup, find_packages -version = "0.18" +version = "0.19" setup(name="staffjoy", packages=find_packages(), version=version, diff --git a/staffjoy/resources/role.py b/staffjoy/resources/role.py index b9db876..8c7173f 100644 --- a/staffjoy/resources/role.py +++ b/staffjoy/resources/role.py @@ -19,7 +19,7 @@ def create_worker(self, **kwargs): return Worker.create(parent=self, **kwargs) def get_schedules(self, **kwargs): - return Schedule.get_all(parent=self) + return Schedule.get_all(parent=self, **kwargs) def get_schedule(self, id): return Schedule.get(parent=self, id=id) From 4a4cc47c43b45fc9ea53580058c810fc3c822117 Mon Sep 17 00:00:00 2001 From: andhess Date: Wed, 1 Jun 2016 10:50:57 -0700 Subject: [PATCH 15/27] need kwargs on location --- setup.py | 2 +- staffjoy/resources/organization.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index 3bab3cc..758fc8c 100644 --- a/setup.py +++ b/setup.py @@ -1,6 +1,6 @@ from setuptools import setup, find_packages -version = "0.19" +version = "0.20" setup(name="staffjoy", packages=find_packages(), version=version, diff --git a/staffjoy/resources/organization.py b/staffjoy/resources/organization.py index 3801b76..9761c5c 100644 --- a/staffjoy/resources/organization.py +++ b/staffjoy/resources/organization.py @@ -8,8 +8,8 @@ class Organization(Resource): PATH = "organizations/{organization_id}" ID_NAME = "organization_id" - def get_locations(self): - return Location.get_all(parent=self) + def get_locations(self, **kwargs): + return Location.get_all(parent=self, **kwargs) def get_location(self, id): return Location.get(parent=self, id=id) From 25e823b00f884ffb5a5b2f097434f5bdfba6409b Mon Sep 17 00:00:00 2001 From: andhess Date: Thu, 30 Jun 2016 09:33:08 -0700 Subject: [PATCH 16/27] adding shift query --- setup.py | 2 +- staffjoy/resources/role.py | 4 ++++ staffjoy/resources/shift_query.py | 6 ++++++ 3 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 staffjoy/resources/shift_query.py diff --git a/setup.py b/setup.py index 758fc8c..f9a3b91 100644 --- a/setup.py +++ b/setup.py @@ -1,6 +1,6 @@ from setuptools import setup, find_packages -version = "0.20" +version = "0.21" setup(name="staffjoy", packages=find_packages(), version=version, diff --git a/staffjoy/resources/role.py b/staffjoy/resources/role.py index 8c7173f..6cf7d19 100644 --- a/staffjoy/resources/role.py +++ b/staffjoy/resources/role.py @@ -2,6 +2,7 @@ from staffjoy.resources.worker import Worker from staffjoy.resources.schedule import Schedule from staffjoy.resources.shift import Shift +from staffjoy.resources.shift_query import ShiftQuery from staffjoy.resources.recurring_shift import RecurringShift @@ -33,6 +34,9 @@ def get_shift(self, id): def create_shift(self, **kwargs): return Shift.create(parent=self, **kwargs) + def get_shift_query(self, **kwargs): + return ShiftQuery.get_all(parent=self, **kwargs) + def get_recurring_shifts(self, **kwargs): return RecurringShift.get_all(parent=self, **kwargs) diff --git a/staffjoy/resources/shift_query.py b/staffjoy/resources/shift_query.py new file mode 100644 index 0000000..bb5a527 --- /dev/null +++ b/staffjoy/resources/shift_query.py @@ -0,0 +1,6 @@ +from staffjoy.resource import Resource + + +class ShiftQuery(Resource): + """Returns workers that can claim a potential shift""" + PATH = "organizations/{organization_id}/locations/{location_id}/roles/{role_id}/shiftquery/" From 1f4767573becdc01c454cf6b38912cb173d0d5af Mon Sep 17 00:00:00 2001 From: "Philip I. Thomas" Date: Thu, 30 Jun 2016 16:23:42 -0700 Subject: [PATCH 17/27] speed improvement! --- staffjoy/resource.py | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/staffjoy/resource.py b/staffjoy/resource.py index 2bfe5a6..1da3aba 100644 --- a/staffjoy/resource.py +++ b/staffjoy/resource.py @@ -1,14 +1,16 @@ import time +from datetime import datetime from copy import copy import requests from staffjoy.config import config_from_env from staffjoy.exceptions import UnauthorizedException, NotFoundException, BadRequestException +MICROSECONDS_PER_SECOND = 10**6 class Resource: - # Seconds to sleep between requests (bc of rate limits) - REQUEST_SLEEP = 0.5 + # Slow each request to this (bc of rate limits) + REQUEST_TIME_MICROSECONDS = 0.3 * MICROSECONDS_PER_SECOND # 0.3 seconds PATH = "" # URL path added to base, including route variables ID_NAME = None # What is this ID called in the route of children? @@ -71,10 +73,11 @@ def get_all(cls, parent=None, **params): base_obj = cls(key=parent.key, route=route, config=parent.config) """Perform a read request against the resource""" + start = datetime.now() r = requests.get(base_obj._url(), auth=(base_obj.key, ""), params=params) - time.sleep(cls.REQUEST_SLEEP) + cls._delay_for_ratelimits(start) if r.status_code not in cls.TRUTHY_CODES: return base_obj._handle_request_exception(r) @@ -121,8 +124,9 @@ def _handle_request_exception(request): def fetch(self): """Perform a read request against the resource""" + start = datetime.now() r = requests.get(self._url(), auth=(self.key, "")) - time.sleep(self.REQUEST_SLEEP) + self._delay_for_ratelimits(start) if r.status_code not in self.TRUTHY_CODES: return self._handle_request_exception(r) @@ -144,16 +148,18 @@ def _process_meta(self, response): def delete(self): """Delete the object""" + start = datetime.now() r = requests.delete(self._url(), auth=(self.key, "")) - time.sleep(self.REQUEST_SLEEP) + self._delay_for_ratelimits(start) if r.status_code not in self.TRUTHY_CODES: return self._handle_request_exception(r) def patch(self, **kwargs): """Change attributes of the item""" + start = datetime.now() r = requests.patch(self._url(), auth=(self.key, ""), data=kwargs) - time.sleep(self.REQUEST_SLEEP) + self._delay_for_ratelimits(start) if r.status_code not in self.TRUTHY_CODES: return self._handle_request_exception(r) @@ -175,8 +181,9 @@ def create(cls, parent=None, **kwargs): obj = cls(key=parent.key, route=route, config=parent.config) + start = datetime.now() response = requests.post(obj._url(), auth=(obj.key, ""), data=kwargs) - time.sleep(cls.REQUEST_SLEEP) + cls._delay_for_ratelimits(start) if response.status_code not in cls.TRUTHY_CODES: return cls._handle_request_exception(response) @@ -191,6 +198,14 @@ def create(cls, parent=None, **kwargs): def get_id(self): return self.data.get("id", self.route.get(self.ID_NAME)) + @classmethod + def _delay_for_ratelimits(cls, start): + """If request was shorter than max request time, delay""" + stop = datetime.now() + duration_microseconds = (stop-start).microseconds + if duration_microseconds < cls.REQUEST_TIME_MICROSECONDS: + time.sleep((cls.REQUEST_TIME_MICROSECONDS - duration_microseconds) / MICROSECONDS_PER_SECOND) + def __str__(self): return "{} id {}".format(self.__class__.__name__, self.route.get(self.ID_NAME)) From 58c079ae25e1b2c7d8f35426dc43a6070506b297 Mon Sep 17 00:00:00 2001 From: "Philip I. Thomas" Date: Fri, 1 Jul 2016 12:26:35 -0700 Subject: [PATCH 18/27] update yapf version --- requirements-test.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-test.txt b/requirements-test.txt index b014aa0..ea72794 100644 --- a/requirements-test.txt +++ b/requirements-test.txt @@ -1,2 +1,2 @@ -yapf==0.6.2 +yapf==0.10.0 pytest==2.8.7 From 971e3d8ddc8733ac665c8c5054f2593bfb99425c Mon Sep 17 00:00:00 2001 From: "Philip I. Thomas" Date: Fri, 1 Jul 2016 12:26:58 -0700 Subject: [PATCH 19/27] final format change --- staffjoy/resource.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/staffjoy/resource.py b/staffjoy/resource.py index 1da3aba..4367426 100644 --- a/staffjoy/resource.py +++ b/staffjoy/resource.py @@ -8,9 +8,10 @@ MICROSECONDS_PER_SECOND = 10**6 + class Resource: # Slow each request to this (bc of rate limits) - REQUEST_TIME_MICROSECONDS = 0.3 * MICROSECONDS_PER_SECOND # 0.3 seconds + REQUEST_TIME_MICROSECONDS = 0.3 * MICROSECONDS_PER_SECOND # 0.3 seconds PATH = "" # URL path added to base, including route variables ID_NAME = None # What is this ID called in the route of children? @@ -202,9 +203,10 @@ def get_id(self): def _delay_for_ratelimits(cls, start): """If request was shorter than max request time, delay""" stop = datetime.now() - duration_microseconds = (stop-start).microseconds + duration_microseconds = (stop - start).microseconds if duration_microseconds < cls.REQUEST_TIME_MICROSECONDS: - time.sleep((cls.REQUEST_TIME_MICROSECONDS - duration_microseconds) / MICROSECONDS_PER_SECOND) + time.sleep((cls.REQUEST_TIME_MICROSECONDS - duration_microseconds) + / MICROSECONDS_PER_SECOND) def __str__(self): return "{} id {}".format(self.__class__.__name__, From d82f4863fb9353d640fc7a020e6f0847854d6d7e Mon Sep 17 00:00:00 2001 From: "Philip I. Thomas" Date: Wed, 17 Aug 2016 11:08:29 -0700 Subject: [PATCH 20/27] moving apiv2 to suite.staffjoy.com --- setup.py | 2 +- staffjoy/config.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index f9a3b91..f617fb9 100644 --- a/setup.py +++ b/setup.py @@ -1,6 +1,6 @@ from setuptools import setup, find_packages -version = "0.21" +version = "0.22" setup(name="staffjoy", packages=find_packages(), version=version, diff --git a/staffjoy/config.py b/staffjoy/config.py index 514058f..a13d9cd 100644 --- a/staffjoy/config.py +++ b/staffjoy/config.py @@ -4,7 +4,7 @@ class DefaultConfig: ENV = "prod" LOG_LEVEL = logging.INFO - BASE = "https://www.staffjoy.com/api/v2/" + BASE = "https://suite.staffjoy.com/api/v2/" REQUEST_SLEEP = 0.5 From de15bd229f0fab798f1d5c12da8385c08d4e3610 Mon Sep 17 00:00:00 2001 From: "Philip I. Thomas" Date: Thu, 23 Feb 2017 21:07:29 -0800 Subject: [PATCH 21/27] update dev, bump release, update formatting --- LICENSE.txt | 3 ++- README.md | 10 +++------- requirements-test.txt | 2 +- setup.py | 4 ++-- staffjoy/client.py | 6 ++---- staffjoy/config.py | 2 +- staffjoy/resource.py | 20 +++++++++++--------- test/test_functional.py | 7 ++++--- 8 files changed, 26 insertions(+), 28 deletions(-) diff --git a/LICENSE.txt b/LICENSE.txt index 354b463..41e964a 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,5 +1,6 @@ MIT License -Copyright (c) 2016 Staffjoy, Inc. + +Copyright (c) 2016-2017 Staffjoy, Inc. 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: diff --git a/README.md b/README.md index 88077bb..b77a22d 100644 --- a/README.md +++ b/README.md @@ -4,11 +4,11 @@ A light wrapper for the [Staffjoy](https://www.staffjoy.com) API in Python. This library does not include permissions management, and it is primarily used across microservices internally. Some of its features include internal-only endpoints. -[![Build Status](https://travis-ci.org/Staffjoy/client_python.svg?branch=master)](https://travis-ci.org/Staffjoy/client_python) +[![Build Status](https://travis-ci.org/Staffjoy/client_python.svg?branch=master)](https://travis-ci.org/Staffjoy/client_python) [![Moonlight](https://img.shields.io/badge/Contractors-1-brightgreen.svg)](https://moonlightwork.com/staffjoy) ## Installation -`pip install staffjoy` +`pip install --upgrade staffjoy` ## Authentication @@ -22,11 +22,7 @@ To get your organization ID, look at the URL path when you go to the Manager app ## Rate Limits -This client sleeps for .5 seconds after every request. Thus, in a single thread, requests are limited to 120 per minute. This is done to avoid rate limiting. Staffjoy's API currently rate limits to 300 requests per second across keys and IPs. Thus, by using this library, you should never encounter a rate limit (assuming one executing thread per IP address). - -## Updates - -If you use this library, please subscribe to the [Staffjoy API Updates Google Group](https://groups.google.com/forum/#!forum/staffjoy-api-updates) for important notifications about changes and deprecations. +This client sleeps after every request in order to limit requests to 120 per minute. This is done to avoid rate limiting. Staffjoy's API currently rate limits to 300 requests per second across keys and IPs. Thus, by using this library, you should never encounter a rate limit (assuming one executing thread per IP address). ## Usage diff --git a/requirements-test.txt b/requirements-test.txt index b014aa0..ee7ab8b 100644 --- a/requirements-test.txt +++ b/requirements-test.txt @@ -1,2 +1,2 @@ -yapf==0.6.2 +yapf==0.16.0 pytest==2.8.7 diff --git a/setup.py b/setup.py index f617fb9..af54dac 100644 --- a/setup.py +++ b/setup.py @@ -1,12 +1,12 @@ from setuptools import setup, find_packages -version = "0.22" +version = "0.23" setup(name="staffjoy", packages=find_packages(), version=version, description="Staffjoy API Wrapper in Python", author="Philip Thomas", - author_email="help@staffjoy.com", + author_email="philip@staffjoy.com", license="MIT", url="https://github.com/staffjoy/client_python", download_url="https://github.com/StaffJoy/client_python/archive/%s.tar.gz" % version, diff --git a/staffjoy/client.py b/staffjoy/client.py index bbc7045..5789d78 100644 --- a/staffjoy/client.py +++ b/staffjoy/client.py @@ -9,10 +9,8 @@ class Client(Resource): def get_organizations(self, limit=25, offset=0, **kwargs): - return Organization.get_all(parent=self, - limit=limit, - offset=offset, - **kwargs) + return Organization.get_all( + parent=self, limit=limit, offset=offset, **kwargs) def get_organization(self, id): return Organization.get(parent=self, id=id) diff --git a/staffjoy/config.py b/staffjoy/config.py index a13d9cd..be1ba82 100644 --- a/staffjoy/config.py +++ b/staffjoy/config.py @@ -16,7 +16,7 @@ class StageConfig(DefaultConfig): class DevelopmentConfig(DefaultConfig): ENV = "dev" LOG_LEVEL = logging.DEBUG - BASE = "http://dev.staffjoy.com/api/v2/" + BASE = "http://suite.local/api/v2/" config_from_env = { # Determined in main.py diff --git a/staffjoy/resource.py b/staffjoy/resource.py index 2bfe5a6..89be6ad 100644 --- a/staffjoy/resource.py +++ b/staffjoy/resource.py @@ -14,8 +14,10 @@ class Resource: ID_NAME = None # What is this ID called in the route of children? META_ENVELOPES = [] # Metadata keys for what to unpack from response ENVELOPE = "data" # We "envelope" response data in the "data" section - TRUTHY_CODES = [requests.codes.ok, requests.codes.created, - requests.codes.no_content, requests.codes.accepted] + TRUTHY_CODES = [ + requests.codes.ok, requests.codes.created, requests.codes.no_content, + requests.codes.accepted + ] def __init__(self, key="", @@ -71,9 +73,8 @@ def get_all(cls, parent=None, **params): base_obj = cls(key=parent.key, route=route, config=parent.config) """Perform a read request against the resource""" - r = requests.get(base_obj._url(), - auth=(base_obj.key, ""), - params=params) + r = requests.get( + base_obj._url(), auth=(base_obj.key, ""), params=params) time.sleep(cls.REQUEST_SLEEP) if r.status_code not in cls.TRUTHY_CODES: @@ -85,10 +86,11 @@ def get_all(cls, parent=None, **params): return_objects = [] for data in objects_data: # Note that this approach does not get meta data - return_objects.append(cls.get(parent=parent, - id=data.get(cls.ID_NAME, data.get( - "id")), - data=data)) + return_objects.append( + cls.get( + parent=parent, + id=data.get(cls.ID_NAME, data.get("id")), + data=data)) return return_objects diff --git a/test/test_functional.py b/test/test_functional.py index 9d7aaa2..782a703 100644 --- a/test/test_functional.py +++ b/test/test_functional.py @@ -58,9 +58,10 @@ def test_org_crud(): r.patch(name="Cocina") logger.debug("Adding worker") r.get_workers() - r.create_worker(email=TEST_WORKER, - min_hours_per_workweek=30, - max_hours_per_workweek=40) + r.create_worker( + email=TEST_WORKER, + min_hours_per_workweek=30, + max_hours_per_workweek=40) logger.debug("Deleting worker") r.delete() From 88ff40950bf0c307825acbe68263a438df75f214 Mon Sep 17 00:00:00 2001 From: "Philip I. Thomas" Date: Thu, 23 Feb 2017 21:21:42 -0800 Subject: [PATCH 22/27] update fmt --- staffjoy/resource.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/staffjoy/resource.py b/staffjoy/resource.py index 0242f9c..9a35737 100644 --- a/staffjoy/resource.py +++ b/staffjoy/resource.py @@ -77,9 +77,8 @@ def get_all(cls, parent=None, **params): """Perform a read request against the resource""" start = datetime.now() - r = requests.get(base_obj._url(), - auth=(base_obj.key, ""), - params=params) + r = requests.get( + base_obj._url(), auth=(base_obj.key, ""), params=params) cls._delay_for_ratelimits(start) if r.status_code not in cls.TRUTHY_CODES: From 161a2f66eb45ce1474b56e95911c08322c3411af Mon Sep 17 00:00:00 2001 From: "Philip I. Thomas" Date: Mon, 3 Apr 2017 15:36:46 -0700 Subject: [PATCH 23/27] allow custom domains --- README.md | 9 +++++++++ staffjoy/resource.py | 5 +++++ 2 files changed, 14 insertions(+) diff --git a/README.md b/README.md index b77a22d..9870d89 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,15 @@ This library does not include permissions management, and it is primarily used a `pip install --upgrade staffjoy` +## Self-Hosted Use + +If you are self-hosting Staffjoy on a custom domain, please pass a `url_base` to the client. It defaults to `https://suite.staffjoy.com/api/v2/"`. (Trailing slash may matter). + +```python +from Staffjoy import Client +c = Client(key=YOUR_API_KEY, url_base="https://staffjoy.example.com/api/v2/") +``` + ## Authentication Authentication keys are currently tied to an individual user's account. To issue multiple keys, we currently suggest diff --git a/staffjoy/resource.py b/staffjoy/resource.py index 9a35737..7e96284 100644 --- a/staffjoy/resource.py +++ b/staffjoy/resource.py @@ -26,6 +26,7 @@ def __init__(self, key="", config=None, env="prod", + url_base=None, data={}, route={}, meta={}): @@ -34,6 +35,10 @@ def __init__(self, self.config = config or config_from_env.get(env, "prod") + # Used for self-hosted Staffjoy users + if url_base: + self.config.BASE = url_base + # These should be overridden by child classes self.data = data # Data from the read method self.route = route # Route variables From 0b50354356c038cf94df8a107e429d85b0a27783 Mon Sep 17 00:00:00 2001 From: "Philip I. Thomas" Date: Mon, 3 Apr 2017 15:44:48 -0700 Subject: [PATCH 24/27] bump version --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index af54dac..f68aad3 100644 --- a/setup.py +++ b/setup.py @@ -1,6 +1,6 @@ from setuptools import setup, find_packages -version = "0.23" +version = "0.24" setup(name="staffjoy", packages=find_packages(), version=version, From 7ecd925bface243ed289a9a96b86afa066643eac Mon Sep 17 00:00:00 2001 From: "Philip I. Thomas" Date: Mon, 3 Apr 2017 18:42:08 -0700 Subject: [PATCH 25/27] disable tests --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 8f989ff..bee3ba9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,7 @@ python: - '3.5' script: - pip install -r requirements-test.txt -- make test +#- make test deploy: provider: pypi user: philipithomas From c231f0695dad1564de3af024bceec985d920d967 Mon Sep 17 00:00:00 2001 From: "Philip I. Thomas" Date: Mon, 26 Jun 2017 15:33:42 -0500 Subject: [PATCH 26/27] Update moonlight badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9870d89..d4da5b9 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ A light wrapper for the [Staffjoy](https://www.staffjoy.com) API in Python. This library does not include permissions management, and it is primarily used across microservices internally. Some of its features include internal-only endpoints. -[![Build Status](https://travis-ci.org/Staffjoy/client_python.svg?branch=master)](https://travis-ci.org/Staffjoy/client_python) [![Moonlight](https://img.shields.io/badge/Contractors-1-brightgreen.svg)](https://moonlightwork.com/staffjoy) +[![Build Status](https://travis-ci.org/Staffjoy/client_python.svg?branch=master)](https://travis-ci.org/Staffjoy/client_python) [![Moonlight contractors](https://img.shields.io/badge/contractors-1147-brightgreen.svg)](https://moonlightwork.com/for/staffjoy) ## Installation From e8811b0c06651a15e691c96cbfd41e7da4f7f213 Mon Sep 17 00:00:00 2001 From: "Philip I. Thomas" Date: Wed, 28 Mar 2018 18:56:03 -0300 Subject: [PATCH 27/27] Update moonlight badge --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d4da5b9..e104455 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,11 @@ # client_python +[![Build Status](https://travis-ci.org/Staffjoy/client_python.svg?branch=master)](https://travis-ci.org/Staffjoy/client_python) [![Moonlight contractors](https://www.moonlightwork.com/shields/python.svg)](https://www.moonlightwork.com/for/python?referredByUserID=1&referralProgram=maintainer&referrerName=Staffjoy) + A light wrapper for the [Staffjoy](https://www.staffjoy.com) API in Python. This library does not include permissions management, and it is primarily used across microservices internally. Some of its features include internal-only endpoints. -[![Build Status](https://travis-ci.org/Staffjoy/client_python.svg?branch=master)](https://travis-ci.org/Staffjoy/client_python) [![Moonlight contractors](https://img.shields.io/badge/contractors-1147-brightgreen.svg)](https://moonlightwork.com/for/staffjoy) - ## Installation `pip install --upgrade staffjoy`