From d263b928b71e5ae43bc71d361d228f990212f59f Mon Sep 17 00:00:00 2001 From: Josh W <5985422+DolphDev@users.noreply.github.com> Date: Wed, 22 Sep 2021 20:59:56 -0400 Subject: [PATCH] 3.1.4 New Version Release (#20) * 3.1.4 Code Commit * Testing Update * More Test Fixes * Update nationstates.rst * More Test Additions * testing fixes --- docs/conf.py | 4 +- docs/pages/nationstates.rst | 4 +- docs/pages/ratelimit.rst | 2 +- nationstates/exceptions.py | 13 ++- nationstates/info.py | 2 + nationstates/main.py | 7 +- nationstates/nsapiwrapper/exceptions.py | 8 +- nationstates/objects.py | 113 ++++++++++++------- setup.py | 2 +- tests/test_call.py | 142 +++++++++++++++++++++--- 10 files changed, 226 insertions(+), 71 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index d7c9a29..91e0a18 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -57,9 +57,9 @@ # built documents. # # The short X.Y version. -version = '3.0.3' +version = '3.1' # The full version, including alpha/beta/rc tags. -release = '3.0.3.9' +release = '3.1.4' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/docs/pages/nationstates.rst b/docs/pages/nationstates.rst index 3ec129e..c56abca 100644 --- a/docs/pages/nationstates.rst +++ b/docs/pages/nationstates.rst @@ -84,7 +84,9 @@ You can view what each endpoint currently supports in it's magic methods by view >>> nationstates.get_shard {'get_customreligion', 'get_rcensus', 'get_banners', 'get_govtpriority', 'get_banner', 'get_census', 'get_gavote', 'get_wcensus', 'get_firstlogin', 'get_notable', 'get_admirable', 'get_foundedtime', 'get_category', 'get_customleader', 'get_flag', 'get_currency', 'get_endorsements', 'get_lastlogin', 'get_region', 'get_religion', 'get_capital', 'get_name', 'get_type', 'get_happenings', 'get_crime', 'get_govtdesc', 'get_majorindustry', 'get_influence', 'get_customcapital', 'get_tax', 'get_tgcanrecruit', 'get_demonym2', 'get_legislation', 'get_poorest', 'get_wa', 'get_sectors', 'get_deaths', 'get_dbid', 'get_policies', 'get_scvote', 'get_lastactivity', 'get_demonym', 'get_freedom', 'get_animal', 'get_factbooklist', 'get_industrydesc', 'get_income', 'get_population', 'get_founded', 'get_richest', 'get_demonym2plural', 'get_gdp', 'get_dispatches', 'get_publicsector', 'get_fullname', 'get_motto', 'get_tgcancampaign', 'get_govt', 'get_sensibilities', 'get_dispatchlist', 'get_wabadges', 'get_factbooks', 'get_animaltrait', 'get_leader'} + + Is pynationstates thread safe? ============================== -pynationstates does have locks in place that should make it safe to use across threads. However, the author recommends you have independent `nationstates.Nationstates` instances for earch thread. This guarntees everything will work. +Pynationstates is now fully thread safe and will work as is across threads. diff --git a/docs/pages/ratelimit.rst b/docs/pages/ratelimit.rst index 98f2ee3..6b056c5 100644 --- a/docs/pages/ratelimit.rst +++ b/docs/pages/ratelimit.rst @@ -8,7 +8,7 @@ The Nationstates package constains an automatic ratelimiter. It's a simple imple How to use the Rate Limiter --------------------------- -The Rate Limit system is completely automatic, and will simply ``time.sleep()`` your thread if it thinks your getting close to the api limit. Each thread keeps tracks of its own requests, so it can leave this period as soon as possible. Due to the possibility of multiple threads, this library slightly lowers the amount of requests per 30 second block to prevent accidental breaches of the ratelimit. +The Rate Limit system is completely automatic, and will simply ``time.sleep()`` your thread if it thinks your getting close to the api limit. Each process keeps tracks of its own requests, so it can leave this period as soon as possible. Due to the possibility of multiple processes, this library slightly lowers the amount of requests per 30 second block to prevent accidental breaches of the ratelimit. Disabling the Rate Limiter -------------------------- diff --git a/nationstates/exceptions.py b/nationstates/exceptions.py index ff1271e..a344cb0 100644 --- a/nationstates/exceptions.py +++ b/nationstates/exceptions.py @@ -8,14 +8,21 @@ NotFound, APIRateLimitBan, APIUsageError, - DispatchTooRecent, + ActionTooRecent, InternalServerError, CloudflareServerError, BadRequest, ServerError, - BadResponse + BadResponse, + BetaDisabled ) class NotAuthenticated(Exception): """If an action requires Authentication but the object isn't Authenticated""" - pass \ No newline at end of file + pass + +class BetaDisabled(Exception): + """Beta Disabled""" + message = 'This Feature is marked as Beta. Pass True to Nationstates() object to enable this functionality' + +DispatchTooRecent = ActionTooRecent \ No newline at end of file diff --git a/nationstates/info.py b/nationstates/info.py index a4dd24d..7eb69e4 100644 --- a/nationstates/info.py +++ b/nationstates/info.py @@ -149,5 +149,7 @@ ) dispatch_to_soon = 'Your nation is attempting to issue many announcements in a short period of time. Please wait for the international press to catch their breath, then try again.' +rmb_to_soon = 'To prevent spam, you cannot post a message so soon after your previous one. Please try again in a few moments.' + diff --git a/nationstates/main.py b/nationstates/main.py index 78d632a..ad9f873 100644 --- a/nationstates/main.py +++ b/nationstates/main.py @@ -6,8 +6,8 @@ class Nationstates: def __init__(self, user_agent, version="11", ratelimit_sleep=True, ratelimit_limit=40, ratelimit_timeframe=30, ratelimit_sleep_time=4, ratelimit_maxsleeps=10, ratelimit_enabled=True, do_retry=True, - retry_sleep=5, max_retries=5, use_nsdict=True, use_session=True, threading_mode=False, - max_ongoing_requests=20): + retry_sleep=5, max_retries=5, use_nsdict=True, use_session=True, threading_mode=True, + max_ongoing_requests=20, enable_beta=False): self.api = nsapiwrapper.Api(user_agent, version=version, ratelimit_sleep=ratelimit_sleep, ratelimit_sleep_time=ratelimit_sleep_time, @@ -15,11 +15,12 @@ def __init__(self, user_agent, version="11", ratelimit_sleep=True, ratelimit_within=ratelimit_timeframe, ratelimit_maxsleeps=ratelimit_maxsleeps, ratelimit_enabled=ratelimit_enabled, - use_session=use_session and threading_mode) + use_session=use_session and not threading_mode) self.do_retry = do_retry self.retry_sleep = retry_sleep self.max_retries = max_retries self.use_nsdict = use_nsdict + self.enable_beta = enable_beta def nation(self, nation_name, password=None, autologin=None): """Setup access to the Nation API with the Nation object diff --git a/nationstates/nsapiwrapper/exceptions.py b/nationstates/nsapiwrapper/exceptions.py index 2367220..997bc04 100644 --- a/nationstates/nsapiwrapper/exceptions.py +++ b/nationstates/nsapiwrapper/exceptions.py @@ -36,7 +36,8 @@ class APIRateLimitBan(APIError): class APIUsageError(APIError): pass -class DispatchTooRecent(APIUsageError): + +class ActionTooRecent(APIUsageError): pass class ServerError(APIError): @@ -46,6 +47,7 @@ class ServerError(APIError): class ConflictError(ServerError): """ConflictError from Server""" pass + class InternalServerError(ServerError): pass @@ -56,6 +58,8 @@ class BadResponse(ServerError): # When NS returns an odd response we can't otherwise classify pass - class BadRequest(APIError): + pass + +class BetaDisabled(NSBaseError): pass \ No newline at end of file diff --git a/nationstates/objects.py b/nationstates/objects.py index 5f946a2..952142e 100644 --- a/nationstates/objects.py +++ b/nationstates/objects.py @@ -6,9 +6,9 @@ from time import sleep from functools import wraps -from .exceptions import ConflictError, InternalServerError, CloudflareServerError, APIUsageError, NotAuthenticated, BadResponse, DispatchTooRecent +from .exceptions import ConflictError, InternalServerError, CloudflareServerError, APIUsageError, NotAuthenticated, BadResponse, DispatchTooRecent, BetaDisabled, ActionTooRecent, NotFound from requests.exceptions import ConnectionError -from .info import nation_shards, region_shards, world_shards, wa_shards, individual_cards_shards, dispatch_to_soon +from .info import nation_shards, region_shards, world_shards, wa_shards, individual_cards_shards, dispatch_to_soon, rmb_to_soon import html @@ -44,17 +44,30 @@ def dispatch_token(resp, use_exception): return False return data['success'] -def dispatch_error_check(resp, use_exception): +def dispatch_error_check(resp, use_exception, custom_message='PlaceHolder'): + if custom_message: + checks = {dispatch_to_soon, rmb_to_soon, custom_message} + else: + checks = {dispatch_to_soon, rmb_to_soon} + data = resp['data'][Nation.api_name] if data.get('error'): if use_exception: - if data['error'] == dispatch_to_soon: - raise DispatchTooRecent(data['error']) + if data['error'] in checks: + raise ActionTooRecent(data['error']) raise APIUsageError(data['error']) else: return False return True +def action_full_response(api, final_resp, full_response): + if final_resp is False: + return False + elif full_response: + return final_resp + else: + return final_resp['data'][api.api_name] + class NSDict(dict): """Specialized Dict""" @@ -219,6 +232,10 @@ def __get_shards__(self, *args, full_response=False, use_post=False): resp = self.request(shards=args, full_response=full_response, use_post=False) return resp + def _check_beta(self): + if not self.api_mother.enable_beta: + raise BetaDisabled('Beta Endpoints are not enabled. Pass enable_beta = True to nationstates.Nationstates to suppress') + def get_shards(self, *args, full_response=False): """Get Shards""" return self.__get_shards__(*args, full_response=full_response, use_post=False) @@ -268,6 +285,13 @@ def _check_auth(self): if not self.is_auth: raise NotAuthenticated("Action requires authentication") + def exists(self): + try: + self.get_shards('name') + return True + except NotFound: + return False + def authenticate(self, password=None, autologin=None): self._set_apiwrapper(self._determine_api(self.nation_name, password, autologin)) return self @@ -287,33 +311,40 @@ def pick_issue(self, issue_id, option, full_response=False, raise_exception_if_f else: return resp["data"][self.api_name] - def _dispatch_request(self, dispatch, use_exception=True, **kwargs): - self._check_auth() - token_resp = self.command('dispatch', dispatch=dispatch, mode='prepare', nation=self.nation_name, full_response=True, use_post=True, **kwargs) + + def _prepare_execute_request(self, name, bad_message, use_exception=True, **kwargs): + token_resp = self.command(name, mode='prepare', nation=self.nation_name, full_response=True, use_post=True, **kwargs) token = dispatch_token(token_resp, use_exception) if use_exception is False and token is False: return False - final_resp = self.command('dispatch', dispatch=dispatch, mode='execute', token=token, nation=self.nation_name, full_response=True, use_post=True, **kwargs) - check = dispatch_error_check(final_resp, use_exception) - # Check was False - we need to return False down the line + final_resp = self.command(name, mode='execute', nation=self.nation_name, token=token, full_response=True, use_post=True, **kwargs) + check = dispatch_error_check(final_resp, use_exception, bad_message) if not check: return check else: return final_resp - def _dispatch(self, dispatch, use_exception=True, **kwargs): - limit = 10 - sleep_time = 5 + def execute_command(self, name, use_exception=True, limit=10, sleep_time=5, too_soon_message=None, **kwargs): + """ Executes a command that follows the prepare and execute paradigm """ last_exc = None while limit > 0: try: - return self._dispatch_request(dispatch, use_exception=use_exception, **kwargs) - except DispatchTooRecent as Exc: + return self._prepare_execute_request(name, too_soon_message, use_exception=use_exception, **kwargs) + except ActionTooRecent as Exc: limit = limit - 1 - sleep_thread(sleep_time) last_exc = Exc + sleep_thread(sleep_time) raise last_exc + def _dispatch(self, dispatch, use_exception=True, **kwargs): + if not self.api_mother.enable_beta: + print('Warning: Beta Features are not enabled, but due to backwards compatiblity this method is not disabled. Enable Beta Flag to supress this message') + self._check_auth() + + + kwargs['dispatch'] = dispatch + + return self.execute_command('dispatch', use_exception=use_exception, **kwargs) def create_dispatch(self, title=None, text=None, category=None, subcategory=None, full_response=False, use_exception=True): cant_be_none(title=title, text=text, category=category, subcategory=subcategory) @@ -321,12 +352,7 @@ def create_dispatch(self, title=None, text=None, category=None, subcategory=None final_resp = self._dispatch('add', title=title, text=text, category=category, subcategory=subcategory, use_exception=use_exception) - if final_resp is False: - return False - elif full_response: - return final_resp - else: - return final_resp['data'][self.api_name] + return action_full_response(self, final_resp, full_response) def edit_dispatch(self, dispatch_id=None, title=None, text=None, category=None, subcategory=None, full_response=False, use_exception=True): cant_be_none(dispatch_id=dispatch_id, title=title, text=text, category=category, subcategory=subcategory) @@ -334,24 +360,16 @@ def edit_dispatch(self, dispatch_id=None, title=None, text=None, category=None, final_resp = self._dispatch('edit', dispatchid=dispatch_id, title=title, text=text, category=category, subcategory=subcategory, use_exception=use_exception) - if final_resp is False: - return False - elif full_response: - return final_resp - else: - return final_resp['data'][self.api_name] + return action_full_response(self, final_resp, full_response) + def remove_dispatch(self, dispatch_id=None, full_response=False, use_exception=True): cant_be_none(dispatch_id=dispatch_id) final_resp = self._dispatch('remove', dispatchid=dispatch_id, use_exception=use_exception) - if final_resp is False: - return False - elif full_response: - return final_resp - else: - return final_resp['data'][self.api_name] + return action_full_response(self, final_resp, full_response) + def send_telegram(self, telegram=None, client_key=None, tgid=None, key=None): """Sends Telegram. Can either provide a telegram directly, or provide the api details and created internally @@ -367,6 +385,15 @@ def send_telegram(self, telegram=None, client_key=None, tgid=None, key=None): telegram = self.api_mother.telegram(client_key, tgid, key) telegram.send_telegram(self.nation_name) + def send_rmb(self, region=None, text=None, full_response=False): + self._check_beta() + self._check_auth() + cant_be_none(region=region, text=text) + if isinstance(region, Region): + region = region.region_name + final_resp = self.execute_command('rmbpost', nation_name=self.nation_name, region=region, text=text) + return action_full_response(self, final_resp, full_response) + def verify(self, checksum=None, token=None): """Wraps around the verify API""" cant_be_none(checksum=checksum, token=token) @@ -401,6 +428,13 @@ def __repr__(self): value=self.region_name, hexloc=hex(id(self)).upper().replace("X", "x")) + def exists(self): + try: + self.get_shards('name') + return True + except NotFound: + return False + @property def nations(self): resp = self._auto_shard("nations") @@ -450,13 +484,8 @@ def _determine_api(self, chamber): @property def nations(self): - resp = self._auto_shard("nations") - return tuple(self.api_mother.nation(x) for x in resp.split(":")) - - @property - def regions(self): - resp = self._auto_shard("regions") - return tuple(self.api_mother.region(x) for x in resp.split(":")) + resp = self._auto_shard("members") + return tuple(self.api_mother.nation(x) for x in resp.split(",")) class Telegram(API_WRAPPER): api_name = TelegramAPI.api_name diff --git a/setup.py b/setup.py index 8d42d3e..bbceae1 100644 --- a/setup.py +++ b/setup.py @@ -26,7 +26,7 @@ """ -version = '3.0.3.9' +version = '3.1.4' from setuptools import setup setup(name='nationstates', diff --git a/tests/test_call.py b/tests/test_call.py index 81d3371..f3371bd 100644 --- a/tests/test_call.py +++ b/tests/test_call.py @@ -16,16 +16,20 @@ sep_api = ns.Nationstates(USERAGENT) joint_api = ns.Nationstates(USERAGENT) +joint_api_enable_beta = ns.Nationstates(USERAGENT, enable_beta=True) +joint_api_use_session = ns.Nationstates(USERAGENT, threading_mode=False) test_nation_nonauth = joint_api.nation(test_nation) test_auth_nation = joint_api.nation(test_nation, password=PASSWORD) +test_auth_nation_BETA = joint_api_enable_beta.nation(test_nation, password=PASSWORD) + test_nation_r = joint_api.nation(test_nation_r) issue_nation_1 = joint_api.nation('Pynationstates Issue Farm 1', password=PASSWORD) issue_nation_2 = joint_api.nation('Pynationstates Issue Farm 2', password=PASSWORD) issue_nation_3 = joint_api.nation('Pynationstates Issue Farm 3', password=PASSWORD) issue_nation_zero = joint_api.nation('pynationstates_0_issues_test_nation', password=PASSWORD) api_threads = ns.Nationstates(USERAGENT, threading_mode=True) - - +fake_nation = joint_api.nation('FAKE NATION 1 FAKE NATION 1 FAKE NATION 1 FAKE NATION 1') +fake_region = joint_api.region('FAKE REGION 1 FAKE REGION 1 FAKE REGION 1 FAKE REGION 1') def grab_id(newfactbookresponse_text): part1 = newfactbookresponse_text.split('id=') return part1[1].split('">')[0] @@ -39,6 +43,8 @@ def test_create_ns(self): except Exception as Err: self.fail(Err) + + class SeperateCallTest(unittest.TestCase): def test_nation_call(self): @@ -51,6 +57,35 @@ def test_nation_call(self): except Exception as Err: self.fail(Err) + def test_nation_region_calls(self): + try: + api = sep_api + mycall = api.nation("testlandia") + myr = mycall.region + myr.nations + api.world().nations + api.world().regions + api.wa('0').nations + + except Exception as Err: + self.fail(Err) + + def test_beta(self): + from datetime import datetime + now = datetime.now + try: + test_auth_nation_BETA._check_beta() + + except Exception as Err: + self.fail(Err) + + try: + test_auth_nation._check_beta() + self.fail('beta flag false') + + except Exception as Err: + pass + def test_region_call(self): try: api = sep_api @@ -114,6 +149,36 @@ def test_cards_decks_call(self): except Exception as Err: self.fail(Err) + def test_cards_decks_call_null(self): + try: + api = sep_api + + mycall = api.cards() + mycall.decks() + + self.fail(Err) + + # mycall.get_shards(choice(mycall.auto_shards)) + # mycall.get_shards(choice(mycall.auto_shards), full_response=True) + except Exception as Err: + pass + + def test_cards_decks_call_both(self): + try: + api = sep_api + + mycall = api.cards() + mycall.decks(nation_name='testlandia', nation_id=1) + + self.fail('fail') + + # mycall.get_shards(choice(mycall.auto_shards)) + # mycall.get_shards(choice(mycall.auto_shards), full_response=True) + except Exception as Err: + pass + + + def test_cards_decksinfo_call(self): try: api = sep_api @@ -157,6 +222,7 @@ def test_cards_collections_call(self): self.fail(Err) + def test_cards_auctions_call(self): try: api = sep_api @@ -230,18 +296,41 @@ def test_private_nation(self): except Exception as Err: self.fail(Err) + def test_exists(self): + assert fake_nation.exists() is False + assert fake_region.exists() is False + assert test_auth_nation.exists() + assert fake_nation.exists() is False + assert test_auth_nation.region.exists() def test_create_dispatch(self): from datetime import datetime now = datetime.now try: - resp = test_auth_nation.create_dispatch(title='AUTOMATED ADD DISPATCH TEST', text=str(now()), category=1, subcategory=105, full_response=True) + resp = test_auth_nation_BETA.create_dispatch(title='AUTOMATED ADD DISPATCH TEST', text=str(now()), category=1, subcategory=105, full_response=True) dispatch_id = grab_id(resp['data']['nation']['success']) - resp = test_auth_nation.remove_dispatch(dispatch_id=dispatch_id, full_response=True) + resp = test_auth_nation_BETA.remove_dispatch(dispatch_id=dispatch_id, full_response=True) - resp = test_auth_nation.create_dispatch(title='AUTOMATED ADD DISPATCH TEST', text=str(now()), category=1, subcategory=105, full_response=False) + resp = test_auth_nation_BETA.create_dispatch(title='AUTOMATED ADD DISPATCH TEST', text=str(now()), category=1, subcategory=105, full_response=False) dispatch_id = grab_id(resp.success) - resp = test_auth_nation.remove_dispatch(dispatch_id=dispatch_id, full_response=True) + resp = test_auth_nation_BETA.remove_dispatch(dispatch_id=dispatch_id, full_response=True) + + + except Exception as Err: + self.fail(Err) + + + def test_create_dispatch(self): + from datetime import datetime + now = datetime.now + try: + resp = test_auth_nation_BETA.create_dispatch(title='AUTOMATED ADD DISPATCH TEST', text=str(now()), category=1, subcategory=105, full_response=True) + dispatch_id = grab_id(resp['data']['nation']['success']) + resp = test_auth_nation_BETA.remove_dispatch(dispatch_id=dispatch_id, full_response=True) + + resp = test_auth_nation_BETA.create_dispatch(title='AUTOMATED ADD DISPATCH TEST', text=str(now()), category=1, subcategory=105, full_response=False) + dispatch_id = grab_id(resp.success) + resp = test_auth_nation_BETA.remove_dispatch(dispatch_id=dispatch_id, full_response=True) except Exception as Err: @@ -251,14 +340,14 @@ def test_edit_dispatch(self): from datetime import datetime now = datetime.now try: - resp = test_auth_nation.create_dispatch(title='AUTOMATED ADD DISPATCH EDIT TEST', text=str(now()), category=1, subcategory=105, full_response=False) + resp = test_auth_nation_BETA.create_dispatch(title='AUTOMATED ADD DISPATCH EDIT TEST', text=str(now()), category=1, subcategory=105, full_response=False) dispatch_id = grab_id(resp.success) - resp = test_auth_nation.edit_dispatch(dispatch_id=dispatch_id, title='EDIT TEST', text="THIS POST WAS LAST EDITED AT:" + str(now()), category=1, subcategory=111, full_response=False) - resp = test_auth_nation.remove_dispatch(dispatch_id=dispatch_id, full_response=True) - resp = test_auth_nation.create_dispatch(title='AUTOMATED ADD DISPATCH EDIT TEST', text=str(now()), category=1, subcategory=105, full_response=False) + resp = test_auth_nation_BETA.edit_dispatch(dispatch_id=dispatch_id, title='EDIT TEST', text="THIS POST WAS LAST EDITED AT:" + str(now()), category=1, subcategory=111, full_response=False) + resp = test_auth_nation_BETA.remove_dispatch(dispatch_id=dispatch_id, full_response=True) + resp = test_auth_nation_BETA.create_dispatch(title='AUTOMATED ADD DISPATCH EDIT TEST', text=str(now()), category=1, subcategory=105, full_response=False) dispatch_id = grab_id(resp.success) - resp = test_auth_nation.edit_dispatch(dispatch_id=dispatch_id, title='EDIT TEST', text="THIS POST WAS LAST EDITED AT:" + str(now()), category=1, subcategory=111, full_response=True) - resp = test_auth_nation.remove_dispatch(dispatch_id=dispatch_id, full_response=True) + resp = test_auth_nation_BETA.edit_dispatch(dispatch_id=dispatch_id, title='EDIT TEST', text="THIS POST WAS LAST EDITED AT:" + str(now()), category=1, subcategory=111, full_response=True) + resp = test_auth_nation_BETA.remove_dispatch(dispatch_id=dispatch_id, full_response=True) except Exception as Err: self.fail(Err) @@ -267,15 +356,36 @@ def test_remove_dispatch(self): from datetime import datetime now = datetime.now try: - resp = test_auth_nation.create_dispatch(title='AUTOMATED ADD DISPATCH REMOVE TEST', text=str(now()), category=1, subcategory=105, full_response=False) + resp = test_auth_nation_BETA.create_dispatch(title='AUTOMATED ADD DISPATCH REMOVE TEST', text=str(now()), category=1, subcategory=105, full_response=False) dispatch_id = grab_id(resp.success) - resp = test_auth_nation.remove_dispatch(dispatch_id=dispatch_id) - resp = test_auth_nation.create_dispatch(title='AUTOMATED ADD DISPATCH REMOVE TEST', text=str(now()), category=1, subcategory=105, full_response=False) + resp = test_auth_nation_BETA.remove_dispatch(dispatch_id=dispatch_id) + resp = test_auth_nation_BETA.create_dispatch(title='AUTOMATED ADD DISPATCH REMOVE TEST', text=str(now()), category=1, subcategory=105, full_response=False) dispatch_id = grab_id(resp.success) - resp = test_auth_nation.remove_dispatch(dispatch_id=dispatch_id, full_response=True) + resp = test_auth_nation_BETA.remove_dispatch(dispatch_id=dispatch_id, full_response=True) except Exception as Err: self.fail(Err) + def test_remove_dispatch(self): + from datetime import datetime + now = datetime.now + try: + resp = test_auth_nation_BETA.remove_dispatch(dispatch_id=None, full_response=True) + self.fail('should of failed') + + except Exception as Err: + pass + + + def test_send_rmb(self): + from datetime import datetime + now = datetime.now + try: + test_auth_nation_BETA.send_rmb(test_auth_nation.region, 'Circle CI: Automated Test') + + except Exception as Err: + self.fail(Err) + + def test_telegram_send(self): from datetime import datetime