def test_gild__no_creddits(self): self.reddit.read_only = False with self.recorder.use_cassette('TestComment.test_gild__no_creddits'): with pytest.raises(BadRequest) as excinfo: Comment(self.reddit, 'd1616q2').gild() reason = excinfo.value.response.json()['reason'] assert 'INSUFFICIENT_CREDDITS' == reason
def test_refresh__removed_comment(self): with self.recorder.use_cassette("TestComment.test_refresh__removed_comment"): with pytest.raises(ClientException) as excinfo: Comment(self.reddit, "dma3mi5").refresh() assert ( "This comment does not appear to be in the comment tree", ) == excinfo.value.args
def test_attributes(self): with self.recorder.use_cassette('TestComment.test_attributes'): comment = Comment(self.reddit, 'cklhv0f') assert comment.author == 'bboe' assert comment.body.startswith('Yes it does.') assert not comment.is_root assert comment.submission == '2gmzqe'
def test_refresh__deleted_comment(self): with self.recorder.use_cassette( 'TestComment.test_refresh__deleted_comment'): with pytest.raises(ClientException) as excinfo: Comment(self.reddit, 'd7ltvl0').refresh() assert ('This comment does not appear to be in the ' 'comment tree', ) == excinfo.value.args
def test_attributes(self): with self.recorder.use_cassette("TestComment.test_attributes"): comment = Comment(self.reddit, "cklhv0f") assert comment.author == "bboe" assert comment.body.startswith("Yes it does.") assert not comment.is_root assert comment.submission == "2gmzqe"
def test_gild__no_creddits(self): self.reddit.read_only = False with self.recorder.use_cassette("TestComment.test_gild__no_creddits"): with pytest.raises(BadRequest) as excinfo: Comment(self.reddit, "d1616q2").gild() reason = excinfo.value.response.json()["reason"] assert "INSUFFICIENT_CREDDITS" == reason
def test_gild__no_creddits(self): self.reddit.read_only = False with self.recorder.use_cassette("TestComment.test_gild__no_creddits"): with pytest.raises(RedditAPIException) as excinfo: Comment(self.reddit, "d1616q2").gild() exception = excinfo.value assert "INSUFFICIENT_CREDDITS" == exception.error_type
def test_delete(self, _): self.reddit.read_only = False with self.use_cassette(): comment = Comment(self.reddit, "d1616q2") comment.delete() assert comment.author is None assert comment.body == "[deleted]"
def test_parent__submission(self): comment = Comment(self.reddit, "cklfmye") with self.recorder.use_cassette("TestComment.test_parent__submission"): parent = comment.parent() assert comment in parent.comments assert isinstance(parent, Submission) assert parent.fullname == comment.parent_id
def test_delete(self, _): self.reddit.read_only = False with self.recorder.use_cassette('TestComment.test_delete'): comment = Comment(self.reddit, 'd1616q2') comment.delete() assert comment.author is None assert comment.body == '[deleted]'
def delete_removal_comment(subreddit: Subreddit, post_removal): logger.warning("2: Deleting removal comment {post_id}".format(post_id=post_removal.removal_comment_id)) removal_comment = Comment(id=post_removal.removal_comment_id, reddit=subreddit.reddit_api) removal_comment.delete() post_removal.removal_comment_id = None post_removal.save()
def run(self): for cid in self.cids: author = Comment(self.reddit, id=cid).author try: self.authors.append('Null' if author is None or author.created_utc > self.dateline else author.name) except: self.authors.append('NULL-ERR') self.i += 1
def test_award__self_gild(self): self.reddit.read_only = False with self.recorder.use_cassette("TestComment.test_award__self_gild"): with pytest.raises(RedditAPIException) as excinfo: Comment(self.reddit, "g7cn9xb").award( gild_type="award_2385c499-a1fb-44ec-b9b7-d260f3dc55de") exception = excinfo.value assert "SELF_GILDING_NOT_ALLOWED" == exception.error_type
def test_award__not_enough_coins(self): self.reddit.read_only = False with self.use_cassette(): with pytest.raises(RedditAPIException) as excinfo: Comment(self.reddit, "g7cmlgc").award( gild_type="award_2385c499-a1fb-44ec-b9b7-d260f3dc55de") exception = excinfo.value assert "INSUFFICIENT_COINS_WITH_AMOUNT" == exception.error_type
def test_parent__comment(self): comment = Comment(self.reddit, "cklhv0f") with self.recorder.use_cassette("TestComment.test_parent__comment"): parent = comment.parent() parent.refresh() assert comment in parent.replies assert isinstance(parent, Comment) assert parent.fullname == comment.parent_id
def test_comment_no_has_url(self): comment = Comment( reddit, url= "https://www.reddit.com/r/worldnews/comments/98aj0i/former_un_chief_kofi_annan_dies_at_80/e4en2bt/", ) assert find_urls_in(comment) is None
def replay_remove_pending_tip(reddit, tx_queue, failover_time): # check if user have pending tips list_tips = user_function.get_unregistered_tip() if list_tips: for arr_tip in list_tips: tip = models.Tip().create_from_array(arr_tip) bot_logger.logger.info("replay tipping check for %s" % str(tip.id)) # check if it's not too old & replay tipping if not tip.is_expired(): if tip.receiver.is_registered(): bot_logger.logger.info( "replay tipping %s - %s send %s to %s " % (str(tip.id), tip.sender.username, tip.amount, tip.receiver.username)) tip.tx_id = crypto.tip_user(tip.sender.address, tip.receiver.address, tip.amount, tx_queue, failover_time) if tip.tx_id: tip.finish = True user_function.remove_pending_tip(tip.id) if tip.message_fullname is not None: msg_id = re.sub(r't\d+_(?P<id>\w+)', r'\g<id>', tip.message_fullname) msg = Comment(reddit, msg_id) msg.reply( Template(lang.message_tip).render( sender=tip.sender.username, receiver=tip.receiver.username, amount=str(tip.amount), value_usd=str(tip.get_value_usd()), txid=tip.tx_id)) else: tip.status = "waiting registration of receiver" bot_logger.logger.info( "replay check for %s - user %s not registered " % (str(tip.id), tip.receiver.username)) else: tip.status = "receiver not registered in time" tip.finish = "" bot_logger.logger.info( "delete old tipping - %s send %s to %s " % (tip.sender.username, tip.amount, tip.receiver.username)) user_function.remove_pending_tip(tip.id) # update tip status history.update_tip(tip.sender.username, tip) history.update_tip(tip.receiver.username, tip) else: bot_logger.logger.info("no pending tipping")
def test_construct_failure(self): message = "Exactly one of `id`, `url`, or `_data` must be provided." with pytest.raises(TypeError) as excinfo: Comment(self.reddit) assert str(excinfo.value) == message with pytest.raises(TypeError) as excinfo: Comment(self.reddit, id="dummy", url="dummy") assert str(excinfo.value) == message with pytest.raises(TypeError) as excinfo: Comment(self.reddit, "dummy", _data={"id": "dummy"}) assert str(excinfo.value) == message with pytest.raises(TypeError) as excinfo: Comment(self.reddit, url="dummy", _data={"id": "dummy"}) assert str(excinfo.value) == message with pytest.raises(TypeError) as excinfo: Comment(self.reddit, "dummy", "dummy", {"id": "dummy"}) assert str(excinfo.value) == message with pytest.raises(ValueError): Comment(self.reddit, "") with pytest.raises(ValueError): Comment(self.reddit, url="")
def test_reply(self): self.reddit.read_only = False with self.recorder.use_cassette("TestComment.test_reply"): parent_comment = Comment(self.reddit, "d1616q2") comment = parent_comment.reply("Comment reply") assert comment.author == self.reddit.config.username assert comment.body == "Comment reply" assert not comment.is_root assert comment.parent_id == parent_comment.fullname
def test_comment_has_url(self): comment = Comment( reddit, url= "https://www.reddit.com/r/worldnews/comments/986846/ukraine_demands_15_year_sentence_for_ousted/e4dqaw1/", ) assert find_urls_in(comment) == [ "https://www.businessinsider.com/paul-manafort-daughter-text-messages-ukraine-2017-3" ]
def test_parent__chain(self): comment = Comment(self.reddit, "dkk4qjd") counter = 0 with self.recorder.use_cassette("TestComment.test_parent__chain"): comment.refresh() parent = comment.parent() while parent != comment.submission: if counter % 9 == 0: parent.refresh() counter += 1 parent = parent.parent()
def reply_to_comment(self, comment_id: Text, comment_body: Text, subreddit: Text = None) -> Optional[Comment]: if self.live_response: return self._reply_to_comment(comment_id, comment_body, subreddit=subreddit) log.debug('Live response disabled') # TODO - 1/12/2021 - Sketchy at best return Comment(self.reddit.reddit, id='1111')
def test_construct_failure(self): message = 'Exactly one of `id`, `url`, or `_data` must be provided.' with pytest.raises(TypeError) as excinfo: Comment(self.reddit) assert str(excinfo.value) == message with pytest.raises(TypeError) as excinfo: Comment(self.reddit, id='dummy', url='dummy') assert str(excinfo.value) == message with pytest.raises(TypeError) as excinfo: Comment(self.reddit, 'dummy', _data={'id': 'dummy'}) assert str(excinfo.value) == message with pytest.raises(TypeError) as excinfo: Comment(self.reddit, url='dummy', _data={'id': 'dummy'}) assert str(excinfo.value) == message with pytest.raises(TypeError) as excinfo: Comment(self.reddit, 'dummy', 'dummy', {'id': 'dummy'}) assert str(excinfo.value) == message
def test_comment_has_urls(self): comment = Comment( reddit, url= "https://www.reddit.com/r/worldnews/comments/98aq8n/new_paper_shows_that_ants_are_so_productive/e4ek8my/", ) assert find_urls_in(comment) == [ "https://www.nytimes.com/2018/08/16/science/ants-worker-idleness.html", "http://np.reddit.com/r/autotldr/comments/98aw7d/new_paper_shows_that_ants_are_so_productive/", "http://np.reddit.com/r/autotldr/comments/31b9fm/faq_autotldr_bot/", "http://np.reddit.com/message/compose?to=%23autotldr", ]
def test_refresh__with_reply_sort_and_limit(self): with self.use_cassette(): comment = Comment(self.reddit, "e4j4830") comment.reply_limit = 4 comment.reply_sort = "new" comment.refresh() replies = comment.replies last_created = float("inf") for reply in replies: if isinstance(reply, Comment): if reply.created_utc > last_created: assert False, "sort order incorrect" last_created = reply.created_utc assert len(comment.replies) == 3
def run(self): for cid in self.cids: author = Comment(self.reddit, id=cid).author try: if author is None: # Deleted comment self.authors.append("Null") continue if author.created_utc > self.dateline: # New user self.dq_age.add(author.name) self.authors.append(author.name) except: # thread CANNOT crash, typically means suspended user self.authors.append('NULL*')
def scan_comments(subreddit): """Use Pushshift API to search comments, hardcoded to default to the last 3 days. See https://redd.it/5gawot for API v2 documentation""" _endpoint = 'https://apiv2.pushshift.io/reddit/comment/search/' _fields = [ 'author', 'body', 'created_utc', 'id', 'link_author', 'link_created_utc', 'link_id', 'link_num_comments', 'link_permalink', 'parent_id', 'url' ] _args = '?q={0}&subreddit={1}&sort=desc&after=3d&fields={2}'.format( baseurl, subreddit, ','.join(_fields)) url = _endpoint + _args req = requests.get(url) log.info('[%s] %s', req.status_code, req.headers['content-type']) status = req.status_code if status == 200: # log.debug('content: %s', r.text) result = req.json() for data in result['data']: log.info('Start sorting comment search result.') # skip own & replied comment if data['author'] == botlogin: log.info('Skipping own comment: %s', data['id']) continue elif data['author'] in botlist: log.info('Skipping bot comment: %s', data['author']) continue elif check_replied(data['id']): log.info('Skipping comment %s: replied', data['id']) continue # skip non-query comment elif not contain_url(data['body']): log.info('Skipping comment %s: no url found', data['id']) continue else: # get reddit.comment instance from praw.models import Comment comment = Comment(r, id=data['id']) reply(comment) log.info('Pausing') sleep() else: log_error = reddb(error_url=url, error_log='status: {0}'.format(status)) session.add(log_error) session.commit() log.info('%s. Logged to db', status) log.debug('[%s] code: %s, url: %s.', log_error.error_logtime, log_error.error_log, log_error.error_url)
def test_refresh__with_reply_sort_and_limit(self): with self.recorder.use_cassette( 'TestComment.test_refresh__with_reply_sort_and_limit'): comment = Comment(self.reddit, 'e4j4830') comment.reply_limit = 4 comment.reply_sort = 'new' comment.refresh() replies = comment.replies last_created = float('inf') for reply in replies: if isinstance(reply, Comment): if (reply.created_utc > last_created): assert False, 'sort order incorrect' last_created = reply.created_utc assert len(comment.replies) == 3
def replay_remove_pending_tip(rpc, reddit, tx_queue, failover_time): # check if it's not too old & replay tipping limit_date = datetime.datetime.now() - datetime.timedelta(days=3) # check if user have pending tips list_tips = user_function.get_unregistered_tip() if list_tips: for tip in list_tips: bot_logger.logger.info("replay tipping check for %s" % str(tip['id'])) if (datetime.datetime.strptime(tip['time'], '%Y-%m-%dT%H:%M:%S.%f') > limit_date): if (user_function.user_exist(tip['receiver'])): bot_logger.logger.info( "replay tipping %s - %s send %s to %s " % (str(tip['id']), tip['sender'], tip['amount'], tip['receiver'])) txid = crypto.tip_user(rpc, tip['sender'], tip['receiver'], tip['amount'], tx_queue, failover_time) user_function.remove_pending_tip(tip['id']) value_usd = utils.get_coin_value(tip['amount']) if 'message_fullname' in tip.keys(): msg_id = re.sub(r't\d+_(?P<id>\w+)', r'\g<id>', tip['message_fullname']) msg = Comment(reddit, msg_id) msg.reply( Template(lang.message_tip).render( sender=tip['sender'], receiver=tip['receiver'], amount=str(tip['amount']), value_usd=str(value_usd), txid=txid)) else: bot_logger.logger.info( "replay check for %s - user %s not registered " % (str(tip['id']), tip['receiver'])) else: bot_logger.logger.info( "delete old tipping - %s send %s for %s " % (tip['sender'], tip['amount'], tip['receiver'])) user_function.remove_pending_tip(tip['id']) else: bot_logger.logger.info("no pending tipping")
def downvote_deleter(): reddit = get_reddit() redis_client = get_redis_client() logging.info('Monitoring downvotes') while True: for comment_id in redis_client.smembers('comments'): try: comment = Comment(reddit, id=comment_id.decode( 'utf-8')) # redis-py bug, not decoding to UTF-8 if comment.score < 1: comment.delete() redis_client.srem('comments', comment_id) logging.info(f'Removed downvoted comment {comment.id}') except praw.exceptions.PRAWException as e: logging.exception(e) time.sleep(60)