Ejemplo n.º 1
0
def _translate_category(category: str, s: str) -> Tuple[bool, str]:
    if ref(category) in _category_map() and s == '0':
        return True, _category_map()[ref(
            category)]  # yield correct name from ref name of category

    # if it isn't 0, then it doesn't apply, return given
    # if not in the list, return given
    return False, s
Ejemplo n.º 2
0
 def __badge_check(title_list):
     accepted = list(
         map(lambda s: ref(s), [
             'general assembly resolution author',
             'Historical Resolution Author'
         ]))
     title_list = list(map(lambda s: ref(s), title_list))
     for accept in accepted:
         if any(accept in s for s in title_list):
             return True
     return False
Ejemplo n.º 3
0
    def __init__(self,
                 voter,
                 post_num,
                 parsed_ballot,
                 max_entries=10,
                 require_all_ranks=False):
        self.voter_name = ref(voter)
        if not self.is_valid_voter(voter):
            raise RuntimeError('voter {} ineligible'.format(voter))

        self.ballot = parsed_ballot  # internally is [[1, 'title'], [2, 'title']]
        ranks, resolution_list = [], []
        for internal_list in parsed_ballot:
            ranks.append(internal_list[0])  # list of numbers as parsed_ballot
            resolution_list.append(
                internal_list[1])  # list of resolution titles in parsed_ballot

        if max(ranks) > max_entries:
            raise RuntimeError('more provided rankings than max')
        if duplicates(ranks, excluding=[]):
            raise RuntimeError('duplicate entry of same rank')
        if duplicates(resolution_list):
            raise RuntimeError('same resolution provided more than once')
        if set(ranks) != set(range(1, max_entries + 1)) and require_all_ranks:
            raise RuntimeError('incomplete, rankings not fully expressed')

        self.post_num = post_num
        print(f'validated entry {self}')
Ejemplo n.º 4
0
def join_author_lists_as_set(df):
    df = df.copy()
    df['Co-authors'] = df['Co-authors'].fillna('')
    joined = df[['Author', 'Co-authors']] \
        .apply(lambda r: [ref(s) for s in set(','.join(r.values).split(','))], axis=1) \
        .explode()
    joined = joined[joined != '']
    return set(joined.values)
Ejemplo n.º 5
0
    def is_valid_voter(voter_name):
        """ Returns true if nation is a GA resolution author or co-author or if has trophy saying it is a GA or UN
        resolution author. """
        if ref(voter_name) in get_full_author_list(): return True

        url = 'https://www.nationstates.net/nation={}'.format(
            voter_name.lower().replace(' ', '_'))
        title_list = [
            image.attrs['title']
            for image in BeautifulSoup(requests.get(url).text, 'lxml').select(
                'div.trophyline span.trophyrack img')
        ]

        time.sleep(2)  # rate limit
        return AnnRevEntry.__badge_check(title_list)
Ejemplo n.º 6
0
def _category_map():
    d = {
        'Advancement of Industry': 'Environmental Deregulation',
        'Civil Rights': 'Mild',
        'Human Rights': 'Mild',
        'Education and Creativity': 'Artistic',
        'Environmental': 'Automotive',
        'Free Trade': 'Mild',
        'Furtherment of Democracy': 'Mild',
        'Global Disarmament': 'Mild',
        'Health': 'Healthcare',
        'International Security': 'Mild',
        'Moral Decency': 'Mild',
        'Political Stability': 'Mild',
        'Regulation': 'Consumer Protection',
        'Gun Control': 'Tighten',
        'Social Justice': 'Mild'
    }
    return {ref(k): v for k, v in d.items()}  # force ref name for matching
Ejemplo n.º 7
0
        time.sleep(
            2)  # sleep 5 seconds __between__ pages, exclude first and last

print('loaded web ballot data')

resolutions = pd.read_csv('../../output/ANNUAL_resolutions.csv')
resolutions['Implemented'] = pd.to_datetime(resolutions['Implemented'],
                                            utc=True)
resolutions['Score'] = 0
resolutions['_lowercase_titles'] = resolutions['Title'].str.lower().str.strip()
print('loaded resolutions data')

# check for puppets
aliases = pd.read_csv('../../db/aliases.csv')
aliases['_joined'] = aliases.apply(
    lambda r: [ref(s) for s in set(','.join(r.values).split(','))], axis=1)
voters = [ref(e.voter_name) for e in entry_list]  # persist list of voters

# validated 2022-04-04 15.54 cy.par
for alias_list in aliases['_joined'].values:
    # determine for all aliases whether the alias voted
    results_dict = {a: a in voters for a in alias_list}

    if sum(results_dict.values()) > 1:
        # if more than one alias voted... tell us
        duplicate_names = [k for k, v in results_dict.items() if v]
        print('aliases ' + str(duplicate_names) + ' appear more than once!')
        print('removing later vote')

        # find entries of that player, sort by ballot post number
        matching_entries = sorted(
Ejemplo n.º 8
0
    def parse_ga(res_num, council=1):

        from src.wa_cacher import Cacher
        try:
            cacher = Cacher.load()
        except FileNotFoundError:
            cacher = Cacher()  # init new

        api_url = 'https://www.nationstates.net/cgi-bin/api.cgi?wa={}&id={}&q=resolution'.format(
            council, res_num)
        in_cacher = cacher.contains(api_url)
        if not in_cacher:
            this_response = call_api(api_url)
            cacher.update(api_url, this_response)
        else:
            this_response = cacher.get(api_url)

        xml = etree.parse(io.StringIO(this_response))
        if not xml.xpath('/WA/RESOLUTION/NAME'):
            raise ValueError(
                f'resolution number {res_num} is invalid; no such resolution exists'
            )

        resolution_is_repealed = xml.xpath('/WA/RESOLUTION/REPEALED_BY') != []
        resolution_is_a_repeal = xml.xpath(
            '/WA/RESOLUTION/REPEALS_COUNCILID') != []

        resolution_text = html.unescape(
            xml.xpath('/WA/RESOLUTION/DESC')[0].text)

        resolution_author = xml.xpath('/WA/RESOLUTION/PROPOSED_BY')[0].text
        print(resolution_author)
        print(type(resolution_author))
        if resolution_author is None or str(resolution_author).strip() == '':
            raise RuntimeError('resolution author is empty')

        author = capitalise(resolution_author)

        resolution = WaPassedResolution(
            council=_get_council(council),
            resolution_num=res_num,
            title=xml.xpath('/WA/RESOLUTION/NAME')[0].text,
            implementation=localised(
                datetime.utcfromtimestamp(
                    int(xml.xpath('/WA/RESOLUTION/IMPLEMENTED')[0].text)),
                'UTC').astimezone(
                    timezone('US/Eastern')),  # convert to eastern time
            chamber=clean_chamber_input(
                xml.xpath('/WA/RESOLUTION/COUNCIL')[0].text)[1],
            category=capitalise(xml.xpath('/WA/RESOLUTION/CATEGORY')[0].text),
            strength=capitalise(
                _translate_category(
                    xml.xpath('/WA/RESOLUTION/CATEGORY')[0].text,  # category
                    xml.xpath('/WA/RESOLUTION/OPTION')[0].text  # option
                )[1]  # get name
            ),
            is_repealed=resolution_is_repealed,
            repealed_by=int(xml.xpath('/WA/RESOLUTION/REPEALED_BY')[0].text)
            if resolution_is_repealed else None,
            is_repeal=resolution_is_a_repeal,
            repeals=int(xml.xpath('/WA/RESOLUTION/REPEALS_COUNCILID')[0].text)
            if resolution_is_a_repeal else None,

            # text and author
            text=resolution_text.strip(),
            author=author.strip(),

            # vote data
            votes_for=int(xml.xpath('/WA/RESOLUTION/TOTAL_VOTES_FOR')[0].text),
            votes_against=int(
                xml.xpath('/WA/RESOLUTION/TOTAL_VOTES_AGAINST')[0].text))

        assert resolution.strength != '0', 'resolution {} has strength 0 with category {}'.format(
            resolution.title, resolution.category)

        # overwrite category if repeal with the repeals field; NS API is broken sometimes for some reason
        if resolution_is_a_repeal:
            resolution.strength = str(int(
                resolution.repeals))  # cast to integer

        # check for co-authors
        coauth_list = xml.xpath('/WA/RESOLUTION/COAUTHOR/N')
        if len(coauth_list) != 0:
            print('received from API coauthors: {}'.format(', '.join(
                [capitalise(n.text) for n in coauth_list])))

            try:
                resolution.coauthor0 = capitalise(coauth_list[0].text)
            except IndexError:
                pass

            try:
                resolution.coauthor1 = capitalise(coauth_list[1].text)
            except IndexError:
                pass

            try:
                resolution.coauthor2 = capitalise(coauth_list[2].text)
            except IndexError:
                pass

        else:
            cleaned_resolution_text = resolution_text \
                .replace('[i]', '').replace('[/i]', '') \
                .replace('[b]', '').replace('[/b]', '') \
                .replace('[u]', '').replace('[/u]', '')
            coauthor_matches = [
                s for s in cleaned_resolution_text.splitlines() if re.search(
                    r'(Co-?((Author(ed)?:?)|written|writer) ?(by|with)? ?:?)|'
                    r'(This resolution includes significant contributions made by\s+)',
                    s, re.IGNORECASE)
            ]
            if len(coauthor_matches) > 0:
                coauthor_line = re.sub(
                    r'Co-?((Author(ed)?:?)|written|writer) ?(by|with)? ?:? ',
                    repl='',
                    string=coauthor_matches[0],
                    flags=re.IGNORECASE)
                print(f'\tidentified coauthor line: "{coauthor_line}"')
                coauthor_line = coauthor_line \
                    .replace('[i]', '') \
                    .replace('[/i]', '') \
                    .replace('[b]', '') \
                    .replace('[/b]', '') \
                    .replace('[u]', '') \
                    .replace('[/u]', '')

                if '[nation' in coauthor_line.lower(
                ):  # scion used the [Nation] tag instead of lower case once
                    amended_line = re.sub(
                        r'(?<=\[nation)=(.*?)(?=\])', '',
                        coauthor_line.lower())  # remove 'noflag' etc
                    coauthors = re.findall(
                        r'(?<=\[nation\])(.*?)(?=\[/nation\])',
                        amended_line.lower())

                else:
                    # this will break with names like "Sch'tz and West Runk'land"
                    coauthors = re.split(r'(,? and )|(, )', coauthor_line,
                                         re.IGNORECASE)
                    coauthors = [
                        i for i in coauthors
                        if i is not None and i.strip() != 'and'
                    ]  # post facto patching...

                coauthors = [ref(s).replace('.', '')
                             for s in coauthors]  # cast to reference name
                print(f'\tidentified coauthors as {coauthors}')

                # pass each co-author in turn
                '''
                While it could be changed so that the original line's capitalisation is preserved, doing this might 
                introduce inconsistency in capitalisation of the same nation. Eg '[nation]imperium_anglorum[/nation]' would
                be done under capitalisation rules while something provided as 'Imperium ANGLORUM' would be let through.
                
                Because some authors use a ref'd name IN the nation tags, something like [nation]transilia[/nation] cannot
                be disentangled from 'Transilia' if the former is proper and the latter is not. A proper-capitalisation
                dictionary would be necessary and I am unwilling to download and parse all historical daily dumps for 
                something this minor. 
                '''
                try:
                    resolution.coauthor0 = capitalise(coauthors[0])
                except IndexError:
                    pass

                try:
                    resolution.coauthor1 = capitalise(coauthors[1])
                except IndexError:
                    pass

                try:
                    resolution.coauthor2 = capitalise(coauthors[2])
                except IndexError:
                    pass

        cacher.save()
        return resolution