示例#1
0
class CriticalPower(grumble.Model, Timestamped):
    cpdef = grumble.ReferenceProperty(sweattrails.config.CriticalPowerInterval)
    timestamp = grumble.TimeDeltaProperty(verbose_name="Starting on")
    atdistance = grumble.IntegerProperty(verbose_name="At distance")
    power = grumble.IntegerProperty(verbose_name="Power")

    @classmethod
    def get_best_for(cls, cpdef):
        for best in CriticalPower.query(cpdef=cpdef).add_sort(
                "power", False).set_limit(1):
            return best
        return None

    @classmethod
    def get_progression(cls, cpdef, user):
        q = cls.query(cpdef=cpdef).add_sort("p.start_time")
        q.add_parent_join(BikePart, "part")
        q.add_join(Session, "_parent", "session", "part")
        q.add_join(sweattrails.config.CriticalPowerInterval,
                   "cpdef",
                   alias="cpi")
        q.add_filter("session.athlete =", user)
        q.add_condition(
            """k.power > COALESCE((SELECT MAX(cp.power) FROM %s cp
                           INNER JOIN %s bp ON (bp._key = cp._parent)
                           INNER JOIN %s sess ON (sess._key = bp._parent)
                           WHERE cp.cpdef = %%s AND sess.start_time < session.start_time), k.power - 1)"""
            % (cls.modelmanager.tablename, BikePart.modelmanager.tablename,
               Session.modelmanager.tablename), str(cpdef.key()))
        q.add_sort("k.power", False)
        return q
示例#2
0
class GeoData(grumble.Model):
    max_elev = grumble.IntegerProperty(
        default=-100, verbose_name="Max. Elevation")  # In meters
    min_elev = grumble.IntegerProperty(
        default=10000, verbose_name="Min. Elevation")  # In meters
    elev_gain = grumble.IntegerProperty(
        default=0, verbose_name="Elevation Gain")  # In meters
    elev_loss = grumble.IntegerProperty(
        default=0, verbose_name="Elevation Loss")  # In meters
    bounding_box = grumble.geopt.GeoBoxProperty()

    def get_session(self):
        return self.parent().get_session()
示例#3
0
class RunPart(IntervalPart):
    average_power = grumble.IntegerProperty(verbose_name="Average Power",
                                            default=0,
                                            suffix="W")  # W
    average_watts_per_kg = WattsPerKgProperty(powerproperty="average_power",
                                              suffix="W/kg")
    normalized_power = grumble.IntegerProperty(verbose_name="Normalized Power",
                                               suffix="W")  # W
    normalized_watts_per_kg = WattsPerKgProperty(
        powerproperty="normalized_power", suffix="W/kg")
    max_power = grumble.IntegerProperty(verbose_name="Maximum Power",
                                        default=0,
                                        suffix="W")  # W
    max_watts_per_kg = WattsPerKgProperty(powerproperty="max_power",
                                          suffix="W/kg")
    average_cadence = grumble.IntegerProperty(default=0,
                                              suffix="strides/min")  # rpm
    max_cadence = grumble.IntegerProperty(default=0,
                                          suffix="strides/min")  # rpm

    def reset(self):
        RunPace.query(ancestor=self).delete()
        self.average_cadence = 0
        self.max_cadence = 0

    def reducers(self):
        ret = []
        for cpdef in self.get_activityprofile().get_all_linked_references(
                sweattrails.config.CriticalPace):
            if cpdef.distance <= self.get_interval().distance:
                p = RunPace(parent=self)
                p.cpdef = cpdef
                p.distance = cpdef.distance
                ret.append(RunPaceReducer(p))
        maxspeed = None
        for pzdef in self.get_activityprofile().get_all_linked_references(
                sweattrails.config.PaceZone):
            p = TimeInPaceZone(parent=self)
            p.pzdef = pzdef
            ret.append(TimeInZoneReducer(p, maxspeed))
            maxspeed = pzdef.minSpeed - 1
        ret.extend([
            Maximize("power", self, "max_power"),
            AverageOverTime("timestamp", "power", self, "average_power"),
            NormalizedPowerReducer(self),
            Maximize("cadence", self, "max_cadence"),
            AverageOverTime("timestamp", "cadence", self, "average_cadence")
        ])
        return ret
示例#4
0
class Person(grumble.Model):
    name = grumble.TextProperty(required=True,
                                is_label=True,
                                is_key=True,
                                scoped=True)
    age = grumble.IntegerProperty(default=30, validator=check_age)
    can_drive = CanDriveProperty()
示例#5
0
class HttpAccess(grumble.Model):
    _flat = True
    _audit = False
    timestamp = grumble.DateTimeProperty(auto_now_add=True)
    remote_addr = grumble.TextProperty()
    user = grumble.TextProperty()
    path = grumble.TextProperty()
    method = grumble.TextProperty()
    status = grumble.TextProperty()
    elapsed = grumble.IntegerProperty()
示例#6
0
class BikePart(IntervalPart):
    average_power = grumble.IntegerProperty(verbose_name="Average Power",
                                            default=0,
                                            suffix="W")  # W
    average_watts_per_kg = WattsPerKgProperty(powerproperty="average_power",
                                              suffix="W/kg")
    normalized_power = grumble.IntegerProperty(verbose_name="Normalized Power",
                                               suffix="W")  # W
    normalized_watts_per_kg = WattsPerKgProperty(
        powerproperty="normalized_power", suffix="W/kg")
    max_power = grumble.IntegerProperty(verbose_name="Maximum Power",
                                        default=0,
                                        suffix="W")  # W
    max_watts_per_kg = WattsPerKgProperty(powerproperty="max_power",
                                          suffix="W/kg")
    average_cadence = grumble.IntegerProperty(verbose_name="Average Cadence",
                                              default=0,
                                              suffix="rpm")  # rpm
    max_cadence = grumble.IntegerProperty(verbose_name="Maximum Cadence",
                                          default=0,
                                          suffix="rpm")  # rpm
    average_torque = grumble.FloatProperty(verbose_name="Average Torque",
                                           default=0.0,
                                           suffix="Nm")  # Nm
    max_torque = grumble.FloatProperty(verbose_name="Maximum Torque",
                                       default=0.0,
                                       suffix="Nm")  # Nm
    vi = VIProperty(verbose_name="VI", default=0.0)
    intensity_factor = IFProperty(verbose_name="IF", default=0.0)
    tss = TSSProperty(verbose_name="TSS", default=0.0)

    def get_ftp(self):
        if not hasattr(self, "_ftp"):
            interval = self.parent()()
            athlete = interval.get_athlete()
            bikepart = sweattrails.userprofile.BikeProfile.get_userpart(
                athlete)
            self._ftp = bikepart.get_ftp(
                self.get_date()) if bikepart is not None else 0
        return self._ftp

    def get_max_power(self):
        interval = self.parent()()
        athlete = interval.get_athlete()
        bikepart = sweattrails.userprofile.BikeProfile.get_userpart(athlete)
        return bikepart.get_max_power(
            self.get_date()) if bikepart is not None else 0

    def set_max_power(self, max_power):
        interval = self.parent()()
        athlete = interval.get_athlete()
        bikepart = sweattrails.userprofile.BikeProfile.get_userpart(athlete)
        if bikepart is not None:
            bikepart.set_max_power(max_power, self.get_date())

    def get_watts_per_kg(self, watts):
        interval = self.parent()()
        athlete = interval.get_athlete()
        bikepart = sweattrails.userprofile.BikeProfile.get_userpart(athlete)
        return bikepart.get_watts_per_kg(
            watts, self.get_date()) if bikepart is not None else 0

    def reducers(self):
        ret = []
        for cpdef in self.get_activityprofile().get_all_linked_references(
                sweattrails.config.CriticalPowerInterval):
            if cpdef.duration <= self.get_interval().duration:
                cp = CriticalPower(parent=self)
                cp.cpdef = cpdef
                cp.put()
                ret.append(CriticalPowerReducer(cp))

        maxpower = None
        for pzdef in self.get_activityprofile().get_all_linked_references(
                sweattrails.config.PowerZone):
            p = TimeInPowerZone(parent=self)
            p.pzdef = pzdef
            ret.append(TimeInZoneReducer(p, maxpower))
            maxpower = pzdef.minPower - 1

        ret.extend([
            Maximize("torque", self, "max_torque"),
            AverageOverTime("timestamp", "torque", self, "average_torque"),
            Maximize("cadence", self, "max_cadence"),
            AverageOverTime("timestamp", "cadence", self, "average_cadence"),
            Maximize("power", self, "max_power"),
            AverageOverTime("timestamp", "power", self, "average_power"),
            NormalizedPowerReducer(self)
        ])
        return ret

    def reset(self):
        CriticalPower.query(ancestor=self).delete()
        self.average_power = 0
        self.normalized_power = 0
        self.max_power = 0
        self.average_cadence = 0
        self.max_cadence = 0
        self.average_torque = 0
        self.max_torque = 0
示例#7
0
    def __call__(self, cls):
        assert isinstance(cls, grumble.ModelMetaClass)
        logger.debug("Decorating %s as a process", cls.__name__)
        cls.add_property("starttime", grumble.DateTimeProperty())
        cls.add_property("finishtime", grumble.DateTimeProperty())
        cls.add_property("semaphore", grumble.IntegerProperty(default=0))
        cls._grudge_process_class = True
        cls._statuses = {}
        for (propname, propdef) in cls.__dict__.items():
            if isinstance(propdef, Status):
                propdef.name(propname)
                cls._statuses[propname] = propdef
        cls._on_started = []
        cls._on_stopped = []
        cls._subprocesses = []
        cls._parent_process = grumble.Model.for_name(
            self.parent) if self.parent else None
        if cls._parent_process:
            cls._parent_process._subprocesses.append(cls)
        cls._entrypoint = self.entrypoint
        cls._exitpoint = self.exitpoint
        cls._start_semaphore = self.start_semaphore

        def get_status(cls, s):
            return cls._statuses.get(s.name() if isinstance(s, Status) else s)

        cls.get_status = classmethod(get_status)

        def statusses(cls):
            return cls._statuses

        cls.statusses = classmethod(statusses)

        def on_started(cls, action):
            cls._on_started.append(action)

        cls.on_started = classmethod(on_started)

        def on_stopped(cls, action):
            cls._on_stopped.append(action)

        cls.on_stopped = classmethod(on_stopped)

        def subprocesses(cls):
            return cls._subprocesses

        cls.subprocesses = classmethod(subprocesses)

        def instantiate(cls, parent=None, **kwargs):
            logger.debug("instantiate %s", cls.__name__)
            with gripe.db.Tx.begin():
                p = cls(parent=parent, **kwargs)
                p.put()
                for sub in cls.subprocesses():
                    subcls = grumble.Model.for_name(sub.__name__)
                    subcls.instantiate(p)
                return p

        cls.instantiate = classmethod(instantiate)

        def start(self):
            if self.starttime is None:
                with gripe.db.Tx.begin():
                    self.semaphore += 1
                    if self.semaphore < self._start_semaphore:
                        logger.debug(
                            "start semaphore value is %s threshold of %s not yet reached",
                            self.semaphore, self._start_semaphore)
                        self.put()
                        return
                    else:
                        logger.debug("starting instance of %s",
                                     self.__class__.__name__)
                        self.starttime = datetime.datetime.now()
                        self.put()
                        for a in self._on_started:
                            _queue.put_action(a, process=self)
                with gripe.db.Tx.begin():
                    ep = grumble.Model.for_name(
                        self._entrypoint) if self._entrypoint else None
                    if ep:
                        logger.debug("Entrypoint of %s: %s",
                                     self.__class__.__name__, ep.__name__)
                        ep_instance = grumble.Query(ep, False,
                                                    parent=self).get()
                        assert ep_instance, "No instance of entrypoint class '%s' found" % self._entrypoint
                        logger.debug("Starting entrypoint instance")
                        ep_instance.start()
                    else:
                        logger.debug("No entrypoint")

        cls.start = start

        def stop(self):
            if self.starttime is not None and self.finishtime is None:
                logger.debug("stop instance of %s", self.__class__.__name__)
                with gripe.db.Tx.begin():
                    if self.subprocesses():
                        for sub in grumble.Query(self.subprocesses(),
                                                 ancestor=self):
                            sub.stop()
                    self.finishtime = datetime.datetime.now()
                    self.put()
                    for a in self._on_stopped:
                        _queue.put_action(a, process=self)
                    if self._exitpoint:
                        p = self.parent()
                        p.stop()

        cls.stop = stop

        def has_status(self, status):
            status = status.name() if isinstance(status, Status) else status
            assert status in self._statuses, "Cannot add status %s to process %s" % (
                status, self.__class__.__name__)
            logger.debug("Checking status %s on process %s", status,
                         self.__class__.__name__)
            added = None
            with gripe.db.Tx.begin():
                for s in AddedStatus.query(parent=self):
                    logger.debug(" -- Status %s found", s.status)
                    if s.status == status:
                        added = s
                return added is not None

        cls.has_status = has_status

        def add_status(self, status):
            status = status.name() if isinstance(status, Status) else status
            assert status in self._statuses, "Cannot add status %s to process %s" % (
                status, self.__class__.__name__)
            logger.debug("Adding status %s to process %s", status,
                         self.__class__.__name__)
            statusdef = self._statuses[status]
            added = None
            with gripe.db.Tx.begin():
                for s in AddedStatus.query(parent=self):
                    if s.status == status:
                        added = s
                if added is None:
                    added = AddedStatus(status=status, parent=self)
                    added.put()
                    statusdef.added(self)
                return added

        cls.add_status = add_status

        def remove_status(self, status):
            status = status.name() if isinstance(status, Status) else status
            assert status in self._statuses, "Cannot remove status %s from process %s" % (
                status, self.__class__.__name__)
            logger.debug("Removing status %s from process %s", status,
                         self.__class__.__name__)
            statusdef = self._statuses[status]
            remove = None
            with gripe.db.Tx.begin():
                for s in AddedStatus.query(parent=self):
                    if s.status == status:
                        remove = s
                if remove is not None:
                    grumble.delete(remove)
                    statusdef.removed(self)
                return

        cls.remove_status = remove_status

        def resolve_process(self, path):
            assert path, "Called process.resolve_process with empty path"
            logger.debug("resolving %s for %s", path, self)
            proc = self
            for elem in path.split("/"):
                logger.debug("Looking for '%s'", elem)
                if elem == "..":
                    proc = proc().parent()
                    logger.debug("resolved '..' -> %s", proc)
                elif elem and elem != ".":
                    proc = grumble.Query(elem, parent=proc).get()
                    logger.debug("resolved '%s' -> %s", elem, proc)
                else:
                    logger.debug("resolve: no-op '%s'", elem)
                assert proc, "Path %s does not resolve for process %s" % (path,
                                                                          self)
            return proc()

        cls.resolve_process = resolve_process

        def resolve_attribute(self, path, args=None, kwargs=None):
            assert path, "Called process.resolve_attribute with empty path"
            logger.debug("resolving attribute %s for %s", path, self)
            proc = self
            (procpath, delim, attribname) = path.rpartition(":")
            call = False
            if attribname.endswith("()"):
                call = True
                attribname = attribname[:-2]
            if procpath:
                proc = self.resolve_process(procpath)()
            assert hasattr(proc, attribname), \
                "Resolving %s: Objects of class %s do not have attribute %s" % \
                (path, proc.__class__.__name__, attribname)
            attr = getattr(proc, attribname)
            if call:
                assert callable(attr), "Attribute %s of class %s is not callable" % \
                    (attribname, proc.__class__.__name__)
                if args is not None:
                    return attr(
                        *args) if kwargs is None else attr(*args, **kwargs)
                else:
                    return attr() if kwargs is None else attr(**kwargs)
            else:
                return attr

        cls.resolve_attribute = resolve_attribute
        return cls
示例#8
0
 class Test(grumble.Model):
     quux = grumble.StringProperty()
     froz = grumble.IntegerProperty()
     icon = grumble.image.ImageProperty()
示例#9
0
 class Test3(grumble.Model):
     name = grumble.TextProperty(required=True, is_label=True)
     value = grumble.IntegerProperty(default=12)