Beispiel #1
0
    def get_surveys(self, page=None):
        """
        Get a table of lists under the account.

        `Args:`
            page : int
                Retrieve a specific page of responses. If not given,
                then all pages are retrieved.

        `Returns:`
            Table Class
        """

        r = self._client.api.survey.list(page)
        data = r['data']

        if not page:
            while r['page'] < r['total_pages']:
                r = self._client.api.survey.list(page=(r['page']+1))
                data.extend(r['data'])

        tbl = Table(data).remove_column('links')
        tbl.unpack_dict('statistics', prepend=False)

        logger.info(f"Found {tbl.num_rows} surveys.")

        return tbl
Beispiel #2
0
    def get_agents(self, email=None, mobile=None, phone=None, state=None):
        """
        List agents.

        `Args:`
            email: str
                Filter by email address.
            mobile: str
                Filter by mobile phone number
            phone: str
                Filter by phone number
            state: str
                Filter by state
        `Returns:`
            Parsons Table
                See :ref:`parsons-table` for output options.
        """

        params = {
            'email': email,
            'mobile': mobile,
            'phone': phone,
            'state': state
        }

        tbl = Table(self.get_request('agents', params=params))
        logger.info(f'Found {tbl.num_rows} agents.')
        tbl = self.transform_table(tbl)
        tbl = tbl.unpack_dict('contact', prepend=False)
        tbl.remove_column(
            'signature')  # Removing since raw HTML might cause issues.

        return tbl
Beispiel #3
0
    def get_records(self, fields=None, max_records=None, view=None, formula=None, sort=None):
        """
        `Args:`
            fields: str or lst
                Only return specified column or list of columns. The column name is
                case sensitive
            max_records: int
                The maximum total number of records that will be returned.
            view: str
                If set, only the records in that view will be returned. The records will be
                sorted according to the order of the view.
            formula: str
                The formula will be evaluated for each record, and if the result
                is not 0, false, "", NaN, [], or #Error! the record will be included
                in the response.

                If combined with view, only records in that view which satisfy the
                formula will be returned. For example, to only include records where
                ``COLUMN_A`` isn't empty, pass in: ``"NOT({COLUMN_A}='')"``

                For more information see
                `Airtable Docs on formulas. <https://airtable.com/api>`_

                Usage - Text Column is not empty:

                ``airtable.get_all(formula="NOT({COLUMN_A}='')")``

                Usage - Text Column contains:

                ``airtable.get_all(formula="FIND('SomeSubText', {COLUMN_STR})=1")``

            sort: str or lst
                Specifies how the records will be ordered. If you set the view parameter, the
                returned records in that view will be sorted by these fields. If sorting by
                multiple columns, column names can be passed as a list. Sorting Direction is
                ascending by default, but can be reversed by prefixing the column name with a minus
                sign -.

                Example usage:
                ``airtable.get_records(sort=['ColumnA', '-ColumnB'])``

        `Returns:`
            Parsons Table
                See :ref:`parsons-table` for output options.
        """

        # Raises an error if sort is None type. Thus, only adding if populated.
        kwargs = {'fields': fields, 'max_records': max_records, 'view': view, 'formula': formula}
        if sort:
            kwargs['sort'] = sort

        tbl = Table(self.at.get_all(**kwargs))

        # If the results are empty, then return an empty table.
        if 'fields' not in tbl.columns:
            return Table([[]])

        return tbl.unpack_dict(column='fields', prepend=False)
Beispiel #4
0
    def get_polling_locations(self,
                              election_id,
                              table,
                              address_field='address'):
        """
        Get polling location information for a table of addresses.

        `Args:`
            election_id: int
                A valid election id. Election ids can be found by running the
                :meth:`get_elections` method.
            address: str
                A valid US address in a single string.
            address_field: str
                The name of the column where the address is stored.
        `Returns:`
            Parsons Table
                See :ref:`parsons-table` for output options.
        """

        polling_locations = []

        # Iterate through the rows of the table
        for row in table:
            loc = self.get_polling_location(election_id, row[address_field])
            # Insert original passed address
            loc[0]['passed_address'] = row[address_field]

            # Add to list of lists
            polling_locations.append(loc[0])

        # Unpack values
        tbl = Table(polling_locations)
        tbl.unpack_dict('address', prepend_value='polling')
        tbl.unpack_list('sources', replace=True)
        tbl.unpack_dict('sources_0', prepend_value='source')
        tbl.rename_column('polling_line1', 'polling_address')

        # Resort columns
        tbl.move_column('pollingHours', len(tbl.columns))
        tbl.move_column('notes', len(tbl.columns))
        tbl.move_column('polling_locationName', 1)
        tbl.move_column('polling_address', 2)

        return tbl
Beispiel #5
0
    def get_campaigns(self,
                      state=None,
                      zip=None,
                      include_generic=False,
                      include_private=False,
                      include_content=True):
        """
        Returns a list of campaigns

        `Args:`
            state: str
                Filter by US postal abbreviation for a state or territory e.g., "CA" "NY" or "DC"
            zip: int
                Filter by 5 digit zip code
            include_generic: boolean
                When filtering by state or ZIP code, include unrestricted campaigns
            include_private: boolean
                If true, will include private campaigns in results
            include_content: boolean
                If true, include campaign content fields, which may vary. This may cause
                sync errors.
        `Returns:`
            Parsons Table
                See :ref:`parsons-table` for output options.
        """
        url = self.uri + 'campaigns'

        args = {
            'state': state,
            'zip': zip,
            'includeGeneric': str(include_generic),
            'includePrivate': str(include_private)
        }

        tbl = Table(self._request(url, args=args).json())
        tbl.unpack_dict('updated_at')
        if include_content:
            tbl.unpack_dict('content')

        return tbl
Beispiel #6
0
    def process_json(self, json_blob, obj_type, tidy=False):
        # Internal method for converting most types of json responses into a list of Parsons tables

        # Output goes here
        table_list = []

        # Original table & columns
        obj_table = Table(json_blob)
        cols = obj_table.get_columns_type_stats()
        list_cols = [x['name'] for x in cols if 'list' in x['type']]
        dict_cols = [x['name'] for x in cols if 'dict' in x['type']]

        # Unpack all list columns
        if len(list_cols) > 0:
            for l in list_cols:  # noqa E741
                # Check for nested data
                list_rows = obj_table.select_rows(
                    lambda row: isinstance(row[l], list)
                    and any(isinstance(x, dict) for x in row[l])
                )
                # Add separate long table for each column with nested data
                if list_rows.num_rows > 0:
                    logger.debug(l, 'is a nested column')
                    if len([x for x in cols if x['name'] == l]) == 1:
                        table_list.append({
                            'name': f'{obj_type}_{l}',
                            'tbl': obj_table.long_table(['id'], l)
                        })
                    else:
                        # Ignore if column doesn't exist (or has multiples)
                        continue
                else:
                    if tidy is False:
                        logger.debug(l, 'is a normal list column')
                        obj_table.unpack_list(l)

        # Unpack all dict columns
        if len(dict_cols) > 0 and tidy is False:
            for d in dict_cols:
                logger.debug(d, 'is a dict column')
                obj_table.unpack_dict(d)

        if tidy is not False:
            packed_cols = list_cols + dict_cols
            for p in packed_cols:
                if p in obj_table.columns:
                    logger.debug(p, 'needs to be unpacked into rows')

                    # Determine whether or not to expand based on tidy
                    unpacked_tidy = obj_table.unpack_nested_columns_as_rows(p, expand_original=tidy)
                    # Check if column was removed as sign it was unpacked into separate table
                    if p not in obj_table.columns:
                        table_list.append({
                            'name': f'{obj_type}_{p}',
                            'tbl': unpacked_tidy
                        })
                    else:
                        obj_table = unpacked_tidy

        # Original table will have had all nested columns removed
        if len(obj_table.columns) > 1:
            table_list.append({'name': obj_type, 'tbl': obj_table})

        return table_list