Example #1
0
class VLANS:
    '''
    Manage a bunch of VLANs, as a dictionary
    '''
    def __init__(self, vlans=None, delemiter=",", range_delemiter="-"):
        super().__init__()
        self._delemiter = delemiter
        self._range_delemiter = range_delemiter
        self._vlans = AttrDict()
        if vlans:
            self.__iadd__(vlans)

    def __add__(self, other):
        """
        Add two VLANS to each other
        """
        if not isinstance(other, VLANS):
            raise TypeError("Error: Can only handle object of VLANS()")
        tmp = self.copy()
        for vlan in other._vlans.values():
            tmp._vlans[vlan.id] = vlan
        return tmp

    def __iadd__(self, other):
        if isinstance(other, VLANS):
            for vlan in other._vlans.values():
                self._vlans[vlan.id] = vlan
        elif isinstance(other, VLAN):
            self._vlans[other.id] = other
        else:
            raise TypeError(
                "Error: Can only handle object of VLANS() or VLAN() got %s" %
                type(other))
        return self

    def __str__(self):
        return dict_to_vlan_str(self._vlans,
                                delemiter=self._delemiter,
                                range_delemiter=self._range_delemiter)

    def __repr__(self):
        s = ""
        for vlan in self._vlans.values():
            s += "(%s)" % vlan.to_str()
        return "VLANS(%s)" % s

    def __iter__(self):
        return iter(self.__dict__)

    def items(self):
        for item in self._vlans.items():
            yield item

    def keys(self):
        for item in self._vlans.keys():
            yield item

    def values(self):
        for item in self._vlans.values():
            yield item
Example #2
0
    def __init__(self, *args, **kwargs):
        self._view = None
        self._session = None
        self._active = False
        self._filters = AttrDict(
            {n: f(provider=self, name=n)
             for n, f in self.FILTERS.items()})

        rules = AttrDict(self.config.rules.label,
                         **config.settings.profile.rules.label)

        labels = AttrDict(self.config.labels, **config.settings.profile.labels)

        self.rule_map = AttrDict([(re.compile(k, re.IGNORECASE), v)
                                  for k, v in [(r, rules[r])
                                               for r in rules.keys()]])

        self.highlight_map = AttrDict([(re.compile(k,
                                                   re.IGNORECASE), labels[v])
                                       for k, v in rules.items()])

        self.highlight_re = re.compile(
            "(" + "|".join([k.pattern
                            for k in self.highlight_map.keys()]) + ")",
            re.IGNORECASE)
Example #3
0
    def test_change_chart(self):
        # Test case for all native charts charts.
        with assert_raises(AttributeError):
            pptgen.pptgen(
                source=self.input,
                only=25,
                data={'data': {}},
                change={'Invalid Input': {
                    'chart': {
                        'data': 'data'
                    }
                }})

        xaxis, opacity = 'city', 0.5
        slidenumbers = AttrDict(Bar_Chart=2,
                                Column_Chart=10,
                                Line_Chart=11,
                                Area_Chart=12,
                                Scatter_Chart=13,
                                Bubble_Chart=14,
                                Bubble_Chart_3D=15,
                                Radar_Chart=16,
                                Donut_Chart=17,
                                Pie_Chart=18)
        for chart_name, slidenumber in slidenumbers.items():
            # Replacing `_` with a white space. Because chart names in input slides contains
            # spaces not `_`.
            chart_name = chart_name.replace('_', ' ')
            if chart_name in ['Pie Chart', 'Donut Chart']:
                series = ['sales']
                chart_colors = {
                    'Singapore': '#D34817',
                    'Hyderabad': '#9B2D1F',
                    'Bangalore': '#A28E6A',
                    'Coimbatore': '#956251',
                    'Newport Beach': '#918485',
                    'South Plainfield': '#855D5D'
                }
            else:
                series = ['growth', 'sales']
                chart_colors = {
                    'sales': '#D34817',
                    'growth': '#9B2D1F',
                }
            data = self.data.groupby(xaxis, as_index=False)[series].sum()
            rule = {
                chart_name: {
                    'chart': {
                        'data': 'data["data"]',
                        'x': xaxis,
                        'color': chart_colors,
                        'opacity': opacity
                    }
                }
            }
            target = self.draw_chart(slidenumber, data, rule)
            shape = self.get_shape(target, chart_name)[0]
            self.check_chart(shape, data, series, xaxis, chart_name,
                             chart_colors, opacity)
Example #4
0
class VLANS:
    '''
    Manage a bunch of VLANs, as a dictionary
    '''
    def __init__(self, vlans=None, delemiter=",", range_delemiter="-"):
        super().__init__()
        self._delemiter = delemiter
        self._range_delemiter = range_delemiter
        self._vlans = AttrDict()
        if vlans:
            self.__iadd__(vlans)

    def __add__(self, other):
        """
        Add two VLANS to each other
        """
        if not isinstance(other, VLANS):
            raise TypeError("Error: Can only handle object of VLANS()")
        tmp = self.copy()
        for vlan in other._vlans.values():
            tmp._vlans[vlan.id] = vlan
        return tmp

    def __iadd__(self, other):
        if isinstance(other, VLANS):
            for vlan in other._vlans.values():
                self._vlans[vlan.id] = vlan
        elif isinstance(other, VLAN):
            self._vlans[other.id] = other
        else:
            raise TypeError("Error: Can only handle object of VLANS() or VLAN() got %s" % type(other))
        return self

    def __str__(self):
        return dict_to_vlan_str(self._vlans,
                                delemiter=self._delemiter,
                                range_delemiter=self._range_delemiter)

    def __repr__(self):
        s = ""
        for vlan in self._vlans.values():
            s += "(%s)" % vlan.to_str()
        return "VLANS(%s)" % s

    def __iter__(self):
        return iter(self.__dict__)

    def items(self):
        for item in self._vlans.items():
            yield item

    def keys(self):
        for item in self._vlans.keys():
            yield item
            
    def values(self):
        for item in self._vlans.values():
            yield item
Example #5
0
 def get(self):
     limit = int(self.getq('limit', [100])[0])
     if isinstance(self.query, dict):
         # Bind all queries and run them in parallel
         args = {
             key: self.getq(key, [''])[0]
             for name, query in self.query.items()
             for key, _bindparams in query._bindparams.items()
         }
         stmts = AttrDict([
             (key,
              q.bindparams(
                  **{k: v
                     for k, v in args.items() if k in q._bindparams}))
             for key, q in self.query.items()
         ])
         if self.thread:
             futures = AttrDict([
                 (key,
                  gramex.service.threadpool.submit(self.run, stmt, limit))
                 for key, stmt in stmts.items()
             ])
             self.result = AttrDict()
             for key, future in futures.items():
                 self.result[key] = yield future
         else:
             self.result = AttrDict([(key, self.run(stmt, limit))
                                     for key, stmt in stmts.items()])
         self.renderdatas()
     else:
         # Bind query and run it
         args = {
             key: self.getq(key, [''])[0]
             for key in self.query._bindparams
         }
         stmt = self.query.bindparams(
             **
             {k: v
              for k, v in args.items() if k in self.query._bindparams})
         if self.thread:
             self.result = yield gramex.service.threadpool.submit(
                 self.run, stmt, limit)
         else:
             self.result = self.run(stmt, limit)
         self.renderdata()
Example #6
0
def prune_keys(conf, keys={}):
    '''
    Returns a deep copy of a configuration removing specified keys.
    ``prune_keys(conf, {'comment'})`` drops the "comment" key from any dict or sub-dict.
    '''
    if isinstance(conf, dict):
        conf = AttrDict(
            {k: prune_keys(v, keys)
             for k, v in conf.items() if k not in keys})
    elif isinstance(conf, (list, tuple)):
        conf = [prune_keys(v, keys) for v in conf]
    return conf
Example #7
0
class HighlightRuleConfig(object):

    # def __init__(self, config):
    def __init__(self, config_file):
        self._config_file = config_file
        self.config = config.Config(
            self._config_file
        )
        self.flags = 0 if self.config.match.case_sensitive else re.IGNORECASE
        # import ipdb; ipdb.set_trace()
        self.rules = AttrDict([
            (label,
             HighlightRuleList(
                 self.highlight_config.get(label),
                 [ dict(subject=k, **(v or {})) for k, v in rule_dict.items() ],
                 config=self.config
             )
             )
            for label, rule_dict in self.label_config.items()
        ])
        self.RE_MAP = dict()

    @property
    def highlight_config(self):
        return self.config.get("highlight", {})

    @property
    def label_config(self):
        return self.config.get("label", {})

    @property
    def labels(self):
        return self.label_config.keys()

    def __getitem__(self, key):
        return self.rules[key]

    def add_rule(self, label, subject, group=None, patterns=None):
        targets = [subject] + (patterns if patterns else [])
        self.remove_rule(targets)
        rule = HighlightRule(subject, group=group, patterns=patterns)
        self.rules[label].append(rule)
        self.save()

    def remove_rule(self, targets):
        if not isinstance(targets, list):
            targets = [targets]
        self.rules = AttrDict([
            (label, HighlightRuleList(
                self.highlight_config.get(label),
                [
                    r for r in self.rules[label]
                    if r.subject not in targets
                    and not any(pattern in targets for pattern in r.patterns)
                ],
                config=self.config
            ))
            for label, rule_list in self.rules.items()
        ])

        self.save()

    def save(self):

        self.config.label = {
            label: {
                d.subject: {
                    k: v for k, v in d.items()
                    if k != "subject"
                } or None
                for d in [
                    rule.to_dict()
                    for rule in sorted(rule_list)
                ]
            }
            for label, rule_list in self.rules.items()
        }

        self.config.save()
        # temp_config = config.Config(
        #     self._config_file + ".new.yaml"
        # )
        # temp_config.update(self.config.tree)

        # temp_config.label = {
        #     label: {
        #         d.subject: {
        #             k: v for k, v in d.items()
        #             if k != "subject"
        #         } or None
        #         for d in [
        #             rule.to_dict()
        #             for rule in sorted(rule_list)
        #         ]
        #     }
        #     for label, rule_list in self.rules.items()
        # }
        # temp_config.save()

    def get_regex(self, rules):
        rules_set = frozenset(rules.items())
        if rules_set not in self.RE_MAP:
            pattern = '|'.join(
                f"{rules_list.pattern}"
                for label, rules_list in rules.items()
                if len(rules_list)
            )
            pattern_grouped = '|'.join(
                f"(?P<{label}>{rules_list.pattern})"
                for label, rules_list in rules.items()
                if len(rules_list)
            )
#             pattern_tokens = f"{pattern_grouped}|(?P<none>(?!{pattern})(.+?))"
            pattern_tokens = "|".join([
                p for p in [pattern_grouped, "(?P<none>(?!{pattern})(.+?))"]
                if len(p)
            ])
            self.RE_MAP[rules_set] = tuple(
                re.compile(p, self.flags)
                for p in [pattern, pattern_grouped, pattern_tokens]
            )
        return self.RE_MAP[rules_set]

    @property
    def pattern_rules(self):
        return self.get_regex(self.rules)[0]

    @property
    def pattern_rules_grouped(self):
        return self.get_regex(self.rules)[1]

    @property
    def pattern_rules_tokens(self):
        return self.get_regex(self.rules)[2]

    def search(self, text):
        return next(
            (
                match for match in (
                    rules.search(text)
                    for rules in self.rules.values()
                )
                if match
            ),
            None
        )

    def tokenize(self, text, candidates=[], aliases={}):

        for subject, alias_list in aliases.items():
            text = re.sub("|".join(
                (
                    alias
                    for alias in alias_list
                )
            ), subject, text)

        if candidates:
            rules = AttrDict([
                (label, HighlightRuleList(
                    self.highlight_config[label],
                    [
                        r for r in rule_list
                        if r.subject in candidates
                    ],
                    config=self.config
                ))
                for label, rule_list in self.rules.items()
            ])
        else:
            rules = self.rules

        (pattern, pattern_grouped, pattern_tokens) = self.get_regex(rules)

        tokens = (
            (match.lastgroup, match.group())
            for match in re.finditer(pattern_tokens, text)
        )

        out = []
        for k, g in groupby(tokens, lambda x: x[0] == "none"):
            if k:
                out.append(((None, None), "".join(item[1] for item in g)))
            else:
                (attr, text) = next(g)
                label, rule = self.rule_for_token(text)
                attr = rule.attr if (rule and rule.attr) else attr
                out.append(((label, attr), text))
        return out


    def apply(self, text, candidates=[], aliases={}):

        return [
            (attr, token) if attr else token
            for attr, token in [
                    (self.highlight_config.get(attr, attr), token)
                    for ( (label, attr), token) in self.tokenize(text, candidates=candidates, aliases=aliases)
                ]
        ]

    def get_tokens(self, text, candidates=[], aliases={}):
        return [
            token
            for (attr, token) in self.tokenize(text, candidates=candidates, aliases=aliases)
            if attr
        ]

    def rule_for_token(self, token):
        return next(
            (
                (label, rule) for label, rule in (
                    (label, rules.rule_for_token(token))
                    for label, rules in self.rules.items()
                )
                if rule
            ),
            (None, None)
        )
Example #8
0
class BaseProvider(abc.ABC):
    """
    Abstract base class from which providers should inherit from
    """

    SESSION_CLASS = StreamSession
    ITEM_CLASS = model.MediaItem
    # VIEW_CLASS = SimpleProviderView
    FILTERS = AttrDict()
    ATTRIBUTES = AttrDict(title={"width": ("weight", 1)})
    MEDIA_TYPES = None

    def __init__(self, *args, **kwargs):
        self._view = None
        self._session = None
        self._active = False
        self._filters = AttrDict(
            {n: f(provider=self, name=n)
             for n, f in self.FILTERS.items()})

        rules = AttrDict(self.config.rules.label,
                         **config.settings.profile.rules.label)

        labels = AttrDict(self.config.labels, **config.settings.profile.labels)

        self.rule_map = AttrDict([(re.compile(k, re.IGNORECASE), v)
                                  for k, v in [(r, rules[r])
                                               for r in rules.keys()]])

        self.highlight_map = AttrDict([(re.compile(k,
                                                   re.IGNORECASE), labels[v])
                                       for k, v in rules.items()])

        self.highlight_re = re.compile(
            "(" + "|".join([k.pattern
                            for k in self.highlight_map.keys()]) + ")",
            re.IGNORECASE)

    def init_config(self):
        pass

    @property
    def LISTING_CLASS(self):
        for cls in [self.__class__] + list(self.__class__.__bases__):
            pkg = sys.modules.get(cls.__module__)
            pkgname = pkg.__name__.split(".")[-1]
            try:
                return next(
                    v for k, v in pkg.__dict__.items()
                    if pkgname in k.lower() and k.endswith("MediaListing"))
            except StopIteration:
                continue
        return model.MediaListing

    @property
    def MEDIA_SOURCE_CLASS(self):
        for cls in [self.__class__] + list(self.__class__.mro()):
            pkg = sys.modules.get(cls.__module__)
            pkgname = pkg.__name__.split(".")[-1]
            try:
                return next(
                    v for k, v in pkg.__dict__.items()
                    if pkgname in k.lower() and k.endswith("MediaSource"))
            except (StopIteration, AttributeError):
                continue
        return model.MediaSource

    @property
    def session_params(self):
        return {"proxies": config.settings.profile.get("proxies")}

    @property
    def session(self):
        if self._session is None:
            session_params = self.session_params
            self._session = self.SESSION_CLASS.new(self.IDENTIFIER,
                                                   **session_params)
        return self._session

    @property
    def gui(self):
        return self._view is not None

    @property
    def filters(self):
        return self._filters

    @property
    def view(self):
        if not self._view:
            self._view = self.make_view()
            self._view.update()
        return self._view

    @property
    def is_active(self):
        return self._active

    def activate(self):
        if self.is_active:
            return
        self._active = True
        self.on_activate()

    def deactivate(self):
        if not self.is_active:
            return
        self.on_deactivate()
        self._active = False

    def on_activate(self):
        pass

    def on_deactivate(self):
        pass

    @abc.abstractmethod
    def make_view(self):
        pass

    @classproperty
    def IDENTIFIER(cls):
        return next(c.__module__ for c in cls.__mro__
                    if __package__ in c.__module__).split(".")[-1]

    @classproperty
    @abc.abstractmethod
    def NAME(cls):
        return cls.__name__.replace("Provider", "")

    @property
    def FILTERS_BROWSE(self):
        return AttrDict()

    @property
    def FILTERS_OPTIONS(self):
        return AttrDict()

    @property
    def FILTERS(self):
        d = getattr(self, "FILTERS_BROWSE", AttrDict())
        d.update(getattr(self, "FILTERS_OPTIONS", {}))
        return d

    def parse_identifier(self, identifier):
        return

    def new_media_source(self, *args, **kwargs):
        return self.MEDIA_SOURCE_CLASS(self.IDENTIFIER, *args, **kwargs)

    def new_listing(self, **kwargs):
        return self.LISTING_CLASS(self.IDENTIFIER, **kwargs)

    @abc.abstractmethod
    def listings(self, filters=None):
        pass

    def should_download(self, listing):
        return listing.label in (list(self.config.rules) +
                                 list(config.settings.profile.rules.download))

    def on_new_listing(self, listing):
        try:
            label = next(l for r, l in self.rule_map.items()
                         if r.search(listing.title))
            listing.label = label
            if self.should_download(listing):
                self.download(listing)

        except StopIteration:
            pass

    @property
    def config(self):
        return config.ConfigTree(
            config.settings.profile.providers.get(self.IDENTIFIER, {}))

    @property
    def config_is_valid(self):
        def check_config(required, cfg):
            if isinstance(required, dict):
                for k, v in required.items():
                    if not k in cfg:
                        return False
                    if not check_config(required[k], cfg[k]):
                        return False
            else:
                for k in required:
                    if not k in cfg:
                        return False
            return True

        # return all([ self.config.get(x, None) is not None
        # for x in getattr(self, "REQUIRED_CONFIG", [])
        return check_config(getattr(self, "REQUIRED_CONFIG", []), self.config)

    def parse_options(self, options):
        if not options:
            return AttrDict()
        return AttrDict(
            [(list(self.FILTERS_OPTIONS.keys())[n], v) for n, v in enumerate(
                [o for o in options.split(",") if "=" not in o])],
            **dict(o.split("=") for o in options.split(",") if "=" in o))

    def get_source(self, selection, **kwargs):
        source = selection.content
        if not isinstance(source, list):
            source = [source]
        return source

    def play_args(self, selection, **kwargs):
        source = self.get_source(selection, **kwargs)
        kwargs = {
            k: v
            for k, v in list(kwargs.items()) +
            [(f, self.filters[f].value)
             for f in self.filters if f not in kwargs]
        }
        return (source, kwargs)

    def play(self, selection, no_task_manager=False, **kwargs):

        try:
            sources, kwargs = self.play_args(selection, **kwargs)
        except SGStreamNotFound as e:
            logger.error(f"stream not found: {e}")
            return
        # media_type = kwargs.pop("media_type", None)

        # FIXME: For now, we just throw playlists of media items at the default
        # player program and hope it can handle all of them.

        player_spec = None
        helper_spec = None

        if not isinstance(sources, list):
            sources = [sources]

        for s in sources:
            if not s.media_type:
                # Try to set the content types of the source(s) with a HTTP HEAD
                # request if the provider didn't specify one.
                s.media_type = self.session.head(
                    s.locator).headers.get("Content-Type").split("/")[0]

        media_types = set([s.media_type for s in sources if s.media_type])
        player_spec = {"media_types": media_types}
        if media_types == {"image"}:
            helper_spec = {None: None}
        else:
            helper_spec = getattr(self.config, "helpers",
                                  None) or sources[0].helper

        task = model.PlayMediaTask(provider=self.NAME,
                                   title=selection.title,
                                   sources=sources)

        if not (no_task_manager or state.options.debug_console):
            return state.task_manager.play(task, player_spec, helper_spec,
                                           **kwargs)
        else:
            return state.asyncio_loop.create_task(
                Player.play(task, player_spec, helper_spec, **kwargs))

    def download(self, selection, no_task_manager=False, **kwargs):

        sources, kwargs = self.play_args(selection, **kwargs)
        # filename = selection.download_filename

        if not isinstance(sources, list):
            sources = [sources]

        for i, s in enumerate(sources):
            # filename = s.download_filename
            # kwargs = {"ext": getattr(s, "ext", None)}
            if len(sources):
                kwargs["index"] = i
            try:
                filename = selection.download_filename(**kwargs)
            except SGInvalidFilenameTemplate as e:
                logger.warn(
                    f"filename template for provider {self.IDENTIFIER} is invalid: {e}"
                )
            helper_spec = getattr(self.config, "helpers") or s.download_helper
            # logger.info(f"helper: {helper_spec}")

            task = model.DownloadMediaTask(provider=self.NAME,
                                           title=selection.title,
                                           sources=[s],
                                           dest=filename)

            # s = AttrDict(dataclasses.asdict(s))
            # s.provider = self.NAME
            # s.title = selection.title
            # s.dest = filename

            if not (no_task_manager or state.options.debug_console):
                return state.task_manager.download(task, filename, helper_spec,
                                                   **kwargs)
            else:
                return state.asyncio_loop.create_task(
                    Downloader.download(task, filename, helper_spec, **kwargs))

    def on_select(self, widget, selection):
        self.play(selection)

    @property
    def limit(self):
        return None

    def refresh(self):
        self.view.refresh()

    def reset(self):
        self.view.reset()

    def __str__(self):
        return self.NAME

    def __repr__(self):
        return f"<{type(self)}: {self.NAME}>"
Example #9
0
    def _call(self, inp, inp_features, is_training, is_posterior=True, prop_state=None):
        print("\n" + "-" * 10 + " ConvGridObjectLayer(is_posterior={}) ".format(is_posterior) + "-" * 10)

        # --- set up sub networks and attributes ---

        self.maybe_build_subnet("box_network", builder=cfg.build_conv_lateral, key="box")
        self.maybe_build_subnet("attr_network", builder=cfg.build_conv_lateral, key="attr")
        self.maybe_build_subnet("z_network", builder=cfg.build_conv_lateral, key="z")
        self.maybe_build_subnet("obj_network", builder=cfg.build_conv_lateral, key="obj")

        self.maybe_build_subnet("object_encoder")

        _, H, W, _, n_channels = tf_shape(inp_features)

        if self.B != 1:
            raise Exception("NotImplemented")

        if not self.initialized:
            # Note this limits the re-usability of this module to images
            # with a fixed shape (the shape of the first image it is used on)
            self.batch_size, self.image_height, self.image_width, self.image_depth = tf_shape(inp)
            self.H = H
            self.W = W
            self.HWB = H*W
            self.batch_size = tf.shape(inp)[0]
            self.is_training = is_training
            self.float_is_training = tf.to_float(is_training)

        inp_features = tf.reshape(inp_features, (self.batch_size, H, W, n_channels))
        is_posterior_tf = tf.ones_like(inp_features[..., :2])
        if is_posterior:
            is_posterior_tf = is_posterior_tf * [1, 0]
        else:
            is_posterior_tf = is_posterior_tf * [0, 1]

        objects = AttrDict()

        base_features = tf.concat([inp_features, is_posterior_tf], axis=-1)

        # --- box ---

        layer_inp = base_features
        n_features = self.n_passthrough_features
        output_size = 8

        network_output = self.box_network(layer_inp, output_size + n_features, self.is_training)
        rep_input, features = tf.split(network_output, (output_size, n_features), axis=-1)

        _objects = self._build_box(rep_input, self.is_training)
        objects.update(_objects)

        # --- attr ---

        if is_posterior:
            # --- Get object attributes using object encoder ---

            yt, xt, ys, xs = tf.split(objects['normalized_box'], 4, axis=-1)

            yt, xt, ys, xs = coords_to_image_space(
                yt, xt, ys, xs, (self.image_height, self.image_width), self.anchor_box, top_left=False)

            transform_constraints = snt.AffineWarpConstraints.no_shear_2d()
            warper = snt.AffineGridWarper(
                (self.image_height, self.image_width), self.object_shape, transform_constraints)

            _boxes = tf.concat([xs, 2*xt - 1, ys, 2*yt - 1], axis=-1)
            _boxes = tf.reshape(_boxes, (self.batch_size*H*W, 4))
            grid_coords = warper(_boxes)
            grid_coords = tf.reshape(grid_coords, (self.batch_size, H, W, *self.object_shape, 2,))

            if self.edge_resampler:
                glimpse = resampler_edge.resampler_edge(inp, grid_coords)
            else:
                glimpse = tf.contrib.resampler.resampler(inp, grid_coords)
        else:
            glimpse = tf.zeros((self.batch_size, H, W, *self.object_shape, self.image_depth))

        # Create the object encoder network regardless of is_posterior, otherwise messes with ScopedFunction
        encoded_glimpse = apply_object_wise(
            self.object_encoder, glimpse, n_trailing_dims=3, output_size=self.A, is_training=self.is_training)

        if not is_posterior:
            encoded_glimpse = tf.zeros_like(encoded_glimpse)

        layer_inp = tf.concat([base_features, features, encoded_glimpse, objects['local_box']], axis=-1)
        network_output = self.attr_network(layer_inp, 2 * self.A + n_features, self.is_training)
        attr_mean, attr_log_std, features = tf.split(network_output, (self.A, self.A, n_features), axis=-1)

        attr_std = self.std_nonlinearity(attr_log_std)

        attr = Normal(loc=attr_mean, scale=attr_std).sample()

        objects.update(attr_mean=attr_mean, attr_std=attr_std, attr=attr, glimpse=glimpse)

        # --- z ---

        layer_inp = tf.concat([base_features, features, objects['local_box'], objects['attr']], axis=-1)
        n_features = self.n_passthrough_features

        network_output = self.z_network(layer_inp, 2 + n_features, self.is_training)
        z_mean, z_log_std, features = tf.split(network_output, (1, 1, n_features), axis=-1)
        z_std = self.std_nonlinearity(z_log_std)

        z_mean = self.training_wheels * tf.stop_gradient(z_mean) + (1-self.training_wheels) * z_mean
        z_std = self.training_wheels * tf.stop_gradient(z_std) + (1-self.training_wheels) * z_std
        z_logit = Normal(loc=z_mean, scale=z_std).sample()
        z = self.z_nonlinearity(z_logit)

        objects.update(z_logit_mean=z_mean, z_logit_std=z_std, z_logit=z_logit, z=z)

        # --- obj ---

        layer_inp = tf.concat([base_features, features, objects['local_box'], objects['attr'], objects['z']], axis=-1)
        rep_input = self.obj_network(layer_inp, 1, self.is_training)

        _objects = self._build_obj(rep_input, self.is_training)
        objects.update(_objects)

        # --- final ---

        _objects = AttrDict()
        for k, v in objects.items():
            _, _, _, *trailing_dims = tf_shape(v)
            _objects[k] = tf.reshape(v, (self.batch_size, self.HWB, *trailing_dims))
        objects = _objects

        if prop_state is not None:
            objects.prop_state = tf.tile(prop_state[0:1, None], (self.batch_size, self.HWB, 1))
            objects.prior_prop_state = tf.tile(prop_state[0:1, None], (self.batch_size, self.HWB, 1))

        # --- misc ---

        objects.n_objects = tf.fill((self.batch_size,), self.HWB)
        objects.pred_n_objects = tf.reduce_sum(objects.obj, axis=(1, 2))
        objects.pred_n_objects_hard = tf.reduce_sum(tf.round(objects.obj), axis=(1, 2))

        return objects
Example #10
0
class BaseProvider(abc.ABC, Observable):
    """
    Abstract base class from which providers should inherit from
    """

    SESSION_CLASS = StreamSession
    LISTING_CLASS = model.TitledMediaListing
    # VIEW_CLASS = SimpleProviderView
    # FILTERS = AttrDict()
    ATTRIBUTES = AttrDict(title={"width": ("weight", 1)})
    MEDIA_TYPES = None
    RPC_METHODS = []

    def __init__(self, *args, **kwargs):
        self._view = None
        self._session = None
        self._active = False
        self._filters = AttrDict(
            {n: f(provider=self, name=n)
             for n, f in self.FILTERS.items()})

        rules = AttrDict(self.config.rules.label or {},
                         **config.settings.profile.rules.label or {})

        labels = AttrDict(self.config.labels, **config.settings.profile.labels)

        self.rule_map = AttrDict([(re.compile(k, re.IGNORECASE), v)
                                  for k, v in [(r, rules[r])
                                               for r in rules.keys()]])

        self.highlight_map = AttrDict([(re.compile(k,
                                                   re.IGNORECASE), labels[v])
                                       for k, v in rules.items()])

        self.highlight_re = re.compile(
            "(" + "|".join([k.pattern
                            for k in self.highlight_map.keys()]) + ")",
            re.IGNORECASE)
        # print(self.filters)
        self.filters["search"].connect("changed", self.on_search_change)

    def init_config(self):
        with db_session:
            try:
                self.provider_data = model.ProviderData.get(
                    name=self.IDENTIFIER).settings
            except AttributeError:
                self.provider_data = model.ProviderData(
                    name=self.IDENTIFIER).settings

        for name, f in self.filters.items():
            value = self.default_filter_values.get(name, None)
            if value:
                try:
                    f.value = value
                except (ValueError, ):
                    # import ipdb; ipdb.set_trace()
                    pass

    @property
    def default_filter_values(self):
        return AttrDict()

    @db_session
    def save_provider_data(self):
        model.ProviderData.get(
            name=self.IDENTIFIER).settings = self.provider_data
        commit()

    @property
    def LISTING_CLASS(self):
        for cls in [self.__class__] + list(self.__class__.__bases__):
            pkg = sys.modules.get(cls.__module__)
            pkgname = pkg.__name__.split(".")[-1]
            try:
                return next(
                    v for k, v in pkg.__dict__.items()
                    if pkgname in k.lower() and k.endswith("MediaListing"))
            except StopIteration:
                continue
        return model.TitledMediaListing

    @property
    def MEDIA_SOURCE_CLASS(self):
        for cls in [self.__class__] + list(self.__class__.mro()):
            pkg = sys.modules.get(cls.__module__)
            pkgname = pkg.__name__.split(".")[-1]
            try:
                return next(
                    v for k, v in pkg.__dict__.items()
                    if pkgname in k.lower() and k.endswith("MediaSource"))
            except (StopIteration, AttributeError):
                continue
        return model.MediaSource

    @property
    def helper(self):
        return None

    @property
    def session_params(self):
        return {"proxies": config.settings.profile.get("proxies")}

    @property
    def PREVIEW_TYPES(self):
        return ["default"]

    @property
    def session(self):
        if self._session is None:
            session_params = self.session_params
            self._session = self.SESSION_CLASS.new(self.IDENTIFIER,
                                                   **session_params)
        return self._session

    @property
    def gui(self):
        return self._view is not None

    @property
    def filters(self):
        return self._filters

    @property
    def view(self):
        if not self._view:
            self._view = self.make_view()
            self._view.update()
        return self._view

    @property
    def toolbar(self):
        return self.view.toolbar

    @property
    def is_active(self):
        return self._active

    def activate(self):
        if self.is_active:
            return
        self._active = True
        self.on_activate()

    def deactivate(self):
        if not self.is_active:
            return
        self.on_deactivate()
        self._active = False

    def on_activate(self):
        self.reset()

    def on_deactivate(self):
        self.view.on_deactivate()

    @property
    def VIEW(self):
        return SimpleProviderView(self, ProviderDataTable(self))

    # @abc.abstractmethod
    def make_view(self):
        if not self.config_is_valid:
            return InvalidConfigView(self.NAME, self.REQUIRED_CONFIG)
        return self.VIEW

    @classproperty
    def IDENTIFIER(cls):
        return next(c.__module__ for c in cls.__mro__
                    if __package__ in c.__module__).split(".")[-1]

    @classproperty
    @abc.abstractmethod
    def NAME(cls):
        return cls.__name__.replace("Provider", "")

    @property
    def FILTERS_BROWSE(self):
        return AttrDict()

    @property
    def FILTERS_OPTIONS(self):
        return AttrDict([("search", TextFilter)])

    @property
    def FILTERS(self):
        d = getattr(self, "FILTERS_BROWSE", AttrDict())
        d.update(getattr(self, "FILTERS_OPTIONS", {}))
        return d

    def on_search_change(self, value, *args):

        if getattr(self, "search_task", False):
            self.search_task.cancel()

        async def apply_search_async():
            await asyncio.sleep(1)
            await self.apply_search_query(value)

        self.search_task = state.event_loop.create_task(apply_search_async())

    async def apply_search_query(self, query):
        self.view.apply_search_query(query)

    def parse_spec(self, spec):

        (identifier, options) = MEDIA_SPEC_RE.search(spec).groups()

        try:
            selection, filters, identifier_options = self.parse_identifier(
                identifier)
            self.apply_identifier(selection, filters, identifier_options)
        except SGIncompleteIdentifier:
            selection, identifier_options = None, {}

        options = AttrDict(identifier_options, **self.parse_options(options))
        self.apply_options(options)
        return (selection, options)

    def parse_identifier(self, identifier):
        return (None, identifier, {})

    def apply_identifier(self, selection, filters, options):

        if filters:
            selected_filters = zip(self.filters.keys(), filters)

            for f, value in selected_filters:
                if value is None or value in [
                        getattr(self.filters[f], "selected_label", None),
                        self.filters[f].value
                ]:
                    continue
                try:
                    self.filters[f].selected_label = value
                except ValueError:
                    self.filters[f].value = value

    def parse_options(self, options):
        if not options:
            options = ""

        d = AttrDict(
            [(list(self.FILTERS_OPTIONS.keys())[n], v) for n, v in enumerate(
                [o for o in options.split(",") if "=" not in o]) if v],
            **dict(o.split("=") for o in options.split(",") if "=" in o))
        return d

    def apply_options(self, options):

        for k, v in options.items():
            if v is None:
                continue
            if k in self.filters:
                logger.debug(f"option: {k}={v}")
                try:
                    if self.filters[k].value != v:
                        self.filters[k].value = v
                except StopIteration:
                    raise SGException("invalid value for %s: %s" % (k, v))

    def new_media_source(self, *args, **kwargs):
        return self.MEDIA_SOURCE_CLASS.attr_class(provider_id=self.IDENTIFIER,
                                                  *args,
                                                  **kwargs)

    def new_listing(self, **kwargs):
        return self.LISTING_CLASS.attr_class(provider_id=self.IDENTIFIER,
                                             **kwargs)

    async def play(self, listing, **kwargs):
        # sources, kwargs = self.extract_sources(listing, **kwargs)
        task = self.create_play_task(listing, **kwargs)
        yield state.task_manager.play(task)

    async def download(self,
                       listing,
                       index=None,
                       no_task_manager=False,
                       **kwargs):
        for task in self.create_download_tasks(listing, index=index, **kwargs):
            yield state.task_manager.download(task)

    def translate_template(self, template):
        return template

    # def new_listing_attr(self, **kwargs):
    #     return self.LISTING_CLASS.attr_class(
    #         provider_id = self.IDENTIFIER,
    #         **kwargs
    #     )

    def sort(self, field, reverse=False):
        self.view.sort(field, reverse=reverse)

    @abc.abstractmethod
    def listings(self, filters=None):
        pass

    def should_download(self, listing):
        return listing.label in (list(self.config.rules) +
                                 list(config.settings.profile.rules.download))

    def on_new_listing(self, listing):
        try:
            label = next(l for r, l in self.rule_map.items()
                         if r.search(listing.title))
            listing.label = label
            if self.should_download(listing):
                self.download(listing)

        except StopIteration:
            pass

    @property
    def config(self):
        return config.ConfigTree(
            config.settings.profile.providers.get(self.IDENTIFIER, {}))

    @property
    def config_is_valid(self):
        def check_config(required, cfg):
            if isinstance(required, dict):
                for k, v in required.items():
                    if not k in cfg:
                        return False
                    if not check_config(required[k], cfg[k]):
                        return False
            else:
                for k in required:
                    if not k in cfg:
                        return False
            return True

        # return all([ self.config.get(x, None) is not None
        # for x in getattr(self, "REQUIRED_CONFIG", [])
        return check_config(getattr(self, "REQUIRED_CONFIG", []), self.config)

    def get_source(self, selection, **kwargs):
        sources = sorted(selection.sources,
                         key=lambda s: getattr(s, "rank", 0))
        if not isinstance(sources, list):
            sources = [sources]

        return sources

    def play_args(self, selection, **kwargs):
        source = self.get_source(selection, **kwargs)
        return (source, kwargs)

    def filter_args(self):
        return {f: self.filters[f].value for f in self.filters}

    def extract_sources(self, listing, **kwargs):
        try:
            sources, kwargs = self.play_args(listing, **kwargs)
            kwargs.update({
                k: v
                for k, v in self.filter_args().items() if k not in kwargs
            })
        except SGStreamNotFound as e:
            logger.error(f"stream not found: {e}")
            return

        # FIXME: For now, we just throw playlists of media items at the default
        # player program and hope it can handle all of them.

        player_spec = None
        downloader_spec = None

        if not isinstance(sources, list):
            sources = [sources]

        for s in sources:
            if not s.media_type:
                # Try to set the content types of the source(s) with a HTTP HEAD
                # request if the provider didn't specify one.
                s.media_type = self.session.head(
                    s.locator).headers.get("Content-Type").split("/")[0]

        return sources, kwargs

    def create_play_task(self, listing, **kwargs):

        sources, kwargs = self.extract_sources(listing, **kwargs)

        media_types = set([s.media_type for s in sources if s.media_type])

        player_spec = {"media_types": media_types}

        if media_types == {"image"}:
            downloader_spec = {None: None}
        else:
            downloader_spec = (getattr(self.config, "helpers", None)
                               or getattr(sources[0], "helper", None)
                               or self.helper)

        return ListingsPlayMediaTask.attr_class(provider=self.NAME,
                                                title=listing.title,
                                                listing=listing,
                                                sources=sources,
                                                args=(player_spec,
                                                      downloader_spec),
                                                kwargs=kwargs)

    @property
    def limit(self):
        return None

    def refresh(self):
        self.view.refresh()

    def reset(self):
        self.view.reset()

    def __str__(self):
        return self.NAME

    def __repr__(self):
        return f"<{type(self)}: {self.NAME}>"

    @property
    def playlist_title(self):
        return f"[{self.IDENTIFIER}"

    @property
    def auto_preview_enabled(self):
        return not self.config.auto_preview.disabled

    @property
    def auto_preview_default(self):
        return self.config.auto_preview.default if self.auto_preview_enabled else "default"

    @property
    def strip_emoji(self):
        return (self.config.get("strip_emoji")
                or config.settings.profile.tables.get("strip_emoji") or False)

    @property
    def translate(self):
        return (self.config.get("translate")
                or config.settings.profile.tables.get("translate") or False)

    @property
    def translate_src(self):
        return "auto"

    @property
    def translate_dest(self):
        return (self.config.get("translate_dest")
                or config.settings.profile.tables.get("translate_dest")
                or "en")

    @property
    def output_path(self):
        return (self.config.get_path("output.path")
                or config.settings.profile.get_path("output.path"))
Example #11
0
class CachedFeedProvider(BackgroundTasksMixin, TabularProviderMixin,
                         FeedProvider):

    UPDATE_INTERVAL = (60 * 60 * 4)

    RATE_LIMIT = 5
    BURST_LIMIT = 5

    DEFAULT_FETCH_LIMIT = 50

    TASKS = [
        # ("update", UPDATE_INTERVAL, [], {"force": True})
        ("update", UPDATE_INTERVAL)
    ]

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.search_filter = None
        self.items_query = None
        self.custom_filters = AttrDict()
        urwid.connect_signal(self.view, "feed_change", self.on_feed_change)
        urwid.connect_signal(self.view, "feed_select", self.on_feed_select)
        self.filters["status"].connect("changed", self.on_status_change)
        self.filters["filters"].connect("changed", self.on_custom_change)
        self.pagination_cursor = None
        self.limiter = get_limiter(rate=self.RATE_LIMIT,
                                   capacity=self.BURST_LIMIT)
        self.listing_lock = asyncio.Lock()

    @property
    def VIEW(self):
        return FeedProviderView(
            self,
            CachedFeedProviderBodyView(self,
                                       CachedFeedProviderDataTable(self)))

    def init_config(self):
        super().init_config()
        if config.settings.profile.cache.max_age > 0:
            with db_session(optimistic=False):
                FeedMediaChannel.purge_all(
                    min_items=config.settings.profile.cache.min_items,
                    max_items=config.settings.profile.cache.max_items,
                    max_age=config.settings.profile.cache.max_age)

    def format_feed(feed):
        return feed.name if hasattr(feed, "name") else ""

    ATTRIBUTES = AttrDict(
        media_listing_id={"hide": True},
        feed={
            "width": 30,
            "format_fn": format_feed
        },
        created={"width": 19},
        title={
            "width": ("weight", 1),
            "truncate": True
        },
    )
    # @property
    # def ATTRIBUTES(self):
    #     def format_feed(feed):
    #         return feed.name if hasattr(feed, "name") else ""

    #     return AttrDict(
    #         media_listing_id = {"hide": True},
    #         feed = {"width": 32, "format_fn": format_feed },
    #         created = {"width": 19},
    #         title = {"width": ("weight", 1), "truncate": False},
    #     )

    # @property
    # def RPC_METHODS(self):
    #     return [
    #         ("mark_items_read", self.mark_items_read)
    #     ]

    @property
    def status(self):
        return self.filters["status"].value

    # @property
    # def search_string(self):
    #     return self.filters["search"].value

    @property
    def feeds(self):
        locators = [c.locator for c in self.view.selected_channels]
        with db_session:
            return [
                self.FEED_CLASS.get(locator=locator) for locator in locators
            ]

    @property
    def fetch_limit(self):
        return self.config.fetch_limit or self.DEFAULT_FETCH_LIMIT

    @property
    def translate(self):
        return (self.translate_src and super().translate)

    def create_feeds(self):

        all_channels = list(self.view.all_channels)
        with db_session:
            for channel in all_channels:

                feed = self.FEED_CLASS.get(provider_id=self.IDENTIFIER,
                                           locator=channel.locator)
                if not feed:
                    feed = self.FEED_CLASS(provider_id=self.IDENTIFIER,
                                           locator=channel.locator)
                feed.name = channel.name
                feed.attrs.update(channel.attrs)

            for channel in self.FEED_CLASS.select():
                if channel.locator not in [c.get_key() for c in all_channels]:
                    self.FEED_CLASS[channel.channel_id].delete()

    def feed_attrs(self, feed_name):
        return {}

    @property
    def feed_filters(self):
        return None

    def on_feed_change(self, source, selection):
        self.provider_data["selected_feed"] = [n.identifier for n in selection]
        self.save_provider_data()

    def on_feed_select(self, source, selection):
        if not self.is_active:
            return
        self.update_count = True
        self.reset()

    def on_status_change(self, status, *args):
        with db_session:
            self.provider_data["selected_status"] = status
            self.save_provider_data()
        if not self.is_active:
            return
        self.reset()

    def on_custom_change(self, custom, *args):
        logger.info(f"{custom}, {args}")
        self.custom_filters = custom
        self.reset()

    def open_popup(self, text):
        class UpdateMessage(BasePopUp):
            def __init__(self):
                self.text = urwid.Text(text, align="center")
                self.filler = urwid.Filler(self.text)
                super().__init__(self.filler)

            def selectable(self):
                return False

        self.message = UpdateMessage()
        self.view.open_popup(self.message, width=24, height=5)

    def close_popup(self):
        self.view.close_popup()

    async def update(self, force=False, resume=False, replace=False):
        logger.info(f"update: force={force} resume={resume}")
        state.loop.draw_screen()
        # self.open_popup("Updating feeds...")
        # asyncio.create_task(
        await self.update_feeds(force=force, resume=resume, replace=replace)
        # )
        # self.close_popup()
        self.reset()
        # update_task = state.event_loop.run_in_executor(None, update_feeds)

    async def update_feeds(self, force=False, resume=False, replace=False):
        logger.info(f"update_feeds: {force} {resume} {replace}")
        with db_session:
            # feeds = select(f for f in self.FEED_CLASS if f in self.selected_channels)
            # if not self.feed_entity:
            #     feeds = self.FEED_CLASS.select()
            # else:
            #     feeds = [self.feed_entity]

            for feed in self.selected_channels:
                if (force or feed.updated is None
                        or datetime.now() - feed.updated >
                        timedelta(seconds=feed.update_interval)):
                    logger.info(f"updating {feed.locator}")
                    with limit(self.limiter):
                        await feed.update(resume=resume, replace=replace)
                        # f.updated = datetime.now()
                    # commit()

    def refresh(self):
        logger.info("+feed provider refresh")
        # self.update_query()
        self.view.refresh()
        # state.loop.draw_screen()
        logger.info("-feed provider refresh")

    def reset(self):
        logger.info("provider reset")
        self.pagination_cursor = None
        self.update_query()
        super().reset()

    def on_activate(self):
        super().on_activate()
        self.create_feeds()
        # self.reset()

    # def on_deactivate(self):
    #     if self.view.player:
    #         self.view.quit_player()
    #     super().on_deactivate()

    @property
    def total_item_count(self):
        with db_session:
            return self.all_items_query.count()

    @property
    def feed_item_count(self):
        with db_session:
            return self.feed_items_query.count()

    @db_session
    def update_query(self, sort=None, cursor=None):

        logger.info(f"update_query: {cursor}")
        status_filters = {
            "all": lambda: True,
            "unread": lambda i: i.read is None,
            "not_downloaded": lambda i: i.downloaded is None
        }

        self.all_items_query = (self.LISTING_CLASS.select())

        if self.selected_channels:
            self.feed_items_query = self.all_items_query.filter(
                lambda i: i.channel in self.selected_channels)
        else:
            self.feed_items_query = self.all_items_query

        self.items_query = self.feed_items_query
        if self.feed_filters:
            for f in self.feed_filters:
                self.items_query = self.items_query.filter(f)

        self.items_query = self.items_query.filter(
            status_filters[self.filters.status.value])

        if self.search_filter:
            (field, query) = re.search("(?:(\w+):)?(.*)",
                                       self.search_filter).groups()
            if field and field in [a.name for a in self.LISTING_CLASS._attrs_]:
                self.items_query = self.items_query.filter(
                    lambda i: getattr(i, field) == query)
            else:
                # raise Exception(query, self.pagination_cursor)
                self.items_query = self.items_query.filter(
                    lambda i: query.lower() in i.title.lower())

        if self.custom_filters:
            for k, v in self.custom_filters.items():
                self.items_query = self.items_query.filter(
                    lambda i: v in getattr(i, k))

        (sort_field, sort_desc) = sort if sort else self.view.sort_by
        if cursor:
            op = "<" if sort_desc else ">"
            self.items_query = self.items_query.filter(
                raw_sql(f"{sort_field} {op} '{cursor}'"))

        if sort_field:
            if sort_desc:
                sort_fn = lambda i: desc(getattr(i, sort_field))
            else:
                sort_fn = lambda i: getattr(i, sort_field)

            # break ties with primary key to ensure pagination cursor is correct
            pk_sort_attr = self.LISTING_CLASS._pk_
            if sort_desc:
                pk_sort_attr = desc(pk_sort_attr)
            # self.items_query = self.items_query.order_by(pk_sort_attr)
            self.items_query = self.items_query.order_by(sort_fn)
            # logger.info(self.items_query.get_sql())
        self.view.update_count = True

    async def apply_search_query(self, query):
        self.pagination_cursor = None
        self.search_filter = query
        self.update_query()
        self.reset()

    def update_fetch_indicator(self, num):
        self.view.update_fetch_indicator(num, self.fetch_limit)

    def show_message(self, message):
        self.view.show_message(message)

    def listings(self,
                 sort=None,
                 cursor=None,
                 offset=None,
                 limit=None,
                 *args,
                 **kwargs):

        count = 0
        # cursor = None

        if not offset:
            offset = 0

        if not limit:
            limit = self.limit

        with db_session(optimistic=False):

            self.update_query(sort=sort, cursor=cursor)

            for listing in self.items_query[:limit]:
                sources = [
                    source.detach() for source in
                    listing.sources.select().order_by(lambda s: s.rank)
                ]
                listing = listing.detach()
                listing.channel = listing.channel.detach()
                listing.channel.listings = None
                listing.sources = sources

                # get last item's sort key and store it as our pagination cursor
                # cursor = getattr(listing, self.view.sort_by[0])

                # if not listing.check():
                #     logger.debug("listing broken, fixing...")
                #     listing.refresh()
                #     # have to force a reload here since sources may have changed
                #     listing = listing.attach().detach()

                yield listing

        self.update_query(sort=sort, cursor=cursor)

        self.pagination_cursor = cursor
        # self.update_query(cursor, sort=sort)

    @db_session
    async def mark_items_read(self, request):
        media_listing_ids = list(set(request.params))
        logger.info(f"mark_items_read: {media_listing_ids}")
        with db_session:
            try:
                for item in self.LISTING_CLASS.select(
                        lambda i: i.media_listing_id in media_listing_ids):
                    item.read = datetime.now()
                commit()
                self.reset()
            except pony.orm.core.ObjectNotFound:
                logger.info(
                    f("mark_item_read: item {media_listing_id} not found"))

    @property
    def playlist_title(self):
        return f"[{self.IDENTIFIER}]"