def fail_warning(page: pywikibot.page.BasePage,
                 review_license: str,
                 is_old: bool = False) -> None:
    user_talk = get_author_talk(page)
    message = string.Template(config["old_fail_warn"] if is_old else
                              config["fail_warn"]).safe_substitute(
                                  filename=page.title(with_ns=True),
                                  review_license=review_license)
    summary = string.Template(config["review_summary"]).safe_substitute(
        status="fail", review_license=review_license, version=__version__)
    if not simulate:
        utils.check_runpage(site, run_override)
        logger.info(f"Saving {user_talk.title()}")
        utils.retry(
            utils.save_page,
            3,
            text=message,
            page=user_talk,
            summary=summary,
            bot=False,
            minor=False,
            mode="append",
        )
    else:
        logger.info("Saving disabled")
        logger.info(summary)
        logger.info(message)
def save_page(page: pywikibot.page.BasePage, new_text: str, status: str,
              review_license: str) -> None:
    """Replaces the wikitext of the specified page with new_text

    If the global simulate variable is true, the wikitext will be printed
    instead of saved to Commons.
    """
    summary = string.Template(config["review_summary"]).safe_substitute(
        status=status, review_license=review_license, version=__version__)
    if not simulate:
        utils.check_runpage(site, run_override)
        logger.info(f"Saving {page.title()}")
        utils.retry(
            utils.save_page,
            3,
            text=new_text,
            page=page,
            summary=summary,
            bot=False,
            minor=False,
        )
    else:
        logger.info("Saving disabled")
        logger.debug(summary)
        logger.debug(new_text)
def test_check_runpage_stop_anything():
    page = mock.MagicMock()
    page.return_value.text = "Stop!"

    with pytest.raises(pywikibot.UserBlocked):
        with mock.patch("pywikibot.Page", page):
            utils.check_runpage(inrbot.site)
def test_check_runpage_stop():
    page = mock.MagicMock()
    page.return_value.text = "<!-- Set to False to stop bot. -->\nFalse"

    with pytest.raises(pywikibot.UserBlocked):
        with mock.patch("pywikibot.Page", page):
            utils.check_runpage(inrbot.site)
def review_file(inpage: pywikibot.page.BasePage,
                throttle: Optional[utils.Throttle] = None) -> Optional[bool]:
    """Performs a license review on the input page

    inpage must be in the file namespace.

    Returns None if the file was skipped
    Returns False if there was an error during review
    Returns True if the file was successfully reviewed (pass or fail)
    """
    try:
        page = pywikibot.FilePage(inpage)
    except ValueError:
        return None
    logger.info(f"Checking {page.title(as_link=True)}")

    utils.check_runpage(site, run_override)
    if not check_can_run(page):
        return None

    raw_obs_id, raw_photo_id = find_ina_id(page)
    logger.info(f"ID found in wikitext: {raw_obs_id} {raw_photo_id}")
    if raw_photo_id and not raw_obs_id:
        raw_obs_id = get_observation_from_photo(raw_photo_id)

    if not raw_obs_id:
        logger.info("No observation ID could be found")
        update_review(page, status="error", reason="url", throttle=throttle)
        return False

    ina_throttle = utils.Throttle(10)
    ina_data = get_ina_data(raw_obs_id, ina_throttle)

    if not ina_data:
        logger.warning("No data retrieved from iNaturalist!")
        update_review(page, status="error", reason="nodata", throttle=throttle)
        return False

    photo_id, found = find_photo_in_obs(page, raw_obs_id, ina_data,
                                        raw_photo_id, ina_throttle)
    if photo_id is None:
        logger.info(f"Images did not match: {found}")
        update_review(page, status="error", reason=found, throttle=throttle)
        return False
    else:
        assert isinstance(photo_id, iNaturalistID)

    ina_license = find_ina_license(ina_data, photo_id)
    logger.debug(f"iNaturalist License: {ina_license}")
    ina_author = find_ina_author(ina_data)
    logger.debug(f"Author: {ina_author}")

    com_license = find_com_license(page)
    logger.debug(f"Commons License: {com_license}")
    status = check_licenses(ina_license, com_license)

    if status == "fail":
        is_old = file_is_old(page)
    else:
        is_old = False

    if config["use_wayback"] and status in ("pass", "pass-change"):
        archive = waybackpy.Url(str(photo_id), user_agent).save()
    else:
        archive = ""

    reviewed = update_review(
        page,
        photo_id,
        status=status,
        author=ina_author,
        review_license=ina_license,
        upload_license=com_license,
        reason=found,
        is_old=is_old,
        throttle=throttle,
        archive=archive,
    )
    if status == "fail" and reviewed:
        fail_warning(page, ina_license, is_old)

    return reviewed
def test_check_runpage_run():
    page = mock.MagicMock()
    page.return_value.text = "<!-- Set to False to stop bot. -->\nTrue"

    with mock.patch("pywikibot.Page", page):
        utils.check_runpage(inrbot.site)