<commit_before>import importlib
import json
import jwt
import time
import uuid

from collections import namedtuple
from contextlib import closing
from hyper import HTTP20Connection

from .exceptions import (
    InternalException,
    ImproperlyConfigured,
    PayloadTooLarge,
    BadDeviceToken
)

from .utils import validate_private_key, wrap_private_key


ALGORITHM = 'ES256'
SANDBOX_HOST = 'api.development.push.apple.com:443'
PRODUCTION_HOST = 'api.push.apple.com:443'
MAX_NOTIFICATION_SIZE = 4096

APNS_RESPONSE_CODES = {
    'Success': 200,
    'BadRequest': 400,
    'TokenError': 403, 
    'MethodNotAllowed': 405,
    'TokenInactive': 410,
    'PayloadTooLarge': 413,
    'TooManyRequests': 429,
    'InternalServerError': 500, 
    'ServerUnavailable': 503,
}
APNSResponseStruct = namedtuple('APNSResponseStruct', ' '.join(APNS_RESPONSE_CODES.keys()))
APNSResponse = APNSResponseStruct(**APNS_RESPONSE_CODES)


class APNsClient(object):

    def __init__(self, team_id, auth_key_id, 
            auth_key=None, auth_key_filepath=None, bundle_id=None, use_sandbox=False, force_proto=None
        ):

        if not (auth_key_filepath or auth_key):
            raise ImproperlyConfigured(
                'You must provide either an auth key or a path to a file containing the auth key'
            )

        if not auth_key:
            try:
                with open(auth_key_filepath, "r") as f:
                    auth_key = f.read()

            except Exception as e:
                raise ImproperlyConfigured("The APNS auth key file at %r is not readable: %s" % (auth_key_filepath, e))

        validate_private_key(auth_key)
        auth_key = wrap_private_key(auth_key) # Some have had issues with keys that aren't wrappd to 64 lines

        self.team_id = team_id
        self.bundle_id = bundle_id
        self.auth_key = auth_key
        self.auth_key_id = auth_key_id
        self.force_proto = force_proto
        self.host = SANDBOX_HOST if use_sandbox else PRODUCTION_HOST

    def send_message(self, registration_id, alert, **kwargs):
        return self._send_message(registration_id, alert, **kwargs)

    def send_bulk_message(self, registration_ids, alert, **kwargs):
        good_registration_ids = []
        bad_registration_ids = []

        with closing(self._create_connection()) as connection:
            for registration_id in registration_ids:
                try:
                    res = self._send_message(registration_id, alert, connection=connection, **kwargs)
                    good_registration_ids.append(registration_id)
                except:
                    bad_registration_ids.append(registration_id)

        if not bad_registration_ids:
            return res

        if not good_registration_ids:
            raise BadDeviceToken("None of the registration ids were accepted"
                                 "Rerun individual ids with ``send_message()``"
                                 "to get more details about why")

        if bad_registration_ids and good_registration_ids:
            raise PartialBulkMessage(
                "Some of the registration ids were accepted. Rerun individual "
                "ids with ``send_message()`` to get more details about why. "
                "The ones that failed: \n:"
                "{bad_string}\n"
                "The ones that were pushed successfully: \n:"
                "{good_string}\n".format(
                    bad_string="\n".join(bad_registration_ids),
                    good_string = "\n".join(good_registration_ids)
                )
            )

    def _create_connection(self):
        return HTTP20Connection(self.host, force_proto=self.force_proto)

    def _create_token(self):
        token = jwt.encode(
            {<commit_msg>Bind bad registration ids to PartialBulkMessage exception<commit_after>import importlib
import json
import jwt
import time
import uuid

from collections import namedtuple
from contextlib import closing
from hyper import HTTP20Connection

from .exceptions import (
    InternalException,
    ImproperlyConfigured,
    PayloadTooLarge,
    BadDeviceToken
)

from .utils import validate_private_key, wrap_private_key


ALGORITHM = 'ES256'
SANDBOX_HOST = 'api.development.push.apple.com:443'
PRODUCTION_HOST = 'api.push.apple.com:443'
MAX_NOTIFICATION_SIZE = 4096

APNS_RESPONSE_CODES = {
    'Success': 200,
    'BadRequest': 400,
    'TokenError': 403, 
    'MethodNotAllowed': 405,
    'TokenInactive': 410,
    'PayloadTooLarge': 413,
    'TooManyRequests': 429,
    'InternalServerError': 500, 
    'ServerUnavailable': 503,
}
APNSResponseStruct = namedtuple('APNSResponseStruct', ' '.join(APNS_RESPONSE_CODES.keys()))
APNSResponse = APNSResponseStruct(**APNS_RESPONSE_CODES)


class APNsClient(object):

    def __init__(self, team_id, auth_key_id, 
            auth_key=None, auth_key_filepath=None, bundle_id=None, use_sandbox=False, force_proto=None
        ):

        if not (auth_key_filepath or auth_key):
            raise ImproperlyConfigured(
                'You must provide either an auth key or a path to a file containing the auth key'
            )

        if not auth_key:
            try:
                with open(auth_key_filepath, "r") as f:
                    auth_key = f.read()

            except Exception as e:
                raise ImproperlyConfigured("The APNS auth key file at %r is not readable: %s" % (auth_key_filepath, e))

        validate_private_key(auth_key)
        auth_key = wrap_private_key(auth_key) # Some have had issues with keys that aren't wrappd to 64 lines

        self.team_id = team_id
        self.bundle_id = bundle_id
        self.auth_key = auth_key
        self.auth_key_id = auth_key_id
        self.force_proto = force_proto
        self.host = SANDBOX_HOST if use_sandbox else PRODUCTION_HOST

    def send_message(self, registration_id, alert, **kwargs):
        return self._send_message(registration_id, alert, **kwargs)

    def send_bulk_message(self, registration_ids, alert, **kwargs):
        good_registration_ids = []
        bad_registration_ids = []

        with closing(self._create_connection()) as connection:
            for registration_id in registration_ids:
                try:
                    res = self._send_message(registration_id, alert, connection=connection, **kwargs)
                    good_registration_ids.append(registration_id)
                except:
                    bad_registration_ids.append(registration_id)

        if not bad_registration_ids:
            return res

        if not good_registration_ids:
            raise BadDeviceToken("None of the registration ids were accepted"
                                 "Rerun individual ids with ``send_message()``"
                                 "to get more details about why")

        if bad_registration_ids and good_registration_ids:
            raise PartialBulkMessage(
                "Some of the registration ids were accepted. Rerun individual "
                "ids with ``send_message()`` to get more details about why. "
                "The ones that failed: \n:"
                "{bad_string}\n"
                "The ones that were pushed successfully: \n:"
                "{good_string}\n".format(
                    bad_string="\n".join(bad_registration_ids),
                    good_string = "\n".join(good_registration_ids)
                ),
                bad_registration_ids
            )

    def _create_connection(self):
        return HTTP20Connection(self.host, force_proto=self.force_proto)

    def _create_token(self):
        token = jwt.encode(
            {
{'fraction_non_alphanumeric': 0.07729531781323568, 'fraction_numerical': 0.012032435260266806, 'mean_word_length': 2.407754010695187, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1266558', 'n_tokens_mistral': 2311, 'n_tokens_neox': 2114, 'n_words': 549}