def test_source(): source = Source("foo", "bar") assert source.nick == "foo" assert source.url == "bar" with pytest.raises(TypeError): Source()
def timeline(ctx, pager, limit, twtfile, sorting, timeout, porcelain, source, cache): """Retrieve your personal timeline.""" if source: source_obj = ctx.obj["conf"].get_source_by_nick(source) if not source_obj: logger.debug("Not following {0}, trying as URL".format(source)) source_obj = Source(source, source) sources = [source_obj] else: sources = ctx.obj["conf"].following tweets = get_remote_tweets(sources, limit, timeout, cache) if twtfile and not source: source = Source(ctx.obj["conf"].nick, ctx.obj["conf"].twturl, file=twtfile) tweets.extend(get_local_tweets(source, limit)) tweets = sort_and_truncate_tweets(tweets, sorting, limit) if not tweets: return if pager: click.echo_via_pager(style_timeline(tweets, porcelain)) else: click.echo(style_timeline(tweets, porcelain))
def timeline(ctx, pager, limit, twtfile, sorting, timeout, porcelain, source, cache, force_update): """Retrieve your personal timeline.""" if source: source_obj = ctx.obj["conf"].get_source_by_nick(source) if not source_obj: logger.debug("Not following {0}, trying as URL".format(source)) source_obj = Source(source, source) sources = [source_obj] else: sources = ctx.obj["conf"].following tweets = [] if cache: try: with Cache.discover(update_interval=ctx.obj["conf"]. timeline_update_interval) as cache: force_update = force_update or not cache.is_valid if force_update: tweets = get_remote_tweets(sources, limit, timeout, cache) else: logger.debug( "Multiple calls to 'timeline' within {0} seconds. Skipping update" .format(cache.update_interval)) # Behold, almighty list comprehensions! (I might have gone overboard here…) tweets = list( chain.from_iterable([ cache.get_tweets(source.url) for source in sources ])) except OSError as e: logger.debug(e) tweets = get_remote_tweets(sources, limit, timeout) else: tweets = get_remote_tweets(sources, limit, timeout) if twtfile and not source: source = Source(ctx.obj["conf"].nick, ctx.obj["conf"].twturl, file=twtfile) tweets.extend(get_local_tweets(source, limit)) if not tweets: return tweets = sort_and_truncate_tweets(tweets, sorting, limit) if pager: click.echo_via_pager(style_timeline(tweets, porcelain)) else: click.echo(style_timeline(tweets, porcelain))
def get_source_by_nick(self, nick): """Returns the :class:`Source` of the given nick. :param str nick: nickname for which will be searched in the config """ url = self.cfg.get("following", nick, fallback=None) return Source(nick, url) if url else None
def test_tweet_ordering(): now = datetime.now(timezone.utc) tweet_1 = Tweet("A", now) tweet_2 = Tweet("B", now + timedelta(hours=1)) tweet_3 = Tweet("C", now + timedelta(hours=2)) tweet_4 = Tweet("D", now + timedelta(hours=2)) tweet_5 = Tweet("D", now + timedelta(hours=2)) source = Source("foo", "bar") # explicit testing with pytest.raises(TypeError): tweet_1 < source with pytest.raises(TypeError): tweet_1 <= source with pytest.raises(TypeError): tweet_1 > source with pytest.raises(TypeError): tweet_1 >= source assert tweet_1 != source assert tweet_1 < tweet_2 assert tweet_1 <= tweet_2 assert tweet_2 > tweet_1 assert tweet_2 >= tweet_1 assert tweet_3 != tweet_4 assert tweet_5 == tweet_4 assert tweet_5 >= tweet_4 assert tweet_5 <= tweet_4 assert not (tweet_3 <= tweet_4) assert not (tweet_3 >= tweet_4)
def test_parse_tweets(): """Test parsing multiple tweet lines""" source = Source("foo", "bar") raw_tweets = [ "2016-02-08T00:00:00\tHallo", "2016-02-08T00:00:00\tBar\n", "2016-02-08T00:00:00\tFoo\n", "3000-02-08T00:00:00\tHallo\n", ] tweets = parse_tweets(raw_tweets, source) assert len(tweets) == 3
def following(self): """Returns a list of all source objects.""" following = [] try: for (nick, url) in self.cfg.items("following"): source = Source(nick, url) following.append(source) except configparser.NoSectionError as e: logger.debug(e) return following
def test_parse_tweet(): """Test parsing single tweet line.""" source = Source("foo", "bar") raw_line = "2016-02-08T00:00:00\tHallo" tweet = parse_tweet(raw_line, source) assert tweet.text == "Hallo" assert tweet.created_at == datetime(year=2016, month=2, day=8, tzinfo=timezone.utc) with pytest.raises(ValueError) as e: raw_line = "3000-02-08T00:00:00\tHallo" parse_tweet(raw_line, source) assert "Tweet is from the future" in str(e.value)
def follow(ctx, nick, url): """Add a new source to your followings.""" source = Source(nick, url) sources = ctx.obj['conf'].following if source.nick in (source.nick for source in sources): click.confirm("➤ You’re already following {}. Overwrite?".format( click.style(source.nick, bold=True)), default=False, abort=True) ctx.obj['conf'].add_source(source) click.echo("✓ You’re now following {}.".format( click.style(source.nick, bold=True)))
def test_add_get_remove_source(): conf = Config.discover() conf.cfg.remove_section("following") assert conf.remove_source_by_nick("foo") is False assert conf.get_source_by_nick("baz") is None conf.add_source(Source("foo", "bar")) source = conf.get_source_by_nick("foo") assert source.nick == "foo" assert source.url == "bar" assert conf.remove_source_by_nick("baz") is False assert conf.remove_source_by_nick("foo") is True assert conf.following == []
def test_tweet_init(): with pytest.raises(ValueError) as e: Tweet("") assert "empty text" in str(e.value) with pytest.raises(TypeError) as e: Tweet("foobar", 0) assert "created_at is of invalid type" in str(e.value) source = Source("foo", "bar") created_at = datetime.now(timezone.utc) tweet = Tweet("foobar", created_at, source) assert tweet.text == "foobar" assert tweet.created_at == created_at.replace(microsecond=0) assert tweet.source == source
def follow(ctx, nick, url, force): """Add a new source to your followings.""" source = Source(nick, url) sources = ctx.obj['conf'].following if not force: if source.nick in (source.nick for source in sources): click.confirm("➤ You’re already following {0}. Overwrite?".format( click.style(source.nick, bold=True)), default=False, abort=True) _, status = get_remote_status([source])[0] if status != 200: click.confirm("➤ The feed of {0} at {1} is not available. Follow anyway?".format( click.style(source.nick, bold=True), click.style(source.url, bold=True)), default=False, abort=True) ctx.obj['conf'].add_source(source) click.echo("✓ You’re now following {0}.".format( click.style(source.nick, bold=True)))
def get_source_by_nick(self, nick): """Returns the source of the given nick.""" url = self.cfg.get("following", nick, fallback=None) return Source(nick, url) if url else None
def source(self): return Source(self.nick, self.twturl)