コード例 #1
0
class Application(object):
    def __init__(self, name='', badge='', statistics='', is_long=False, tasks=None):
        """use is_long = True when passed name is the long name (i.e. from wuprop)"""
        if name == None:
            raise ValueError('Name is None')
        if not(is_long):
            self.setName_shortLong(name)                # Hopefully on the form Say No to Schistosoma (sn2s)
        else:
            self.name_short = name
            self.name_long = name

        if tasks is None:
            self.tasks = list()
        else:
            self.tasks = tasks
        self.badge = badge
        self.statistics = statistics
    
    @property
    def credit(self):
        try:
            return self.statistics.credit
        except:
            try:
                return self.badge.credit
            except:
                return 0

    @property
    def runtime(self):
        try:
            return self.statistics.runtime
        except:
            try:
                return self.badge.runtime
            except:
                return datetime.timedelta(0)

    def setNameFromXML(self, xml):
        """
        Expects the application block:
        <app>
        ...
        </app>
        from the boinc rpc
        """        
        soup = BeautifulSoup(xml, "xml")
        self.setNameFromSoup(soup)

    def setNameFromSoup(self, soup):
        self.name_short = soup.find('name').text   # Vops: soup.name is 'reserved' so need to use find('name')
        user_friendly_name = soup.find('user_friendly_name').text
        #self.setName_shortLong(user_friendly_name)
        self.name_long  = user_friendly_name

    def appendTaskFromXML(self, xml):
        t = task.Task_local.createFromXML(xml)
        self.tasks.append(t)
        return t
    
    def appendStatistics(self, statistics):
        #self.statistics += str(statistics)
        logger.debug('Appending application statistics "%s" to "%s"', 
                     statistics, self.statistics)
        
        # TODO: shorten the code?
        if self.statistics == '':
            if isinstance(statistics, StatisticsList):
                self.statistics = statistics
            else:
                self.statistics = StatisticsList([statistics])
        else:
            if isinstance(statistics, StatisticsList):
                self.statistics.extend(statistics)
            else:
                self.statistics.append(statistics)
        
    # Name
    """Name should be on the form <long> (<short>), do a regexp when the name is set.
    name_long returns <long> and name_short returns <short>"""
    @property
    def name(self):
        return "{} ({})".format(self.name_long.encode('utf8'), self.name_short.encode('utf8'))

    def setName_shortLong(self, name):
        """
        Sets self.name_long and self.name_short based on the following pattern
        <long> (<short>)
        """
        try:
            reg = re.findall('([^(]+)\((\w+)\)', name)
        except TypeError as e:
            logging.exception('Expected string, got type = %s, "%s"', type(name), name)
            reg = []

        if reg != []:
            reg = reduce(lambda x,y: x+y, reg) # flatten list
            name_long = "".join(reg[:-1]).strip()
            name_short = reg[-1].strip()
        else:
            name_long = name
            name_short = ''
        
        self.setName_long(name_long)
        self.name_short = name_short

    def setName_long(self, name_long=None):
        """
        Removes the version part of the application long name (if any)
        """
        if name_long is None: name_long = self.name_long
        
        reg = re.search('(v\d+.\d+)', name_long)
        if reg:
            s = reg.start()
            e = reg.end()
            self.version = reg.group()
            name_long = name_long[:s] + name_long[e:]
            name_long = name_long.replace('  ', ' ')
        else:
            name_long = name_long
        self.name_long = name_long.strip()

    def __str__(self):
        ret = ["= {} = {} {}".format(self.name, self.statistics, 
                                     self.badge)]
        for t in self.tasks:
            ret.append(str(t))
        return "\n".join(ret)

    def __len__(self):
        """
        Number of tasks
        """
        return len(self.tasks)

    def pendingTime(self, include_elapsedCPUtime=True):
        """Returns total seconds for
        pending,
        started
        and tasks waiting for validation.
        """
        pending = 0
        running = 0
        validation = 0
        for task in self.tasks:
            try:
                (p, r, v) = task.pendingTime(include_elapsedCPUtime=include_elapsedCPUtime)
                pending    += p
                running    += r
                validation += v 
            except AttributeError:
                pass

        return pending, running, validation
コード例 #2
0
ファイル: project.py プロジェクト: Turante/py-boinc-plotter
class Project(object):
    def __init__(self, url=None, name=None, 
                 user=None, statistics=None, settings=None):
        self.name = name
        if name == None:
            self.setName(url)
        self.setUrl(url)

        self.user = user
        self.applications = dict()
        self.statistics = statistics
        self.settings = settings
        self.fileTransfers = list() # list of task like objects with files in transit (will mostly be empty)

        self._appNames = dict() # key is task name and value is application name
        self._badges = list()
        self.show_empty = False

    # 
    # XML related
    # 
    @staticmethod
    def createFromXML(xml):
        """
        Expects the project block:
        <project>
        ...
        </project>
        from the boinc rpc
        """        
        soup = BeautifulSoup(xml, "xml")
        settings = Settings.createFromSoup(soup)
        # Get the statistics
        s = ProjectStatistics.createFromSoup(soup)
        url = soup.master_url.text
        name = soup.project_name.text
        return Project(url=url, name=name,
                       statistics=s, settings=settings)

    def appendApplicationFromXML(self, xml):
        a = Application()
        a.setNameFromXML(xml)
        self.applications[a.name_long] = a
        return a
    
    def appendWorkunitFromXML(self, xml):
        # Currently, the only thing of interest is the mapping between name and app_name
        soup = BeautifulSoup(xml)
        name = soup.find('name').text
        app_name = soup.find('app_name').text
        self._appNames[name] = app_name
        return 'name %s, app_name %s' % (name, app_name)
    
    def appendResultFromXML(self, xml):
        t = Task_local.createFromXML(xml)

        try:
            app_name = self._appNames[t.name]
        except KeyError:
            raise KeyError('Unknown app_name for task %s, known names %s' % (t.name, self._appNames))

        #logger.debug('trying to find app_name %s', app_name)
        for key, app in self.applications.items():
            if app.name_short == app_name:
                app.tasks.append(t)
                break
        else:
            raise KeyError('Could not find app_name %s in list of applications' % app_name)

        return t

    # 
    # HTML related
    # 
    def appendApplicationShort(self, name_short):
        for key, app in self.applications.items():
            if app.name_short == name_short:
                return app
        else:
            app = Application(name_short, is_long=True)
            self.applications[name_short] = app
        return app

    def appendApplication(self, name, is_long=False):
        app = Application(name=name, is_long=is_long)
        name_long = app.name_long
        if not(name_long in self.applications):
            self.applications[name_long] = app

        return self.applications[name_long]

    def appendBadge(self, app_name='', badge=''):
        # Normally badges are associated with an application, but numbersfields and wuprop associates with project instead.
        if app_name != '':
            app = self.appendApplication(app_name)
            logger.debug('Appending badge %s, to %s', badge, app_name)
            app.badge = badge
            return app
        else:
            self._badges.append((self, badge))

    @property
    def badges(self):
        ret = list()
        for key, app in sorted(self.applications.items()):
            b = app.badge
            if b != '':
                ret.append((app, b))
        ret.extend(self._badges)
        return ret
        
    def appendStatistics(self, statistics):
        if statistics is None:
            return

        logger.debug('Appending project statistics "%s" to "%s"', 
                     statistics, self.statistics)
        if self.statistics is None:
            self.statistics = StatisticsList([statistics])
        elif isinstance(statistics, list):
            self.statistics.extend(statistics)
        else:
            self.statistics.append(statistics)
        
    def setName(self, name):
        if name == None: 
            self.name = name
            return

        self.name = name.replace('https://', '')
        self.name = self.name.replace('http://', '')
        self.name = self.name.replace('www.', '')
        self.name = self.name.replace('.org', '')
        if self.name[-1] == '/':
            self.name = self.name[:-1]
        self.name = self.name.replace('/', '_')
        self.name = self.name#.capitalize()

    def setUrl(self, url):
        if url is None:
            self.url = url
            return

        if url.endswith('/'):
            self.url = url[:-1]
        else:
            self.url = url

        http = 'http://'
        ix = self.url.find(http)
        if ix != -1:
            name = self.url[ix+len(http):]
            if not(name.startswith('www.')):
                name = 'www.' + name
                self.url = http + name

    def __str__(self):
        ret = ["== {} ==".format(self.name.title())]
        for prop in [self.settings, self.statistics]:
            if prop != None:
                ret.append(str(prop))

        for _, badge in self._badges:
            ret.append(str(badge))

        for key in sorted(self.applications):
            if len(self.applications[key]) != 0 or self.show_empty:
                ret.append(str(self.applications[key]))

        if len(self.fileTransfers) != 0:
            ret.append('- File Transfers -')
            for t in self.fileTransfers:
                ret.append(str(t))

        return "\n".join(ret)

    def __len__(self):
        """
        Number of tasks
        """
        n = 0
        for key in self.applications:
            n += len(self.applications[key])
        return n

    def tasks(self):
        """ Syntax sugar for generator for each task contained by project
        """
        for key in sorted(self.applications):
            for task in self.applications[key].tasks:
                yield task