Example #1
0
class CredentialedGirderTask(Task):
    """
    Provide a task with a requests session via self.session, this is the default task.

    This base task should always be used in conjunction with setting bind=True in order
    to access the session.
    """
    def __call__(self, *args, **kwargs):
        """
        Create a token and configure a requests session object with it.

        The child class overrides run, so __call__ must be used to hook in before a task
        is executed.
        """
        # TODO: Revoke token in post task signal
        self.token = Token().createToken(
            user=getAdminUser(),
            days=1,
            scope=[TokenScope.DATA_READ, TokenScope.DATA_WRITE])
        self.session = BaseUrlSession(settings.ISIC_API_URL)
        self.session.headers.update({'Girder-Token': str(self.token['_id'])})

        retry = Retry(total=10,
                      read=10,
                      connect=10,
                      backoff_factor=.2,
                      method_whitelist=False,
                      status_forcelist=[500, 502, 503, 504])
        adapter = HTTPAdapter(max_retries=retry)
        self.session.mount('http://', adapter)
        self.session.mount('https://', adapter)  #
        super(CredentialedGirderTask, self).__call__(*args, **kwargs)
Example #2
0
    def __init__(self, api_token: str, account_id: int) -> None:
        self.account_id = account_id

        # Rather than assigning directly to `self`, this is the recommended idiom so atexit.register behaves nicely with GC.
        session = BaseUrlSession(
            base_url=f"{self.api_domain}/{self.api_version}/{account_id}/")
        session.auth = (api_token, "")
        session.headers.update({"User-Agent": self.drip_py_ua})
        session.mount(self.api_domain, GzipAdapter())
        register(session.close)
        self.session = session
Example #3
0
def test_connection_keepalive(simple_wsgi_server):
    """Test the connection keepalive works (duh)."""
    session = Session(base_url=simple_wsgi_server['url'])
    pooled = requests.adapters.HTTPAdapter(
        pool_connections=1, pool_maxsize=1000,
    )
    session.mount('http://', pooled)

    def do_request():
        with ExceptionTrap(requests.exceptions.ConnectionError) as trap:
            resp = session.get('info')
            resp.raise_for_status()
        return bool(trap)

    with ThreadPoolExecutor(max_workers=50) as pool:
        tasks = [
            pool.submit(do_request)
            for n in range(1000)
        ]
        failures = sum(task.result() for task in tasks)

    assert not failures
class MyTurnCA:
    """Main API class"""
    def __init__(self, api_key: str):
        self.logger = logging.getLogger(__name__)
        self.session = BaseUrlSession(base_url=MY_TURN_URL)
        self.session.mount('https://', HTTPAdapter(max_retries=DEFAULT_RETRY_STRATEGY))
        self.session.headers.update({**REQUEST_HEADERS, GOOD_BOT_HEADER: api_key})
        self.vaccine_data = self._get_vaccine_data()

    def _get_vaccine_data(self) -> str:
        """Retrieve initial vaccine data"""
        response = self._send_request(url=ELIGIBILITY_URL, body=ELIGIBLE_REQUEST_BODY).json()
        if response['eligible'] is False:
            raise RuntimeError('something is wrong, default /eligibility body returned \'eligible\' = False')

        return response['vaccineData']

    def get_locations(self, latitude: float, longitude: float) -> List[Location]:
        """Gets available locations near the given coordinates"""
        body = {
            'location': {
                'lat': latitude,
                'lng': longitude
            },
            'fromDate': datetime.now(tz=pytz.timezone('US/Pacific')).strftime('%Y-%m-%d'),
            'vaccineData': self.vaccine_data,
            'locationQuery': {
                'includePools': LOCATION_POOLS,
                'excludeTags': [],
                'includeTags': []
            }
        }

        response = self._send_request(url=LOCATIONS_URL, body=body)
        try:
            return [Location(location_id=x['extId'], name=x['name'], address=x['displayAddress'], booking_type=x['type'],
                             vaccine_data=x['vaccineData'], distance=x['distanceInMeters'])
                    for x in response.json()['locations']]
        except json.JSONDecodeError:
            self.logger.error(JSON_DECODE_ERROR_MSG.format(body=response.text))
            return []

    def get_availability(self, location: Location, start_date: date, end_date: date) -> LocationAvailability:
        """Gets a given vaccination location's availability"""
        body = {
            'startDate': start_date.strftime('%Y-%m-%d'),
            'endDate': end_date.strftime('%Y-%m-%d'),
            'vaccineData': location.vaccine_data,
            'doseNumber': 1
        }

        response = self._send_request(url=LOCATION_AVAILABILITY_URL.format(location_id=location.location_id), body=body)
        try:
            return LocationAvailability(location=location,
                                        dates_available=[datetime.strptime(x['date'], '%Y-%m-%d').date()
                                                         for x in response.json()['availability'] if x['available'] is True])
        except json.JSONDecodeError:
            self.logger.error(JSON_DECODE_ERROR_MSG.format(body=response.text))
            return LocationAvailability(location=location, dates_available=[])

    def get_slots(self, location: Location, start_date: date) -> LocationAvailabilitySlots:
        """Gets a given location's available appointments"""
        body = {
            'vaccineData': location.vaccine_data
        }

        response = self._send_request(url=LOCATION_AVAILABILITY_SLOTS_URL.format(location_id=location.location_id,
                                                                                 start_date=start_date.strftime('%Y-%m-%d')),
                                      body=body)
        try:
            return LocationAvailabilitySlots(location=location,
                                             slots=[self._combine_date_and_time(start_date, x['localStartTime'])
                                                    for x in response.json()['slotsWithAvailability']
                                                    if self._combine_date_and_time(start_date, x['localStartTime']) > datetime.now(tz=pytz.timezone('US/Pacific'))])
        except json.JSONDecodeError:
            self.logger.error(JSON_DECODE_ERROR_MSG.format(body=response.text))
            return LocationAvailabilitySlots(location=location, slots=[])

    def get_appointments(self, latitude: float, longitude: float, start_date: date, end_date: date) -> List[LocationAvailabilitySlots]:
        """Retrieves available appointments from all vaccination locations near the given coordinates"""
        locations = self.get_locations(latitude=latitude, longitude=longitude)
        if not locations:
            return []

        if start_date > end_date:
            raise ValueError('Provided start_date must be before end_date')

        appointments = []
        for location in locations:
            days_available = self.get_availability(location=location, start_date=start_date, end_date=end_date).dates_available
            if not days_available:
                continue

            location_appointments = [location_appointment for location_appointment in
                                     [self.get_slots(location=location, start_date=day_available)
                                      for day_available in days_available] if location_appointment.slots]
            if not location_appointments:
                continue

            # combines appointments on different days for the same location
            appointments.append(LocationAvailabilitySlots(location=location_appointments[0].location,
                                                          slots=functools.reduce(operator.add,
                                                                                 [location_appointment.slots for location_appointment in location_appointments])))

        return appointments

    @staticmethod
    def _combine_date_and_time(start_date: date, timestamp: str) -> datetime:
        """Private helper function to combine a date and timestamp"""
        return datetime.combine(start_date, datetime.strptime(timestamp, '%H:%M:%S').time(),
                                tzinfo=pytz.timezone('US/Pacific'))

    def _send_request(self, url: str, body: dict) -> Response:
        """Private helper function to make HTTP POST requests"""
        self.logger.info(f'sending request to {MY_TURN_URL}{url} with body - {body}')
        response = self.session.post(url=url, json=body)
        self.logger.info(f'got response from /{url} - {response.__dict__}')
        return response