mirror of https://github.com/caronc/apprise
				
				
				
			Use aware UTC datetimes internally (#887)
In lieu of Python v3.12 deprecation warningspull/893/head
							parent
							
								
									3346977297
								
							
						
					
					
						commit
						3d36108446
					
				| 
						 | 
				
			
			@ -43,6 +43,7 @@ from email import charset
 | 
			
		|||
 | 
			
		||||
from socket import error as SocketError
 | 
			
		||||
from datetime import datetime
 | 
			
		||||
from datetime import timezone
 | 
			
		||||
 | 
			
		||||
from .NotifyBase import NotifyBase
 | 
			
		||||
from ..URLBase import PrivacyMode
 | 
			
		||||
| 
						 | 
				
			
			@ -805,7 +806,8 @@ class NotifyEmail(NotifyBase):
 | 
			
		|||
            base['To'] = formataddr((to_name, to_addr), charset='utf-8')
 | 
			
		||||
            base['Message-ID'] = make_msgid(domain=self.smtp_host)
 | 
			
		||||
            base['Date'] = \
 | 
			
		||||
                datetime.utcnow().strftime("%a, %d %b %Y %H:%M:%S +0000")
 | 
			
		||||
                datetime.now(timezone.utc)\
 | 
			
		||||
                .strftime("%a, %d %b %Y %H:%M:%S +0000")
 | 
			
		||||
            base['X-Application'] = self.app_id
 | 
			
		||||
 | 
			
		||||
            if cc:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -47,6 +47,7 @@ from cryptography.hazmat.primitives import asymmetric
 | 
			
		|||
from cryptography.exceptions import UnsupportedAlgorithm
 | 
			
		||||
from datetime import datetime
 | 
			
		||||
from datetime import timedelta
 | 
			
		||||
from datetime import timezone
 | 
			
		||||
from json.decoder import JSONDecodeError
 | 
			
		||||
from urllib.parse import urlencode as _urlencode
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -106,7 +107,7 @@ class GoogleOAuth:
 | 
			
		|||
        # Our keys we build using the provided content
 | 
			
		||||
        self.__refresh_token = None
 | 
			
		||||
        self.__access_token = None
 | 
			
		||||
        self.__access_token_expiry = datetime.utcnow()
 | 
			
		||||
        self.__access_token_expiry = datetime.now(timezone.utc)
 | 
			
		||||
 | 
			
		||||
    def load(self, path):
 | 
			
		||||
        """
 | 
			
		||||
| 
						 | 
				
			
			@ -117,7 +118,7 @@ class GoogleOAuth:
 | 
			
		|||
        self.content = None
 | 
			
		||||
        self.private_key = None
 | 
			
		||||
        self.__access_token = None
 | 
			
		||||
        self.__access_token_expiry = datetime.utcnow()
 | 
			
		||||
        self.__access_token_expiry = datetime.now(timezone.utc)
 | 
			
		||||
 | 
			
		||||
        try:
 | 
			
		||||
            with open(path, mode="r", encoding=self.encoding) as fp:
 | 
			
		||||
| 
						 | 
				
			
			@ -199,7 +200,7 @@ class GoogleOAuth:
 | 
			
		|||
                'token with.')
 | 
			
		||||
            return None
 | 
			
		||||
 | 
			
		||||
        if self.__access_token_expiry > datetime.utcnow():
 | 
			
		||||
        if self.__access_token_expiry > datetime.now(timezone.utc):
 | 
			
		||||
            # Return our no-expired key
 | 
			
		||||
            return self.__access_token
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -209,7 +210,7 @@ class GoogleOAuth:
 | 
			
		|||
        key_identifier = self.content.get('private_key_id')
 | 
			
		||||
 | 
			
		||||
        # Generate our Assertion
 | 
			
		||||
        now = datetime.utcnow()
 | 
			
		||||
        now = datetime.now(timezone.utc)
 | 
			
		||||
        expiry = now + self.access_token_lifetime_sec
 | 
			
		||||
 | 
			
		||||
        payload = {
 | 
			
		||||
| 
						 | 
				
			
			@ -301,7 +302,7 @@ class GoogleOAuth:
 | 
			
		|||
        if 'expires_in' in response:
 | 
			
		||||
            delta = timedelta(seconds=int(response['expires_in']))
 | 
			
		||||
            self.__access_token_expiry = \
 | 
			
		||||
                delta + datetime.utcnow() - self.clock_skew
 | 
			
		||||
                delta + datetime.now(timezone.utc) - self.clock_skew
 | 
			
		||||
 | 
			
		||||
        else:
 | 
			
		||||
            # Allow some grace before we expire
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -50,6 +50,7 @@ import requests
 | 
			
		|||
from json import loads
 | 
			
		||||
from json import dumps
 | 
			
		||||
from datetime import datetime
 | 
			
		||||
from datetime import timezone
 | 
			
		||||
 | 
			
		||||
from .NotifyBase import NotifyBase
 | 
			
		||||
from ..common import NotifyImageSize
 | 
			
		||||
| 
						 | 
				
			
			@ -99,7 +100,7 @@ class NotifyGitter(NotifyBase):
 | 
			
		|||
    request_rate_per_sec = 0
 | 
			
		||||
 | 
			
		||||
    # For Tracking Purposes
 | 
			
		||||
    ratelimit_reset = datetime.utcnow()
 | 
			
		||||
    ratelimit_reset = datetime.now(timezone.utc).replace(tzinfo=None)
 | 
			
		||||
 | 
			
		||||
    # Default to 1
 | 
			
		||||
    ratelimit_remaining = 1
 | 
			
		||||
| 
						 | 
				
			
			@ -298,7 +299,7 @@ class NotifyGitter(NotifyBase):
 | 
			
		|||
            # Gitter server.  One would hope we're on NTP and our clocks are
 | 
			
		||||
            # the same allowing this to role smoothly:
 | 
			
		||||
 | 
			
		||||
            now = datetime.utcnow()
 | 
			
		||||
            now = datetime.now(timezone.utc).replace(tzinfo=None)
 | 
			
		||||
            if now < self.ratelimit_reset:
 | 
			
		||||
                # We need to throttle for the difference in seconds
 | 
			
		||||
                # We add 0.5 seconds to the end just to allow a grace
 | 
			
		||||
| 
						 | 
				
			
			@ -350,8 +351,9 @@ class NotifyGitter(NotifyBase):
 | 
			
		|||
            try:
 | 
			
		||||
                self.ratelimit_remaining = \
 | 
			
		||||
                    int(r.headers.get('X-RateLimit-Remaining'))
 | 
			
		||||
                self.ratelimit_reset = datetime.utcfromtimestamp(
 | 
			
		||||
                    int(r.headers.get('X-RateLimit-Reset')))
 | 
			
		||||
                self.ratelimit_reset = datetime.fromtimestamp(
 | 
			
		||||
                    int(r.headers.get('X-RateLimit-Reset')), timezone.utc
 | 
			
		||||
                ).replace(tzinfo=None)
 | 
			
		||||
 | 
			
		||||
            except (TypeError, ValueError):
 | 
			
		||||
                # This is returned if we could not retrieve this information
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -35,6 +35,7 @@ import requests
 | 
			
		|||
from copy import deepcopy
 | 
			
		||||
from json import dumps, loads
 | 
			
		||||
from datetime import datetime
 | 
			
		||||
from datetime import timezone
 | 
			
		||||
 | 
			
		||||
from .NotifyBase import NotifyBase
 | 
			
		||||
from ..URLBase import PrivacyMode
 | 
			
		||||
| 
						 | 
				
			
			@ -150,7 +151,7 @@ class NotifyMastodon(NotifyBase):
 | 
			
		|||
    request_rate_per_sec = 0
 | 
			
		||||
 | 
			
		||||
    # For Tracking Purposes
 | 
			
		||||
    ratelimit_reset = datetime.utcnow()
 | 
			
		||||
    ratelimit_reset = datetime.now(timezone.utc).replace(tzinfo=None)
 | 
			
		||||
 | 
			
		||||
    # Default to 1000; users can send up to 1000 DM's and 2400 toot a day
 | 
			
		||||
    # This value only get's adjusted if the server sets it that way
 | 
			
		||||
| 
						 | 
				
			
			@ -834,7 +835,7 @@ class NotifyMastodon(NotifyBase):
 | 
			
		|||
            # Mastodon server.  One would hope we're on NTP and our clocks are
 | 
			
		||||
            # the same allowing this to role smoothly:
 | 
			
		||||
 | 
			
		||||
            now = datetime.utcnow()
 | 
			
		||||
            now = datetime.now(timezone.utc).replace(tzinfo=None)
 | 
			
		||||
            if now < self.ratelimit_reset:
 | 
			
		||||
                # We need to throttle for the difference in seconds
 | 
			
		||||
                # We add 0.5 seconds to the end just to allow a grace
 | 
			
		||||
| 
						 | 
				
			
			@ -892,8 +893,9 @@ class NotifyMastodon(NotifyBase):
 | 
			
		|||
                # Capture rate limiting if possible
 | 
			
		||||
                self.ratelimit_remaining = \
 | 
			
		||||
                    int(r.headers.get('X-RateLimit-Remaining'))
 | 
			
		||||
                self.ratelimit_reset = datetime.utcfromtimestamp(
 | 
			
		||||
                    int(r.headers.get('X-RateLimit-Limit')))
 | 
			
		||||
                self.ratelimit_reset = datetime.fromtimestamp(
 | 
			
		||||
                    int(r.headers.get('X-RateLimit-Limit')), timezone.utc
 | 
			
		||||
                ).replace(tzinfo=None)
 | 
			
		||||
 | 
			
		||||
            except (TypeError, ValueError):
 | 
			
		||||
                # This is returned if we could not retrieve this information
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -56,6 +56,7 @@ import requests
 | 
			
		|||
from json import loads
 | 
			
		||||
from datetime import timedelta
 | 
			
		||||
from datetime import datetime
 | 
			
		||||
from datetime import timezone
 | 
			
		||||
 | 
			
		||||
from .NotifyBase import NotifyBase
 | 
			
		||||
from ..URLBase import PrivacyMode
 | 
			
		||||
| 
						 | 
				
			
			@ -134,7 +135,7 @@ class NotifyReddit(NotifyBase):
 | 
			
		|||
    request_rate_per_sec = 0
 | 
			
		||||
 | 
			
		||||
    # For Tracking Purposes
 | 
			
		||||
    ratelimit_reset = datetime.utcnow()
 | 
			
		||||
    ratelimit_reset = datetime.now(timezone.utc).replace(tzinfo=None)
 | 
			
		||||
 | 
			
		||||
    # Default to 1.0
 | 
			
		||||
    ratelimit_remaining = 1.0
 | 
			
		||||
| 
						 | 
				
			
			@ -275,7 +276,7 @@ class NotifyReddit(NotifyBase):
 | 
			
		|||
        # Our keys we build using the provided content
 | 
			
		||||
        self.__refresh_token = None
 | 
			
		||||
        self.__access_token = None
 | 
			
		||||
        self.__access_token_expiry = datetime.utcnow()
 | 
			
		||||
        self.__access_token_expiry = datetime.now(timezone.utc)
 | 
			
		||||
 | 
			
		||||
        self.kind = kind.strip().lower() \
 | 
			
		||||
            if isinstance(kind, str) \
 | 
			
		||||
| 
						 | 
				
			
			@ -417,10 +418,10 @@ class NotifyReddit(NotifyBase):
 | 
			
		|||
        if 'expires_in' in response:
 | 
			
		||||
            delta = timedelta(seconds=int(response['expires_in']))
 | 
			
		||||
            self.__access_token_expiry = \
 | 
			
		||||
                delta + datetime.utcnow() - self.clock_skew
 | 
			
		||||
                delta + datetime.now(timezone.utc) - self.clock_skew
 | 
			
		||||
        else:
 | 
			
		||||
            self.__access_token_expiry = self.access_token_lifetime_sec + \
 | 
			
		||||
                datetime.utcnow() - self.clock_skew
 | 
			
		||||
                datetime.now(timezone.utc) - self.clock_skew
 | 
			
		||||
 | 
			
		||||
        # The Refresh Token
 | 
			
		||||
        self.__refresh_token = response.get(
 | 
			
		||||
| 
						 | 
				
			
			@ -547,7 +548,7 @@ class NotifyReddit(NotifyBase):
 | 
			
		|||
            # Gitter server.  One would hope we're on NTP and our clocks are
 | 
			
		||||
            # the same allowing this to role smoothly:
 | 
			
		||||
 | 
			
		||||
            now = datetime.utcnow()
 | 
			
		||||
            now = datetime.now(timezone.utc).replace(tzinfo=None)
 | 
			
		||||
            if now < self.ratelimit_reset:
 | 
			
		||||
                # We need to throttle for the difference in seconds
 | 
			
		||||
                wait = abs(
 | 
			
		||||
| 
						 | 
				
			
			@ -671,8 +672,9 @@ class NotifyReddit(NotifyBase):
 | 
			
		|||
                self.ratelimit_remaining = \
 | 
			
		||||
                    float(r.headers.get(
 | 
			
		||||
                        'X-RateLimit-Remaining'))
 | 
			
		||||
                self.ratelimit_reset = datetime.utcfromtimestamp(
 | 
			
		||||
                    int(r.headers.get('X-RateLimit-Reset')))
 | 
			
		||||
                self.ratelimit_reset = datetime.fromtimestamp(
 | 
			
		||||
                    int(r.headers.get('X-RateLimit-Reset')), timezone.utc
 | 
			
		||||
                ).replace(tzinfo=None)
 | 
			
		||||
 | 
			
		||||
            except (TypeError, ValueError):
 | 
			
		||||
                # This is returned if we could not retrieve this information
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -89,6 +89,7 @@ import base64
 | 
			
		|||
import requests
 | 
			
		||||
from hashlib import sha256
 | 
			
		||||
from datetime import datetime
 | 
			
		||||
from datetime import timezone
 | 
			
		||||
from collections import OrderedDict
 | 
			
		||||
from xml.etree import ElementTree
 | 
			
		||||
from email.mime.text import MIMEText
 | 
			
		||||
| 
						 | 
				
			
			@ -436,7 +437,8 @@ class NotifySES(NotifyBase):
 | 
			
		|||
                base['Reply-To'] = formataddr(reply_to, charset='utf-8')
 | 
			
		||||
            base['Cc'] = ','.join(cc)
 | 
			
		||||
            base['Date'] = \
 | 
			
		||||
                datetime.utcnow().strftime("%a, %d %b %Y %H:%M:%S +0000")
 | 
			
		||||
                datetime.now(
 | 
			
		||||
                    timezone.utc).strftime("%a, %d %b %Y %H:%M:%S +0000")
 | 
			
		||||
            base['X-Application'] = self.app_id
 | 
			
		||||
 | 
			
		||||
            if attach:
 | 
			
		||||
| 
						 | 
				
			
			@ -585,7 +587,7 @@ class NotifySES(NotifyBase):
 | 
			
		|||
        }
 | 
			
		||||
 | 
			
		||||
        # Get a reference time (used for header construction)
 | 
			
		||||
        reference = datetime.utcnow()
 | 
			
		||||
        reference = datetime.now(timezone.utc)
 | 
			
		||||
 | 
			
		||||
        # Provide Content-Length
 | 
			
		||||
        headers['Content-Length'] = str(len(payload))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -35,6 +35,7 @@ import hmac
 | 
			
		|||
import requests
 | 
			
		||||
from hashlib import sha256
 | 
			
		||||
from datetime import datetime
 | 
			
		||||
from datetime import timezone
 | 
			
		||||
from collections import OrderedDict
 | 
			
		||||
from xml.etree import ElementTree
 | 
			
		||||
from itertools import chain
 | 
			
		||||
| 
						 | 
				
			
			@ -396,7 +397,7 @@ class NotifySNS(NotifyBase):
 | 
			
		|||
        }
 | 
			
		||||
 | 
			
		||||
        # Get a reference time (used for header construction)
 | 
			
		||||
        reference = datetime.utcnow()
 | 
			
		||||
        reference = datetime.now(timezone.utc)
 | 
			
		||||
 | 
			
		||||
        # Provide Content-Length
 | 
			
		||||
        headers['Content-Length'] = str(len(payload))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -36,6 +36,7 @@ import re
 | 
			
		|||
import requests
 | 
			
		||||
from copy import deepcopy
 | 
			
		||||
from datetime import datetime
 | 
			
		||||
from datetime import timezone
 | 
			
		||||
from requests_oauthlib import OAuth1
 | 
			
		||||
from json import dumps
 | 
			
		||||
from json import loads
 | 
			
		||||
| 
						 | 
				
			
			@ -124,7 +125,7 @@ class NotifyTwitter(NotifyBase):
 | 
			
		|||
    request_rate_per_sec = 0
 | 
			
		||||
 | 
			
		||||
    # For Tracking Purposes
 | 
			
		||||
    ratelimit_reset = datetime.utcnow()
 | 
			
		||||
    ratelimit_reset = datetime.now(timezone.utc).replace(tzinfo=None)
 | 
			
		||||
 | 
			
		||||
    # Default to 1000; users can send up to 1000 DM's and 2400 tweets a day
 | 
			
		||||
    # This value only get's adjusted if the server sets it that way
 | 
			
		||||
| 
						 | 
				
			
			@ -678,7 +679,7 @@ class NotifyTwitter(NotifyBase):
 | 
			
		|||
            # Twitter server.  One would hope we're on NTP and our clocks are
 | 
			
		||||
            # the same allowing this to role smoothly:
 | 
			
		||||
 | 
			
		||||
            now = datetime.utcnow()
 | 
			
		||||
            now = datetime.now(timezone.utc).replace(tzinfo=None)
 | 
			
		||||
            if now < self.ratelimit_reset:
 | 
			
		||||
                # We need to throttle for the difference in seconds
 | 
			
		||||
                # We add 0.5 seconds to the end just to allow a grace
 | 
			
		||||
| 
						 | 
				
			
			@ -736,8 +737,9 @@ class NotifyTwitter(NotifyBase):
 | 
			
		|||
                # Capture rate limiting if possible
 | 
			
		||||
                self.ratelimit_remaining = \
 | 
			
		||||
                    int(r.headers.get('x-rate-limit-remaining'))
 | 
			
		||||
                self.ratelimit_reset = datetime.utcfromtimestamp(
 | 
			
		||||
                    int(r.headers.get('x-rate-limit-reset')))
 | 
			
		||||
                self.ratelimit_reset = datetime.fromtimestamp(
 | 
			
		||||
                    int(r.headers.get('x-rate-limit-reset')), timezone.utc
 | 
			
		||||
                ).replace(tzinfo=None)
 | 
			
		||||
 | 
			
		||||
            except (TypeError, ValueError):
 | 
			
		||||
                # This is returned if we could not retrieve this information
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -40,6 +40,7 @@ from helpers import AppriseURLTester
 | 
			
		|||
 | 
			
		||||
from json import dumps
 | 
			
		||||
from datetime import datetime
 | 
			
		||||
from datetime import timezone
 | 
			
		||||
 | 
			
		||||
# Disable logging for a cleaner testing output
 | 
			
		||||
import logging
 | 
			
		||||
| 
						 | 
				
			
			@ -156,13 +157,14 @@ def test_plugin_gitter_general(mock_post, mock_get):
 | 
			
		|||
    ]
 | 
			
		||||
 | 
			
		||||
    # Epoch time:
 | 
			
		||||
    epoch = datetime.utcfromtimestamp(0)
 | 
			
		||||
    epoch = datetime.fromtimestamp(0, timezone.utc)
 | 
			
		||||
 | 
			
		||||
    request = mock.Mock()
 | 
			
		||||
    request.content = dumps(response_obj)
 | 
			
		||||
    request.status_code = requests.codes.ok
 | 
			
		||||
    request.headers = {
 | 
			
		||||
        'X-RateLimit-Reset': (datetime.utcnow() - epoch).total_seconds(),
 | 
			
		||||
        'X-RateLimit-Reset': (
 | 
			
		||||
            datetime.now(timezone.utc) - epoch).total_seconds(),
 | 
			
		||||
        'X-RateLimit-Remaining': 1,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -211,21 +213,21 @@ def test_plugin_gitter_general(mock_post, mock_get):
 | 
			
		|||
 | 
			
		||||
    # Return our object, but place it in the future forcing us to block
 | 
			
		||||
    request.headers['X-RateLimit-Reset'] = \
 | 
			
		||||
        (datetime.utcnow() - epoch).total_seconds() + 1
 | 
			
		||||
        (datetime.now(timezone.utc) - epoch).total_seconds() + 1
 | 
			
		||||
    request.headers['X-RateLimit-Remaining'] = 0
 | 
			
		||||
    obj.ratelimit_remaining = 0
 | 
			
		||||
    assert obj.send(body="test") is True
 | 
			
		||||
 | 
			
		||||
    # Return our object, but place it in the future forcing us to block
 | 
			
		||||
    request.headers['X-RateLimit-Reset'] = \
 | 
			
		||||
        (datetime.utcnow() - epoch).total_seconds() - 1
 | 
			
		||||
        (datetime.now(timezone.utc) - epoch).total_seconds() - 1
 | 
			
		||||
    request.headers['X-RateLimit-Remaining'] = 0
 | 
			
		||||
    obj.ratelimit_remaining = 0
 | 
			
		||||
    assert obj.send(body="test") is True
 | 
			
		||||
 | 
			
		||||
    # Return our limits to always work
 | 
			
		||||
    request.headers['X-RateLimit-Reset'] = \
 | 
			
		||||
        (datetime.utcnow() - epoch).total_seconds()
 | 
			
		||||
        (datetime.now(timezone.utc) - epoch).total_seconds()
 | 
			
		||||
    request.headers['X-RateLimit-Remaining'] = 1
 | 
			
		||||
    obj.ratelimit_remaining = 1
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -36,6 +36,7 @@ from unittest import mock
 | 
			
		|||
import requests
 | 
			
		||||
from json import dumps, loads
 | 
			
		||||
from datetime import datetime
 | 
			
		||||
from datetime import timezone
 | 
			
		||||
from apprise import Apprise
 | 
			
		||||
from apprise import NotifyType
 | 
			
		||||
from apprise import AppriseAttachment
 | 
			
		||||
| 
						 | 
				
			
			@ -175,13 +176,14 @@ def test_plugin_mastodon_general(mock_post, mock_get):
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    # Epoch time:
 | 
			
		||||
    epoch = datetime.utcfromtimestamp(0)
 | 
			
		||||
    epoch = datetime.fromtimestamp(0, timezone.utc)
 | 
			
		||||
 | 
			
		||||
    request = mock.Mock()
 | 
			
		||||
    request.content = dumps(response_obj)
 | 
			
		||||
    request.status_code = requests.codes.ok
 | 
			
		||||
    request.headers = {
 | 
			
		||||
        'X-RateLimit-Limit': (datetime.utcnow() - epoch).total_seconds(),
 | 
			
		||||
        'X-RateLimit-Limit': (
 | 
			
		||||
            datetime.now(timezone.utc) - epoch).total_seconds(),
 | 
			
		||||
        'X-RateLimit-Remaining': 1,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -231,21 +233,21 @@ def test_plugin_mastodon_general(mock_post, mock_get):
 | 
			
		|||
 | 
			
		||||
    # Return our object, but place it in the future forcing us to block
 | 
			
		||||
    request.headers['X-RateLimit-Limit'] = \
 | 
			
		||||
        (datetime.utcnow() - epoch).total_seconds() + 1
 | 
			
		||||
        (datetime.now(timezone.utc) - epoch).total_seconds() + 1
 | 
			
		||||
    request.headers['X-RateLimit-Remaining'] = 0
 | 
			
		||||
    obj.ratelimit_remaining = 0
 | 
			
		||||
    assert obj.send(body="test") is True
 | 
			
		||||
 | 
			
		||||
    # Return our object, but place it in the future forcing us to block
 | 
			
		||||
    request.headers['X-RateLimit-Limit'] = \
 | 
			
		||||
        (datetime.utcnow() - epoch).total_seconds() - 1
 | 
			
		||||
        (datetime.now(timezone.utc) - epoch).total_seconds() - 1
 | 
			
		||||
    request.headers['X-RateLimit-Remaining'] = 0
 | 
			
		||||
    obj.ratelimit_remaining = 0
 | 
			
		||||
    assert obj.send(body="test") is True
 | 
			
		||||
 | 
			
		||||
    # Return our limits to always work
 | 
			
		||||
    request.headers['X-RateLimit-Limit'] = \
 | 
			
		||||
        (datetime.utcnow() - epoch).total_seconds()
 | 
			
		||||
        (datetime.now(timezone.utc) - epoch).total_seconds()
 | 
			
		||||
    request.headers['X-RateLimit-Remaining'] = 1
 | 
			
		||||
    obj.ratelimit_remaining = 1
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -39,6 +39,7 @@ from unittest import mock
 | 
			
		|||
from json import dumps
 | 
			
		||||
from datetime import datetime
 | 
			
		||||
from datetime import timedelta
 | 
			
		||||
from datetime import timezone
 | 
			
		||||
 | 
			
		||||
# Disable logging for a cleaner testing output
 | 
			
		||||
import logging
 | 
			
		||||
| 
						 | 
				
			
			@ -250,7 +251,7 @@ def test_plugin_reddit_general(mock_post):
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    # Epoch time:
 | 
			
		||||
    epoch = datetime.utcfromtimestamp(0)
 | 
			
		||||
    epoch = datetime.fromtimestamp(0, timezone.utc)
 | 
			
		||||
 | 
			
		||||
    good_response = mock.Mock()
 | 
			
		||||
    good_response.content = dumps({
 | 
			
		||||
| 
						 | 
				
			
			@ -267,7 +268,8 @@ def test_plugin_reddit_general(mock_post):
 | 
			
		|||
    })
 | 
			
		||||
    good_response.status_code = requests.codes.ok
 | 
			
		||||
    good_response.headers = {
 | 
			
		||||
        'X-RateLimit-Reset': (datetime.utcnow() - epoch).total_seconds(),
 | 
			
		||||
        'X-RateLimit-Reset': (
 | 
			
		||||
            datetime.now(timezone.utc) - epoch).total_seconds(),
 | 
			
		||||
        'X-RateLimit-Remaining': 1,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -296,7 +298,8 @@ def test_plugin_reddit_general(mock_post):
 | 
			
		|||
 | 
			
		||||
    # Force a case where there are no more remaining posts allowed
 | 
			
		||||
    good_response.headers = {
 | 
			
		||||
        'X-RateLimit-Reset': (datetime.utcnow() - epoch).total_seconds(),
 | 
			
		||||
        'X-RateLimit-Reset': (
 | 
			
		||||
            datetime.now(timezone.utc) - epoch).total_seconds(),
 | 
			
		||||
        'X-RateLimit-Remaining': 0,
 | 
			
		||||
    }
 | 
			
		||||
    # behind the scenes, it should cause us to update our rate limit
 | 
			
		||||
| 
						 | 
				
			
			@ -305,7 +308,8 @@ def test_plugin_reddit_general(mock_post):
 | 
			
		|||
 | 
			
		||||
    # This should cause us to block
 | 
			
		||||
    good_response.headers = {
 | 
			
		||||
        'X-RateLimit-Reset': (datetime.utcnow() - epoch).total_seconds(),
 | 
			
		||||
        'X-RateLimit-Reset': (
 | 
			
		||||
            datetime.now(timezone.utc) - epoch).total_seconds(),
 | 
			
		||||
        'X-RateLimit-Remaining': 10,
 | 
			
		||||
    }
 | 
			
		||||
    assert obj.send(body="test") is True
 | 
			
		||||
| 
						 | 
				
			
			@ -319,7 +323,8 @@ def test_plugin_reddit_general(mock_post):
 | 
			
		|||
 | 
			
		||||
    # Reset our variable back to 1
 | 
			
		||||
    good_response.headers = {
 | 
			
		||||
        'X-RateLimit-Reset': (datetime.utcnow() - epoch).total_seconds(),
 | 
			
		||||
        'X-RateLimit-Reset': (
 | 
			
		||||
            datetime.now(timezone.utc) - epoch).total_seconds(),
 | 
			
		||||
        'X-RateLimit-Remaining': 1,
 | 
			
		||||
    }
 | 
			
		||||
    # Handle cases where our epoch time is wrong
 | 
			
		||||
| 
						 | 
				
			
			@ -328,7 +333,8 @@ def test_plugin_reddit_general(mock_post):
 | 
			
		|||
 | 
			
		||||
    # Return our object, but place it in the future forcing us to block
 | 
			
		||||
    good_response.headers = {
 | 
			
		||||
        'X-RateLimit-Reset': (datetime.utcnow() - epoch).total_seconds() + 1,
 | 
			
		||||
        'X-RateLimit-Reset': (
 | 
			
		||||
            datetime.now(timezone.utc) - epoch).total_seconds() + 1,
 | 
			
		||||
        'X-RateLimit-Remaining': 0,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -337,7 +343,8 @@ def test_plugin_reddit_general(mock_post):
 | 
			
		|||
 | 
			
		||||
    # Return our object, but place it in the future forcing us to block
 | 
			
		||||
    good_response.headers = {
 | 
			
		||||
        'X-RateLimit-Reset': (datetime.utcnow() - epoch).total_seconds() - 1,
 | 
			
		||||
        'X-RateLimit-Reset': (
 | 
			
		||||
            datetime.now(timezone.utc) - epoch).total_seconds() - 1,
 | 
			
		||||
        'X-RateLimit-Remaining': 0,
 | 
			
		||||
    }
 | 
			
		||||
    assert obj.send(body="test") is True
 | 
			
		||||
| 
						 | 
				
			
			@ -348,7 +355,8 @@ def test_plugin_reddit_general(mock_post):
 | 
			
		|||
    # Invalid JSON
 | 
			
		||||
    response = mock.Mock()
 | 
			
		||||
    response.headers = {
 | 
			
		||||
        'X-RateLimit-Reset': (datetime.utcnow() - epoch).total_seconds(),
 | 
			
		||||
        'X-RateLimit-Reset': (
 | 
			
		||||
            datetime.now(timezone.utc) - epoch).total_seconds(),
 | 
			
		||||
        'X-RateLimit-Remaining': 1,
 | 
			
		||||
    }
 | 
			
		||||
    response.content = '{'
 | 
			
		||||
| 
						 | 
				
			
			@ -393,7 +401,8 @@ def test_plugin_reddit_general(mock_post):
 | 
			
		|||
    })
 | 
			
		||||
    good_response.status_code = requests.codes.ok
 | 
			
		||||
    good_response.headers = {
 | 
			
		||||
        'X-RateLimit-Reset': (datetime.utcnow() - epoch).total_seconds(),
 | 
			
		||||
        'X-RateLimit-Reset': (
 | 
			
		||||
            datetime.now(timezone.utc) - epoch).total_seconds(),
 | 
			
		||||
        'X-RateLimit-Remaining': 1,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -34,6 +34,7 @@ import json
 | 
			
		|||
import logging
 | 
			
		||||
import os
 | 
			
		||||
from datetime import datetime
 | 
			
		||||
from datetime import timezone
 | 
			
		||||
from unittest.mock import Mock, patch
 | 
			
		||||
 | 
			
		||||
import pytest
 | 
			
		||||
| 
						 | 
				
			
			@ -341,13 +342,14 @@ def test_plugin_twitter_general(mocker):
 | 
			
		|||
    }]
 | 
			
		||||
 | 
			
		||||
    # Epoch time:
 | 
			
		||||
    epoch = datetime.utcfromtimestamp(0)
 | 
			
		||||
    epoch = datetime.fromtimestamp(0, timezone.utc)
 | 
			
		||||
 | 
			
		||||
    request = Mock()
 | 
			
		||||
    request.content = json.dumps(response_obj)
 | 
			
		||||
    request.status_code = requests.codes.ok
 | 
			
		||||
    request.headers = {
 | 
			
		||||
        'x-rate-limit-reset': (datetime.utcnow() - epoch).total_seconds(),
 | 
			
		||||
        'x-rate-limit-reset': (
 | 
			
		||||
            datetime.now(timezone.utc) - epoch).total_seconds(),
 | 
			
		||||
        'x-rate-limit-remaining': 1,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -402,21 +404,21 @@ def test_plugin_twitter_general(mocker):
 | 
			
		|||
 | 
			
		||||
    # Return our object, but place it in the future forcing us to block
 | 
			
		||||
    request.headers['x-rate-limit-reset'] = \
 | 
			
		||||
        (datetime.utcnow() - epoch).total_seconds() + 1
 | 
			
		||||
        (datetime.now(timezone.utc) - epoch).total_seconds() + 1
 | 
			
		||||
    request.headers['x-rate-limit-remaining'] = 0
 | 
			
		||||
    obj.ratelimit_remaining = 0
 | 
			
		||||
    assert obj.send(body="test") is True
 | 
			
		||||
 | 
			
		||||
    # Return our object, but place it in the future forcing us to block
 | 
			
		||||
    request.headers['x-rate-limit-reset'] = \
 | 
			
		||||
        (datetime.utcnow() - epoch).total_seconds() - 1
 | 
			
		||||
        (datetime.now(timezone.utc) - epoch).total_seconds() - 1
 | 
			
		||||
    request.headers['x-rate-limit-remaining'] = 0
 | 
			
		||||
    obj.ratelimit_remaining = 0
 | 
			
		||||
    assert obj.send(body="test") is True
 | 
			
		||||
 | 
			
		||||
    # Return our limits to always work
 | 
			
		||||
    request.headers['x-rate-limit-reset'] = \
 | 
			
		||||
        (datetime.utcnow() - epoch).total_seconds()
 | 
			
		||||
        (datetime.now(timezone.utc) - epoch).total_seconds()
 | 
			
		||||
    request.headers['x-rate-limit-remaining'] = 1
 | 
			
		||||
    obj.ratelimit_remaining = 1
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -595,10 +597,11 @@ def test_plugin_twitter_dm_attachments_basic(
 | 
			
		|||
    mock_post = mocker.patch("requests.post")
 | 
			
		||||
 | 
			
		||||
    # Epoch time:
 | 
			
		||||
    epoch = datetime.utcfromtimestamp(0)
 | 
			
		||||
    epoch = datetime.fromtimestamp(0, timezone.utc)
 | 
			
		||||
    mock_get.return_value = good_message_response
 | 
			
		||||
    mock_post.return_value.headers = {
 | 
			
		||||
        'x-rate-limit-reset': (datetime.utcnow() - epoch).total_seconds(),
 | 
			
		||||
        'x-rate-limit-reset': (
 | 
			
		||||
            datetime.now(timezone.utc) - epoch).total_seconds(),
 | 
			
		||||
        'x-rate-limit-remaining': 1,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue