Exemple #1
0
    def _load_actions_and_plans(cls, path, plan=None, depth=0):
        import os
        list = os.listdir(path)

        if depth == 0:
            cls.plans._objects = qlist()
            cls.actions._objects = qlist()

        # iterate through files and directories in actions directory
        for d in list:

            # treat directories as plans and files as actions
            if os.path.isdir(path + '/' + d) is True:

                # load plans
                p = cls.plans.load(path + '/' + d, plan)

                # recursively load actions and plans
                cls._load_actions_and_plans(path + '/' + d, p, depth=depth+1)

            else:
                # ignore .plans file, it is processed when loading a plans
                if d != '.plan':
                    # load actions
                    a = cls.actions.load(path + '/' + d, plan)
Exemple #2
0
    def __init__(self):
        super(Plan, self).__init__()

        # persisted attrs
        self._type_ = type

        # non-persisted attrs
        self._parent = None
        self._actions = qlist(listener=self._actions_listener)
        self._plans = qlist(listener=self._plans_listener)
Exemple #3
0
    def __init__(self):
        super(Plan, self).__init__()

        # persisted attrs
        self._type_ = type

        # non-persisted attrs
        self._parent = None
        self._actions = qlist(listener=self._actions_listener)
        self._plans = qlist(listener=self._plans_listener)
Exemple #4
0
    def __init__(self):

        # persistance attrs
        self.ignore_changes = False
        self.persisted = {}
        self.id = None

        # persisted attrs
        self._name_ = None
        self._tags_ = qlist(listener=self._tags_listener, before_add=self._tags_before_add)
        self._targets_ = qlist(listener=self._targets_listener)

        # explicit persistance - not in json
        self._docs = qlist(listener=self._docs_listener)
Exemple #5
0
    def __init__(self):

        # persistance attrs
        self.ignore_changes = False
        self.persisted = {}
        self.id = None

        # persisted attrs
        self._name_ = None
        self._tags_ = qlist(listener=self._tags_listener,
                            before_add=self._tags_before_add)
        self._targets_ = qlist(listener=self._targets_listener)

        # explicit persistance - not in json
        self._docs = qlist(listener=self._docs_listener)
Exemple #6
0
    def _load_logs(cls):

        cls.logentries._objects = qlist()

        import os
        list_ = os.listdir('/'.join([cls.life_prj_path, LOGS_DIR]))

        # iterate through files in logs directory
        for d in list_:

            # don't load .changes log files, they are only logged for debug info
            if not d.endswith('.changes') and os.path.isfile('/'.join([cls.life_prj_path, LOGS_DIR, d])):

                with open('/'.join([cls.life_prj_path, LOGS_DIR, d])) as logfile:

                    # load log entry
                    for line in logfile.readlines():

                        # load line into LogEntry instance
                        logentry = cls.logentries.load(line, d)

                        # resolve model reference
                        model = cls.actions.get(name=logentry.obj)
                        if model is None:
                            model = cls.plans.get(name=logentry.obj)

                        # relate logentry to models
                        if model is not None:
                            logentry.obj = model
                            model.history.append(logentry)
                            parent = model.parent
                            while parent is not None:
                                parent.history.append(logentry)
                                parent = parent.parent
Exemple #7
0
def get_test_obj(listener=None):
    """Returns a qlist for testing

    :returns: Returns a qlist for testing
    :rtype: hoomanpy.qlist
    """

    ql = qlist(listener=listener)

    for i in range(0, 10):
        ql.append(DummyModel('Object #{}'.format(i), i + 1))

    ql[2].status = "inactive"
    ql[4].status = "inactive"
    ql[6].status = "inactive"
    ql[3].status = "in progress"
    ql[5].status = "in progress"
    ql[7].status = "in progress"

    ql[0].tags.extend(['pop', 'rock', 'groovy', 'music'])
    ql[1].tags.extend(['pop', 'rock', 'groovy', 'music'])
    ql[2].tags.extend(['pop', 'rock', 'groovy', 'music'])

    ql[3].tags.extend(['country', 'live', 'depressing', 'music'])
    ql[4].tags.extend(['country', 'live', 'depressing', 'music'])
    ql[5].tags.extend(['country', 'live', 'depressing', 'music'])

    ql[6].tags.extend(['folk', 'indie', 'hipster', 'music'])
    ql[7].tags.extend(['folk', 'indie', 'hipster', 'music'])
    ql[8].tags.extend(['folk', 'indie', 'hipster', 'music'])

    return ql
Exemple #8
0
    def setup(cls, life_path, stdout=None, logfilename=None):
        # set up data access
        cls.life_prj_path = life_path

        if logfilename is None:
            import datetime
            cls.log_file_name = datetime.datetime.today().strftime('%Y-%m-%d')

        cls.stdout = stdout

        m.dal = DataAccess

        # connect model data access classes
        cls.actions = ActionManager
        cls.plans = PlanManager
        cls.logentries = LogEntryManager
        cls.targets = TargetManager
        cls.changed = []
        cls.changed_log = qlist()

        # load models
        cls.ignore_changes = True
        cls._load_actions_and_plans('/'.join([cls.life_prj_path, ACTIONS_DIR]))
        cls._load_logs()
        cls.ignore_changes = False
Exemple #9
0
    def purge_object_from_logs(cls, obj):
        """Remove all log entries for an action and clear the ``action.history`` property."""

        # get distinct list of log file names from the action history
        log_filenames = cls.get_log_file_names(obj.history)

        # no log history
        if log_filenames is None:
            return

        # loop over a sliced copy of self.logentries to avoid skipping items
        # due to the internal indexing of the iteration
        for logentry in cls.logentries.all()[:]:
            if logentry.obj is obj:
                cls.logentries.remove(logentry)
                if logentry.type == 3 and isinstance(obj, m.Action) and obj.parent is not None:
                    obj.parent.history.remove(logentry)

        # read lines from each logfile and then rewrite the
        # logfile, omitting lines that are for this action
        for log_filename in log_filenames:
            with open('/'.join([cls.life_prj_path, LOGS_DIR, log_filename]), 'r') as logfile:
                lines = logfile.readlines()

            with open('/'.join([cls.life_prj_path, LOGS_DIR, log_filename]), 'w') as logfile:
                for line in lines:
                    if line.find('"obj": "' + obj.name + '"') < 0:
                        logfile.write(line)

        # reset object's history property
        obj.history = qlist()
Exemple #10
0
def get_test_obj(listener=None):
    """Returns a qlist for testing

    :returns: Returns a qlist for testing
    :rtype: hoomanpy.qlist
    """

    ql = qlist(listener=listener)

    for i in range(0, 10):
        ql.append(DummyModel("Object #{}".format(i), i + 1))

    ql[2].status = "inactive"
    ql[4].status = "inactive"
    ql[6].status = "inactive"
    ql[3].status = "in progress"
    ql[5].status = "in progress"
    ql[7].status = "in progress"

    ql[0].tags.extend(["pop", "rock", "groovy", "music"])
    ql[1].tags.extend(["pop", "rock", "groovy", "music"])
    ql[2].tags.extend(["pop", "rock", "groovy", "music"])

    ql[3].tags.extend(["country", "live", "depressing", "music"])
    ql[4].tags.extend(["country", "live", "depressing", "music"])
    ql[5].tags.extend(["country", "live", "depressing", "music"])

    ql[6].tags.extend(["folk", "indie", "hipster", "music"])
    ql[7].tags.extend(["folk", "indie", "hipster", "music"])
    ql[8].tags.extend(["folk", "indie", "hipster", "music"])

    return ql
Exemple #11
0
    def get_actions(self, status='all', plan=None, tags=None):
        """Return a list of actions.

        :param status: Status to include (active, inactive, future, or all).
        :type status: str
        :param plan: Plan to filter actions to.
        :type plan: models.Plan
        :param tags: Tags to filter the list of actions by.
        :type tags: str, list<str>
        :returns: A list of actions.
        :rtype: hoomanpy.qlist
        """

        if plan is not None:
            list_ = plan.actions
        else:
            list_ = qlist()
            list_.extend(dal.actions.all())
            list_.extend(dal.plans.filter(type='option', actions__count__gt=0))

        if status in ('active', 'inactive', 'future'):
            list_ = list_.filter(status=status)

        if tags is not None:
            if not hasattr(tags, '__iter__'):
                tags = [tags]
            list_ = list_.filter(tags__in=tags)

        return list_
Exemple #12
0
    def get_tags(self, status='all'):
        """Return a distinct, alphetically-sorted list of tags assigned.

        :param status: 'all', 'active', 'inactive', or 'notinuse' to Return tags assigned to actions and plans that
                       have the given status. 'old' will return tags that are assigned only to inactive actions
                       and plans.
        :type status: str
        :return: A distinct list of tags.
        :rtype: hoomanpy.qlist
        """

        if status == 'all':
            tags = dal.actions.all().distinct('tags')
            tags.extend(dal.plans.all().distinct('tags'))
        elif status == 'active':
            tags = dal.actions.active().distinct('tags')
            tags.extend(dal.plans.active().distinct('tags'))
        elif status == 'inactive':
            old = self.get_tags('inactive')
            new = self.get_tags('active')
            a = set(old)
            b = set(new)
            c = a - b
            tags = qlist()
            tags.extend(c)
        else:
            raise AttributeError(
                "{} is not a supported status argument. Must be 'all', 'active', or 'inactive'"
            )

        return tags.sort().distinct()
Exemple #13
0
    def get_actions(self, status='all', plan=None, tags=None):
        """Return a list of actions.

        :param status: Status to include (active, inactive, future, or all).
        :type status: str
        :param plan: Plan to filter actions to.
        :type plan: models.Plan
        :param tags: Tags to filter the list of actions by.
        :type tags: str, list<str>
        :returns: A list of actions.
        :rtype: hoomanpy.qlist
        """

        if plan is not None:
            list_ = plan.actions
        else:
            list_ = qlist()
            list_.extend(dal.actions.all())
            list_.extend(dal.plans.filter(type='option', actions__count__gt=0))

        if status in ('active', 'inactive', 'future'):
            list_ = list_.filter(status=status)

        if tags is not None:
            if not hasattr(tags, '__iter__'):
                tags = [tags]
            list_ = list_.filter(tags__in=tags)

        return list_
Exemple #14
0
    def get_tags(self, status='all'):
        """Return a distinct, alphetically-sorted list of tags assigned.

        :param status: 'all', 'active', 'inactive', or 'notinuse' to Return tags assigned to actions and plans that
                       have the given status. 'old' will return tags that are assigned only to inactive actions
                       and plans.
        :type status: str
        :return: A distinct list of tags.
        :rtype: hoomanpy.qlist
        """

        if status == 'all':
            tags = dal.actions.all().distinct('tags')
            tags.extend(dal.plans.all().distinct('tags'))
        elif status == 'active':
            tags = dal.actions.active().distinct('tags')
            tags.extend(dal.plans.active().distinct('tags'))
        elif status == 'inactive':
            old = self.get_tags('inactive')
            new = self.get_tags('active')
            a = set(old)
            b = set(new)
            c = a - b
            tags = qlist()
            tags.extend(c)
        else:
            raise AttributeError("{} is not a supported status argument. Must be 'all', 'active', or 'inactive'")

        return tags.sort().distinct()
Exemple #15
0
    def __init__(self):

        super(ActionableModel, self).__init__()

        # non-persisted attrs
        self.history = qlist()
        self._on_logged = None

        # persisted attrs
        self._status_ = 'active'
        self._progress_ = 0
        self._minutes_ = 0
        self._order_ = 0
Exemple #16
0
    def __init__(self):

        super(ActionableModel, self).__init__()

        # non-persisted attrs
        self.history = qlist()
        self._on_logged = None

        # persisted attrs
        self._status_ = 'active'
        self._progress_ = 0
        self._minutes_ = 0
        self._order_ = 0
Exemple #17
0
    def _load_from_file(path):

        jsondict = {}
        data = {}
        data['tags'] = qlist()
        data['targets'] = qlist()
        data['docs'] = qlist()

        # extract tags and props from header
        from json import loads
        with open(path) as f:
            for i, line in enumerate(f):
                if i == 0:
                    if line.strip() != '':
                        jsondict = loads(line)
                        if isinstance(jsondict, dict):
                            for key, value in jsondict.iteritems():
                                if key == 'tags':
                                    tags = value.split()
                                    if len(tags) > 0:
                                        data[key].extend(tags)
                                elif key == 'targets':
                                    for t in value:
                                        t = loads(t)
                                        target = m.Target.load(t['freq'], t['starts'], t['measure'],
                                                          period_target=t['period_target'], interval=t['interval'],
                                                          met_after=t['met_after'])
                                        data[key].append(target)
                                else:
                                    data[key] = value
                else:
                    docs = line.replace('\n', '').rstrip()
                    if len(docs) != 0 or len(data['docs']) != 0:
                        data['docs'].append(docs)

        data['persisted'] = jsondict
        return data
Exemple #18
0
def translate_action_or_plan(hooman_input, context=None):
    """Translate string to a model reference.

    :param hooman_input: String input
    :type hooman_input: str
    """
    # index translation
    if context.index_mode in ['actions', 'plans']:
        translated, model = translate_index_to_model(hooman_input, context)
        if translated:
            return True, model

    # model id translation
    translated, model = translate_id_to_action(hooman_input, context)
    if translated:
        return True, model

    translated, model = translate_id_to_plan(hooman_input, context)
    if translated:
        return True, model

    # model name translation
    # build list of matches
    matches = qlist()
    action_matches = context.controller.get_actions().filter(
        name__contains=hooman_input)
    plan_matches = context.controller.get_plans().filter(
        name__contains=hooman_input)
    if action_matches is not None:
        matches.extend(action_matches)
    if plan_matches is not None:
        matches.extend(plan_matches)
    if len(matches) == 1:
        return True, matches[0]
    # todo: implement Match Certainty to notify user we aren't sure this is what they wanted
    elif len(matches) > 1:
        closest_match = None
        len_diff = 1000
        for item in matches:
            if len_diff > len(item.name) - len(hooman_input):
                len_diff = len(item.name) - len(hooman_input)
                closest_match = item

        if len_diff < 2:
            return True, closest_match

    return False, None
Exemple #19
0
def translate_action_or_plan(hooman_input, context=None):
    """Translate string to a model reference.

    :param hooman_input: String input
    :type hooman_input: str
    """
    # index translation
    if context.index_mode in ["actions", "plans"]:
        translated, model = translate_index_to_model(hooman_input, context)
        if translated:
            return True, model

    # model id translation
    translated, model = translate_id_to_action(hooman_input, context)
    if translated:
        return True, model

    translated, model = translate_id_to_plan(hooman_input, context)
    if translated:
        return True, model

    # model name translation
    # build list of matches
    matches = qlist()
    action_matches = context.controller.get_actions().filter(name__contains=hooman_input)
    plan_matches = context.controller.get_plans().filter(name__contains=hooman_input)
    if action_matches is not None:
        matches.extend(action_matches)
    if plan_matches is not None:
        matches.extend(plan_matches)
    if len(matches) == 1:
        return True, matches[0]
    # todo: implement Match Certainty to notify user we aren't sure this is what they wanted
    elif len(matches) > 1:
        closest_match = None
        len_diff = 1000
        for item in matches:
            if len_diff > len(item.name) - len(hooman_input):
                len_diff = len(item.name) - len(hooman_input)
                closest_match = item

        if len_diff < 2:
            return True, closest_match

    return False, None
Exemple #20
0
def translate_action_plan_target_or_tag(hooman_input, context=None):
    """Translate string to a model reference.

    :param hooman_input: String input
    :type hooman_input: str
    """
    # index translation
    if context.index_mode in ['actions', 'plans', 'targets', 'tags']:
        translated, model = translate_index_to_model(hooman_input, context)
        if translated:
            return True, model

    # model id translation
    translated, model = translate_id_to_action(hooman_input, context)
    if translated:
        return True, model

    translated, model = translate_id_to_plan(hooman_input, context)
    if translated:
        return True, model

    # tag name translation
    if hooman_input.startswith('#'):  # tag format
        tags = context.controller.get_tags().filter(
            name__contains=hooman_input)
        if len(tags) == 1:
            return True, tags[0]

    # model name translation
    # build list of matches
    matches = qlist()
    action_matches = context.controller.get_actions().filter(
        name__contains=hooman_input)
    plan_matches = context.controller.get_plans().filter(
        name__contains=hooman_input)
    if action_matches is not None:
        matches.extend(action_matches)
    if plan_matches is not None:
        matches.extend(plan_matches)
    if len(matches) == 1:
        return True, matches[0]

    return False, None
Exemple #21
0
def translate_action_plan_target_or_tag(hooman_input, context=None):
    """Translate string to a model reference.

    :param hooman_input: String input
    :type hooman_input: str
    """
    # index translation
    if context.index_mode in ["actions", "plans", "targets", "tags"]:
        translated, model = translate_index_to_model(hooman_input, context)
        if translated:
            return True, model

    # model id translation
    translated, model = translate_id_to_action(hooman_input, context)
    if translated:
        return True, model

    translated, model = translate_id_to_plan(hooman_input, context)
    if translated:
        return True, model

    # tag name translation
    if hooman_input.startswith("#"):  # tag format
        tags = context.controller.get_tags().filter(name__contains=hooman_input)
        if len(tags) == 1:
            return True, tags[0]

    # model name translation
    # build list of matches
    matches = qlist()
    action_matches = context.controller.get_actions().filter(name__contains=hooman_input)
    plan_matches = context.controller.get_plans().filter(name__contains=hooman_input)
    if action_matches is not None:
        matches.extend(action_matches)
    if plan_matches is not None:
        matches.extend(plan_matches)
    if len(matches) == 1:
        return True, matches[0]

    return False, None
Exemple #22
0
class ModelManager(object):

    _objects = qlist()

    @classmethod
    def all(cls):
        return cls._objects

    @classmethod
    def filter(cls, **kwargs):
        return cls._objects.filter(**kwargs)

    @classmethod
    def distinct(cls, attribute=None):
        return cls._objects.distinct(attribute=attribute)

    @classmethod
    def get(cls, **kwargs):
        return cls._objects.get(**kwargs)

    @classmethod
    def append(cls, obj):
        cls._objects.append(obj)

    @classmethod
    def remove(cls, obj):
        cls._objects.remove(obj)

    @classmethod
    def extend(cls, iterable):
        cls._objects.extend(iterable)

    @staticmethod
    def _load_from_file(path):

        jsondict = {}
        data = {}
        data['tags'] = qlist()
        data['targets'] = qlist()
        data['docs'] = qlist()

        # extract tags and props from header
        from json import loads
        with open(path) as f:
            for i, line in enumerate(f):
                if i == 0:
                    if line.strip() != '':
                        jsondict = loads(line)
                        if isinstance(jsondict, dict):
                            for key, value in jsondict.iteritems():
                                if key == 'tags':
                                    tags = value.split()
                                    if len(tags) > 0:
                                        data[key].extend(tags)
                                elif key == 'targets':
                                    for t in value:
                                        t = loads(t)
                                        target = m.Target.load(t['freq'], t['starts'], t['measure'],
                                                          period_target=t['period_target'], interval=t['interval'],
                                                          met_after=t['met_after'])
                                        data[key].append(target)
                                else:
                                    data[key] = value
                else:
                    docs = line.replace('\n', '').rstrip()
                    if len(docs) != 0 or len(data['docs']) != 0:
                        data['docs'].append(docs)

        data['persisted'] = jsondict
        return data
Exemple #23
0
 def inactive(cls):
     inactive_list = qlist()
     for plan in cls._objects:
         if not cls.has_active_children(plan):
             inactive_list.append(plan)
     return inactive_list