<commit_before>import os
from lxml import etree
from lxml.etree import tostring
from itertools import chain
from .utils import *

__all__ = [
    'list_xml_path',
    'parse_pubmed_xml',
    'parse_pubmed_paragraph',
    'parse_pubmed_references',
    'parse_pubmed_caption'
]

def list_xml_path(path_dir):
    """
    List full xml path under given directory

    Parameters
    ----------
    path_dir: str, path to directory that contains xml or nxml file

    Returns
    -------
    path_list: list, list of xml or nxml file from given path
    """
    fullpath = [os.path.join(dp, f) for dp, dn, fn in os.walk(os.path.expanduser(path_dir)) for f in fn]
    path_list = [folder for folder in fullpath if os.path.splitext(folder)[-1] == ('.nxml' or '.xml')]
    return path_list

def zip_author(author):
    """
    Give a list of author and its affiliation keys
    in this following format
    [first_name, last_name, [key1, key2]]
    return [[first_name, last_name, key1], [first_name, last_name, key2]] instead
    """
    author_zipped = list(zip([[author[0], author[1]]] * len(author[-1]), author[-1]))
    return list(map(lambda x: x[0] + [x[-1]], author_zipped))

def flatten_zip_author(author_list):
    """
    Apply zip_author to author_list and flatten it
    """
    author_zipped_list = map(zip_author, author_list)
    return list(chain.from_iterable(author_zipped_list))

def parse_article_meta(tree):
    """
    Parse PMID, PMC and DOI from given article tree
    """
    article_meta = tree.find('//article-meta')
    pmid_node = article_meta.find('article-id[@pub-id-type="pmid"]')
    pmc_node = article_meta.find('article-id[@pub-id-type="pmc"]')
    pub_id_node = article_meta.find('article-id[@pub-id-type="publisher-id"]')
    doi_node = article_meta.find('article-id[@pub-id-type="doi"]')

    pmid = pmid_node.text if pmid_node is not None else ''
    pmc = pmc_node.text if pmc_node is not None else ''
    pub_id = pub_id_node.text if pub_id_node is not None else ''
    doi = doi_node.text if doi_node is not None else ''

    dict_article_meta = {'pmid': pmid,
                         'pmc': pmc,
                         'doi': doi,
                         'publisher_id': pub_id}

    return dict_article_meta

def parse_pubmed_xml(path, include_path=False):
    """
    Given single xml path, extract information from xml file
    and return parsed xml file in dictionary format.
    """
    tree = read_xml(path)

    tree_title = tree.find('//title-group/article-title')
    if tree_title is not None:
        title = [t for t in tree_title.itertext()]
        sub_title = tree.xpath('//title-group/subtitle/text()')
        title.extend(sub_title)
        title = [t.replace('\n', ' ').replace('\t', ' ') for t in title]
        full_title = ' '.join(title)
    else:
        full_title = ''

    try:
        abstract = ' '.join(tree.xpath('//abstract//text()'))
    except:
        abstract = ''

    journal_node = tree.findall('//journal-title')
    if journal_node is not None:
        journal = ' '.join([j.text for j in journal_node])
    else:
        journal = ''

    dict_article_meta = parse_article_meta(tree)
    pub_year_node = tree.find('//pub-date/year')
    pub_year = pub_year_node.text if pub_year_node is not None else ''

    subjects_node = tree.findall('//article-categories//subj-group/subject')
    subjects = list()
    if subjects_node is not None:
        for s in subjects_node:
            subject = ' '.join([s_.strip() for s_ in s.itertext()]).strip()
            subjects.append(subject)
        subjects = '; '.join(subjects)
    else:
        subjects = ''

    # create affiliation dictionary
    affil_id = tree.xpath('//aff[@id]/@id')
    if len(affil_id) > 0:
        affil_id = list(map(str, affil_id))
    else:
        affil_id = ['']  # replace id with empty list

    affil_name = tree.xpath('//aff[@id]')
    affil_name_list = list()
    for e in affil_name:
        name = stringify_affiliation_rec(e)
        name = name.strip().replace('\n', ' ')
        affil_name_list.append(name)
    affiliation_list = [[idx, name] for idx, name in zip(affil_id, affil_name_list)]

    tree_author = tree.xpath('//contrib-group/contrib[@contrib-type="author"]')
    author_list = list()
    for author in tree_author:
        author_aff = author.findall('xref[@ref-type="aff"]')
        try:
            ref_id_list = [str(a.attrib['rid']) for a in author_aff]
        except:
            ref_id_list = ''
        try:
            author_list.append([author.find('name/surname').text,
                                author.find('name/given-names').text,
                                ref_id_list])
        except:
            author_list.append(['', '', ref_id_list])
    author_list = flatten_zip_author(author_list)

    dict_out = {'full_title': full_title.strip(),
                'abstract': abstract,
                'journal': journal,
                'pmid': dict_article_meta['pmid'],
                'pmc': dict_article_meta['pmc'],
                'doi': dict_article_meta['doi'],
                'publisher_id': dict_article_meta['publisher_id'],
                'author_list': author_list,
                'affiliation_list': affiliation_list,
                'publication_year': pub_year,
                'subjects': subjects}
    if include_path:
        dict_out['path_to_file'] = path
    return dict_out

def parse_references(tree):
    """
    Give a tree as an input,
    parse it to dictionary if ref-id and cited PMID
    """
    dict_article_meta = parse_article_meta(tree)
    pmid = dict_article_meta['pmid']
    pmc = dict_article_meta['pmc']

    references = tree.xpath('//ref-list/ref[@id]')
    dict_refs = list()
    for r in references:
        ref_id = r.attrib['id']
        for rc in r:
            if 'publication-type' in rc.attrib.keys():
                if rc.attrib.values() is not None:
                    journal_type = rc.attrib.values()[0]
                else:
                    journal_type = ''
                names = list()
                if rc.find('name') is not None:
                    for n in rc.findall('name'):
                        name = join([t.text for t in n.getchildren()][::-1])
                        names.append(name)
                elif rc.find('person-group') is not None:
                    for n in rc.find('person-group'):
                        name = ' '.join(n.xpath('given-names/text()') + n.xpath('surname/text()'))
                        names.append(name)
                try:
                    article_title = rc.findall('article-title')[0].text
                except:
                    article_title = ''
                try:
                    journal = rc.findall('source')[0].text
                except:
                    journal = ''
                try:
                    pmid_cited = rc.findall('pub-id[@pub-id-type="pmid"]')[0].text
                except:
                    pmid_cited = ''
                dict_ref = {'ref_id': ref_id,
                            'name': '; '.join(names),
                            'article_title': article_title,
                            'journal': journal,
                            'journal_type': journal_type,
                            'pmid': pmid,
                            'pmc': pmc,
                            'pmid_cited': pmid_cited}
                dict_refs.append(dict_ref)
    return dict_refs

def parse_pubmed_references(path):
    """
    Given path to xml file, parse all references
    from that PMID
    """
    tree = read_xml(path)
    dict_refs = parse_references(tree)
    return dict_refs

def parse_paragraph(tree, dict_refs):
    """
    Give tree and reference dictionary
    return dictionary of referenced paragraph, section that it belongs to,
    and its cited PMID
    """
    dict_article_meta = parse_article_meta(tree)
    pmid = dict_article_meta['pmid']
    pmc = dict_article_meta['pmc']

    paragraphs = tree.xpath('//body//p')
    dict_pars = list()
    for p in paragraphs:
        try:
            text = join(p.xpath('text()')) # text of the paragraph
        except:
            text = ''
        try:
            section = p.xpath('../title/text()')[0]
        except:
            section = ''

        # find the reference codes used in the paragraphs, can be compared with bibliogrpahy
        try:
            par_bib_refs = p.findall('.//xref[@ref-type="bibr"]')
            par_refs = list()
            for r in par_bib_refs:
                par_refs.append(r.xpath('@rid')[0])
        except:
            par_refs = ''

        # search bibliography for PubMed ID's of referenced articles
        try:
            pm_ids = list()
            for r in par_refs:
                r_ref = list(filter(lambda ref: ref['ref_id'] == r, dict_refs))
                if r_ref[0]['pmid'] != '':
                    pm_ids.append(r_ref[0]['pmid'])
        except:
            pm_ids = list()

        dict_par = {'pmc': pmc,
                    'pmid': pmid,
                    'references_code': par_refs,
                    'references_pmids': pm_ids,
                    'section': section,
                    'text': text}
        dict_pars.append(dict_par)
    return dict_pars

def parse_pubmed_paragraph(path):
    """
    Given single xml path, extract information from xml file
    and return parsed xml file in dictionary format.
    """
    tree = read_xml(path)
    dict_refs = parse_references(tree)
    dict_pars = parse_paragraph(tree, dict_refs)
    return dict_pars

def parse_pubmed_caption(path):
    """
    Given single xml path, extract figure caption and
    reference id back to that figure
    """
    tree = read_xml(path)

    dict_article_meta = parse_article_meta(tree)
    pmid = dict_article_meta['pmid']
    pmc = dict_article_meta['pmc']

    figs = tree.findall('//fig')
    dict_captions = list()
    if figs is not None:
        for fig in figs:
            fig_id = fig.attrib['id']
            fig_label = stringify_children(fig.find('label'))
            fig_captions = fig.find('caption').getchildren()
            caption = join([stringify_children(c) for c in fig_captions])
            graphic = fig.find('graphic')
            if graphic is not None:
                graphic_ref = graphic.attrib.values()[0]
            dict_caption = {'pmid': pmid,
                            'pmc': pmc,
                            'fig_caption': caption,
                            'fig_id': fig_id,
                            'fig_label': fig_label,
                            'graphic_ref': graphic_ref}
            dict_captions.append(dict_caption)
    if not dict_captions:
        dict_captions = None
    return dict_captions
<commit_msg>Partially clean abstract text<commit_after>import os
from lxml import etree
from lxml.etree import tostring
from itertools import chain
from .utils import *

__all__ = [
    'list_xml_path',
    'parse_pubmed_xml',
    'parse_pubmed_paragraph',
    'parse_pubmed_references',
    'parse_pubmed_caption'
]

def list_xml_path(path_dir):
    """
    List full xml path under given directory

    Parameters
    ----------
    path_dir: str, path to directory that contains xml or nxml file

    Returns
    -------
    path_list: list, list of xml or nxml file from given path
    """
    fullpath = [os.path.join(dp, f) for dp, dn, fn in os.walk(os.path.expanduser(path_dir)) for f in fn]
    path_list = [folder for folder in fullpath if os.path.splitext(folder)[-1] == ('.nxml' or '.xml')]
    return path_list

def zip_author(author):
    """
    Give a list of author and its affiliation keys
    in this following format
    [first_name, last_name, [key1, key2]]
    return [[first_name, last_name, key1], [first_name, last_name, key2]] instead
    """
    author_zipped = list(zip([[author[0], author[1]]] * len(author[-1]), author[-1]))
    return list(map(lambda x: x[0] + [x[-1]], author_zipped))

def flatten_zip_author(author_list):
    """
    Apply zip_author to author_list and flatten it
    """
    author_zipped_list = map(zip_author, author_list)
    return list(chain.from_iterable(author_zipped_list))

def parse_article_meta(tree):
    """
    Parse PMID, PMC and DOI from given article tree
    """
    article_meta = tree.find('//article-meta')
    pmid_node = article_meta.find('article-id[@pub-id-type="pmid"]')
    pmc_node = article_meta.find('article-id[@pub-id-type="pmc"]')
    pub_id_node = article_meta.find('article-id[@pub-id-type="publisher-id"]')
    doi_node = article_meta.find('article-id[@pub-id-type="doi"]')

    pmid = pmid_node.text if pmid_node is not None else ''
    pmc = pmc_node.text if pmc_node is not None else ''
    pub_id = pub_id_node.text if pub_id_node is not None else ''
    doi = doi_node.text if doi_node is not None else ''

    dict_article_meta = {'pmid': pmid,
                         'pmc': pmc,
                         'doi': doi,
                         'publisher_id': pub_id}

    return dict_article_meta

def parse_pubmed_xml(path, include_path=False):
    """
    Given single xml path, extract information from xml file
    and return parsed xml file in dictionary format.
    """
    tree = read_xml(path)

    tree_title = tree.find('//title-group/article-title')
    if tree_title is not None:
        title = [t for t in tree_title.itertext()]
        sub_title = tree.xpath('//title-group/subtitle/text()')
        title.extend(sub_title)
        title = [t.replace('\n', ' ').replace('\t', ' ') for t in title]
        full_title = ' '.join(title)
    else:
        full_title = ''

    try:
        abstracts = list()
        abstract_tree = tree.findall('//abstract')
        for a in abstract_tree:
            for t in a.itertext():
                text = t.replace('\n', ' ').replace('\t', ' ').strip()
                abstracts.append(text)
        abstract = ' '.join(abstracts)
    except:
        abstract = ''

    journal_node = tree.findall('//journal-title')
    if journal_node is not None:
        journal = ' '.join([j.text for j in journal_node])
    else:
        journal = ''

    dict_article_meta = parse_article_meta(tree)
    pub_year_node = tree.find('//pub-date/year')
    pub_year = pub_year_node.text if pub_year_node is not None else ''

    subjects_node = tree.findall('//article-categories//subj-group/subject')
    subjects = list()
    if subjects_node is not None:
        for s in subjects_node:
            subject = ' '.join([s_.strip() for s_ in s.itertext()]).strip()
            subjects.append(subject)
        subjects = '; '.join(subjects)
    else:
        subjects = ''

    # create affiliation dictionary
    affil_id = tree.xpath('//aff[@id]/@id')
    if len(affil_id) > 0:
        affil_id = list(map(str, affil_id))
    else:
        affil_id = ['']  # replace id with empty list

    affil_name = tree.xpath('//aff[@id]')
    affil_name_list = list()
    for e in affil_name:
        name = stringify_affiliation_rec(e)
        name = name.strip().replace('\n', ' ')
        affil_name_list.append(name)
    affiliation_list = [[idx, name] for idx, name in zip(affil_id, affil_name_list)]

    tree_author = tree.xpath('//contrib-group/contrib[@contrib-type="author"]')
    author_list = list()
    for author in tree_author:
        author_aff = author.findall('xref[@ref-type="aff"]')
        try:
            ref_id_list = [str(a.attrib['rid']) for a in author_aff]
        except:
            ref_id_list = ''
        try:
            author_list.append([author.find('name/surname').text,
                                author.find('name/given-names').text,
                                ref_id_list])
        except:
            author_list.append(['', '', ref_id_list])
    author_list = flatten_zip_author(author_list)

    dict_out = {'full_title': full_title.strip(),
                'abstract': abstract,
                'journal': journal,
                'pmid': dict_article_meta['pmid'],
                'pmc': dict_article_meta['pmc'],
                'doi': dict_article_meta['doi'],
                'publisher_id': dict_article_meta['publisher_id'],
                'author_list': author_list,
                'affiliation_list': affiliation_list,
                'publication_year': pub_year,
                'subjects': subjects}
    if include_path:
        dict_out['path_to_file'] = path
    return dict_out

def parse_references(tree):
    """
    Give a tree as an input,
    parse it to dictionary if ref-id and cited PMID
    """
    dict_article_meta = parse_article_meta(tree)
    pmid = dict_article_meta['pmid']
    pmc = dict_article_meta['pmc']

    references = tree.xpath('//ref-list/ref[@id]')
    dict_refs = list()
    for r in references:
        ref_id = r.attrib['id']
        for rc in r:
            if 'publication-type' in rc.attrib.keys():
                if rc.attrib.values() is not None:
                    journal_type = rc.attrib.values()[0]
                else:
                    journal_type = ''
                names = list()
                if rc.find('name') is not None:
                    for n in rc.findall('name'):
                        name = join([t.text for t in n.getchildren()][::-1])
                        names.append(name)
                elif rc.find('person-group') is not None:
                    for n in rc.find('person-group'):
                        name = ' '.join(n.xpath('given-names/text()') + n.xpath('surname/text()'))
                        names.append(name)
                try:
                    article_title = rc.findall('article-title')[0].text
                except:
                    article_title = ''
                try:
                    journal = rc.findall('source')[0].text
                except:
                    journal = ''
                try:
                    pmid_cited = rc.findall('pub-id[@pub-id-type="pmid"]')[0].text
                except:
                    pmid_cited = ''
                dict_ref = {'ref_id': ref_id,
                            'name': '; '.join(names),
                            'article_title': article_title,
                            'journal': journal,
                            'journal_type': journal_type,
                            'pmid': pmid,
                            'pmc': pmc,
                            'pmid_cited': pmid_cited}
                dict_refs.append(dict_ref)
    return dict_refs

def parse_pubmed_references(path):
    """
    Given path to xml file, parse all references
    from that PMID
    """
    tree = read_xml(path)
    dict_refs = parse_references(tree)
    return dict_refs

def parse_paragraph(tree, dict_refs):
    """
    Give tree and reference dictionary
    return dictionary of referenced paragraph, section that it belongs to,
    and its cited PMID
    """
    dict_article_meta = parse_article_meta(tree)
    pmid = dict_article_meta['pmid']
    pmc = dict_article_meta['pmc']

    paragraphs = tree.xpath('//body//p')
    dict_pars = list()
    for p in paragraphs:
        try:
            text = join(p.xpath('text()')) # text of the paragraph
        except:
            text = ''
        try:
            section = p.xpath('../title/text()')[0]
        except:
            section = ''

        # find the reference codes used in the paragraphs, can be compared with bibliogrpahy
        try:
            par_bib_refs = p.findall('.//xref[@ref-type="bibr"]')
            par_refs = list()
            for r in par_bib_refs:
                par_refs.append(r.xpath('@rid')[0])
        except:
            par_refs = ''

        # search bibliography for PubMed ID's of referenced articles
        try:
            pm_ids = list()
            for r in par_refs:
                r_ref = list(filter(lambda ref: ref['ref_id'] == r, dict_refs))
                if r_ref[0]['pmid'] != '':
                    pm_ids.append(r_ref[0]['pmid'])
        except:
            pm_ids = list()

        dict_par = {'pmc': pmc,
                    'pmid': pmid,
                    'references_code': par_refs,
                    'references_pmids': pm_ids,
                    'section': section,
                    'text': text}
        dict_pars.append(dict_par)
    return dict_pars

def parse_pubmed_paragraph(path):
    """
    Given single xml path, extract information from xml file
    and return parsed xml file in dictionary format.
    """
    tree = read_xml(path)
    dict_refs = parse_references(tree)
    dict_pars = parse_paragraph(tree, dict_refs)
    return dict_pars

def parse_pubmed_caption(path):
    """
    Given single xml path, extract figure caption and
    reference id back to that figure
    """
    tree = read_xml(path)

    dict_article_meta = parse_article_meta(tree)
    pmid = dict_article_meta['pmid']
    pmc = dict_article_meta['pmc']

    figs = tree.findall('//fig')
    dict_captions = list()
    if figs is not None:
        for fig in figs:
            fig_id = fig.attrib['id']
            fig_label = stringify_children(fig.find('label'))
            fig_captions = fig.find('caption').getchildren()
            caption = join([stringify_children(c) for c in fig_captions])
            graphic = fig.find('graphic')
            if graphic is not None:
                graphic_ref = graphic.attrib.values()[0]
            dict_caption = {'pmid': pmid,
                            'pmc': pmc,
                            'fig_caption': caption,
                            'fig_id': fig_id,
                            'fig_label': fig_label,
                            'graphic_ref': graphic_ref}
            dict_captions.append(dict_caption)
    if not dict_captions:
        dict_captions = None
    return dict_captions
<|endoftext|>


<commit_before>from abc import ABCMeta, abstractmethod
import subprocess

# send a command to the shell and return the result
def cmd(cmd):
    # print cmd
    return subprocess.Popen(
        cmd, shell=True,
        stdout=subprocess.PIPE, stderr=subprocess.STDOUT).stdout.read()

# abstracts away wireless connection
class Wireless:
    _driver = None

    # init
    def __init__(self, interface=None):
        # detect and init appropriate driver
        name = self._detectDriver()
        if name == 'nmcli':
            self._driver = NmcliWireless(interface=interface)
        elif name == 'networksetup':
            self._driver = NetworksetupWireless(interface=interface)

        # attempt to auto detect the interface if none was provided
        if self.interface() is None:
            interfaces = self.interfaces()
            if len(interfaces) > 0:
                self.interface(interfaces[0])

        # raise an error if there is still no interface defined
        if self.interface() is None:
            raise Exception('Unabled to auto-detect the network interface.')

    def _detectDriver(self):
        # try nmcli (Ubuntu 14.04)
        response = cmd('which nmcli')
        if len(response) > 0 and 'not found' not in response:
            return 'nmcli'

        # try networksetup (Mac OS 10.10)
        response = cmd('which networksetup')
        if len(response) > 0 and 'not found' not in response:
            return 'networksetup'

        raise Exception('Cannot find compatible wireless API.')

    # connect to a network
    def connect(self, ssid, password):
        return self._driver.connect(ssid, password)

    # return the ssid of the current network
    def current(self):
        return self._driver.current()

    # return a list of wireless adapters
    def interfaces(self):
        return self._driver.interfaces()

    # return the current wireless adapter
    def interface(self, interface=None):
        return self._driver.interface(interface)

    # return the current wireless adapter
    def power(self, power=None):
        return self._driver.power(power)

# abstract class for all wireless drivers
class WirelessDriver:
    __metaclass__ = ABCMeta

    @abstractmethod
    def connect(self, ssid, password):
        pass

    @abstractmethod
    def current(self):
        pass

    @abstractmethod
    def interfaces(self):
        pass

    @abstractmethod
    def interface(self, interface=None):
        pass

    @abstractmethod
    def power(self, power=None):
        pass

# Linux nmcli Driver
class NmcliWireless(WirelessDriver):
    _interface = None

    # init
    def __init__(self, interface=None):
        self.interface(interface)

    # clean up connections where partial is part of the connection name
    # this is needed to prevent the following error after extended use:
    # 'maximum number of pending replies per connection has been reached'
    def _clean(self, partial):
        # list matching connections
        response = cmd('nmcli --fields UUID,NAME con list | grep {}'.format(
            partial))

        # delete all of the matching connections
        for line in response.splitlines():
            if len(line) > 0:
                uuid = line.split()[0]
                cmd('nmcli con delete uuid {}'.format(uuid))

    # ignore warnings in nmcli output
    # sometimes there are warnings but we connected just fine
    def _errorInResponse(self, response):
        # no error if no response
        if len(response) == 0:
            return False

        # loop through each line
        for line in response.splitlines():
            # all error lines start with 'Error'
            if line.startswith('Error'):
                return True

        # if we didn't find an error then we are in the clear
        return False

    # connect to a network
    def connect(self, ssid, password):
        # clean up previous connection
        self._clean(self.current())

        # attempt to connect
        response = cmd('nmcli dev wifi connect {} password {} {}'.format(
            ssid, password, self._interface))

        # parse response
        return not self._errorInResponse(response)

    # returned the ssid of the current network
    def current(self):
        # list active connections for all interfaces
        response = cmd('nmcli con status | grep {}'.format(
            self.interface()))

        # the current network is in the first column
        for line in response.splitlines():
            return line.split()[0]

        # return none if there was not an active connection
        return None

    # return a list of wireless adapters
    def interfaces(self):
        # grab list of interfaces
        response = cmd('nmcli dev')

        # parse response
        interfaces = []
        for line in response.splitlines():
            if 'wireless' in line:
                # this line has our interface name in the first column
                interfaces.append(line.split()[0])

        # return list
        return interfaces

    # return the current wireless adapter
    def interface(self, interface=None):
        if interface is not None:
            self._interface = interface
        else:
            return self._interface

    # enable/disable wireless networking
    def power(self, power=None):
        if power is True:
            cmd('nmcli nm wifi on')
        elif power is False:
            cmd('nmcli nm wifi off')
        else:
            response = cmd('nmcli nm wifi')
            return 'enabled' in response

# OS X networksetup Driver
class NetworksetupWireless(WirelessDriver):
    _interface = None

    # init
    def __init__(self, interface=None):
        self.interface(interface)

    # connect to a network
    def connect(self, ssid, password):
        # attempt to connect
        response = cmd('networksetup -setairportnetwork {} {} {}'.format(
            self._interface, ssid, password))

        # parse response - assume success when there is no response
        return (len(response) == 0)

    # returned the ssid of the current network
    def current(self):
        # attempt to get current network
        response = cmd('networksetup -getairportnetwork {}'.format(
            self._interface))

        # parse response
        phrase = 'Current Wi-Fi Network: '
        if phrase in response:
            return response.replace('Current Wi-Fi Network: ', '')
        else:
            return None

    # return a list of wireless adapters
    def interfaces(self):
        # grab list of interfaces
        response = cmd('networksetup -listallhardwareports')

        # parse response
        interfaces = []
        detectedWifi = False
        for line in response.splitlines():
            if detectedWifi:
                # this line has our interface name in it
                interfaces.append(line.replace('Device: ', ''))
                detectedWifi = False
            else:
                # search for the line that has 'Wi-Fi' in it
                if 'Wi-Fi' in line:
                    detectedWifi = True

        # return list
        return interfaces

    # return the current wireless adapter
    def interface(self, interface=None):
        if interface is not None:
            self._interface = interface
        else:
            return self._interface

    # enable/disable wireless networking
    def power(self, power=None):
        if power is True:
            cmd('networksetup -setairportpower {} on'.format(
                self._interface))
        elif power is False:
            cmd('networksetup -setairportpower {} off'.format(
                self._interface))
        else:
            response = cmd('networksetup -getairportpower {}'.format(
                self._interface))
            return 'On' in response
<commit_msg>Fix bugs<commit_after>from abc import ABCMeta, abstractmethod
import subprocess

# send a command to the shell and return the result
def cmd(cmd):
    return subprocess.Popen(
        cmd, shell=True,
        stdout=subprocess.PIPE, stderr=subprocess.STDOUT).stdout.read()

# abstracts away wireless connection
class Wireless:
    _driver = None

    # init
    def __init__(self, interface=None):
        # detect and init appropriate driver
        name = self._detectDriver()
        if name == 'nmcli':
            self._driver = NmcliWireless(interface=interface)
        elif name == 'networksetup':
            self._driver = NetworksetupWireless(interface=interface)

        # attempt to auto detect the interface if none was provided
        if self.interface() is None:
            interfaces = self.interfaces()
            if len(interfaces) > 0:
                self.interface(interfaces[0])

        # raise an error if there is still no interface defined
        if self.interface() is None:
            raise Exception('Unabled to auto-detect the network interface.')

    def _detectDriver(self):
        # try nmcli (Ubuntu 14.04)
        response = cmd('which nmcli')
        if len(response) > 0 and 'not found' not in response:
            return 'nmcli'

        # try networksetup (Mac OS 10.10)
        response = cmd('which networksetup')
        if len(response) > 0 and 'not found' not in response:
            return 'networksetup'

        raise Exception('Cannot find compatible wireless API.')

    # connect to a network
    def connect(self, ssid, password):
        return self._driver.connect(ssid, password)

    # return the ssid of the current network
    def current(self):
        return self._driver.current()

    # return a list of wireless adapters
    def interfaces(self):
        return self._driver.interfaces()

    # return the current wireless adapter
    def interface(self, interface=None):
        return self._driver.interface(interface)

    # return the current wireless adapter
    def power(self, power=None):
        return self._driver.power(power)

# abstract class for all wireless drivers
class WirelessDriver:
    __metaclass__ = ABCMeta

    @abstractmethod
    def connect(self, ssid, password):
        pass

    @abstractmethod
    def current(self):
        pass

    @abstractmethod
    def interfaces(self):
        pass

    @abstractmethod
    def interface(self, interface=None):
        pass

    @abstractmethod
    def power(self, power=None):
        pass

# Linux nmcli Driver
class NmcliWireless(WirelessDriver):
    _interface = None

    # init
    def __init__(self, interface=None):
        self.interface(interface)

    # clean up connections where partial is part of the connection name
    # this is needed to prevent the following error after extended use:
    # 'maximum number of pending replies per connection has been reached'
    def _clean(self, partial):
        # list matching connections
        response = cmd('nmcli --fields UUID,NAME con list | grep {}'.format(
            partial))

        # delete all of the matching connections
        for line in response.splitlines():
            if len(line) > 0:
                uuid = line.split()[0]
                cmd('nmcli con delete uuid {}'.format(uuid))

    # ignore warnings in nmcli output
    # sometimes there are warnings but we connected just fine
    def _errorInResponse(self, response):
        # no error if no response
        if len(response) == 0:
            return False

        # loop through each line
        for line in response.splitlines():
            # all error lines start with 'Error'
            if line.startswith('Error'):
                return True

        # if we didn't find an error then we are in the clear
        return False

    # connect to a network
    def connect(self, ssid, password):
        # clean up previous connection
        self._clean(self.current())

        # attempt to connect
        response = cmd('nmcli dev wifi connect {} password {} iface {}'.format(
            ssid, password, self._interface))

        # parse response
        return not self._errorInResponse(response)

    # returned the ssid of the current network
    def current(self):
        # list active connections for all interfaces
        response = cmd('nmcli con status | grep {}'.format(
            self.interface()))

        # the current network is in the first column
        for line in response.splitlines():
            if len(line) > 0:
                return line.split()[0]

        # return none if there was not an active connection
        return None

    # return a list of wireless adapters
    def interfaces(self):
        # grab list of interfaces
        response = cmd('nmcli dev')

        # parse response
        interfaces = []
        for line in response.splitlines():
            if 'wireless' in line:
                # this line has our interface name in the first column
                interfaces.append(line.split()[0])

        # return list
        return interfaces

    # return the current wireless adapter
    def interface(self, interface=None):
        if interface is not None:
            self._interface = interface
        else:
            return self._interface

    # enable/disable wireless networking
    def power(self, power=None):
        if power is True:
            cmd('nmcli nm wifi on')
        elif power is False:
            cmd('nmcli nm wifi off')
        else:
            response = cmd('nmcli nm wifi')
            return 'enabled' in response

# OS X networksetup Driver
class NetworksetupWireless(WirelessDriver):
    _interface = None

    # init
    def __init__(self, interface=None):
        self.interface(interface)

    # connect to a network
    def connect(self, ssid, password):
        # attempt to connect
        response = cmd('networksetup -setairportnetwork {} {} {}'.format(
            self._interface, ssid, password))

        # parse response - assume success when there is no response
        return (len(response) == 0)

    # returned the ssid of the current network
    def current(self):
        # attempt to get current network
        response = cmd('networksetup -getairportnetwork {}'.format(
            self._interface))

        # parse response
        phrase = 'Current Wi-Fi Network: '
        if phrase in response:
            return response.replace('Current Wi-Fi Network: ', '')
        else:
            return None

    # return a list of wireless adapters
    def interfaces(self):
        # grab list of interfaces
        response = cmd('networksetup -listallhardwareports')

        # parse response
        interfaces = []
        detectedWifi = False
        for line in response.splitlines():
            if detectedWifi:
                # this line has our interface name in it
                interfaces.append(line.replace('Device: ', ''))
                detectedWifi = False
            else:
                # search for the line that has 'Wi-Fi' in it
                if 'Wi-Fi' in line:
                    detectedWifi = True

        # return list
        return interfaces

    # return the current wireless adapter
    def interface(self, interface=None):
        if interface is not None:
            self._interface = interface
        else:
            return self._interface

    # enable/disable wireless networking
    def power(self, power=None):
        if power is True:
            cmd('networksetup -setairportpower {} on'.format(
                self._interface))
        elif power is False:
            cmd('networksetup -setairportpower {} off'.format(
                self._interface))
        else:
            response = cmd('networksetup -getairportpower {}'.format(
                self._interface))
            return 'On' in response
<|endoftext|>


<commit_before>#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.
#

from setuptools import setup
from distutils.core import Extension
from distutils.util import strtobool
from os import environ
import subprocess
import sys

from distutils.command import build_ext

import xml.etree.ElementTree as ET
from os.path import dirname, realpath, join

def get_version():
    use_full_pom_name = strtobool(environ.get('USE_FULL_POM_NAME', 'False'))

    # Get the pulsar version from pom.xml
    TOP_LEVEL_PATH = dirname(dirname(dirname(realpath(__file__))))
    POM_PATH = join(TOP_LEVEL_PATH, 'pom.xml')
    root = ET.XML(open(POM_PATH).read())
    version = root.find('{http://maven.apache.org/POM/4.0.0}version').text.strip()

    if use_full_pom_name:
        return version
    else:
        # Strip the '-incubating' suffix, since it prevents the packages
        # from being uploaded into PyPI
        return version.split('-')[0]

def get_name():
    postfix = environ.get('NAME_POSTFIX', '')
    base = 'pulsar-client'
    return base + postfix

VERSION = get_version()
NAME = get_name()

print(VERSION)
print(NAME)

if sys.version_info[0] == 2:
    PY2 = True
else:
    PY2 = False

# This is a workaround to have setuptools to include
# the already compiled _pulsar.so library
class my_build_ext(build_ext.build_ext):
    def build_extension(self, ext):
        import shutil
        import os.path

        try:
            os.makedirs(os.path.dirname(self.get_ext_fullpath(ext.name)))
        except OSError as e:
            if e.errno != 17:  # already exists
                raise
        shutil.copyfile('_pulsar.so', self.get_ext_fullpath(ext.name))

dependencies = [
    'fastavro==0.24.0',
    'grpcio',
    'protobuf>=3.6.1',
    'six',
    'certifi',

    # functions dependencies
    "apache-bookkeeper-client>=4.9.2",
    "prometheus_client",
    "ratelimit"
]

if PY2:
    # Python 2 compat dependencies
    dependencies += ['enum34>=1.1.9']

setup(
    name=NAME,
    version=VERSION,
    packages=['pulsar', 'pulsar.schema', 'pulsar.functions'],
    cmdclass={'build_ext': my_build_ext},
    ext_modules=[Extension('_pulsar', [])],

    author="Pulsar Devs",
    author_email="dev@pulsar.apache.org",
    description="Apache Pulsar Python client library",
    license="Apache License v2.0",
    url="https://pulsar.apache.org/",
    install_requires=dependencies,
)
<commit_msg>Limit enum34 installation via environment markers (#8213)<commit_after>#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.
#

from setuptools import setup
from distutils.core import Extension
from distutils.util import strtobool
from os import environ
import subprocess

from distutils.command import build_ext

import xml.etree.ElementTree as ET
from os.path import dirname, realpath, join

def get_version():
    use_full_pom_name = strtobool(environ.get('USE_FULL_POM_NAME', 'False'))

    # Get the pulsar version from pom.xml
    TOP_LEVEL_PATH = dirname(dirname(dirname(realpath(__file__))))
    POM_PATH = join(TOP_LEVEL_PATH, 'pom.xml')
    root = ET.XML(open(POM_PATH).read())
    version = root.find('{http://maven.apache.org/POM/4.0.0}version').text.strip()

    if use_full_pom_name:
        return version
    else:
        # Strip the '-incubating' suffix, since it prevents the packages
        # from being uploaded into PyPI
        return version.split('-')[0]

def get_name():
    postfix = environ.get('NAME_POSTFIX', '')
    base = 'pulsar-client'
    return base + postfix

VERSION = get_version()
NAME = get_name()

print(VERSION)
print(NAME)

# This is a workaround to have setuptools to include
# the already compiled _pulsar.so library
class my_build_ext(build_ext.build_ext):
    def build_extension(self, ext):
        import shutil
        import os.path

        try:
            os.makedirs(os.path.dirname(self.get_ext_fullpath(ext.name)))
        except OSError as e:
            if e.errno != 17:  # already exists
                raise
        shutil.copyfile('_pulsar.so', self.get_ext_fullpath(ext.name))

dependencies = [
    'fastavro==0.24.0',
    'grpcio',
    'protobuf>=3.6.1',
    'six',
    'certifi',
    'enum34>=1.1.9; python_version < "3.4"',

    # functions dependencies
    "apache-bookkeeper-client>=4.9.2",
    "prometheus_client",
    "ratelimit"
]

setup(
    name=NAME,
    version=VERSION,
    packages=['pulsar', 'pulsar.schema', 'pulsar.functions'],
    cmdclass={'build_ext': my_build_ext},
    ext_modules=[Extension('_pulsar', [])],

    author="Pulsar Devs",
    author_email="dev@pulsar.apache.org",
    description="Apache Pulsar Python client library",
    license="Apache License v2.0",
    url="https://pulsar.apache.org/",
    install_requires=dependencies,
)
<|endoftext|>


<commit_before># Copyright (c) 2013 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

import logging
import subprocess
import tempfile

from telemetry import decorators
from telemetry.core import bitmap
from telemetry.core import exceptions
from telemetry.core import platform
from telemetry.core import util
from telemetry.core.platform import proc_supporting_platform_backend
from telemetry.core.platform import factory
from telemetry.core.platform.power_monitor import android_ds2784_power_monitor
from telemetry.core.platform.power_monitor import android_dumpsys_power_monitor
from telemetry.core.platform.power_monitor import android_temperature_monitor
from telemetry.core.platform.power_monitor import monsoon_power_monitor
from telemetry.core.platform.power_monitor import power_monitor_controller
from telemetry.core.platform.profiler import android_prebuilt_profiler_helper

# Get build/android scripts into our path.
util.AddDirToPythonPath(util.GetChromiumSrcDir(), 'build', 'android')
from pylib import screenshot  # pylint: disable=F0401
from pylib.perf import cache_control  # pylint: disable=F0401
from pylib.perf import perf_control  # pylint: disable=F0401
from pylib.perf import thermal_throttle  # pylint: disable=F0401

try:
  from pylib.perf import surface_stats_collector  # pylint: disable=F0401
except Exception:
  surface_stats_collector = None

_HOST_APPLICATIONS = [
    'avconv',
    'ipfw',
    ]

class AndroidPlatformBackend(
    proc_supporting_platform_backend.ProcSupportingPlatformBackend):
  def __init__(self, device, no_performance_mode):
    super(AndroidPlatformBackend, self).__init__()
    self._device = device
    self._surface_stats_collector = None
    self._perf_tests_setup = perf_control.PerfControl(self._device)
    self._thermal_throttle = thermal_throttle.ThermalThrottle(self._device)
    self._no_performance_mode = no_performance_mode
    self._raw_display_frame_rate_measurements = []
    self._host_platform_backend = factory.GetPlatformBackendForCurrentOS()
    self._can_access_protected_file_contents = \
        self._device.old_interface.CanAccessProtectedFileContents()
    power_controller = power_monitor_controller.PowerMonitorController([
        monsoon_power_monitor.MonsoonPowerMonitor(),
        android_ds2784_power_monitor.DS2784PowerMonitor(device),
        android_dumpsys_power_monitor.DumpsysPowerMonitor(device),
    ])
    self._powermonitor = android_temperature_monitor.AndroidTemperatureMonitor(
        power_controller, device)
    self._video_recorder = None
    self._video_output = None
    if self._no_performance_mode:
      logging.warning('CPU governor will not be set!')

  def IsRawDisplayFrameRateSupported(self):
    return True

  def StartRawDisplayFrameRateMeasurement(self):
    assert not self._surface_stats_collector
    # Clear any leftover data from previous timed out tests
    self._raw_display_frame_rate_measurements = []
    self._surface_stats_collector = \
        surface_stats_collector.SurfaceStatsCollector(self._device)
    self._surface_stats_collector.Start()

  def StopRawDisplayFrameRateMeasurement(self):
    if not self._surface_stats_collector:
      return

    self._surface_stats_collector.Stop()
    for r in self._surface_stats_collector.GetResults():
      self._raw_display_frame_rate_measurements.append(
          platform.Platform.RawDisplayFrameRateMeasurement(
              r.name, r.value, r.unit))

    self._surface_stats_collector = None

  def GetRawDisplayFrameRateMeasurements(self):
    ret = self._raw_display_frame_rate_measurements
    self._raw_display_frame_rate_measurements = []
    return ret

  def SetFullPerformanceModeEnabled(self, enabled):
    if self._no_performance_mode:
      return
    if enabled:
      self._perf_tests_setup.SetHighPerfMode()
    else:
      self._perf_tests_setup.SetDefaultPerfMode()

  def CanMonitorThermalThrottling(self):
    return True

  def IsThermallyThrottled(self):
    return self._thermal_throttle.IsThrottled()

  def HasBeenThermallyThrottled(self):
    return self._thermal_throttle.HasBeenThrottled()

  def GetSystemCommitCharge(self):
    for line in self._device.old_interface.RunShellCommand(
        'dumpsys meminfo', log_result=False):
      if line.startswith('Total PSS: '):
        return int(line.split()[2]) * 1024
    return 0

  @decorators.Cache
  def GetSystemTotalPhysicalMemory(self):
    for line in self._device.old_interface.RunShellCommand(
        'dumpsys meminfo', log_result=False):
      if line.startswith('Total RAM: '):
        return int(line.split()[2]) * 1024
    return 0

  def GetCpuStats(self, pid):
    if not self._can_access_protected_file_contents:
      logging.warning('CPU stats cannot be retrieved on non-rooted device.')
      return {}
    return super(AndroidPlatformBackend, self).GetCpuStats(pid)

  def GetCpuTimestamp(self):
    if not self._can_access_protected_file_contents:
      logging.warning('CPU timestamp cannot be retrieved on non-rooted device.')
      return {}
    return super(AndroidPlatformBackend, self).GetCpuTimestamp()

  def PurgeUnpinnedMemory(self):
    """Purges the unpinned ashmem memory for the whole system.

    This can be used to make memory measurements more stable in particular.
    """
    if not android_prebuilt_profiler_helper.InstallOnDevice(
        self._device, 'purge_ashmem'):
      raise Exception('Error installing purge_ashmem.')
    if self._device.old_interface.RunShellCommand(
        android_prebuilt_profiler_helper.GetDevicePath('purge_ashmem'),
        log_result=True):
      return
    raise Exception('Error while purging ashmem.')

  def GetMemoryStats(self, pid):
    memory_usage = self._device.old_interface.GetMemoryUsageForPid(pid)[0]
    return {'ProportionalSetSize': memory_usage['Pss'] * 1024,
            'SharedDirty': memory_usage['Shared_Dirty'] * 1024,
            'PrivateDirty': memory_usage['Private_Dirty'] * 1024,
            'VMPeak': memory_usage['VmHWM'] * 1024}

  def GetIOStats(self, pid):
    return {}

  def GetChildPids(self, pid):
    child_pids = []
    ps = self._GetPsOutput(['pid', 'name'])
    for curr_pid, curr_name in ps:
      if int(curr_pid) == pid:
        name = curr_name
        for curr_pid, curr_name in ps:
          if curr_name.startswith(name) and curr_name != name:
            child_pids.append(int(curr_pid))
        break
    return child_pids

  def GetCommandLine(self, pid):
    ps = self._GetPsOutput(['pid', 'name'])
    for curr_pid, curr_name in ps:
      if int(curr_pid) == pid:
        return curr_name
    raise exceptions.ProcessGoneException()

  def GetOSName(self):
    return 'android'

  @decorators.Cache
  def GetOSVersionName(self):
    return self._device.old_interface.GetBuildId()[0]

  def CanFlushIndividualFilesFromSystemCache(self):
    return False

  def FlushEntireSystemCache(self):
    cache = cache_control.CacheControl(self._device)
    cache.DropRamCaches()

  def FlushSystemCacheForDirectory(self, directory, ignoring=None):
    raise NotImplementedError()

  def FlushDnsCache(self):
    self._device.old_interface.RunShellCommandWithSU(
        'ndc resolver flushdefaultif')

  def LaunchApplication(
      self, application, parameters=None, elevate_privilege=False):
    if application in _HOST_APPLICATIONS:
      self._host_platform_backend.LaunchApplication(
          application, parameters, elevate_privilege=elevate_privilege)
      return
    if elevate_privilege:
      raise NotImplementedError("elevate_privilege isn't supported on android.")
    if not parameters:
      parameters = ''
    self._device.old_interface.RunShellCommand(
        'am start ' + parameters + ' ' + application)

  def IsApplicationRunning(self, application):
    if application in _HOST_APPLICATIONS:
      return self._host_platform_backend.IsApplicationRunning(application)
    return len(self._device.old_interface.ExtractPid(application)) > 0

  def CanLaunchApplication(self, application):
    if application in _HOST_APPLICATIONS:
      return self._host_platform_backend.CanLaunchApplication(application)
    return True

  def InstallApplication(self, application):
    if application in _HOST_APPLICATIONS:
      self._host_platform_backend.InstallApplication(application)
      return
    raise NotImplementedError(
        'Please teach Telemetry how to install ' + application)

  @decorators.Cache
  def CanCaptureVideo(self):
    return self.GetOSVersionName() >= 'K'

  def StartVideoCapture(self, min_bitrate_mbps):
    min_bitrate_mbps = max(min_bitrate_mbps, 0.1)
    if min_bitrate_mbps > 100:
      raise ValueError('Android video capture cannot capture at %dmbps. '
                       'Max capture rate is 100mbps.' % min_bitrate_mbps)
    self._video_output = tempfile.mkstemp()[1]
    if self.is_video_capture_running:
      self._video_recorder.Stop()
    self._video_recorder = screenshot.VideoRecorder(
        self._device, self._video_output, megabits_per_second=min_bitrate_mbps)
    self._video_recorder.Start()
    util.WaitFor(self._video_recorder.IsStarted, 5)

  @property
  def is_video_capture_running(self):
    return self._video_recorder is not None

  def StopVideoCapture(self):
    assert self.is_video_capture_running, 'Must start video capture first'
    self._video_recorder.Stop()
    self._video_output = self._video_recorder.Pull()
    self._video_recorder = None
    for frame in self._FramesFromMp4(self._video_output):
      yield frame

  def CanMonitorPower(self):
    return self._powermonitor.CanMonitorPower()

  def StartMonitoringPower(self, browser):
    self._powermonitor.StartMonitoringPower(browser)

  def StopMonitoringPower(self):
    return self._powermonitor.StopMonitoringPower()

  def _FramesFromMp4(self, mp4_file):
    if not self.CanLaunchApplication('avconv'):
      self.InstallApplication('avconv')

    def GetDimensions(video):
      proc = subprocess.Popen(['avconv', '-i', video], stderr=subprocess.PIPE)
      dimensions = None
      output = ''
      for line in proc.stderr.readlines():
        output += line
        if 'Video:' in line:
          dimensions = line.split(',')[2]
          dimensions = map(int, dimensions.split()[0].split('x'))
          break
      proc.communicate()
      assert dimensions, ('Failed to determine video dimensions. output=%s' %
                          output)
      return dimensions

    def GetFrameTimestampMs(stderr):
      """Returns the frame timestamp in integer milliseconds from the dump log.

      The expected line format is:
      '  dts=1.715  pts=1.715\n'

      We have to be careful to only read a single timestamp per call to avoid
      deadlock because avconv interleaves its writes to stdout and stderr.
      """
      while True:
        line = ''
        next_char = ''
        while next_char != '\n':
          next_char = stderr.read(1)
          line += next_char
        if 'pts=' in line:
          return int(1000 * float(line.split('=')[-1]))

    dimensions = GetDimensions(mp4_file)
    frame_length = dimensions[0] * dimensions[1] * 3
    frame_data = bytearray(frame_length)

    # Use rawvideo so that we don't need any external library to parse frames.
    proc = subprocess.Popen(['avconv', '-i', mp4_file, '-vcodec',
                             'rawvideo', '-pix_fmt', 'rgb24', '-dump',
                             '-loglevel', 'debug', '-f', 'rawvideo', '-'],
                            stderr=subprocess.PIPE, stdout=subprocess.PIPE)
    while True:
      num_read = proc.stdout.readinto(frame_data)
      if not num_read:
        raise StopIteration
      assert num_read == len(frame_data), 'Unexpected frame size: %d' % num_read
      yield (GetFrameTimestampMs(proc.stderr),
             bitmap.Bitmap(3, dimensions[0], dimensions[1], frame_data))

  def _GetFileContents(self, fname):
    if not self._can_access_protected_file_contents:
      logging.warning('%s cannot be retrieved on non-rooted device.' % fname)
      return ''
    return '\n'.join(
        self._device.old_interface.GetProtectedFileContents(fname))

  def _GetPsOutput(self, columns, pid=None):
    assert columns == ['pid', 'name'] or columns == ['pid'], \
        'Only know how to return pid and name. Requested: ' + columns
    command = 'ps'
    if pid:
      command += ' -p %d' % pid
    ps = self._device.old_interface.RunShellCommand(
        command, log_result=False)[1:]
    output = []
    for line in ps:
      data = line.split()
      curr_pid = data[1]
      curr_name = data[-1]
      if columns == ['pid', 'name']:
        output.append([curr_pid, curr_name])
      else:
        output.append([curr_pid])
    return output
<commit_msg>[Telemetry] Reduce page cycler cycle time by about another 10% on android.<commit_after># Copyright (c) 2013 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

import logging
import subprocess
import tempfile

from telemetry import decorators
from telemetry.core import bitmap
from telemetry.core import exceptions
from telemetry.core import platform
from telemetry.core import util
from telemetry.core.platform import proc_supporting_platform_backend
from telemetry.core.platform import factory
from telemetry.core.platform.power_monitor import android_ds2784_power_monitor
from telemetry.core.platform.power_monitor import android_dumpsys_power_monitor
from telemetry.core.platform.power_monitor import android_temperature_monitor
from telemetry.core.platform.power_monitor import monsoon_power_monitor
from telemetry.core.platform.power_monitor import power_monitor_controller
from telemetry.core.platform.profiler import android_prebuilt_profiler_helper

# Get build/android scripts into our path.
util.AddDirToPythonPath(util.GetChromiumSrcDir(), 'build', 'android')
from pylib import screenshot  # pylint: disable=F0401
from pylib.perf import cache_control  # pylint: disable=F0401
from pylib.perf import perf_control  # pylint: disable=F0401
from pylib.perf import thermal_throttle  # pylint: disable=F0401

try:
  from pylib.perf import surface_stats_collector  # pylint: disable=F0401
except Exception:
  surface_stats_collector = None

_HOST_APPLICATIONS = [
    'avconv',
    'ipfw',
    ]

class AndroidPlatformBackend(
    proc_supporting_platform_backend.ProcSupportingPlatformBackend):
  def __init__(self, device, no_performance_mode):
    super(AndroidPlatformBackend, self).__init__()
    self._device = device
    self._surface_stats_collector = None
    self._perf_tests_setup = perf_control.PerfControl(self._device)
    self._thermal_throttle = thermal_throttle.ThermalThrottle(self._device)
    self._no_performance_mode = no_performance_mode
    self._raw_display_frame_rate_measurements = []
    self._host_platform_backend = factory.GetPlatformBackendForCurrentOS()
    self._can_access_protected_file_contents = \
        self._device.old_interface.CanAccessProtectedFileContents()
    power_controller = power_monitor_controller.PowerMonitorController([
        monsoon_power_monitor.MonsoonPowerMonitor(),
        android_ds2784_power_monitor.DS2784PowerMonitor(device),
        android_dumpsys_power_monitor.DumpsysPowerMonitor(device),
    ])
    self._powermonitor = android_temperature_monitor.AndroidTemperatureMonitor(
        power_controller, device)
    self._video_recorder = None
    self._video_output = None
    if self._no_performance_mode:
      logging.warning('CPU governor will not be set!')

  def IsRawDisplayFrameRateSupported(self):
    return True

  def StartRawDisplayFrameRateMeasurement(self):
    assert not self._surface_stats_collector
    # Clear any leftover data from previous timed out tests
    self._raw_display_frame_rate_measurements = []
    self._surface_stats_collector = \
        surface_stats_collector.SurfaceStatsCollector(self._device)
    self._surface_stats_collector.Start()

  def StopRawDisplayFrameRateMeasurement(self):
    if not self._surface_stats_collector:
      return

    self._surface_stats_collector.Stop()
    for r in self._surface_stats_collector.GetResults():
      self._raw_display_frame_rate_measurements.append(
          platform.Platform.RawDisplayFrameRateMeasurement(
              r.name, r.value, r.unit))

    self._surface_stats_collector = None

  def GetRawDisplayFrameRateMeasurements(self):
    ret = self._raw_display_frame_rate_measurements
    self._raw_display_frame_rate_measurements = []
    return ret

  def SetFullPerformanceModeEnabled(self, enabled):
    if self._no_performance_mode:
      return
    if enabled:
      self._perf_tests_setup.SetHighPerfMode()
    else:
      self._perf_tests_setup.SetDefaultPerfMode()

  def CanMonitorThermalThrottling(self):
    return True

  def IsThermallyThrottled(self):
    return self._thermal_throttle.IsThrottled()

  def HasBeenThermallyThrottled(self):
    return self._thermal_throttle.HasBeenThrottled()

  def GetCpuStats(self, pid):
    if not self._can_access_protected_file_contents:
      logging.warning('CPU stats cannot be retrieved on non-rooted device.')
      return {}
    return super(AndroidPlatformBackend, self).GetCpuStats(pid)

  def GetCpuTimestamp(self):
    if not self._can_access_protected_file_contents:
      logging.warning('CPU timestamp cannot be retrieved on non-rooted device.')
      return {}
    return super(AndroidPlatformBackend, self).GetCpuTimestamp()

  def PurgeUnpinnedMemory(self):
    """Purges the unpinned ashmem memory for the whole system.

    This can be used to make memory measurements more stable in particular.
    """
    if not android_prebuilt_profiler_helper.InstallOnDevice(
        self._device, 'purge_ashmem'):
      raise Exception('Error installing purge_ashmem.')
    if self._device.old_interface.RunShellCommand(
        android_prebuilt_profiler_helper.GetDevicePath('purge_ashmem'),
        log_result=True):
      return
    raise Exception('Error while purging ashmem.')

  def GetMemoryStats(self, pid):
    memory_usage = self._device.old_interface.GetMemoryUsageForPid(pid)[0]
    return {'ProportionalSetSize': memory_usage['Pss'] * 1024,
            'SharedDirty': memory_usage['Shared_Dirty'] * 1024,
            'PrivateDirty': memory_usage['Private_Dirty'] * 1024,
            'VMPeak': memory_usage['VmHWM'] * 1024}

  def GetIOStats(self, pid):
    return {}

  def GetChildPids(self, pid):
    child_pids = []
    ps = self._GetPsOutput(['pid', 'name'])
    for curr_pid, curr_name in ps:
      if int(curr_pid) == pid:
        name = curr_name
        for curr_pid, curr_name in ps:
          if curr_name.startswith(name) and curr_name != name:
            child_pids.append(int(curr_pid))
        break
    return child_pids

  def GetCommandLine(self, pid):
    ps = self._GetPsOutput(['pid', 'name'])
    for curr_pid, curr_name in ps:
      if int(curr_pid) == pid:
        return curr_name
    raise exceptions.ProcessGoneException()

  def GetOSName(self):
    return 'android'

  @decorators.Cache
  def GetOSVersionName(self):
    return self._device.old_interface.GetBuildId()[0]

  def CanFlushIndividualFilesFromSystemCache(self):
    return False

  def FlushEntireSystemCache(self):
    cache = cache_control.CacheControl(self._device)
    cache.DropRamCaches()

  def FlushSystemCacheForDirectory(self, directory, ignoring=None):
    raise NotImplementedError()

  def FlushDnsCache(self):
    self._device.old_interface.RunShellCommandWithSU(
        'ndc resolver flushdefaultif')

  def LaunchApplication(
      self, application, parameters=None, elevate_privilege=False):
    if application in _HOST_APPLICATIONS:
      self._host_platform_backend.LaunchApplication(
          application, parameters, elevate_privilege=elevate_privilege)
      return
    if elevate_privilege:
      raise NotImplementedError("elevate_privilege isn't supported on android.")
    if not parameters:
      parameters = ''
    self._device.old_interface.RunShellCommand(
        'am start ' + parameters + ' ' + application)

  def IsApplicationRunning(self, application):
    if application in _HOST_APPLICATIONS:
      return self._host_platform_backend.IsApplicationRunning(application)
    return len(self._device.old_interface.ExtractPid(application)) > 0

  def CanLaunchApplication(self, application):
    if application in _HOST_APPLICATIONS:
      return self._host_platform_backend.CanLaunchApplication(application)
    return True

  def InstallApplication(self, application):
    if application in _HOST_APPLICATIONS:
      self._host_platform_backend.InstallApplication(application)
      return
    raise NotImplementedError(
        'Please teach Telemetry how to install ' + application)

  @decorators.Cache
  def CanCaptureVideo(self):
    return self.GetOSVersionName() >= 'K'

  def StartVideoCapture(self, min_bitrate_mbps):
    min_bitrate_mbps = max(min_bitrate_mbps, 0.1)
    if min_bitrate_mbps > 100:
      raise ValueError('Android video capture cannot capture at %dmbps. '
                       'Max capture rate is 100mbps.' % min_bitrate_mbps)
    self._video_output = tempfile.mkstemp()[1]
    if self.is_video_capture_running:
      self._video_recorder.Stop()
    self._video_recorder = screenshot.VideoRecorder(
        self._device, self._video_output, megabits_per_second=min_bitrate_mbps)
    self._video_recorder.Start()
    util.WaitFor(self._video_recorder.IsStarted, 5)

  @property
  def is_video_capture_running(self):
    return self._video_recorder is not None

  def StopVideoCapture(self):
    assert self.is_video_capture_running, 'Must start video capture first'
    self._video_recorder.Stop()
    self._video_output = self._video_recorder.Pull()
    self._video_recorder = None
    for frame in self._FramesFromMp4(self._video_output):
      yield frame

  def CanMonitorPower(self):
    return self._powermonitor.CanMonitorPower()

  def StartMonitoringPower(self, browser):
    self._powermonitor.StartMonitoringPower(browser)

  def StopMonitoringPower(self):
    return self._powermonitor.StopMonitoringPower()

  def _FramesFromMp4(self, mp4_file):
    if not self.CanLaunchApplication('avconv'):
      self.InstallApplication('avconv')

    def GetDimensions(video):
      proc = subprocess.Popen(['avconv', '-i', video], stderr=subprocess.PIPE)
      dimensions = None
      output = ''
      for line in proc.stderr.readlines():
        output += line
        if 'Video:' in line:
          dimensions = line.split(',')[2]
          dimensions = map(int, dimensions.split()[0].split('x'))
          break
      proc.communicate()
      assert dimensions, ('Failed to determine video dimensions. output=%s' %
                          output)
      return dimensions

    def GetFrameTimestampMs(stderr):
      """Returns the frame timestamp in integer milliseconds from the dump log.

      The expected line format is:
      '  dts=1.715  pts=1.715\n'

      We have to be careful to only read a single timestamp per call to avoid
      deadlock because avconv interleaves its writes to stdout and stderr.
      """
      while True:
        line = ''
        next_char = ''
        while next_char != '\n':
          next_char = stderr.read(1)
          line += next_char
        if 'pts=' in line:
          return int(1000 * float(line.split('=')[-1]))

    dimensions = GetDimensions(mp4_file)
    frame_length = dimensions[0] * dimensions[1] * 3
    frame_data = bytearray(frame_length)

    # Use rawvideo so that we don't need any external library to parse frames.
    proc = subprocess.Popen(['avconv', '-i', mp4_file, '-vcodec',
                             'rawvideo', '-pix_fmt', 'rgb24', '-dump',
                             '-loglevel', 'debug', '-f', 'rawvideo', '-'],
                            stderr=subprocess.PIPE, stdout=subprocess.PIPE)
    while True:
      num_read = proc.stdout.readinto(frame_data)
      if not num_read:
        raise StopIteration
      assert num_read == len(frame_data), 'Unexpected frame size: %d' % num_read
      yield (GetFrameTimestampMs(proc.stderr),
             bitmap.Bitmap(3, dimensions[0], dimensions[1], frame_data))

  def _GetFileContents(self, fname):
    if not self._can_access_protected_file_contents:
      logging.warning('%s cannot be retrieved on non-rooted device.' % fname)
      return ''
    return '\n'.join(
        self._device.old_interface.GetProtectedFileContents(fname))

  def _GetPsOutput(self, columns, pid=None):
    assert columns == ['pid', 'name'] or columns == ['pid'], \
        'Only know how to return pid and name. Requested: ' + columns
    command = 'ps'
    if pid:
      command += ' -p %d' % pid
    ps = self._device.old_interface.RunShellCommand(
        command, log_result=False)[1:]
    output = []
    for line in ps:
      data = line.split()
      curr_pid = data[1]
      curr_name = data[-1]
      if columns == ['pid', 'name']:
        output.append([curr_pid, curr_name])
      else:
        output.append([curr_pid])
    return output
<|endoftext|>


<commit_before>"""
Simular to test_basic_app, but for plugin bundles
"""
import sys
if (sys.version_info[0] == 2 and sys.version_info[:2] >= (2,7)) or \
        (sys.version_info[0] == 3 and sys.version_info[:2] >= (3,2)):
    import unittest
else:
    import unittest2 as unittest

import subprocess
import shutil
import time
import os
import signal
from distutils.sysconfig import get_config_var
import py2app
import platform

DIR_NAME=os.path.dirname(os.path.abspath(__file__))

class TestBasicPlugin (unittest.TestCase):
    plugin_dir = os.path.join(DIR_NAME, 'basic_plugin')
    py2app_args = []

    # Basic setup code
    #
    # The code in this block needs to be moved to
    # a base-class.
    @classmethod
    def setUpClass(cls):
        try:
            if os.path.exists(os.path.join(cls.plugin_dir, 'build')):
                shutil.rmtree(os.path.join(cls.plugin_dir, 'build'))

            if os.path.exists(os.path.join(cls.plugin_dir, 'dist')):
                shutil.rmtree(os.path.join(cls.plugin_dir, 'dist'))

            cmd = [ sys.executable, 'setup.py', 'py2app'] + cls.py2app_args

            env=os.environ.copy()
            pp = os.path.dirname(os.path.dirname(py2app.__file__))
            if 'PYTHONPATH' in env:
                env['PYTHONPATH'] = pp + ':' + env['PYTHONPATH']
            else:
                env['PYTHONPATH'] = pp

            if 'LANG' not in env:
                env['LANG'] = 'en_US.UTF-8'

            p = subprocess.Popen(
                cmd,
                cwd = cls.plugin_dir,
                stdout=subprocess.PIPE,
                stderr=subprocess.STDOUT,
                close_fds=True,
                env=env)
            lines = p.communicate()[0]
            if p.wait() != 0:
                print (lines)
                raise AssertionError("Creating basic_plugin bundle failed")

            p = subprocess.Popen([
                'xcode-select', '-print-path'
            ], stdout = subprocess.PIPE)
            lines = p.communicate()[0]
            xit = p.wait()
            if p.wait() != 0:
                raise AssertionError("Fetching Xcode root failed")

            root = lines.strip()
            if sys.version_info[0] != 2:
                root = root.decode('utf-8')

            if platform.mac_ver()[0] < '10.6.':
                cc = ['gcc-4.2']
            else:
                cc = ['xcrun', 'clang']

            p = subprocess.Popen(cc
                +  get_config_var('LDFLAGS').split() + [
                    '-o', 'bundle_loader', os.path.join(DIR_NAME, 'bundle_loader.m'),
                    '-framework', 'Foundation'],
                stdout=subprocess.PIPE,
                stderr=subprocess.STDOUT,
                close_fds=True)
            lines = p.communicate()[0]
            if p.wait() != 0:
                print (lines)
                raise AssertionError("Creating bundle_loader failed")

        except:
            cls.tearDownClass()
            raise

    @classmethod
    def tearDownClass(cls):
        if os.path.exists('bundle_loader'):
            os.unlink('bundle_loader')

        if os.path.exists(os.path.join(cls.plugin_dir, 'build')):
            shutil.rmtree(os.path.join(cls.plugin_dir, 'build'))

        if os.path.exists(os.path.join(cls.plugin_dir, 'dist')):
            shutil.rmtree(os.path.join(cls.plugin_dir, 'dist'))

    def start_app(self):
        # Start the test app, return a subprocess object where
        # stdin and stdout are connected to pipes.
        cmd = ['./bundle_loader',
                    os.path.join(self.plugin_dir,
                                'dist/BasicPlugin.bundle'),
        ]
        p = subprocess.Popen(cmd,
                stdin=subprocess.PIPE,
                stdout=subprocess.PIPE,
                close_fds=True,
                )
                #stderr=subprocess.STDOUT)
        return p

    def wait_with_timeout(self, proc, timeout=10):
        for i in range(timeout):
            x = proc.poll()
            if x is None:
                time.sleep(1)
            else:
                return x

        os.kill(proc.pid, signal.SIGKILL)
        return proc.wait()

    #
    # End of setup code
    #

    def test_basic_start(self):
        p = self.start_app()
        v = p.stdout.readline()

        self.assertFalse(v.startswith(b'** Cannot load bundle'))

        p.stdin.write('BasicPlugin.bundle:test startup\n'.encode('latin1'))
        p.stdin.flush()

        v = p.stdout.readline()
        self.assertEqual(v.strip(), b'+ test startup')

        p.stdin.close()
        p.stdout.close()

        exit = self.wait_with_timeout(p)
        self.assertEqual(exit, 0)

class TestBasicAliasPlugin (TestBasicPlugin):
    py2app_args = [ '--alias' ]

class TestBasicSemiStandalonePlugin (TestBasicPlugin):
    py2app_args = [ '--semi-standalone' ]

class TestBasicPluginUnicodePath (TestBasicPlugin):
    if sys.version_info[0] == 2:
        plugin_dir = os.path.join(DIR_NAME, 'basic_plugin ' + unichr(2744).encode('utf-8'))
    else:
        plugin_dir = os.path.join(DIR_NAME, 'basic_plugin ' + chr(2744))

    @classmethod
    def setUpClass(cls):
        try:
            if os.path.exists(cls.plugin_dir):
                shutil.rmtree(cls.plugin_dir)

            assert not os.path.exists(cls.plugin_dir)
            shutil.copytree(TestBasicPlugin.plugin_dir, cls.plugin_dir)

            super(TestBasicPluginUnicodePath, cls).setUpClass()

        except:
            if os.path.exists(cls.plugin_dir):
                shutil.rmtree(cls.plugin_dir)
            raise

    @classmethod
    def tearDownClass(cls):
        if os.path.exists(cls.plugin_dir):
            shutil.rmtree(cls.plugin_dir)

        super(TestBasicPluginUnicodePath, cls).tearDownClass()

class TestBasicAliasPluginUnicodePath (TestBasicPluginUnicodePath):
    py2app_args = [ '--alias' ]

class TestBasicSemiStandalonePluginUnicodePath (TestBasicPluginUnicodePath):
    py2app_args = [ '--semi-standalone' ]

if __name__ == "__main__":
    unittest.main()

<commit_msg>Tweak plugin host compilation flags to ensure test passes on OSX 10.5<commit_after>"""
Simular to test_basic_app, but for plugin bundles
"""
import sys
if (sys.version_info[0] == 2 and sys.version_info[:2] >= (2,7)) or \
        (sys.version_info[0] == 3 and sys.version_info[:2] >= (3,2)):
    import unittest
else:
    import unittest2 as unittest

import subprocess
import shutil
import time
import os
import signal
from distutils.sysconfig import get_config_var
import py2app
import platform

DIR_NAME=os.path.dirname(os.path.abspath(__file__))

class TestBasicPlugin (unittest.TestCase):
    plugin_dir = os.path.join(DIR_NAME, 'basic_plugin')
    py2app_args = []

    # Basic setup code
    #
    # The code in this block needs to be moved to
    # a base-class.
    @classmethod
    def setUpClass(cls):
        try:
            if os.path.exists(os.path.join(cls.plugin_dir, 'build')):
                shutil.rmtree(os.path.join(cls.plugin_dir, 'build'))

            if os.path.exists(os.path.join(cls.plugin_dir, 'dist')):
                shutil.rmtree(os.path.join(cls.plugin_dir, 'dist'))

            cmd = [ sys.executable, 'setup.py', 'py2app'] + cls.py2app_args

            env=os.environ.copy()
            pp = os.path.dirname(os.path.dirname(py2app.__file__))
            if 'PYTHONPATH' in env:
                env['PYTHONPATH'] = pp + ':' + env['PYTHONPATH']
            else:
                env['PYTHONPATH'] = pp

            if 'LANG' not in env:
                env['LANG'] = 'en_US.UTF-8'

            p = subprocess.Popen(
                cmd,
                cwd = cls.plugin_dir,
                stdout=subprocess.PIPE,
                stderr=subprocess.STDOUT,
                close_fds=True,
                env=env)
            lines = p.communicate()[0]
            if p.wait() != 0:
                print (lines)
                raise AssertionError("Creating basic_plugin bundle failed")

            p = subprocess.Popen([
                'xcode-select', '-print-path'
            ], stdout = subprocess.PIPE)
            lines = p.communicate()[0]
            xit = p.wait()
            if p.wait() != 0:
                raise AssertionError("Fetching Xcode root failed")

            root = lines.strip()
            if sys.version_info[0] != 2:
                root = root.decode('utf-8')

            if platform.mac_ver()[0] < '10.6.':
                cc = ['gcc']
                env = dict(os.environ)
                env['MACOSX_DEPLOYMENT_TARGET'] = get_config_var('MACOSX_DEPLOYMENT_TARGET')
            else:
                cc = ['xcrun', 'clang']
                env = dict(os.environ)

            p = subprocess.Popen(cc
                +  get_config_var('LDFLAGS').split() + [
                    '-o', 'bundle_loader', os.path.join(DIR_NAME, 'bundle_loader.m'),
                    '-framework', 'Foundation'],
                env=env,
                stdout=subprocess.PIPE,
                stderr=subprocess.STDOUT,
                close_fds=True)
            lines = p.communicate()[0]
            if p.wait() != 0:
                print (lines)
                raise AssertionError("Creating bundle_loader failed")

        except:
            cls.tearDownClass()
            raise

    @classmethod
    def tearDownClass(cls):
        if os.path.exists('bundle_loader'):
            os.unlink('bundle_loader')

        if os.path.exists(os.path.join(cls.plugin_dir, 'build')):
            shutil.rmtree(os.path.join(cls.plugin_dir, 'build'))

        if os.path.exists(os.path.join(cls.plugin_dir, 'dist')):
            shutil.rmtree(os.path.join(cls.plugin_dir, 'dist'))

    def start_app(self):
        # Start the test app, return a subprocess object where
        # stdin and stdout are connected to pipes.
        cmd = ['./bundle_loader',
                    os.path.join(self.plugin_dir,
                                'dist/BasicPlugin.bundle'),
        ]
        p = subprocess.Popen(cmd,
                stdin=subprocess.PIPE,
                stdout=subprocess.PIPE,
                close_fds=True,
                )
                #stderr=subprocess.STDOUT)
        return p

    def wait_with_timeout(self, proc, timeout=10):
        for i in range(timeout):
            x = proc.poll()
            if x is None:
                time.sleep(1)
            else:
                return x

        os.kill(proc.pid, signal.SIGKILL)
        return proc.wait()

    #
    # End of setup code
    #

    def test_basic_start(self):
        p = self.start_app()
        v = p.stdout.readline()

        self.assertFalse(v.startswith(b'** Cannot load bundle'))

        p.stdin.write('BasicPlugin.bundle:test startup\n'.encode('latin1'))
        p.stdin.flush()

        v = p.stdout.readline()
        self.assertEqual(v.strip(), b'+ test startup')

        p.stdin.close()
        p.stdout.close()

        exit = self.wait_with_timeout(p)
        self.assertEqual(exit, 0)

class TestBasicAliasPlugin (TestBasicPlugin):
    py2app_args = [ '--alias' ]

class TestBasicSemiStandalonePlugin (TestBasicPlugin):
    py2app_args = [ '--semi-standalone' ]

class TestBasicPluginUnicodePath (TestBasicPlugin):
    if sys.version_info[0] == 2:
        plugin_dir = os.path.join(DIR_NAME, 'basic_plugin ' + unichr(2744).encode('utf-8'))
    else:
        plugin_dir = os.path.join(DIR_NAME, 'basic_plugin ' + chr(2744))

    @classmethod
    def setUpClass(cls):
        try:
            if os.path.exists(cls.plugin_dir):
                shutil.rmtree(cls.plugin_dir)

            assert not os.path.exists(cls.plugin_dir)
            shutil.copytree(TestBasicPlugin.plugin_dir, cls.plugin_dir)

            super(TestBasicPluginUnicodePath, cls).setUpClass()

        except:
            if os.path.exists(cls.plugin_dir):
                shutil.rmtree(cls.plugin_dir)
            raise

    @classmethod
    def tearDownClass(cls):
        if os.path.exists(cls.plugin_dir):
            shutil.rmtree(cls.plugin_dir)

        super(TestBasicPluginUnicodePath, cls).tearDownClass()

class TestBasicAliasPluginUnicodePath (TestBasicPluginUnicodePath):
    py2app_args = [ '--alias' ]

class TestBasicSemiStandalonePluginUnicodePath (TestBasicPluginUnicodePath):
    py2app_args = [ '--semi-standalone' ]

if __name__ == "__main__":
    unittest.main()

<|endoftext|>