Example #1
0
def test_comparison(other_subreddit, other_post_ids, identical):
    """Test the comparison of `Post` objects."""
    posts = [
        Post(
            name="episode_{0}".format(post_id),
            submit_at=datetime(2018, 1, 6, 17, 0, 0),
            subreddit="anime",
            title="Slow Start - Episode {0} Discussion".format(post_id),
            body_template="*Slow Start*, Episode {0}".format(post_id),
        ) for post_id in range(1, 3)
    ]
    schedule = Schedule(subreddit="anime", posts=posts)

    other_posts = [
        Post(
            name="episode_{0}".format(post_id),
            submit_at=datetime(2018, 1, 6, 17, 0, 0),
            subreddit="anime",
            title="Slow Start - Episode {0} Discussion".format(post_id),
            body_template="*Slow Start*, Episode {0}".format(post_id),
        ) for post_id in other_post_ids
    ]
    other_schedule = Schedule(subreddit=other_subreddit, posts=other_posts)

    if identical:
        assert schedule == other_schedule
    else:
        assert schedule != other_schedule

    assert schedule.__eq__("schedule") is NotImplemented  # noqa: WPS609
Example #2
0
    def prepare_thumbnail(self, post: Post) -> None:
        """
        Prepare the post for the submission with thumbnail.

        Converted the post to the Rich Text JSON format so that Reddit creates
        a thumbnail for the post.
        """
        log.debug("scheduled_post_convert")
        try:
            post.body_rtjson = self.post_converter.convert_to_rtjson(
                post.body_md, )
        except ImageNotFound:
            log.warning("scheduled_post_missing_image", post=str(post))
            post.submit_with_thumbnail = False
            click.echo(
                click.style(
                    "Warning: No image found in the post.\n" +
                    "To submit a post without image set the " +
                    "'submit_with_thumbnail' option to False.",
                    fg="red",
                ))
        except (RedditError, PostConversionError) as exception:
            log.exception("scheduled_post_convert_error")
            exception.hint = (
                "To avoid further issues you can submit a post without " +
                "image by setting the 'submit_with_thumbnail' option to False."
            )
            raise
Example #3
0
def test_comparison():
    """Test the comparison of `Post` objects."""
    post = Post(
        name="episode_01",
        submit_at=datetime(2018, 1, 6, 17, 0, 0),
        subreddit="anime",
        title="Slow Start - Episode 1 Discussion",
        body_template="*Slow Start*, Episode 1: The First Butterflies",
    )

    identical_post = Post(
        name="episode_01",
        submit_at=datetime(2018, 1, 6, 17, 0, 0),
        subreddit="anime",
        title="Slow Start - Episode 1 Discussion",
        body_template="*Slow Start*, Episode 1: The First Butterflies",
    )

    different_post = Post(
        name="episode_02",
        submit_at=datetime(2018, 1, 13, 12, 0, 0),
        subreddit="anime",
        title="Slow Start - Episode 2 Discussion",
        body_template="*Slow Start*, Episode 2: Exercise Wears Me Out ",
    )

    assert post == identical_post
    assert post != different_post
    assert post.__eq__("post") is NotImplemented  # noqa: WPS609
def test_build_navigation_links(
    mock_substitute_navigation_links,
    post_helper_config,
    reddit,
):
    """Test the preparation of the Navigation Links."""
    posts = [
        Post(
            name="e{0:02}".format(post),
            submit_at=datetime(2018, 1, 6, 17, 0, 0),
            subreddit="anime",
            title="Slow Start - Episode {0} Discussion".format(post),
            body_template="1:$e01|2:$e02|3:$e03",
            navigation_scheduled="-",
            navigation_submitted="$link",
            navigation_current="*",
        ) for post in range(1, 4)
    ]
    post_helper = PostHelper(post_helper_config, reddit)

    post_helper.build_navigation_links(posts[0], posts)
    assert mock_substitute_navigation_links.call_args == call(None, None)

    posts[0].submission_id = "id_1"
    post_helper.build_navigation_links(posts[1], posts)
    assert mock_substitute_navigation_links.call_args == call("id_1", None)

    posts[1].submission_id = "id_2"
    post_helper.build_navigation_links(posts[0], posts)
    assert mock_substitute_navigation_links.call_args == call(None, "id_2")

    posts[2].submission_id = "id_3"
    post_helper.build_navigation_links(posts[1], posts)
    assert mock_substitute_navigation_links.call_args == call("id_1", "id_3")
def post():
    """Return an example Post."""
    body_template = """*Slow Start*, Episode 1: The First Butterflies

---

**Streams:**

* [Crunchyroll](https://www.crunchyroll.com/slow-start/episode-1-the-first-butterflies-759027)
* [VRV](https://vrv.co/watch/G69P1KQ0Y/Slow-Start:The-First-Butterflies)

---

**Show Information:**

* [MyAnimeList](https://myanimelist.net/anime/35540)
* [AniDB](http://anidb.net/perl-bin/animedb.pl?show=anime&aid=13160)
* [AniList](https://anilist.co/anime/98693/SlowStart)
* [Official Website](http://slow-start.com)
* [US Website](http://slowstart-usa.com/)
* [Twitter](https://twitter.com/slosta_anime)
* [US Facebook Page](https://www.facebook.com/SlowStartUSA/)
"""  # noqa: E501

    return Post(
        name="episode_01",
        submit_at=datetime(2018, 1, 6, 17, 0, 0),
        subreddit="anime",
        title="Slow Start - Episode 1 Discussion",
        body_template=body_template,
        submit_with_thumbnail=True,
    )
Example #6
0
def test_create():
    """Test creating a `Post` instance."""
    post = Post(
        name="episode_01",
        submit_at=datetime(2018, 1, 6, 17, 0, 0),
        subreddit="anime",
        title="Slow Start - Episode 1 Discussion",
        body_template="*Slow Start*, Episode 1",
    )

    assert post.submit_at == datetime(2018, 1, 6, 17, 0, 0)
    assert post.subreddit == "anime"
    assert post.title == "Slow Start - Episode 1 Discussion"
    assert post.body_template == "*Slow Start*, Episode 1"

    assert (
        post.submit_with_thumbnail,
        post.flair_id,
        post.navigation_submitted,
        post.navigation_current,
        post.navigation_scheduled,
        post.submission_id,
        post.body_md,
        post.body_rtjson,
    ) == (
        True,  # Set to True by default
        None,
        "$link",  # Default value
        "",  # Default value
        "",  # Default value
        None,
        None,
        None,
    )
Example #7
0
def test_create_with_empty_field():
    """Test that the `Post` cannot be instantiated with empty attributes."""
    with pytest.raises(AttributeError):
        Post(
            name="episode_01",
            submit_at=datetime(2018, 1, 6, 17, 0, 0),
            subreddit="anime",
            title="Slow Start - Episode 1 Discussion",
            body_template=None,  # type: ignore
        )
Example #8
0
def test_string_representation():
    """Test the string representation of a `Post` instance."""
    post = Post(
        name="episode_01",
        submit_at=datetime(2018, 1, 6, 17, 0, 0),
        subreddit="anime",
        title="Slow Start - Episode 1 Discussion",
        body_template="*Slow Start*, Episode 1: The First Butterflies",
    )

    assert "/r/anime Post at 2018-01-06 17:00:00: Slow Start" in str(post)
Example #9
0
def schedule():
    """Return the `Schedule` with 3 posts."""
    posts = [
        Post(
            name="episode_{0}".format(index + 1),
            submit_at=datetime(2018, 1, 6 + index * 7, 17, 0, 0),
            subreddit="anime",
            title="Slow Start - Episode {0} Discussion".format(index + 1),
            body_template="*Slow Start*, Episode {0}".format(index + 1),
        ) for index in range(0, 3)
    ]
    return Schedule(subreddit="anime", posts=posts)
Example #10
0
    def submit_post(self, post: Post) -> Submission:
        """
        Submit the post to Reddit.

        If the post is set to be submitted with thumbnail, submit its body in
        the Rich Text JSON format. Otherwise submit the Markdown content using
        regular method of `PRAW`.
        """
        log.info("post_submit", post=str(post))
        try:
            if post.submit_with_thumbnail and post.body_rtjson:
                submission = self.reddit_helper.submit_post_rtjson(
                    subreddit=post.subreddit,
                    title=post.title,
                    body_rtjson=post.body_rtjson,
                    flair_id=post.flair_id,
                )
            else:
                submission = self.reddit.subreddit(
                    post.subreddit,
                ).submit(
                    title=post.title,
                    selftext=post.body_md,
                    flair_id=post.flair_id,
                )
        except PrawcoreException as exception:
            log.exception("post_submit_error")
            raise RedditError(
                "Failed to submit the post.",
            ) from exception

        post.submission_id = submission.id

        log.debug("post_submit_result", permalink=submission.permalink)

        if not post.submit_with_thumbnail:
            return submission

        delay = self.post_update_delay
        log.debug("post_update_delay", delay=delay)
        click.echo(
            click.style(
                "Waiting {0}s before updating the post.".format(delay / 1000),
                fg="cyan",
            ),
        )
        time.sleep(delay / 1000)

        return self.update_post(post, submission)
Example #11
0
def test_create():
    """Test creating a `Post` instance."""
    posts = [
        Post(
            name="episode_{0}".format(post_id),
            submit_at=datetime(2018, 1, 6, 17, 0, 0),
            subreddit="anime",
            title="Slow Start - Episode {0} Discussion".format(post_id),
            body_template="*Slow Start*, Episode {0}".format(post_id),
        ) for post_id in range(1, 4)
    ]
    schedule = Schedule(subreddit="anime", posts=posts)

    assert schedule.subreddit == "anime"
    assert schedule.posts[0].subreddit == "anime"
    assert schedule.posts[1].title == "Slow Start - Episode 2 Discussion"
    assert schedule.posts[2].submit_with_thumbnail  # Set to True by default
def schedule():
    """
    Return mock `Schedule`.

    The first Post has `submission_id` filled in.
    """
    posts = [
        Post(
            name="episode_{0}".format(post_id),
            submit_at=datetime(2018, 1, 6, 17, 0, 0),
            subreddit="anime",
            title="Slow Start - Episode {0} Discussion".format(post_id),
            body_template="*Slow Start*, Episode {0}".format(post_id),
        ) for post_id in range(1, 4)
    ]
    posts[0].submission_id = "cute_id"

    return Schedule(subreddit="anime", posts=posts)
def test_submit_post_without_thumbnail(
    mock_reddit,
    mock_reddit_helper,
    mock_update_post,
    reddit_cutifier_config,
    post: Post,
):
    """
    Test submitting a post without thumbnail.

    1. Test successful submission:

    Set :attr:`Post.submit_with_thumbnail` to False (to make the test more
    obvious even when the `body_rtjson` is empty).

    Check that :meth:`Reddit.subreddit().submit()` is called with the correct
    arguments.

    Check that :meth:`RedditHelper.submit_post_rtjson()` is not called (used
    only for posts with thumbnail).

    2. Test handling of an exception raised by `PRAW`.
    """
    post.submit_with_thumbnail = False
    reddit_cutifier = RedditCutifier(reddit_cutifier_config)

    subreddit = mock_reddit.return_value.subreddit.return_value
    subreddit.submit.return_value.permalink = "slow_start_link"

    assert reddit_cutifier.submit_post(post).permalink == "slow_start_link"
    assert subreddit.submit.call_args == call(
        title=post.title,
        selftext=post.body_md,
        flair_id=post.flair_id,
    )
    assert not mock_reddit_helper.return_value.submit_post_rtjson.called

    subreddit.submit.side_effect = PrawcoreException
    with pytest.raises(RedditError):
        reddit_cutifier.submit_post(post)

    assert not mock_update_post.called
def test_prepare_post(
    mock_prepare_thumbnail,
    mock_build_navigation_links,
    post_helper_config,
    reddit,
):
    """
    Test the preparation of the post body.

    1. Prepare post without thumbnail.

    2. Prepare post with thumbnail.
    """
    mock_build_navigation_links.return_value = "links"
    posts = [
        Post(
            name="e{0:02}".format(post),
            submit_at=datetime(2018, 1, 6, 17, 0, 0),
            subreddit="anime",
            title="Slow Start - Episode {0} Discussion".format(post),
            body_template="$navigation_links|1:$e01|2:$e02|3:$e03",
            navigation_scheduled="-",
            navigation_submitted="$link",
            navigation_current="*",
        ) for post in range(1, 4)
    ]
    posts[0].submission_id = "cute_id"
    schedule = Schedule(subreddit="anime", posts=posts)

    post_helper = PostHelper(post_helper_config, reddit)

    post_helper.prepare_post(posts[1], schedule)

    assert posts[1].body_md == "links|1:/cute_id|2:*|3:-"
    assert posts[0].body_md is None
    assert mock_prepare_thumbnail.call_count == 0

    post_helper.prepare_post(posts[0], schedule, prepare_thumbnail=True)
    assert posts[0].body_md == "links|1:*|2:-|3:-"
    assert mock_prepare_thumbnail.call_count == 1
def test_submit_post_with_thumbnail(
    mock_reddit,
    mock_reddit_helper,
    mock_sleep,
    mock_update_post,
    reddit_cutifier_config,
    post: Post,
):
    """
    Test submitting a post with thumbnail.

    Set the :attr:`Post.body_rtjson` (empty by default).

    Check that :meth:`RedditHelper.submit_post_rtjson()` is called with the
    correct arguments.

    Check that :meth:`Reddit.subreddit()` is not called (used only for posts
    without thumbnail).

    Check the delay before updating the post.

    Check that :meth:`RedditCutifier.update_post()` is called.
    """
    post.body_rtjson = [{"c": [{"t": "Slow Start"}]}]
    reddit_cutifier = RedditCutifier(reddit_cutifier_config)

    submit_post_rtjson = mock_reddit_helper.return_value.submit_post_rtjson
    mock_update_post.return_value.permalink = "slow_start_link"

    assert reddit_cutifier.submit_post(post).permalink == "slow_start_link"
    assert submit_post_rtjson.call_args == call(
        subreddit=post.subreddit,
        title=post.title,
        body_rtjson=post.body_rtjson,
        flair_id=post.flair_id,
    )
    assert not mock_reddit.return_value.subreddit.called
    assert mock_sleep.call_args == call(2000 / 1000)
    assert mock_update_post.called
Example #16
0
    def prepare_post(
        self,
        post: Post,
        schedule: Schedule,
        prepare_thumbnail=False,
    ) -> None:
        """
        Prepare the post body based on the post body template.

        Substitute placeholders using the attributes of the provided `Schedule`
        instance.

        Call :meth:`prepare_thumbnail()` if :attr:`Post.submit_with_thumbnail`
        is `True`.
        """
        mapping = {}

        for schedule_post in schedule.posts:
            if schedule_post.name == post.name:
                navigation_text = schedule_post.navigation_current
            elif schedule_post.submission_id:
                navigation_text = re.sub(
                    r"\$link",
                    "/{0}".format(schedule_post.submission_id),
                    schedule_post.navigation_submitted,
                )
            else:
                navigation_text = schedule_post.navigation_scheduled

            mapping[schedule_post.name] = navigation_text

        mapping[self.
                navigation_links["placeholder"]] = self.build_navigation_links(
                    post, schedule.posts)

        post.body_md = Template(post.body_template).safe_substitute(mapping, )

        if prepare_thumbnail and post.submit_with_thumbnail:
            self.prepare_thumbnail(post)
def test_update_post(
    mock_reddit,
    reddit_cutifier_config,
    post: Post,
    submission,
    capsys,
):
    """
    Test updating a post.

    1. Test a successful edit.

    2. Test updating without providing both `submission` parameter and
       the :attr:`Post.submission_id`.

    3. Previous test with the `submission_id` provided.

    4. Test handling of an exception raised by `PRAW`.
    """
    reddit_cutifier = RedditCutifier(reddit_cutifier_config)

    reddit_cutifier.update_post(post, submission)

    assert submission.edit.call_args == call(post.body_md)

    with pytest.raises(RuntimeError):
        reddit_cutifier.update_post(post)

    post.submission_id = "cute_id"
    reddit_cutifier.update_post(post)

    assert mock_reddit.return_value.submission.call_args == call("cute_id")

    submission.edit.side_effect = PrawcoreException
    reddit_cutifier.update_post(post, submission)

    captured = capsys.readouterr()
    assert "Failed to update the post" in captured.err
def test_update_posts(
    mock_reddit,
    mock_update_post,
    reddit_cutifier_config,
):
    """Test updating multiple posts."""
    posts = [
        Post(
            name="episode_{0}".format(post_id),
            submit_at=datetime(2018, 1, 6, 17, 0, 0),
            subreddit="anime",
            title="Slow Start - Episode {0} Discussion".format(post_id),
            body_template="*Slow Start*, Episode {0}".format(post_id),
        ) for post_id in range(1, 4)
    ]

    reddit_cutifier = RedditCutifier(reddit_cutifier_config)

    reddit_cutifier.update_posts(posts)

    expected_calls = [call(post) for post in posts]

    assert list(mock_update_post.call_args_list) == expected_calls