Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Moderation streams #1051

Merged
merged 2 commits into from Jan 2, 2020
Merged

Moderation streams #1051

merged 2 commits into from Jan 2, 2020

Conversation

LilSpazJoekp
Copy link
Member

Feature Summary and Justification

This feature provides the ablilty to stream from subreddit.mod methods.
Added Moderator stream for the following:

  • edited
  • mod log
  • modqueue
  • reports
  • spam
  • unmoderated
  • unread
  • modmail_conversations

@LilSpazJoekp
Copy link
Member Author

Sorry for the commits from my previous pr, I wasn't able to figure out how to not have them attached to this pr.

@LilSpazJoekp
Copy link
Member Author

LilSpazJoekp commented Apr 7, 2019

I also want to note that the modmail_conversation() method will not work without 7f2adcf as method modmail.conversations() will not accept params as an argument from stream_generator.

@bboe bboe changed the base branch from master to stream_before July 11, 2019 17:14
@bboe bboe changed the base branch from stream_before to master July 11, 2019 17:15
@bboe
Copy link
Member

bboe commented Jul 11, 2019

@LilSpazJoekp I'll try to get this cleaned up for you.

@bboe
Copy link
Member

bboe commented Jul 11, 2019

Okay, I cleaned up your branch. Please make sure you pull it down before making any changes. Please add a changelog entry for each added item, and we're going to need some tests for each as well. Thanks for the efforts!

@LilSpazJoekp
Copy link
Member Author

I'll need some help writing the tests, I haven't written unit tests before.

@jarhill0
Copy link
Contributor

jarhill0 commented Aug 3, 2019

Is there something specific you'd like? Or more just general guidance?

@LilSpazJoekp
Copy link
Member Author

I haven’t used Betamax before and not sure how to write the code to generate the cassettes.

@jarhill0
Copy link
Contributor

jarhill0 commented Aug 4, 2019

Take a look at the tests for SubredditStreams:

class TestSubredditStreams(IntegrationTest):
@mock.patch("time.sleep", return_value=None)
def test_comments(self, _):
with self.recorder.use_cassette("TestSubredditStreams.comments"):
generator = self.reddit.subreddit("all").stream.comments()
for i in range(400):
assert isinstance(next(generator), Comment)
@mock.patch("time.sleep", return_value=None)
def test_comments__with_pause(self, _):
with self.recorder.use_cassette(
"TestSubredditStreams.comments__with_pause"
):
comment_stream = self.reddit.subreddit("kakapo").stream.comments(
pause_after=0
)
comment_count = 1
pause_count = 1
comment = next(comment_stream)
while comment is not None:
comment_count += 1
comment = next(comment_stream)
while comment is None:
pause_count += 1
comment = next(comment_stream)
assert comment_count == 17
assert pause_count == 2
@mock.patch("time.sleep", return_value=None)
def test_comments__with_skip_existing(self, _):
with self.recorder.use_cassette("TestSubredditStreams.comments"):
generator = self.reddit.subreddit("all").stream.comments(
skip_existing=True
)
count = 0
try:
for comment in generator:
count += 1
except RequestException:
pass
# This test uses the same cassette as test_comments which shows
# that there are at least 400 comments in the stream.
assert count < 400
def test_submissions(self):
with self.recorder.use_cassette("TestSubredditStreams.submissions"):
generator = self.reddit.subreddit("all").stream.submissions()
for i in range(101):
assert isinstance(next(generator), Submission)
@mock.patch("time.sleep", return_value=None)
def test_submissions__with_pause(self, _):
with self.recorder.use_cassette("TestSubredditStreams.submissions"):
generator = self.reddit.subreddit("all").stream.submissions(
pause_after=-1
)
submission = next(generator)
submission_count = 0
while submission is not None:
submission_count += 1
submission = next(generator)
assert submission_count == 100
@mock.patch("time.sleep", return_value=None)
def test_submissions__with_pause_and_skip_after(self, _):
with self.recorder.use_cassette("TestSubredditStreams.submissions"):
generator = self.reddit.subreddit("all").stream.submissions(
pause_after=-1, skip_existing=True
)
submission = next(generator)
assert submission is None # The first thing yielded should be None
submission_count = 0
submission = next(generator)
while submission is not None:
submission_count += 1
submission = next(generator)
assert submission_count < 100

Your tests will probably look something like this (you could even copy, paste, and modify).

The most important parts are the lines like:

with self.recorder.use_cassette("TestSubredditStreams.comments"):

This specifies which Betamax cassette to use so that the network interaction can be replayed consistently.

This docs page has information about recording new Betamax cassettes, which you will have to do when writing new integration tests.

@bboe
Copy link
Member

bboe commented Nov 28, 2019

@LilSpazJoekp do you still have interest in getting this in?

@LilSpazJoekp
Copy link
Member Author

@bboe I do. My apologies, I've been busy with reddit and life stuff and haven't had the chance to get this done.

@LilSpazJoekp
Copy link
Member Author

@bboe This pr is ready.

Copy link
Contributor

@PythonCoderAS PythonCoderAS left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall solid changes. However, in order to address the decrease in coverage, I think you can implement this piece of code in the subreddit test files:

    def test_random(self):
        sub = Subreddit(self.reddit, "mod")
        submodstream = SubreddditModerationStream(self.reddit, sub)
        submodstream.modmail_conversations() # just to cause the untested line to run
        assert submodstream.subreddit = Subreddit(self.reddit, "all")

@LilSpazJoekp
Copy link
Member Author

@LilSpazJoekp
Copy link
Member Author

LilSpazJoekp commented Dec 28, 2019

@PokestarFan Never mind I see why. I’ll get that added.

@PythonCoderAS
Copy link
Contributor

@LilSpazJoekp my test is a unit test not an integration test so I think it can be seperated.

Copy link
Contributor

@PythonCoderAS PythonCoderAS left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good changes, this should increase coverage back to optimal levels.

tests/conftest.py Outdated Show resolved Hide resolved
@PythonCoderAS
Copy link
Contributor

@LilSpazJoekp merge with upstream to deal with the conflict or else it won’t resolve and we can’t merge.

git remote add upstream <praw-dev-git-url>
git pull --all
git merge upstream/master
# copy-paste lines
...

@PythonCoderAS
Copy link
Contributor

@LilSpazJoekp why was this closed?

@LilSpazJoekp
Copy link
Member Author

Did not mean to close it.

@LilSpazJoekp LilSpazJoekp reopened this Dec 29, 2019
Copy link
Contributor

@PythonCoderAS PythonCoderAS left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good, but those tests may need to be ran with a username/password combo.

@LilSpazJoekp
Copy link
Member Author

They all pass with no environment variables set.

@PythonCoderAS
Copy link
Contributor

But what if we build new tests?

@LilSpazJoekp
Copy link
Member Author

See this change here

@PythonCoderAS
Copy link
Contributor

So what if we provide all 3 will that break the script?

@LilSpazJoekp
Copy link
Member Author

But what if we build new tests?

Either provide the prawtest_refresh_token environment variable or take out the setup_reddit method from the test.

So what if we provide all 3 will that break the script?

Nothing will happen because the setup_reddit method in that test is the only thing that uses the refresh_token placeholder.

@LilSpazJoekp
Copy link
Member Author

This will also resolve #1224 because prawtest_refresh_token can be used a environment variable.

@jarhill0
Copy link
Contributor

Now that tests are passing I'll take a look soon (in the next day or so) to look over the changes. Thanks!

Copy link
Contributor

@jarhill0 jarhill0 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your persistence! This PR is looking nearly complete now that tests have been written and cassettes have been recorded. I've read through the changes and requested some changes. Please let me know if you have questions, need clarification, or if I made any mistake. Looking forward to merging this feature!

praw/models/reddit/subreddit.py Outdated Show resolved Hide resolved
praw/models/reddit/subreddit.py Outdated Show resolved Hide resolved
praw/models/reddit/subreddit.py Outdated Show resolved Hide resolved
praw/models/util.py Show resolved Hide resolved
tests/integration/models/reddit/test_subreddit.py Outdated Show resolved Hide resolved
tests/unit/models/reddit/test_subreddit.py Outdated Show resolved Hide resolved
tests/unit/models/reddit/test_subreddit.py Outdated Show resolved Hide resolved
tests/integration/models/reddit/test_subreddit.py Outdated Show resolved Hide resolved
tests/conftest.py Show resolved Hide resolved
@jarhill0 jarhill0 added the Feature New feature or request label Dec 30, 2019
@LilSpazJoekp
Copy link
Member Author

LilSpazJoekp commented Dec 30, 2019

@jarhill0 those corrections have been made and committed.

@jarhill0
Copy link
Contributor

Thanks for the changes. Things are looking good!

I'm not comfortable merging in a change to the way we authenticate test cassettes alongside with a standard new feature, though I am certainly in favor of adding this change as its own PR in a way that is compatible with existing tests.

So, at this point I would like to request that the change in tests/conftest.py and the related override in tests/integration/models/reddit/test_subreddit.py be removed from this PR and the cassettes re-recorded to work without them. For re-recording the tests, there are four options, any of which I'm equally happy with:

  1. If you'd like, I can record the tests on my alt account, which authenticates with username and password.
  2. You could temporarily disable 2FA on your account just to record the tests (this is probably a bad idea, though it is an option).
  3. You could create an alt of your own and mod it in a subreddit and create at least 10 streamable actions per type (since your tests expect at least 10), and use that to record the cassettes.
  4. Now that we know that the tests pass, re-record the cassettes by passing in your password followed by a colon and then the 2FA code. If any cassettes fail, delete those ones and re-record with the new 2FA code.

If it's more trouble than it's worth for you to fiddle around with any of options 2–4, I am more than happy to record the cassettes for you. And as I said, I am interested in getting support for testing even with 2FA and refresh tokens and I'd love to see that as a next PR from you.

Thanks!

@LilSpazJoekp
Copy link
Member Author

All it does is just adds a new placeholder; it doesn’t change the auth process for any of the other tests. The placeholder is benign to the other tests because the default reddit instance doesn’t use it and is only used when an overriding reddit instance is used. If you’re still not comfortable with that, would it be possible to merge a pr for adding the refresh token before this one? Reason being is the cassettes are much smaller when large subs are used (due to higher activity).

@jarhill0
Copy link
Contributor

jarhill0 commented Dec 30, 2019

it doesn’t change the auth process for any of the other tests

My concern is that it should be possible for any PRAW contributor to re-record any cassette if needed, and using different auth schemes for different cassettes disrupts that. That's why I want to hold off on introducing refresh token-based authentication in this particular PR.

If you’re still not comfortable with that, would it be possible to merge a pr for adding the refresh token before this one?

Yes, I would be happy to do that!

@LilSpazJoekp
Copy link
Member Author

I will get that pr started then!

@LilSpazJoekp
Copy link
Member Author

Are you talking about renaming the non-stream methods? If so, yeah I would agree that they could be named differently, but that would be a breaking change for many bots. If not, I feel it would be best to keep the name of the non-stream method to imply what they will be streaming. Just like the streams for comments and submissions are named after their non-streaming counterpart.

@jarhill0
Copy link
Contributor

Are you talking about renaming the non-stream methods?

No, just the streaming methods.

I feel it would be best to keep the name of the non-stream method to imply what they will be streaming. Just like the streams for comments and submissions are named after their non-streaming counterpart.

This is a good point, which is why I'm hesitant to say that a rename is required. That said, I worry especially about the generality of the name unread, which (arguably) makes sense in the context of subreddit.mod.unread but less sense in subreddit.mod.stream.unread because it's not clear really what is being streamed or what is unread. Maybe that could be changed to old_mod_mail or something to the effect?

I'm not really happy with renaming the stream methods because it breaks continuity with their non-streaming counterparts. But neither am I happy with using these names as they feel confusing and non-descriptive.

@LilSpazJoekp
Copy link
Member Author

Hm, yeah I'm split to. I'm kinda leaning towards keeping the name of the non-streaming counter part to stay consistent with the other stream methods.

@LilSpazJoekp
Copy link
Member Author

@jarhill0 I created pr #1233 to add the new placeholder for refresh tokens.

Copy link
Contributor

@jarhill0 jarhill0 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two minor things. Since you're happy with the streaming method names (which we discussed a few days ago), I'm happy with them too.

tests/integration/models/reddit/test_subreddit.py Outdated Show resolved Hide resolved
tests/integration/models/reddit/test_subreddit.py Outdated Show resolved Hide resolved
@jarhill0
Copy link
Contributor

jarhill0 commented Jan 2, 2020

And, lastly, if you could squash these commits and then rebase them on top of master, that would be terrific.

@LilSpazJoekp LilSpazJoekp reopened this Jan 2, 2020
Copy link
Contributor

@jarhill0 jarhill0 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Things look good!

@jarhill0 jarhill0 merged commit edf9650 into praw-dev:master Jan 2, 2020
@jarhill0
Copy link
Contributor

jarhill0 commented Jan 2, 2020

This was a good journey, and it motivated #1233, which is a very useful feature. Thanks for working so hard on this, and I'd love to see more contributions from you in the future! 🎉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Feature New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants