diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index dd6660b7a0f..22ae3e35fc3 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -25,6 +25,7 @@ tsconfig.base.json @WordPress/openverse-frontend # Specific assignments for the 'openverse-maintainers' group .codespell/ @WordPress/openverse-maintainers +.vale/ @WordPress/openverse-maintainers .devcontainer/ @WordPress/openverse-maintainers .github/ @WordPress/openverse-maintainers automations/ @WordPress/openverse-maintainers diff --git a/.github/filters.yml b/.github/filters.yml index 52378c5b24b..a94b5b272f5 100644 --- a/.github/filters.yml +++ b/.github/filters.yml @@ -60,6 +60,7 @@ lint: - .pre-commit-config.yaml - tsconfig.base.json - .codespell + - .vale mgmt: - .github/** - .devcontainer/** diff --git a/.github/workflows/ci_cd.yml b/.github/workflows/ci_cd.yml index f5334d6e7a7..0c350d082dc 100644 --- a/.github/workflows/ci_cd.yml +++ b/.github/workflows/ci_cd.yml @@ -125,6 +125,19 @@ jobs: just precommit just lint + validate-codeowners: + name: Validate CODEOWNERS + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - uses: mszostok/codeowners-validator@v0.7.4 + with: + checks: "files,duppatterns,syntax" + experimental_checks: "notowned,avoid-shadowing" + add-stack-label: name: Add stack label if: | @@ -219,7 +232,7 @@ jobs: uses: docker/build-push-action@v5 with: context: ${{ matrix.context }} - target: ${{ matrix.target }} + target: ${{ matrix.target || '' }} push: false tags: openverse-${{ matrix.image }} file: ${{ matrix.file }} @@ -1107,7 +1120,7 @@ jobs: run: python generate_report.py - name: Send report - uses: slackapi/slack-github-action@v1.24.0 + uses: slackapi/slack-github-action@v1.25.0 with: payload: ${{ steps.report.outputs.payload }} env: diff --git a/.github/workflows/discussion_ping.yml b/.github/workflows/discussion_ping.yml index 1305cebdaf7..7c273f3d83f 100644 --- a/.github/workflows/discussion_ping.yml +++ b/.github/workflows/discussion_ping.yml @@ -13,7 +13,7 @@ jobs: env: discussion_url: ${{ github.event.discussion.html_url }} discussion_number: ${{ github.event.discussion.number }} - discussion_title: ${{ toJSON(github.event.discussion.title) }} + discussion_title: ${{ format('{0}', github.event.discussion.title) }} discussion_author: ${{ github.event.discussion.user.login }} discussion_repo: ${{ github.event.repository.full_name }} SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} @@ -21,7 +21,7 @@ jobs: steps: - name: Send notification for new discussion id: slack - uses: slackapi/slack-github-action@v1.24.0 + uses: slackapi/slack-github-action@v1.25.0 with: payload: | { diff --git a/.github/workflows/generate_pot.yml b/.github/workflows/generate_pot.yml index 0d7b7e3c2e8..b1af0babeef 100644 --- a/.github/workflows/generate_pot.yml +++ b/.github/workflows/generate_pot.yml @@ -16,6 +16,8 @@ jobs: generate-pot: name: Generate POT file runs-on: ubuntu-latest + # Prevent running this workflow on forks, it's unnecessary for external contributors + if: github.repository_owner == 'WordPress' steps: - name: Checkout repository uses: actions/checkout@v4 diff --git a/.github/workflows/issue_automations.yml b/.github/workflows/issue_automations.yml index fd6fefbfcf7..3e0a6678174 100644 --- a/.github/workflows/issue_automations.yml +++ b/.github/workflows/issue_automations.yml @@ -18,6 +18,8 @@ jobs: run: name: Perform issue automations runs-on: ubuntu-latest + # Prevent running this workflow on forks, it's unnecessary for external contributors + if: github.repository_owner == 'WordPress' steps: - name: Checkout repository uses: actions/checkout@v4 diff --git a/.github/workflows/label_sync.yml b/.github/workflows/label_sync.yml index d4d3710faea..fae7b762019 100644 --- a/.github/workflows/label_sync.yml +++ b/.github/workflows/label_sync.yml @@ -10,6 +10,8 @@ jobs: sync_labels: name: Sync labels runs-on: ubuntu-latest + # Prevent running this workflow on forks, it's unnecessary for external contributors + if: github.repository_owner == 'WordPress' steps: - name: Checkout repository uses: actions/checkout@v4 diff --git a/.github/workflows/pr_automations.yml b/.github/workflows/pr_automations.yml index bfc8c0e6c1b..4e67624fad9 100644 --- a/.github/workflows/pr_automations.yml +++ b/.github/workflows/pr_automations.yml @@ -33,6 +33,8 @@ jobs: run: name: Perform PR automations runs-on: ubuntu-latest + # Prevent running this workflow on forks, it's unnecessary for external contributors + if: github.repository_owner == 'WordPress' steps: - name: Checkout repository uses: actions/checkout@v4 diff --git a/.github/workflows/pr_automations_init.yml b/.github/workflows/pr_automations_init.yml index acae02e9253..e54540b5699 100644 --- a/.github/workflows/pr_automations_init.yml +++ b/.github/workflows/pr_automations_init.yml @@ -34,6 +34,8 @@ jobs: run: name: Save event info runs-on: ubuntu-latest + # Prevent running this workflow on forks, it's unnecessary for external contributors + if: github.repository_owner == 'WordPress' steps: - name: Save event info run: | diff --git a/.github/workflows/pr_label_check.yml b/.github/workflows/pr_label_check.yml index 8083bb355ff..abcee295f27 100644 --- a/.github/workflows/pr_label_check.yml +++ b/.github/workflows/pr_label_check.yml @@ -42,7 +42,7 @@ jobs: - get_label_groups steps: - name: Check aspect label - uses: docker://agilepathway/pull-request-label-checker:v1.6.13 + uses: docker://agilepathway/pull-request-label-checker:v1.6.20 with: any_of: ${{ needs.get_label_groups.outputs.aspect }} repo_token: ${{ secrets.GITHUB_TOKEN }} @@ -55,7 +55,7 @@ jobs: - get_label_groups steps: - name: Check goal label - uses: docker://agilepathway/pull-request-label-checker:v1.6.13 + uses: docker://agilepathway/pull-request-label-checker:v1.6.20 with: one_of: ${{ needs.get_label_groups.outputs.goal }} repo_token: ${{ secrets.GITHUB_TOKEN }} @@ -68,7 +68,7 @@ jobs: - get_label_groups steps: - name: Check priority label - uses: docker://agilepathway/pull-request-label-checker:v1.6.13 + uses: docker://agilepathway/pull-request-label-checker:v1.6.20 with: one_of: ${{ needs.get_label_groups.outputs.priority }} repo_token: ${{ secrets.GITHUB_TOKEN }} @@ -81,7 +81,7 @@ jobs: - get_label_groups steps: - name: Check stack label - uses: docker://agilepathway/pull-request-label-checker:v1.6.13 + uses: docker://agilepathway/pull-request-label-checker:v1.6.20 with: any_of: ${{ needs.get_label_groups.outputs.stack }} repo_token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/pr_limit_reminders.yml b/.github/workflows/pr_limit_reminders.yml index af4e700249c..95b4e3d3b37 100644 --- a/.github/workflows/pr_limit_reminders.yml +++ b/.github/workflows/pr_limit_reminders.yml @@ -40,21 +40,13 @@ jobs: echo "required_review_count=$(( pr_count * 2 ))" >> "$GITHUB_ENV" - name: Send notification id: slack - uses: slackapi/slack-github-action@v1.24.0 + uses: slackapi/slack-github-action@v1.25.0 with: - # The JSON below looks malformed, with an invalid multiline string, but YAML's `>` - # construct replaces linebreaks with a space, so the multiline string below will end - # up as a single-line string. The payload will be `{ "user": "...", "message": "..." } - payload: > + # Note: We cannot use the YAML folded chomping block syntax here (`>`) because + # GitHub Actions does not support it (they only support a subset of YAML): + # https://github.com/actions/runner/issues/418#issuecomment-612928525 + payload: | { "user": "${{ env.slack_id }}", - "message": - "Hi, Opener! \n - You currently have ${{ env.pr_count }} Pull Request(s) open with requested - reviews (totalling ${{ env.required_review_count }} required reviews). \n - To help ease the review burden, increase review velocity for older PRs, and - improve the equitable distribution of project maintenance tasks across the team, - please consider reviewing this list of ways to contribute instead of working on - new code contributions: \n - https://docs.openverse.org/meta/maintainer_tasks.html" + "message": "Hi, Opener! \n You currently have ${{ env.pr_count }} Pull Request(s) open with requested reviews (totalling ${{ env.required_review_count }} required reviews). \n To help ease the review burden, increase review velocity for older PRs, and improve the equitable distribution of project maintenance tasks across the team, please consider reviewing this list of ways to contribute instead of working on new code contributions: \n https://docs.openverse.org/meta/maintainer_tasks.html" } diff --git a/.github/workflows/pr_ping.yml b/.github/workflows/pr_ping.yml index fa791839b06..b48eecfc5ba 100644 --- a/.github/workflows/pr_ping.yml +++ b/.github/workflows/pr_ping.yml @@ -10,14 +10,17 @@ on: jobs: send_message: name: Send Slack message + # Prevent running this workflow on forks, it's unnecessary for external contributors + # Also prevent running this for bot-related PRs if: | github.actor != 'dependabot[bot]' && - !startsWith(github.event.pull_request.title, '🔄') + !startsWith(github.event.pull_request.title, '🔄') && + github.repository_owner == 'WordPress' runs-on: ubuntu-latest env: pr_url: ${{ github.event.pull_request.html_url }} pr_number: ${{ github.event.pull_request.number }} - pr_title: ${{ toJSON(github.event.pull_request.title) }} + pr_title: ${{ format('{0}', github.event.pull_request.title) }} pr_author: ${{ github.event.pull_request.user.login }} pr_repo: ${{ github.event.pull_request.base.repo.full_name }} SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} @@ -26,7 +29,7 @@ jobs: - name: Send notification for new PR if: github.event.action == 'opened' id: slack - uses: slackapi/slack-github-action@v1.24.0 + uses: slackapi/slack-github-action@v1.25.0 env: pr_status: ${{ github.event.pull_request.draft && ' draft ' || ' ' }} pr_icon: ${{ github.event.pull_request.draft && ':pr-draft:' || ':pull-request:' }} @@ -47,7 +50,7 @@ jobs: - name: Send notification for PR marked ready if: github.event.action == 'ready_for_review' id: slack-notifications - uses: slackapi/slack-github-action@v1.24.0 + uses: slackapi/slack-github-action@v1.25.0 with: payload: | { diff --git a/.github/workflows/project_thread_update_reminders.yml b/.github/workflows/project_thread_update_reminders.yml index 9d3c8319b60..293d780bd41 100644 --- a/.github/workflows/project_thread_update_reminders.yml +++ b/.github/workflows/project_thread_update_reminders.yml @@ -8,6 +8,8 @@ on: jobs: send-reminders: runs-on: ubuntu-latest + # Prevent running this workflow on forks, it's unnecessary for external contributors + if: github.repository_owner == 'WordPress' steps: - uses: actions/checkout@v4 - uses: actions/github-script@v6 diff --git a/.github/workflows/release-app.yml b/.github/workflows/release-app.yml index 762b5955f5d..eea0a3fbd92 100644 --- a/.github/workflows/release-app.yml +++ b/.github/workflows/release-app.yml @@ -23,6 +23,8 @@ jobs: release-app: name: Release app runs-on: ubuntu-latest + # Prevent running this workflow on forks, it's unnecessary for external contributors + if: github.repository_owner == 'WordPress' permissions: # Needed to create the GitHub release on the repo contents: write diff --git a/.github/workflows/renovate.yml b/.github/workflows/renovate.yml index d10eeda76dd..88b06b2d134 100644 --- a/.github/workflows/renovate.yml +++ b/.github/workflows/renovate.yml @@ -28,7 +28,8 @@ env: jobs: renovate: runs-on: ubuntu-latest - if: github.repository == 'WordPress/openverse' + # Prevent running this workflow on forks, it's unnecessary for external contributors + if: github.repository_owner == 'WordPress' steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/subscribe_to_label.yml b/.github/workflows/subscribe_to_label.yml index 06c5de46eae..a2b9b0aca3d 100644 --- a/.github/workflows/subscribe_to_label.yml +++ b/.github/workflows/subscribe_to_label.yml @@ -8,6 +8,8 @@ on: jobs: subscribe: runs-on: ubuntu-latest + # Prevent running this workflow on forks, it's unnecessary for external contributors + if: github.repository_owner == 'WordPress' steps: - uses: bytecodealliance/subscribe-to-label-action@v1 with: diff --git a/.github/workflows/sync_meta.yml b/.github/workflows/sync_meta.yml index 5ca5d35fbb3..06d54caa360 100644 --- a/.github/workflows/sync_meta.yml +++ b/.github/workflows/sync_meta.yml @@ -16,6 +16,8 @@ jobs: sync_meta: name: Sync meta files runs-on: ubuntu-latest + # Prevent running this workflow on forks, it's unnecessary for external contributors + if: github.repository_owner == 'WordPress' steps: - name: Checkout repository uses: actions/checkout@v4 diff --git a/.github/workflows/weekly_updates.yml b/.github/workflows/weekly_updates.yml index b39018d7c39..6c52d0aee26 100644 --- a/.github/workflows/weekly_updates.yml +++ b/.github/workflows/weekly_updates.yml @@ -15,6 +15,8 @@ jobs: make_post: name: Create post on Make site runs-on: ubuntu-latest + # Prevent running this workflow on forks, it's unnecessary for external contributors + if: github.repository_owner == 'WordPress' steps: - name: Checkout repository uses: actions/checkout@v4 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9778d0ccac7..4b7afaf1435 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -11,6 +11,15 @@ repos: entry: bash -c 'if [ ! -f "$(dirname "$dir")"/frontend/src/locales/ar.json ]; then just frontend/run i18n; fi' language: system pass_filenames: false + - id: fix-console-code-block + name: Ensure "bash" code block is used over "console" + files: ^documentation/.*\.md$ + # Check that we are not using the ```console block in our documentation + # -R recursively checks files + # -l suppresses normal input and only lists files with errors + # Print an error message if any files are found + entry: sed -i -e 's/```console/```bash/g' + language: system - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.5.0 @@ -36,7 +45,7 @@ repos: - id: requirements-txt-fixer - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.1.9 + rev: v0.2.0 hooks: - id: ruff # replaces Flake8, isort, pydocstyle, pyupgrade args: @@ -110,6 +119,7 @@ repos: entry: bash -c 'pnpm run -r types' language: system pass_filenames: false + - id: eslint name: eslint files: (frontend|automations|packages).*?\.(js|ts|vue|json5|json)$ @@ -117,6 +127,7 @@ repos: language: system pass_filenames: false entry: bash -c 'pnpm run eslint --fix' + - id: test:unit name: test:unit files: ^(frontend|packages)/.*$ @@ -125,6 +136,7 @@ repos: pass_filenames: false stages: - push + - id: render-release-drafter name: render-release-drafter files: ^templates/.*$ @@ -132,20 +144,16 @@ repos: language: system pass_filenames: false + - id: vale + name: vale + language: system + entry: bash -c 'just .vale/run' + pass_filenames: false + files: (.vale/.*|.mdx?)$ + - repo: https://github.com/renovatebot/pre-commit-hooks - rev: 37.116.0 + rev: 37.168.1 hooks: - id: renovate-config-validator args: - --strict - - - repo: local - hooks: - - id: codeowners-validator - name: CODEOWNERS validator - language: docker_image - pass_filenames: false - entry: > - -e REPOSITORY_PATH="." - -e CHECKS="files,duppatterns,syntax" - ghcr.io/mszostok/codeowners-validator:v0.7.4 diff --git a/.vale/.gitignore b/.vale/.gitignore new file mode 100644 index 00000000000..f8cea4a9562 --- /dev/null +++ b/.vale/.gitignore @@ -0,0 +1,3 @@ +styles/* +!styles/Vocab/ +!styles/Openverse/ diff --git a/.vale/.vale.ini b/.vale/.vale.ini new file mode 100644 index 00000000000..f3be33fd614 --- /dev/null +++ b/.vale/.vale.ini @@ -0,0 +1,43 @@ +StylesPath = styles + +MinAlertLevel = suggestion +Vocab = Openverse +# Using an explicit reference to downloads for package zips rather than the shorthand allows us to +# pin the package to a specific version. Otherwise, changes in the upstream style configuration can +# cause sudden and unexpected failures during linting. +Packages = https://github.com/errata-ai/proselint/releases/download/v0.3.3/proselint.zip + +# The default settings also ignore `pre` and `code`, which includes admonition code blocks. +# We may encounter false positives by including code blocks, but we use admonitions +# so frequently in Openverse documentation that it is probably worth it to include them. +SkippedScopes = script, style, figure +IgnoredScopes = tt + +[formats] +# Treat mdx as markdown (for Storybook support) +mdx = md + +# Only configure Markdown, because that's the only language we use to write documentation in +# (Except MDX, but if we want to add Vale there it will have to be at a later date to avoid complexity +# in the initial setup) +[*.md] +BasedOnStyles = proselint, Vale, Openverse + +# Avoid Vale.Spelling for now, but we do want Vale.Terms for the vocab at least +Vale.Spelling = NO + +# The suggested terms are obscure +proselint.AnimalLabels = NO + +# These are rarely necessary changes and can be more fiddly than they are helpful +proselint.Typography = NO + +# proselint.Needless considers a host of terms "needless" which are natural and wide-spread changes in the English language, +# and is clearly favouring US changes rather than others (the US isn't the only or even the largest English speaking country). +# You don't have to look far to find examples of this rule preferring variants of terms in line with 18th century elite preferences: +# https://www.merriam-webster.com/grammar/preventive-or-preventative +# In other words, it's a linguistic prescriptive holdover to insist on some of these terms being "needless" when they're in +# fact widespread and well understood. Not all the terms have this issue, but we'd have to rewrite +# practically the entire rule to sort out which ones we cared about. If we find any we _do_ care about, we can add them to our +# own substitution rule. +proselint.Needless = NO diff --git a/.vale/Dockerfile b/.vale/Dockerfile new file mode 100644 index 00000000000..9bd1fd58e0c --- /dev/null +++ b/.vale/Dockerfile @@ -0,0 +1,9 @@ +FROM jdkato/vale:v2.30.0 + +WORKDIR /vale +COPY .vale.ini . +COPY styles styles + +RUN vale sync + +ENTRYPOINT ["vale", "--config=/vale/.vale.ini"] diff --git a/.vale/README.md b/.vale/README.md new file mode 100644 index 00000000000..f00bf6f26ed --- /dev/null +++ b/.vale/README.md @@ -0,0 +1,29 @@ +# Openverse Vale configuration + +Openverse runs Vale using Docker. This bypasses the need for contributors to +install the Vale binary on their computers. It also prevents Vale styles getting +downloaded into the repository in clear text, which is critical to avoid lists +of sensitive terms being accidentally too-easily available. + +For more information about this motivation to avoid lists of sensitive terms in +the Openverse monorepo, refer to the README at +[WordPress/openverse-sensitive-terms](https://github.com/WordPress/openverse-sensitive-terms). + +To run Vale with Openverse's configuration, use the just recipe: + +``` +$ just .vale/run +``` + +This recipe _always_ builds Vale. The Openverse Vale docker image is fast to +build, and the most expensive steps are cached. Docker will automatically reuse +the pre-existing image unless there are changes to the Vale configuration. + +Typically it is unnecessary to run Vale directly, as pre-commit automatically +runs Vale on each commit. You only need to run Vale directly when iterating on +changes to Openverse's Vale configuration. + +Refer to the `VALE_FILES` variable [in the justfile](./justfile) to identify +which files we currently check with Vale. A comment on the variable explains the +rationale for that choice. The list of files will ideally expand in the future +to include all textual content in the repository. diff --git a/.vale/justfile b/.vale/justfile new file mode 100644 index 00000000000..f191286503e --- /dev/null +++ b/.vale/justfile @@ -0,0 +1,64 @@ +COLOR := "\\033[0;34m" +NO_COLOR := "\\033[0m" + + +# Show all available recipes +@_default: + printf "\n{{ COLOR }}# Vale (path: \`.vale/\`)\n" + printf "===================={{ NO_COLOR }}\n" + just --list --unsorted + + +# Build a local version of `openverse-vale:local` for testing +build: + docker build . -t openverse-vale:local + + +# The --glob setting excludes things that should not be linted, including +# build artefacts, dependencies, and automatically generated files like +# the changelogs (without excluding `changelogs/index.md`). Project proposals +# are also excluded for want of a good way to ignore existing proposals and only +# lint _new_ proposals. Project proposals aren't "living documents" in the way +# the rest of our documentation is, so it doesn't seem right to retroactively +# edit them for mere editorial purposes (rather than, for example, to correct +# some grave inacurracy). +# Leading `,` compensates for lack of trailing comma support +# Note the lack of space before the trailing \ on each line, this is to prevent +# the addition of a space between each pattern, which isn't supported by Vale's glob +# If you change this and Vale takes a very long time to run (more than 30 seconds) +# then chances are the change is breaking the glob pattern. Unfortunately the only +# feedback you get when the glob pattern is not working as intended is a very long +# run time for Vale as it checks everything that should have otherwise been ignored, +# but wasn't due to some minor issue in the pattern syntax. +# This is fiddly, but I can't find a good way around it. +_IGNORE_PATTERNS := """ + _build\ + ,_static\ + ,venv\ + ,.venv\ + ,.nuxt\ + ,.pnpm-store\ + ,node_modules\ + ,test-results\ + ,storebook-static\ + ,.ruff-cache\ + ,projects/proposals\ + ,changelogs/api\ + ,changelogs/frontend\ + ,changelogs/catalog\ + ,changelogs/ingestion_server\ +""" + +VALE_GLOB := "--glob='!*{" + _IGNORE_PATTERNS + "}*'" + + +# Run Vale configured for Openverse in Docker. +# Using Docker avoids the need for contributors to install the Vale binary. +#Configuration defaults to what is used for CI. +run +files=".": build + docker run --rm \ + -v $PWD/..:/src:rw,Z \ + --workdir=/src \ + openverse-vale:local \ + {{ files }} \ + {{ VALE_GLOB }} diff --git a/.vale/styles/Openverse/README.md b/.vale/styles/Openverse/README.md new file mode 100644 index 00000000000..1133ae799ed --- /dev/null +++ b/.vale/styles/Openverse/README.md @@ -0,0 +1,8 @@ +# Openverse vale style + +The Openverse vale style is manually curated by Openverse maintainers. These +rules are primarily meant to cater to exceptions in the Openverse documentation +style that do not fit into pre-existing style guides, whether because of +disagreements in style or different institutional or contextual requirements +based on Openverse's domain and nature as a FOSS project within the WordPress +community. diff --git a/.vale/styles/Openverse/TermCasing.yml b/.vale/styles/Openverse/TermCasing.yml new file mode 100644 index 00000000000..90ecadc2eb8 --- /dev/null +++ b/.vale/styles/Openverse/TermCasing.yml @@ -0,0 +1,21 @@ +# While Vale.Terms could be used for these, it is too inflexible, and thus incapable +# of ignoring common false-positives like GitHub usernames or GitHub team names +extends: substitution +message: "Incorrect casing. Use '%s' instead of '%s'." +level: error +ignorecase: false +scope: + - paragraph +swap: + # [^/\.] prevents matching things that look like URLs, file paths, or GitHub team mentions + # For example: @WordPress/openverse-maintainers + '[^/\.]openverse[^.\.]': Openverse + # OpenVerse should never be used, except as an example of something that is always wrong, + # in which case we'll tell Vale to ignore that line. + "OpenVerse": Openverse + '[^/\.]wordpress[^.\.]': WordPress + # Wordpress is the same as OpenVerse + "Wordpress": WordPress + '[^/\.]github[^.\.]': GitHub + # Github is the same as Wordpress and OpenVerse + "Github": GitHub diff --git a/.vale/styles/Vocab/Openverse/accept.txt b/.vale/styles/Vocab/Openverse/accept.txt new file mode 100644 index 00000000000..91d4a023bae --- /dev/null +++ b/.vale/styles/Vocab/Openverse/accept.txt @@ -0,0 +1,3 @@ +# This matches "cliche" rulesets, but we actually use this term in earnest and with clear explanation of what we mean by it +Decision-Making Process +decision-making process diff --git a/api/Pipfile b/api/Pipfile index e3a046ab3be..69d9f1907e6 100644 --- a/api/Pipfile +++ b/api/Pipfile @@ -19,7 +19,7 @@ pook = {ref = "master", git = "git+https://github.com/h2non/pook.git"} [packages] adrf = "~=0.1.2" -aiohttp = "~=3.8" +aiohttp = "~=3.9" aws-requests-auth = "~=0.4" deepdiff = "~=6.4" Django = "~=4.2" @@ -33,7 +33,7 @@ django-tqdm = "~=1.3" django-uuslug = "~=2.0" djangorestframework = "~=3.14" drf-spectacular = "*" -elasticsearch = "==8.11.1" +elasticsearch = "==8.12.0" elasticsearch-dsl = "~=8.9" future = "~=0.18" limit = "~=0.2" diff --git a/api/Pipfile.lock b/api/Pipfile.lock index 2b978caf7ef..f915a8aef64 100644 --- a/api/Pipfile.lock +++ b/api/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "c147881e50d7edf67d31aba14f738cd27bccf96928eabc9b42ef2d7ac8ef7134" + "sha256": "25c4c5e6a7b1f7950f8db0588c2b0db20d6b0a6acf0d1867de949604d66402f5" }, "pipfile-spec": 6, "requires": { @@ -27,86 +27,86 @@ }, "aiohttp": { "hashes": [ - "sha256:02ab6006ec3c3463b528374c4cdce86434e7b89ad355e7bf29e2f16b46c7dd6f", - "sha256:04fa38875e53eb7e354ece1607b1d2fdee2d175ea4e4d745f6ec9f751fe20c7c", - "sha256:0b0a6a36ed7e164c6df1e18ee47afbd1990ce47cb428739d6c99aaabfaf1b3af", - "sha256:0d406b01a9f5a7e232d1b0d161b40c05275ffbcbd772dc18c1d5a570961a1ca4", - "sha256:0e49b08eafa4f5707ecfb321ab9592717a319e37938e301d462f79b4e860c32a", - "sha256:0e7ba7ff228c0d9a2cd66194e90f2bca6e0abca810b786901a569c0de082f489", - "sha256:11cb254e397a82efb1805d12561e80124928e04e9c4483587ce7390b3866d213", - "sha256:11ff168d752cb41e8492817e10fb4f85828f6a0142b9726a30c27c35a1835f01", - "sha256:176df045597e674fa950bf5ae536be85699e04cea68fa3a616cf75e413737eb5", - "sha256:219a16763dc0294842188ac8a12262b5671817042b35d45e44fd0a697d8c8361", - "sha256:22698f01ff5653fe66d16ffb7658f582a0ac084d7da1323e39fd9eab326a1f26", - "sha256:237533179d9747080bcaad4d02083ce295c0d2eab3e9e8ce103411a4312991a0", - "sha256:289ba9ae8e88d0ba16062ecf02dd730b34186ea3b1e7489046fc338bdc3361c4", - "sha256:2c59e0076ea31c08553e868cec02d22191c086f00b44610f8ab7363a11a5d9d8", - "sha256:2c9376e2b09895c8ca8b95362283365eb5c03bdc8428ade80a864160605715f1", - "sha256:3135713c5562731ee18f58d3ad1bf41e1d8883eb68b363f2ffde5b2ea4b84cc7", - "sha256:3b9c7426923bb7bd66d409da46c41e3fb40f5caf679da624439b9eba92043fa6", - "sha256:3c0266cd6f005e99f3f51e583012de2778e65af6b73860038b968a0a8888487a", - "sha256:41473de252e1797c2d2293804e389a6d6986ef37cbb4a25208de537ae32141dd", - "sha256:4831df72b053b1eed31eb00a2e1aff6896fb4485301d4ccb208cac264b648db4", - "sha256:49f0c1b3c2842556e5de35f122fc0f0b721334ceb6e78c3719693364d4af8499", - "sha256:4b4c452d0190c5a820d3f5c0f3cd8a28ace48c54053e24da9d6041bf81113183", - "sha256:4ee8caa925aebc1e64e98432d78ea8de67b2272252b0a931d2ac3bd876ad5544", - "sha256:500f1c59906cd142d452074f3811614be04819a38ae2b3239a48b82649c08821", - "sha256:5216b6082c624b55cfe79af5d538e499cd5f5b976820eac31951fb4325974501", - "sha256:54311eb54f3a0c45efb9ed0d0a8f43d1bc6060d773f6973efd90037a51cd0a3f", - "sha256:54631fb69a6e44b2ba522f7c22a6fb2667a02fd97d636048478db2fd8c4e98fe", - "sha256:565760d6812b8d78d416c3c7cfdf5362fbe0d0d25b82fed75d0d29e18d7fc30f", - "sha256:598db66eaf2e04aa0c8900a63b0101fdc5e6b8a7ddd805c56d86efb54eb66672", - "sha256:5c4fa235d534b3547184831c624c0b7c1e262cd1de847d95085ec94c16fddcd5", - "sha256:69985d50a2b6f709412d944ffb2e97d0be154ea90600b7a921f95a87d6f108a2", - "sha256:69da0f3ed3496808e8cbc5123a866c41c12c15baaaead96d256477edf168eb57", - "sha256:6c93b7c2e52061f0925c3382d5cb8980e40f91c989563d3d32ca280069fd6a87", - "sha256:70907533db712f7aa791effb38efa96f044ce3d4e850e2d7691abd759f4f0ae0", - "sha256:81b77f868814346662c96ab36b875d7814ebf82340d3284a31681085c051320f", - "sha256:82eefaf1a996060602f3cc1112d93ba8b201dbf5d8fd9611227de2003dddb3b7", - "sha256:85c3e3c9cb1d480e0b9a64c658cd66b3cfb8e721636ab8b0e746e2d79a7a9eed", - "sha256:8a22a34bc594d9d24621091d1b91511001a7eea91d6652ea495ce06e27381f70", - "sha256:8cef8710fb849d97c533f259103f09bac167a008d7131d7b2b0e3a33269185c0", - "sha256:8d44e7bf06b0c0a70a20f9100af9fcfd7f6d9d3913e37754c12d424179b4e48f", - "sha256:8d7f98fde213f74561be1d6d3fa353656197f75d4edfbb3d94c9eb9b0fc47f5d", - "sha256:8d8e4450e7fe24d86e86b23cc209e0023177b6d59502e33807b732d2deb6975f", - "sha256:8fc49a87ac269d4529da45871e2ffb6874e87779c3d0e2ccd813c0899221239d", - "sha256:90ec72d231169b4b8d6085be13023ece8fa9b1bb495e4398d847e25218e0f431", - "sha256:91c742ca59045dce7ba76cab6e223e41d2c70d79e82c284a96411f8645e2afff", - "sha256:9b05d33ff8e6b269e30a7957bd3244ffbce2a7a35a81b81c382629b80af1a8bf", - "sha256:9b05d5cbe9dafcdc733262c3a99ccf63d2f7ce02543620d2bd8db4d4f7a22f83", - "sha256:9c5857612c9813796960c00767645cb5da815af16dafb32d70c72a8390bbf690", - "sha256:a34086c5cc285be878622e0a6ab897a986a6e8bf5b67ecb377015f06ed316587", - "sha256:ab221850108a4a063c5b8a70f00dd7a1975e5a1713f87f4ab26a46e5feac5a0e", - "sha256:b796b44111f0cab6bbf66214186e44734b5baab949cb5fb56154142a92989aeb", - "sha256:b8c3a67eb87394386847d188996920f33b01b32155f0a94f36ca0e0c635bf3e3", - "sha256:bcb6532b9814ea7c5a6a3299747c49de30e84472fa72821b07f5a9818bce0f66", - "sha256:bcc0ea8d5b74a41b621ad4a13d96c36079c81628ccc0b30cfb1603e3dfa3a014", - "sha256:bea94403a21eb94c93386d559bce297381609153e418a3ffc7d6bf772f59cc35", - "sha256:bff7e2811814fa2271be95ab6e84c9436d027a0e59665de60edf44e529a42c1f", - "sha256:c72444d17777865734aa1a4d167794c34b63e5883abb90356a0364a28904e6c0", - "sha256:c7b5d5d64e2a14e35a9240b33b89389e0035e6de8dbb7ffa50d10d8b65c57449", - "sha256:c7e939f1ae428a86e4abbb9a7c4732bf4706048818dfd979e5e2839ce0159f23", - "sha256:c88a15f272a0ad3d7773cf3a37cc7b7d077cbfc8e331675cf1346e849d97a4e5", - "sha256:c9110c06eaaac7e1f5562caf481f18ccf8f6fdf4c3323feab28a93d34cc646bd", - "sha256:ca7ca5abfbfe8d39e653870fbe8d7710be7a857f8a8386fc9de1aae2e02ce7e4", - "sha256:cae4c0c2ca800c793cae07ef3d40794625471040a87e1ba392039639ad61ab5b", - "sha256:cdefe289681507187e375a5064c7599f52c40343a8701761c802c1853a504558", - "sha256:cf2a0ac0615842b849f40c4d7f304986a242f1e68286dbf3bd7a835e4f83acfd", - "sha256:cfeadf42840c1e870dc2042a232a8748e75a36b52d78968cda6736de55582766", - "sha256:d737e69d193dac7296365a6dcb73bbbf53bb760ab25a3727716bbd42022e8d7a", - "sha256:d7481f581251bb5558ba9f635db70908819caa221fc79ee52a7f58392778c636", - "sha256:df9cf74b9bc03d586fc53ba470828d7b77ce51b0582d1d0b5b2fb673c0baa32d", - "sha256:e1f80197f8b0b846a8d5cf7b7ec6084493950d0882cc5537fb7b96a69e3c8590", - "sha256:ecca113f19d5e74048c001934045a2b9368d77b0b17691d905af18bd1c21275e", - "sha256:ee2527134f95e106cc1653e9ac78846f3a2ec1004cf20ef4e02038035a74544d", - "sha256:f27fdaadce22f2ef950fc10dcdf8048407c3b42b73779e48a4e76b3c35bca26c", - "sha256:f694dc8a6a3112059258a725a4ebe9acac5fe62f11c77ac4dcf896edfa78ca28", - "sha256:f800164276eec54e0af5c99feb9494c295118fc10a11b997bbb1348ba1a52065", - "sha256:ffcd828e37dc219a72c9012ec44ad2e7e3066bec6ff3aaa19e7d435dbf4032ca" + "sha256:017a21b0df49039c8f46ca0971b3a7fdc1f56741ab1240cb90ca408049766168", + "sha256:039df344b45ae0b34ac885ab5b53940b174530d4dd8a14ed8b0e2155b9dddccb", + "sha256:055ce4f74b82551678291473f66dc9fb9048a50d8324278751926ff0ae7715e5", + "sha256:06a9b2c8837d9a94fae16c6223acc14b4dfdff216ab9b7202e07a9a09541168f", + "sha256:07b837ef0d2f252f96009e9b8435ec1fef68ef8b1461933253d318748ec1acdc", + "sha256:0ed621426d961df79aa3b963ac7af0d40392956ffa9be022024cd16297b30c8c", + "sha256:0fa43c32d1643f518491d9d3a730f85f5bbaedcbd7fbcae27435bb8b7a061b29", + "sha256:1f5a71d25cd8106eab05f8704cd9167b6e5187bcdf8f090a66c6d88b634802b4", + "sha256:1f5cd333fcf7590a18334c90f8c9147c837a6ec8a178e88d90a9b96ea03194cc", + "sha256:27468897f628c627230dba07ec65dc8d0db566923c48f29e084ce382119802bc", + "sha256:298abd678033b8571995650ccee753d9458dfa0377be4dba91e4491da3f2be63", + "sha256:2c895a656dd7e061b2fd6bb77d971cc38f2afc277229ce7dd3552de8313a483e", + "sha256:361a1026c9dd4aba0109e4040e2aecf9884f5cfe1b1b1bd3d09419c205e2e53d", + "sha256:363afe77cfcbe3a36353d8ea133e904b108feea505aa4792dad6585a8192c55a", + "sha256:38a19bc3b686ad55804ae931012f78f7a534cce165d089a2059f658f6c91fa60", + "sha256:38f307b41e0bea3294a9a2a87833191e4bcf89bb0365e83a8be3a58b31fb7f38", + "sha256:3e59c23c52765951b69ec45ddbbc9403a8761ee6f57253250c6e1536cacc758b", + "sha256:4b4af9f25b49a7be47c0972139e59ec0e8285c371049df1a63b6ca81fdd216a2", + "sha256:504b6981675ace64c28bf4a05a508af5cde526e36492c98916127f5a02354d53", + "sha256:50fca156d718f8ced687a373f9e140c1bb765ca16e3d6f4fe116e3df7c05b2c5", + "sha256:522a11c934ea660ff8953eda090dcd2154d367dec1ae3c540aff9f8a5c109ab4", + "sha256:52df73f14ed99cee84865b95a3d9e044f226320a87af208f068ecc33e0c35b96", + "sha256:595f105710293e76b9dc09f52e0dd896bd064a79346234b521f6b968ffdd8e58", + "sha256:59c26c95975f26e662ca78fdf543d4eeaef70e533a672b4113dd888bd2423caa", + "sha256:5bce0dc147ca85caa5d33debc4f4d65e8e8b5c97c7f9f660f215fa74fc49a321", + "sha256:5eafe2c065df5401ba06821b9a054d9cb2848867f3c59801b5d07a0be3a380ae", + "sha256:5ed3e046ea7b14938112ccd53d91c1539af3e6679b222f9469981e3dac7ba1ce", + "sha256:5fe9ce6c09668063b8447f85d43b8d1c4e5d3d7e92c63173e6180b2ac5d46dd8", + "sha256:648056db9a9fa565d3fa851880f99f45e3f9a771dd3ff3bb0c048ea83fb28194", + "sha256:69361bfdca5468c0488d7017b9b1e5ce769d40b46a9f4a2eed26b78619e9396c", + "sha256:6b0e029353361f1746bac2e4cc19b32f972ec03f0f943b390c4ab3371840aabf", + "sha256:6b88f9386ff1ad91ace19d2a1c0225896e28815ee09fc6a8932fded8cda97c3d", + "sha256:770d015888c2a598b377bd2f663adfd947d78c0124cfe7b959e1ef39f5b13869", + "sha256:7943c414d3a8d9235f5f15c22ace69787c140c80b718dcd57caaade95f7cd93b", + "sha256:7cf5c9458e1e90e3c390c2639f1017a0379a99a94fdfad3a1fd966a2874bba52", + "sha256:7f46acd6a194287b7e41e87957bfe2ad1ad88318d447caf5b090012f2c5bb528", + "sha256:82e6aa28dd46374f72093eda8bcd142f7771ee1eb9d1e223ff0fa7177a96b4a5", + "sha256:835a55b7ca49468aaaac0b217092dfdff370e6c215c9224c52f30daaa735c1c1", + "sha256:84871a243359bb42c12728f04d181a389718710129b36b6aad0fc4655a7647d4", + "sha256:8aacb477dc26797ee089721536a292a664846489c49d3ef9725f992449eda5a8", + "sha256:8e2c45c208c62e955e8256949eb225bd8b66a4c9b6865729a786f2aa79b72e9d", + "sha256:90842933e5d1ff760fae6caca4b2b3edba53ba8f4b71e95dacf2818a2aca06f7", + "sha256:938a9653e1e0c592053f815f7028e41a3062e902095e5a7dc84617c87267ebd5", + "sha256:939677b61f9d72a4fa2a042a5eee2a99a24001a67c13da113b2e30396567db54", + "sha256:9d3c9b50f19704552f23b4eaea1fc082fdd82c63429a6506446cbd8737823da3", + "sha256:a6fe5571784af92b6bc2fda8d1925cccdf24642d49546d3144948a6a1ed58ca5", + "sha256:a78ed8a53a1221393d9637c01870248a6f4ea5b214a59a92a36f18151739452c", + "sha256:ab40e6251c3873d86ea9b30a1ac6d7478c09277b32e14745d0d3c6e76e3c7e29", + "sha256:abf151955990d23f84205286938796c55ff11bbfb4ccfada8c9c83ae6b3c89a3", + "sha256:acef0899fea7492145d2bbaaaec7b345c87753168589cc7faf0afec9afe9b747", + "sha256:b40670ec7e2156d8e57f70aec34a7216407848dfe6c693ef131ddf6e76feb672", + "sha256:b791a3143681a520c0a17e26ae7465f1b6f99461a28019d1a2f425236e6eedb5", + "sha256:b955ed993491f1a5da7f92e98d5dad3c1e14dc175f74517c4e610b1f2456fb11", + "sha256:ba39e9c8627edc56544c8628cc180d88605df3892beeb2b94c9bc857774848ca", + "sha256:bca77a198bb6e69795ef2f09a5f4c12758487f83f33d63acde5f0d4919815768", + "sha256:c3452ea726c76e92f3b9fae4b34a151981a9ec0a4847a627c43d71a15ac32aa6", + "sha256:c46956ed82961e31557b6857a5ca153c67e5476972e5f7190015018760938da2", + "sha256:c7c8b816c2b5af5c8a436df44ca08258fc1a13b449393a91484225fcb7545533", + "sha256:cd73265a9e5ea618014802ab01babf1940cecb90c9762d8b9e7d2cc1e1969ec6", + "sha256:dad46e6f620574b3b4801c68255492e0159d1712271cc99d8bdf35f2043ec266", + "sha256:dc9b311743a78043b26ffaeeb9715dc360335e5517832f5a8e339f8a43581e4d", + "sha256:df822ee7feaaeffb99c1a9e5e608800bd8eda6e5f18f5cfb0dc7eeb2eaa6bbec", + "sha256:e083c285857b78ee21a96ba1eb1b5339733c3563f72980728ca2b08b53826ca5", + "sha256:e5e46b578c0e9db71d04c4b506a2121c0cb371dd89af17a0586ff6769d4c58c1", + "sha256:e99abf0bba688259a496f966211c49a514e65afa9b3073a1fcee08856e04425b", + "sha256:ee43080e75fc92bf36219926c8e6de497f9b247301bbf88c5c7593d931426679", + "sha256:f033d80bc6283092613882dfe40419c6a6a1527e04fc69350e87a9df02bbc283", + "sha256:f1088fa100bf46e7b398ffd9904f4808a0612e1d966b4aa43baa535d1b6341eb", + "sha256:f56455b0c2c7cc3b0c584815264461d07b177f903a04481dfc33e08a89f0c26b", + "sha256:f59dfe57bb1ec82ac0698ebfcdb7bcd0e99c255bd637ff613760d5f33e7c81b3", + "sha256:f7217af2e14da0856e082e96ff637f14ae45c10a5714b63c77f26d8884cf1051", + "sha256:f734e38fd8666f53da904c52a23ce517f1b07722118d750405af7e4123933511", + "sha256:f95511dd5d0e05fd9728bac4096319f80615aaef4acbecb35a990afebe953b0e", + "sha256:fdd215b7b7fd4a53994f238d0f46b7ba4ac4c0adb12452beee724ddd0743ae5d", + "sha256:feeb18a801aacb098220e2c3eea59a512362eb408d4afd0c242044c33ad6d542", + "sha256:ff30218887e62209942f91ac1be902cc80cddb86bf00fbc6783b7a43b2bea26f" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==3.9.1" + "version": "==3.9.3" }, "aiosignal": { "hashes": [ @@ -218,7 +218,7 @@ "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956", "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357" ], - "markers": "python_version >= '3.8'", + "markers": "platform_python_implementation != 'PyPy'", "version": "==1.16.0" }, "charset-normalizer": { @@ -327,32 +327,41 @@ }, "cryptography": { "hashes": [ - "sha256:079b85658ea2f59c4f43b70f8119a52414cdb7be34da5d019a77bf96d473b960", - "sha256:09616eeaef406f99046553b8a40fbf8b1e70795a91885ba4c96a70793de5504a", - "sha256:13f93ce9bea8016c253b34afc6bd6a75993e5c40672ed5405a9c832f0d4a00bc", - "sha256:37a138589b12069efb424220bf78eac59ca68b95696fc622b6ccc1c0a197204a", - "sha256:3c78451b78313fa81607fa1b3f1ae0a5ddd8014c38a02d9db0616133987b9cdf", - "sha256:43f2552a2378b44869fe8827aa19e69512e3245a219104438692385b0ee119d1", - "sha256:48a0476626da912a44cc078f9893f292f0b3e4c739caf289268168d8f4702a39", - "sha256:49f0805fc0b2ac8d4882dd52f4a3b935b210935d500b6b805f321addc8177406", - "sha256:5429ec739a29df2e29e15d082f1d9ad683701f0ec7709ca479b3ff2708dae65a", - "sha256:5a1b41bc97f1ad230a41657d9155113c7521953869ae57ac39ac7f1bb471469a", - "sha256:68a2dec79deebc5d26d617bfdf6e8aab065a4f34934b22d3b5010df3ba36612c", - "sha256:7a698cb1dac82c35fcf8fe3417a3aaba97de16a01ac914b89a0889d364d2f6be", - "sha256:841df4caa01008bad253bce2a6f7b47f86dc9f08df4b433c404def869f590a15", - "sha256:90452ba79b8788fa380dfb587cca692976ef4e757b194b093d845e8d99f612f2", - "sha256:928258ba5d6f8ae644e764d0f996d61a8777559f72dfeb2eea7e2fe0ad6e782d", - "sha256:af03b32695b24d85a75d40e1ba39ffe7db7ffcb099fe507b39fd41a565f1b157", - "sha256:b640981bf64a3e978a56167594a0e97db71c89a479da8e175d8bb5be5178c003", - "sha256:c5ca78485a255e03c32b513f8c2bc39fedb7f5c5f8535545bdc223a03b24f248", - "sha256:c7f3201ec47d5207841402594f1d7950879ef890c0c495052fa62f58283fde1a", - "sha256:d5ec85080cce7b0513cfd233914eb8b7bbd0633f1d1703aa28d1dd5a72f678ec", - "sha256:d6c391c021ab1f7a82da5d8d0b3cee2f4b2c455ec86c8aebbc84837a631ff309", - "sha256:e3114da6d7f95d2dee7d3f4eec16dacff819740bbab931aff8648cb13c5ff5e7", - "sha256:f983596065a18a2183e7f79ab3fd4c475205b839e02cbc0efbbf9666c4b3083d" + "sha256:087887e55e0b9c8724cf05361357875adb5c20dec27e5816b653492980d20380", + "sha256:09a77e5b2e8ca732a19a90c5bca2d124621a1edb5438c5daa2d2738bfeb02589", + "sha256:130c0f77022b2b9c99d8cebcdd834d81705f61c68e91ddd614ce74c657f8b3ea", + "sha256:141e2aa5ba100d3788c0ad7919b288f89d1fe015878b9659b307c9ef867d3a65", + "sha256:28cb2c41f131a5758d6ba6a0504150d644054fd9f3203a1e8e8d7ac3aea7f73a", + "sha256:2f9f14185962e6a04ab32d1abe34eae8a9001569ee4edb64d2304bf0d65c53f3", + "sha256:320948ab49883557a256eab46149df79435a22d2fefd6a66fe6946f1b9d9d008", + "sha256:36d4b7c4be6411f58f60d9ce555a73df8406d484ba12a63549c88bd64f7967f1", + "sha256:3b15c678f27d66d247132cbf13df2f75255627bcc9b6a570f7d2fd08e8c081d2", + "sha256:3dbd37e14ce795b4af61b89b037d4bc157f2cb23e676fa16932185a04dfbf635", + "sha256:4383b47f45b14459cab66048d384614019965ba6c1a1a141f11b5a551cace1b2", + "sha256:44c95c0e96b3cb628e8452ec060413a49002a247b2b9938989e23a2c8291fc90", + "sha256:4b063d3413f853e056161eb0c7724822a9740ad3caa24b8424d776cebf98e7ee", + "sha256:52ed9ebf8ac602385126c9a2fe951db36f2cb0c2538d22971487f89d0de4065a", + "sha256:55d1580e2d7e17f45d19d3b12098e352f3a37fe86d380bf45846ef257054b242", + "sha256:5ef9bc3d046ce83c4bbf4c25e1e0547b9c441c01d30922d812e887dc5f125c12", + "sha256:5fa82a26f92871eca593b53359c12ad7949772462f887c35edaf36f87953c0e2", + "sha256:61321672b3ac7aade25c40449ccedbc6db72c7f5f0fdf34def5e2f8b51ca530d", + "sha256:701171f825dcab90969596ce2af253143b93b08f1a716d4b2a9d2db5084ef7be", + "sha256:841ec8af7a8491ac76ec5a9522226e287187a3107e12b7d686ad354bb78facee", + "sha256:8a06641fb07d4e8f6c7dda4fc3f8871d327803ab6542e33831c7ccfdcb4d0ad6", + "sha256:8e88bb9eafbf6a4014d55fb222e7360eef53e613215085e65a13290577394529", + "sha256:a00aee5d1b6c20620161984f8ab2ab69134466c51f58c052c11b076715e72929", + "sha256:a047682d324ba56e61b7ea7c7299d51e61fd3bca7dad2ccc39b72bd0118d60a1", + "sha256:a7ef8dd0bf2e1d0a27042b231a3baac6883cdd5557036f5e8df7139255feaac6", + "sha256:ad28cff53f60d99a928dfcf1e861e0b2ceb2bc1f08a074fdd601b314e1cc9e0a", + "sha256:b9097a208875fc7bbeb1286d0125d90bdfed961f61f214d3f5be62cd4ed8a446", + "sha256:b97fe7d7991c25e6a31e5d5e795986b18fbbb3107b873d5f3ae6dc9a103278e9", + "sha256:e0ec52ba3c7f1b7d813cd52649a5b3ef1fc0d433219dc8c93827c57eab6cf888", + "sha256:ea2c3ffb662fec8bbbfce5602e2c159ff097a4631d96235fcf0fb00e59e3ece4", + "sha256:fa3dec4ba8fb6e662770b74f62f1a0c7d4e37e25b58b2bf2c1be4c95372b4a33", + "sha256:fbeb725c9dc799a574518109336acccaf1303c30d45c075c665c0793c2f79a7f" ], "markers": "python_version >= '3.7'", - "version": "==41.0.7" + "version": "==42.0.2" }, "deepdiff": { "hashes": [ @@ -477,12 +486,12 @@ }, "elasticsearch": { "hashes": [ - "sha256:360b721324ce4bc7d554afb8acbf4942370e73c5ef8c4dad5f5ba3bb2a70eeae", - "sha256:a98309cee11fef8d6750f388683e9a8005da94bdfd940b36ef85cb6cc53186c7" + "sha256:58fd3876682f7529c33b9eeee701e71cfcc334bb45d725e315e22a0a5e2611fb", + "sha256:d394c5ce746bb8cb97827feae57759dae462bce34df221a6fdb6875c56476389" ], "index": "pypi", - "markers": "python_version >= '3.6'", - "version": "==8.11.1" + "markers": "python_version >= '3.7'", + "version": "==8.12.0" }, "elasticsearch-dsl": { "hashes": [ @@ -892,18 +901,18 @@ }, "python-dotenv": { "hashes": [ - "sha256:a8df96034aae6d2d50a4ebe8216326c61c3eb64836776504fcca410e5937a3ba", - "sha256:f5971a9226b701070a4bf2c38c89e5a3f0d64de8debda981d1db98583009122a" + "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca", + "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a" ], - "version": "==1.0.0" + "version": "==1.0.1" }, "python-slugify": { "hashes": [ - "sha256:70ca6ea68fe63ecc8fa4fcf00ae651fc8a5d02d93dcd12ae6d4fc7ca46c4d395", - "sha256:ce0d46ddb668b3be82f4ed5e503dbc33dd815d83e2eb6824211310d3fb172a27" + "sha256:c71189c161e8c671f1b141034d9a56308a8a5978cd13d40446c879569212fdd1", + "sha256:e04cba5f1c562502a1175c84a8bc23890c54cdaf23fccaaf0bf78511508cabed" ], "markers": "python_version >= '3.7'", - "version": "==8.0.1" + "version": "==8.0.3" }, "python-xmp-toolkit": { "hashes": [ @@ -915,10 +924,10 @@ }, "pytz": { "hashes": [ - "sha256:7b4fddbeb94a1eba4b557da24f19fdf9db575192544270a9101d8509f9f43d7b", - "sha256:ce42d816b81b68506614c11e8937d3aa9e41007ceb50bfdcb0749b921bf646c7" + "sha256:31d4583c4ed539cd037956140d695e42c033a19e984bfce9964a3f7d59bc2b40", + "sha256:f90ef520d95e7c46951105338d918664ebfd6f1d995bd7d153127ce90efafa6a" ], - "version": "==2023.3.post1" + "version": "==2023.4" }, "pyyaml": { "hashes": [ @@ -987,11 +996,11 @@ }, "referencing": { "hashes": [ - "sha256:3c57da0513e9563eb7e203ebe9bb3a1b509b042016433bd1e45a2853466c3dd3", - "sha256:7e4dc12271d8e15612bfe35792f5ea1c40970dadf8624602e33db2758f7ee554" + "sha256:39240f2ecc770258f28b642dd47fd74bc8b02484de54e1882b74b35ebd779bd5", + "sha256:c775fedf74bc0f9189c2a3be1c12fd03e8c23f4d371dce795df44e06c5b412f7" ], "markers": "python_version >= '3.8'", - "version": "==0.32.1" + "version": "==0.33.0" }, "requests": { "hashes": [ @@ -1108,11 +1117,11 @@ }, "sentry-sdk": { "hashes": [ - "sha256:24c83b0b41c887d33328a9166f5950dc37ad58f01c9f2fbff6b87a6f1094170c", - "sha256:acaf597b30258fc7663063b291aa99e58f3096e91fe1e6634f4b79f9c1943e8e" + "sha256:34ad8cfc9b877aaa2a8eb86bfe5296a467fffe0619b931a05b181c45f6da59bf", + "sha256:78575620331186d32f34b7ece6edea97ce751f58df822547d3ab85517881a27a" ], "index": "pypi", - "version": "==1.39.2" + "version": "==1.40.0" }, "six": { "hashes": [ @@ -1171,22 +1180,22 @@ }, "urllib3": { "hashes": [ - "sha256:55901e917a5896a349ff771be919f8bd99aff50b79fe58fec595eb37bbc56bb3", - "sha256:df7aa8afb0148fa78488e7899b2c59b5f4ffcfa82e6c54ccb9dd37c1d7b52d54" + "sha256:051d961ad0c62a94e50ecf1af379c3aba230c66c710493493560c0c223c49f20", + "sha256:ce3711610ddce217e6d113a2732fafad960a03fd0318c91faa79481e35c11224" ], "markers": "python_version >= '3.6'", - "version": "==2.1.0" + "version": "==2.2.0" }, "uvicorn": { "extras": [ "standard" ], "hashes": [ - "sha256:890b00f6c537d58695d3bb1f28e23db9d9e7a17cbcc76d7457c499935f933e24", - "sha256:c855578045d45625fd027367f7653d249f7c49f9361ba15cf9624186b26b8eb6" + "sha256:4b85ba02b8a20429b9b205d015cbeb788a12da527f731811b643fd739ef90d5f", + "sha256:54898fcd80c13ff1cd28bf77b04ec9dbd8ff60c5259b499b4b12bb0917f22907" ], "markers": "python_version >= '3.8'", - "version": "==0.27.0" + "version": "==0.27.0.post1" }, "uvloop": { "hashes": [ @@ -1626,11 +1635,11 @@ }, "faker": { "hashes": [ - "sha256:9a510a31090cc47a7ef7d95c1da8126a891a9d076c7e26b01ad02e1bcf915c3e", - "sha256:a4e689e2f4e62474245364bbd82cec045dcbbf85a539ee742a515fb4e93a6dd5" + "sha256:2b57f0256da6b45b7851dca87836ef5e2ae2fbb64d63d8697f1e47830d7b505d", + "sha256:fa6d969728ef3da6229da91267a1bd4e6b902044c4822012d4fc46c71bb92b26" ], "markers": "python_version >= '3.8'", - "version": "==22.5.0" + "version": "==22.6.0" }, "fakeredis": { "hashes": [ @@ -1667,12 +1676,12 @@ }, "ipython": { "hashes": [ - "sha256:2f21bd3fc1d51550c89ee3944ae04bbc7bc79e129ea0937da6e6c68bfdbf117a", - "sha256:bc9716aad6f29f36c449e30821c9dd0c1c1a7b59ddcc26931685b87b4c569619" + "sha256:1050a3ab8473488d7eee163796b02e511d0735cf43a04ba2a8348bd0f2eaf8a5", + "sha256:48fbc236fbe0e138b88773fa0437751f14c3645fb483f1d4c5dee58b37e5ce73" ], "index": "pypi", "markers": "python_version >= '3.10'", - "version": "==8.20.0" + "version": "==8.21.0" }, "jedi": { "hashes": [ @@ -1844,11 +1853,11 @@ }, "pluggy": { "hashes": [ - "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12", - "sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7" + "sha256:7db9f7b503d67d1c5b95f59773ebb58a8c1c288129a88665838012cfb07b8981", + "sha256:8c85c2876142a764e5b7548e7d9a0e0ddb46f5185161049a79b7e974454223be" ], "markers": "python_version >= '3.8'", - "version": "==1.3.0" + "version": "==1.4.0" }, "pook": { "git": "git+https://github.com/h2non/pook.git", @@ -1914,12 +1923,12 @@ }, "pytest-django": { "hashes": [ - "sha256:4e1c79d5261ade2dd58d91208017cd8f62cb4710b56e012ecd361d15d5d662a2", - "sha256:92d6fd46b1d79b54fb6b060bbb39428073396cec717d5f2e122a990d4b6aa5e8" + "sha256:5d054fe011c56f3b10f978f41a8efb2e5adfc7e680ef36fb571ada1f24779d90", + "sha256:ca1ddd1e0e4c227cf9e3e40a6afc6d106b3e70868fd2ac5798a22501271cd0c7" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==4.7.0" + "version": "==4.8.0" }, "pytest-raises": { "hashes": [ @@ -1955,11 +1964,11 @@ }, "referencing": { "hashes": [ - "sha256:3c57da0513e9563eb7e203ebe9bb3a1b509b042016433bd1e45a2853466c3dd3", - "sha256:7e4dc12271d8e15612bfe35792f5ea1c40970dadf8624602e33db2758f7ee554" + "sha256:39240f2ecc770258f28b642dd47fd74bc8b02484de54e1882b74b35ebd779bd5", + "sha256:c775fedf74bc0f9189c2a3be1c12fd03e8c23f4d371dce795df44e06c5b412f7" ], "markers": "python_version >= '3.8'", - "version": "==0.32.1" + "version": "==0.33.0" }, "remote-pdb": { "hashes": [ diff --git a/api/api/utils/image_proxy/__init__.py b/api/api/utils/image_proxy/__init__.py index 03da60f1888..21b0b302521 100644 --- a/api/api/utils/image_proxy/__init__.py +++ b/api/api/utils/image_proxy/__init__.py @@ -1,4 +1,3 @@ -import itertools import logging from dataclasses import dataclass from typing import Literal @@ -10,11 +9,9 @@ import aiohttp import django_redis -import sentry_sdk from aiohttp.client_exceptions import ClientResponseError from asgiref.sync import sync_to_async from redis.exceptions import ConnectionError -from sentry_sdk import push_scope, set_context from api.utils.aiohttp import get_aiohttp_session from api.utils.asyncio import do_not_wait_for @@ -26,8 +23,6 @@ parent_logger = logging.getLogger(__name__) -exception_iterator = itertools.count() - HEADERS = { "User-Agent": settings.OUTBOUND_USER_AGENT_TEMPLATE.format( purpose="ThumbnailGeneration" @@ -192,28 +187,10 @@ async def get( exception_name = f"{exc.__class__.__module__}.{exc.__class__.__name__}" key = f"thumbnail_error:{exception_name}:{domain}:{month}" try: - count = await tallies_incr(key) + await tallies_incr(key) except ConnectionError: logger.warning("Redis connect failed, thumbnail errors not tallied.") - # We will use a counter to space out Sentry logs. - count = next(exception_iterator) - - if count <= settings.THUMBNAIL_ERROR_INITIAL_ALERT_THRESHOLD or ( - count % settings.THUMBNAIL_ERROR_REPEATED_ALERT_FREQUENCY == 0 - ): - with push_scope() as scope: - set_context( - "upstream_url", - { - "url": upstream_url, - "params": params, - "headers": headers, - }, - ) - scope.set_tag( - "occurrences", settings.THUMBNAIL_ERROR_REPEATED_ALERT_FREQUENCY - ) - sentry_sdk.capture_exception(exc) + if isinstance(exc, ClientResponseError): status = exc.status do_not_wait_for( diff --git a/api/api/views/audio_views.py b/api/api/views/audio_views.py index dcde7266b92..9960ddb524e 100644 --- a/api/api/views/audio_views.py +++ b/api/api/views/audio_views.py @@ -15,9 +15,9 @@ source_collection, stats, tag_collection, + waveform, ) from api.docs.audio_docs import thumbnail as thumbnail_docs -from api.docs.audio_docs import waveform from api.models import Audio from api.serializers.audio_serializers import ( AudioCollectionRequestSerializer, diff --git a/api/api/views/media_views.py b/api/api/views/media_views.py index 0ae6bf66cd6..b6c3e0f3c67 100644 --- a/api/api/views/media_views.py +++ b/api/api/views/media_views.py @@ -174,8 +174,7 @@ def collection(self, request, tag, source, creator, *_, **__): @action(detail=False, methods=["get"], url_path="tag/(?P[^/.]+)") def tag_collection(self, request, tag, *_, **__): - tag_lower = tag.lower() - return self.collection(request, tag_lower, None, None) + return self.collection(request, tag, None, None) @action(detail=False, methods=["get"], url_path="source/(?P[^/.]+)") def source_collection(self, request, source, *_, **__): diff --git a/api/conf/settings/security.py b/api/conf/settings/security.py index a5159b9b701..b2e26c64b50 100644 --- a/api/conf/settings/security.py +++ b/api/conf/settings/security.py @@ -1,10 +1,10 @@ from socket import gethostbyname, gethostname -from decouple import config +from django.core.exceptions import ImproperlyConfigured -from conf.settings.base import INSTALLED_APPS, MIDDLEWARE, ENVIRONMENT +from decouple import config -from django.core.exceptions import ImproperlyConfigured +from conf.settings.base import ENVIRONMENT, INSTALLED_APPS, MIDDLEWARE # Quick-start development settings - unsuitable for production diff --git a/api/conf/settings/thumbnails.py b/api/conf/settings/thumbnails.py index 329bc222244..b5bf94a7b6b 100644 --- a/api/conf/settings/thumbnails.py +++ b/api/conf/settings/thumbnails.py @@ -15,11 +15,3 @@ # to cast them in assertions to match the parsed param types) THUMBNAIL_WIDTH_PX = config("THUMBNAIL_WIDTH_PX", default="600") THUMBNAIL_QUALITY = config("THUMBNAIL_JPG_QUALITY", default="80") - -THUMBNAIL_ERROR_INITIAL_ALERT_THRESHOLD = config( - "THUMBNAIL_ERROR_INITIAL_ALERT_THRESHOLD", default=100, cast=int -) - -THUMBNAIL_ERROR_REPEATED_ALERT_FREQUENCY = config( - "THUMBNAIL_ERROR_REPEATED_ALERT_FREQUENCY", default=1000, cast=int -) diff --git a/api/test/factory/models/audio.py b/api/test/factory/models/audio.py index 9735b2c2c1a..7f0ca49a728 100644 --- a/api/test/factory/models/audio.py +++ b/api/test/factory/models/audio.py @@ -1,10 +1,9 @@ -from test.factory.faker import Faker -from test.factory.models.media import IdentifierFactory, MediaFactory - import factory from factory.django import DjangoModelFactory from api.models.audio import Audio, AudioAddOn, AudioReport, MatureAudio +from test.factory.faker import Faker +from test.factory.models.media import IdentifierFactory, MediaFactory class MatureAudioFactory(DjangoModelFactory): diff --git a/api/test/factory/models/image.py b/api/test/factory/models/image.py index dc034ed3db0..e0758b6a6a6 100644 --- a/api/test/factory/models/image.py +++ b/api/test/factory/models/image.py @@ -1,9 +1,8 @@ -from test.factory.models.media import MediaFactory, MediaReportFactory - import factory from factory.django import DjangoModelFactory from api.models.image import Image, ImageReport, MatureImage +from test.factory.models.media import MediaFactory, MediaReportFactory class MatureImageFactory(DjangoModelFactory): diff --git a/api/test/factory/models/media.py b/api/test/factory/models/media.py index 2df54763b8d..a6e451fa825 100644 --- a/api/test/factory/models/media.py +++ b/api/test/factory/models/media.py @@ -1,4 +1,3 @@ -from test.factory.faker import Faker from uuid import uuid4 from django.conf import settings @@ -11,6 +10,7 @@ from api.constants.licenses import ALL_LICENSES from api.models.media import AbstractMedia +from test.factory.faker import Faker CREATED_BY_FIXTURE_MARKER = "__created_by_test_fixture" diff --git a/api/test/factory/models/oauth2.py b/api/test/factory/models/oauth2.py index 6a749654e39..22b3a697446 100644 --- a/api/test/factory/models/oauth2.py +++ b/api/test/factory/models/oauth2.py @@ -1,5 +1,3 @@ -from test.factory.faker import Faker - from django.utils import timezone import factory @@ -11,6 +9,7 @@ OAuth2Verification, ThrottledApplication, ) +from test.factory.faker import Faker class ThrottledApplicationFactory(DjangoModelFactory): diff --git a/api/test/media_integration.py b/api/test/media_integration.py index 0a4563344ae..2ca5eb699c9 100644 --- a/api/test/media_integration.py +++ b/api/test/media_integration.py @@ -6,10 +6,11 @@ import json import re -from test.constants import API_URL import requests +from test.constants import API_URL + def search(fixture): """Return results for test query.""" @@ -27,14 +28,14 @@ def search_by_category(media_path, category, fixture): assert all(audio_item["category"] == category for audio_item in results) -def tag_collection(media_path): - response = requests.get(f"{API_URL}/v1/{media_path}/tag/cat") +def tag_collection(media_path, tag="cat"): + response = requests.get(f"{API_URL}/v1/{media_path}/tag/{tag}") assert response.status_code == 200 results = response.json()["results"] for r in results: tag_names = [tag["name"] for tag in r["tags"]] - assert "cat" in tag_names + assert tag in tag_names def source_collection(media_path): diff --git a/api/test/test_audio_integration.py b/api/test/test_audio_integration.py index a172a1275bb..6bf1796d682 100644 --- a/api/test/test_audio_integration.py +++ b/api/test/test_audio_integration.py @@ -6,6 +6,12 @@ """ import json + +import pytest +import requests +from django_redis import get_redis_connection + +from api.utils.check_dead_links import CACHE_PREFIX from test.constants import API_URL from test.media_integration import ( creator_collection, @@ -28,12 +34,6 @@ uuid_validation, ) -import pytest -import requests -from django_redis import get_redis_connection - -from api.utils.check_dead_links import CACHE_PREFIX - @pytest.fixture def force_result_validity(): diff --git a/api/test/test_auth.py b/api/test/test_auth.py index 117193bbaeb..752c848fed4 100644 --- a/api/test/test_auth.py +++ b/api/test/test_auth.py @@ -1,6 +1,6 @@ import time import uuid -from test.constants import API_URL +from unittest.mock import patch from django.urls import reverse from django.utils.http import urlencode @@ -9,7 +9,8 @@ from oauth2_provider.models import AccessToken from api.models import OAuth2Verification, ThrottledApplication -from unittest.mock import patch +from test.constants import API_URL + cache_availability_params = pytest.mark.parametrize( "is_cache_reachable, cache_name", diff --git a/api/test/test_backwards_compat.py b/api/test/test_backwards_compat.py index fe1ebe9c843..4250aa5d049 100644 --- a/api/test/test_backwards_compat.py +++ b/api/test/test_backwards_compat.py @@ -6,10 +6,11 @@ """ import uuid -from test.constants import API_URL import requests +from test.constants import API_URL + def test_old_stats_endpoint(): response = requests.get( diff --git a/api/test/test_dead_link_filter.py b/api/test/test_dead_link_filter.py index f767023b3c0..caa4600fb7a 100644 --- a/api/test/test_dead_link_filter.py +++ b/api/test/test_dead_link_filter.py @@ -1,4 +1,3 @@ -from test.constants import API_URL from unittest.mock import patch from uuid import uuid4 @@ -8,6 +7,7 @@ import requests from api.controllers.elasticsearch.helpers import DEAD_LINK_RATIO +from test.constants import API_URL @pytest.fixture diff --git a/api/test/test_examples.py b/api/test/test_examples.py index 203b04d6ca5..e7ff9d648e1 100644 --- a/api/test/test_examples.py +++ b/api/test/test_examples.py @@ -1,10 +1,11 @@ import json import os import subprocess -from test.constants import API_URL import pytest +from test.constants import API_URL + os.environ["AUDIO_REQ_TOKEN"] = "" os.environ["AUDIO_REQ_ORIGIN"] = API_URL diff --git a/api/test/test_image_integration.py b/api/test/test_image_integration.py index 3e2df768bf0..34dcb840b87 100644 --- a/api/test/test_image_integration.py +++ b/api/test/test_image_integration.py @@ -6,6 +6,11 @@ """ import json +from urllib.parse import urlencode + +import pytest +import requests + from test.constants import API_URL from test.media_integration import ( creator_collection, @@ -26,10 +31,6 @@ tag_collection, uuid_validation, ) -from urllib.parse import urlencode - -import pytest -import requests identifier = "cdbd3bf6-1745-45bb-b399-61ee149cd58a" @@ -146,7 +147,11 @@ def test_image_uuid_validation(): def test_image_tag_collection(): - tag_collection("images") + tag_collection("images", "cat") + + +def test_image_tag_collection_case_sensitive(): + tag_collection("images", "Cat") def test_image_source_collection(): diff --git a/api/test/test_v1_integration.py b/api/test/test_v1_integration.py index 752584292fc..b29c57f4a8f 100644 --- a/api/test/test_v1_integration.py +++ b/api/test/test_v1_integration.py @@ -6,7 +6,6 @@ """ import json -from test.constants import API_URL import pytest import requests @@ -14,6 +13,7 @@ from api.constants.licenses import LICENSE_GROUPS from api.models import Image from api.utils.watermark import watermark +from test.constants import API_URL @pytest.fixture diff --git a/api/test/unit/conftest.py b/api/test/unit/conftest.py index 213dafd0ca9..ad70cd77965 100644 --- a/api/test/unit/conftest.py +++ b/api/test/unit/conftest.py @@ -1,10 +1,4 @@ from dataclasses import dataclass -from test.factory import models as model_factories -from test.factory.models.media import ( - CREATED_BY_FIXTURE_MARKER, - MediaFactory, - MediaReportFactory, -) from unittest.mock import MagicMock from rest_framework.test import APIClient, APIRequestFactory @@ -37,6 +31,12 @@ MediaSearchRequestSerializer, MediaSerializer, ) +from test.factory import models as model_factories +from test.factory.models.media import ( + CREATED_BY_FIXTURE_MARKER, + MediaFactory, + MediaReportFactory, +) @pytest.fixture diff --git a/api/test/unit/controllers/elasticsearch/test_related.py b/api/test/unit/controllers/elasticsearch/test_related.py index 8da59714ecf..23370f3dd0b 100644 --- a/api/test/unit/controllers/elasticsearch/test_related.py +++ b/api/test/unit/controllers/elasticsearch/test_related.py @@ -1,9 +1,3 @@ -from test.factory.es_http import ( - MOCK_LIVE_RESULT_URL_PREFIX, - create_mock_es_http_image_response_with_identifier, - create_mock_es_http_image_search_response, -) -from test.factory.models import ImageFactory from unittest import mock import pook @@ -14,6 +8,12 @@ FILTERED_PROVIDERS_CACHE_KEY, FILTERED_PROVIDERS_CACHE_VERSION, ) +from test.factory.es_http import ( + MOCK_LIVE_RESULT_URL_PREFIX, + create_mock_es_http_image_response_with_identifier, + create_mock_es_http_image_search_response, +) +from test.factory.models import ImageFactory pytestmark = pytest.mark.django_db diff --git a/api/test/unit/controllers/test_search_controller.py b/api/test/unit/controllers/test_search_controller.py index 652c43ea0f6..f64d3fa3919 100644 --- a/api/test/unit/controllers/test_search_controller.py +++ b/api/test/unit/controllers/test_search_controller.py @@ -4,12 +4,6 @@ import re from collections.abc import Callable from enum import Enum, auto -from test.factory.es_http import ( - MOCK_DEAD_RESULT_URL_PREFIX, - MOCK_LIVE_RESULT_URL_PREFIX, - create_mock_es_http_image_search_response, -) -from test.factory.models.content_provider import ContentProviderFactory from unittest import mock from unittest.mock import patch from uuid import uuid4 @@ -26,6 +20,12 @@ from api.utils import tallies from api.utils.dead_link_mask import get_query_hash, save_query_mask from api.utils.search_context import SearchContext +from test.factory.es_http import ( + MOCK_DEAD_RESULT_URL_PREFIX, + MOCK_LIVE_RESULT_URL_PREFIX, + create_mock_es_http_image_search_response, +) +from test.factory.models.content_provider import ContentProviderFactory pytestmark = pytest.mark.django_db diff --git a/api/test/unit/management/commands/test_generatewaveforms.py b/api/test/unit/management/commands/test_generatewaveforms.py index bc12a9669d0..c7ca58c6c42 100644 --- a/api/test/unit/management/commands/test_generatewaveforms.py +++ b/api/test/unit/management/commands/test_generatewaveforms.py @@ -1,7 +1,5 @@ import subprocess from io import StringIO -from test.factory.faker import WaveformProvider -from test.factory.models.audio import AudioAddOnFactory, AudioFactory from unittest import mock from django.core.management import call_command @@ -12,6 +10,8 @@ from psycopg.errors import NotNullViolation from api.models.audio import Audio, AudioAddOn +from test.factory.faker import WaveformProvider +from test.factory.models.audio import AudioAddOnFactory, AudioFactory @mock.patch("api.models.audio.generate_peaks") diff --git a/api/test/unit/models/test_audio.py b/api/test/unit/models/test_audio.py index 6a1b0e8c546..3372c6b0e98 100644 --- a/api/test/unit/models/test_audio.py +++ b/api/test/unit/models/test_audio.py @@ -1,10 +1,10 @@ import uuid -from test.factory.faker import WaveformProvider from unittest import mock import pytest from api.models.audio import Audio, AudioAddOn +from test.factory.faker import WaveformProvider @pytest.fixture diff --git a/api/test/unit/serializers/test_media_serializers.py b/api/test/unit/serializers/test_media_serializers.py index d48798c40cb..b6819e3c43d 100644 --- a/api/test/unit/serializers/test_media_serializers.py +++ b/api/test/unit/serializers/test_media_serializers.py @@ -1,6 +1,5 @@ import random import uuid -from test.factory.models.oauth2 import AccessTokenFactory from unittest.mock import MagicMock, patch from django.conf import settings @@ -14,6 +13,7 @@ from api.serializers.audio_serializers import AudioSearchRequestSerializer from api.serializers.image_serializers import ImageSearchRequestSerializer from api.serializers.media_serializers import MediaSearchRequestSerializer +from test.factory.models.oauth2 import AccessTokenFactory @pytest.fixture diff --git a/api/test/unit/utils/test_image_proxy.py b/api/test/unit/utils/test_image_proxy.py index 5cf0e2833a9..8b5401e5371 100644 --- a/api/test/unit/utils/test_image_proxy.py +++ b/api/test/unit/utils/test_image_proxy.py @@ -1,8 +1,5 @@ import asyncio -import itertools from dataclasses import replace -from test.factory.models.image import ImageFactory -from unittest.mock import patch from urllib.parse import urlencode from django.conf import settings @@ -23,6 +20,7 @@ ) from api.utils.image_proxy import get as _photon_get from api.utils.tallies import get_monthly_timestamp +from test.factory.models.image import ImageFactory TEST_IMAGE_DOMAIN = "subdomain.example.com" @@ -331,18 +329,8 @@ def test_get_successful_records_response_code( alert_count_params = pytest.mark.parametrize( - "count_start, should_alert", - [ - (0, True), - (1, True), - (50, True), - (99, True), - (100, False), - (999, True), - (1000, False), - (1500, False), - (1999, True), - ], + "count_start", + [0, 1, 999], ) MOCK_CONNECTION_KEY = ConnectionKey( @@ -385,7 +373,6 @@ def test_get_exception_handles_error( exc, exc_name, count_start, - should_alert, sentry_capture_exception, setup_request_exception, is_cache_reachable, @@ -401,20 +388,10 @@ def test_get_exception_handles_error( if is_cache_reachable: cache.set(key, count_start) - with ( - pytest.raises(UpstreamThumbnailException), - patch( - "api.utils.image_proxy.exception_iterator", itertools.count(count_start + 1) - ), - ): + with pytest.raises(UpstreamThumbnailException): photon_get(TEST_MEDIA_INFO) - assert_func = ( - sentry_capture_exception.assert_called_once - if should_alert - else sentry_capture_exception.assert_not_called - ) - assert_func() + sentry_capture_exception.assert_not_called() if is_cache_reachable: assert cache.get(key) == str(count_start + 1).encode() @@ -438,7 +415,6 @@ def test_get_http_exception_handles_error( status_code, text, count_start, - should_alert, sentry_capture_exception, is_cache_reachable, cache_name, @@ -452,19 +428,12 @@ def test_get_http_exception_handles_error( if is_cache_reachable: cache.set(key, count_start) - with pytest.raises(UpstreamThumbnailException), patch( - "api.utils.image_proxy.exception_iterator", itertools.count(count_start + 1) - ): + with pytest.raises(UpstreamThumbnailException): with pook.use(): pook.get(PHOTON_URL_FOR_TEST_IMAGE).reply(status_code, text) photon_get(TEST_MEDIA_INFO) - assert_func = ( - sentry_capture_exception.assert_called_once - if should_alert - else sentry_capture_exception.assert_not_called - ) - assert_func() + sentry_capture_exception.assert_not_called() if is_cache_reachable: assert cache.get(key) == str(count_start + 1).encode() diff --git a/api/test/unit/utils/test_throttle.py b/api/test/unit/utils/test_throttle.py index 531aecf441e..1afdaff5325 100644 --- a/api/test/unit/utils/test_throttle.py +++ b/api/test/unit/utils/test_throttle.py @@ -1,6 +1,3 @@ -from test.factory.models.image import ImageFactory -from test.factory.models.oauth2 import AccessTokenFactory - from django.http import HttpResponse from rest_framework.settings import api_settings from rest_framework.test import force_authenticate @@ -10,6 +7,8 @@ from api.utils import throttle from api.views.media_views import MediaViewSet +from test.factory.models.image import ImageFactory +from test.factory.models.oauth2 import AccessTokenFactory cache_availability_params = pytest.mark.parametrize( diff --git a/api/test/unit/views/test_image_views.py b/api/test/unit/views/test_image_views.py index 235c56d4464..0fe9aa82aa9 100644 --- a/api/test/unit/views/test_image_views.py +++ b/api/test/unit/views/test_image_views.py @@ -1,6 +1,5 @@ import json from pathlib import Path -from test.factory.models.image import ImageFactory from unittest.mock import patch import pook @@ -8,6 +7,7 @@ from PIL import UnidentifiedImageError from api.views.image_views import ImageViewSet +from test.factory.models.image import ImageFactory _MOCK_IMAGE_PATH = Path(__file__).parent / ".." / ".." / "factory" diff --git a/automations/python/Pipfile.lock b/automations/python/Pipfile.lock index e490e4a11bd..6fdc586fede 100644 --- a/automations/python/Pipfile.lock +++ b/automations/python/Pipfile.lock @@ -88,7 +88,7 @@ "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956", "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357" ], - "markers": "python_version >= '3.8'", + "markers": "platform_python_implementation != 'PyPy'", "version": "==1.16.0" }, "charset-normalizer": { @@ -189,33 +189,42 @@ }, "cryptography": { "hashes": [ - "sha256:068bc551698c234742c40049e46840843f3d98ad7ce265fd2bd4ec0d11306596", - "sha256:0f27acb55a4e77b9be8d550d762b0513ef3fc658cd3eb15110ebbcbd626db12c", - "sha256:2132d5865eea673fe6712c2ed5fb4fa49dba10768bb4cc798345748380ee3660", - "sha256:3288acccef021e3c3c10d58933f44e8602cf04dba96d9796d70d537bb2f4bbc4", - "sha256:35f3f288e83c3f6f10752467c48919a7a94b7d88cc00b0668372a0d2ad4f8ead", - "sha256:398ae1fc711b5eb78e977daa3cbf47cec20f2c08c5da129b7a296055fbb22aed", - "sha256:422e3e31d63743855e43e5a6fcc8b4acab860f560f9321b0ee6269cc7ed70cc3", - "sha256:48783b7e2bef51224020efb61b42704207dde583d7e371ef8fc2a5fb6c0aabc7", - "sha256:4d03186af98b1c01a4eda396b137f29e4e3fb0173e30f885e27acec8823c1b09", - "sha256:5daeb18e7886a358064a68dbcaf441c036cbdb7da52ae744e7b9207b04d3908c", - "sha256:60e746b11b937911dc70d164060d28d273e31853bb359e2b2033c9e93e6f3c43", - "sha256:742ae5e9a2310e9dade7932f9576606836ed174da3c7d26bc3d3ab4bd49b9f65", - "sha256:7e00fb556bda398b99b0da289ce7053639d33b572847181d6483ad89835115f6", - "sha256:85abd057699b98fce40b41737afb234fef05c67e116f6f3650782c10862c43da", - "sha256:8efb2af8d4ba9dbc9c9dd8f04d19a7abb5b49eab1f3694e7b5a16a5fc2856f5c", - "sha256:ae236bb8760c1e55b7a39b6d4d32d2279bc6c7c8500b7d5a13b6fb9fc97be35b", - "sha256:afda76d84b053923c27ede5edc1ed7d53e3c9f475ebaf63c68e69f1403c405a8", - "sha256:b27a7fd4229abef715e064269d98a7e2909ebf92eb6912a9603c7e14c181928c", - "sha256:b648fe2a45e426aaee684ddca2632f62ec4613ef362f4d681a9a6283d10e079d", - "sha256:c5a550dc7a3b50b116323e3d376241829fd326ac47bc195e04eb33a8170902a9", - "sha256:da46e2b5df770070412c46f87bac0849b8d685c5f2679771de277a422c7d0b86", - "sha256:f39812f70fc5c71a15aa3c97b2bbe213c3f2a460b79bd21c40d033bb34a9bf36", - "sha256:ff369dd19e8fe0528b02e8df9f2aeb2479f89b1270d90f96a63500afe9af5cae" + "sha256:0a68bfcf57a6887818307600c3c0ebc3f62fbb6ccad2240aa21887cda1f8df1b", + "sha256:146e971e92a6dd042214b537a726c9750496128453146ab0ee8971a0299dc9bd", + "sha256:14e4b909373bc5bf1095311fa0f7fcabf2d1a160ca13f1e9e467be1ac4cbdf94", + "sha256:206aaf42e031b93f86ad60f9f5d9da1b09164f25488238ac1dc488334eb5e221", + "sha256:3005166a39b70c8b94455fdbe78d87a444da31ff70de3331cdec2c568cf25b7e", + "sha256:324721d93b998cb7367f1e6897370644751e5580ff9b370c0a50dc60a2003513", + "sha256:33588310b5c886dfb87dba5f013b8d27df7ffd31dc753775342a1e5ab139e59d", + "sha256:35cf6ed4c38f054478a9df14f03c1169bb14bd98f0b1705751079b25e1cb58bc", + "sha256:3ca482ea80626048975360c8e62be3ceb0f11803180b73163acd24bf014133a0", + "sha256:56ce0c106d5c3fec1038c3cca3d55ac320a5be1b44bf15116732d0bc716979a2", + "sha256:5a217bca51f3b91971400890905a9323ad805838ca3fa1e202a01844f485ee87", + "sha256:678cfa0d1e72ef41d48993a7be75a76b0725d29b820ff3cfd606a5b2b33fda01", + "sha256:69fd009a325cad6fbfd5b04c711a4da563c6c4854fc4c9544bff3088387c77c0", + "sha256:6cf9b76d6e93c62114bd19485e5cb003115c134cf9ce91f8ac924c44f8c8c3f4", + "sha256:74f18a4c8ca04134d2052a140322002fef535c99cdbc2a6afc18a8024d5c9d5b", + "sha256:85f759ed59ffd1d0baad296e72780aa62ff8a71f94dc1ab340386a1207d0ea81", + "sha256:87086eae86a700307b544625e3ba11cc600c3c0ef8ab97b0fda0705d6db3d4e3", + "sha256:8814722cffcfd1fbd91edd9f3451b88a8f26a5fd41b28c1c9193949d1c689dc4", + "sha256:8fedec73d590fd30c4e3f0d0f4bc961aeca8390c72f3eaa1a0874d180e868ddf", + "sha256:9515ea7f596c8092fdc9902627e51b23a75daa2c7815ed5aa8cf4f07469212ec", + "sha256:988b738f56c665366b1e4bfd9045c3efae89ee366ca3839cd5af53eaa1401bce", + "sha256:a2a8d873667e4fd2f34aedab02ba500b824692c6542e017075a2efc38f60a4c0", + "sha256:bd7cf7a8d9f34cc67220f1195884151426ce616fdc8285df9054bfa10135925f", + "sha256:bdce70e562c69bb089523e75ef1d9625b7417c6297a76ac27b1b8b1eb51b7d0f", + "sha256:be14b31eb3a293fc6e6aa2807c8a3224c71426f7c4e3639ccf1a2f3ffd6df8c3", + "sha256:be41b0c7366e5549265adf2145135dca107718fa44b6e418dc7499cfff6b4689", + "sha256:c310767268d88803b653fffe6d6f2f17bb9d49ffceb8d70aed50ad45ea49ab08", + "sha256:c58115384bdcfe9c7f644c72f10f6f42bed7cf59f7b52fe1bf7ae0a622b3a139", + "sha256:c640b0ef54138fde761ec99a6c7dc4ce05e80420262c20fa239e694ca371d434", + "sha256:ca20550bb590db16223eb9ccc5852335b48b8f597e2f6f0878bbfd9e7314eb17", + "sha256:d97aae66b7de41cdf5b12087b5509e4e9805ed6f562406dfcf60e8481a9a28f8", + "sha256:e9326ca78111e4c645f7e49cbce4ed2f3f85e17b61a563328c85a5208cf34440" ], "index": "pypi", "markers": "python_version >= '3.7'", - "version": "==41.0.6" + "version": "==42.0.0" }, "deprecated": { "hashes": [ diff --git a/automations/python/models/label.py b/automations/python/models/label.py index 0340cd97e60..edbed65a4db 100644 --- a/automations/python/models/label.py +++ b/automations/python/models/label.py @@ -1,6 +1,7 @@ -from models.label_group import LabelGroup from shared.data import get_data +from models.label_group import LabelGroup + class Label: diff --git a/automations/python/shared/labels.py b/automations/python/shared/labels.py index 07dd412364b..04532e123f2 100644 --- a/automations/python/shared/labels.py +++ b/automations/python/shared/labels.py @@ -2,6 +2,7 @@ from models.label import Label from models.label_group import LabelGroup + from shared.data import get_data diff --git a/automations/python/workflows/set_matrix_images.py b/automations/python/workflows/set_matrix_images.py index cbaddce1511..acc4e4cf1ff 100644 --- a/automations/python/workflows/set_matrix_images.py +++ b/automations/python/workflows/set_matrix_images.py @@ -55,6 +55,7 @@ def ser_set(x): build_matrix["image"] |= {"frontend", "frontend_nginx"} publish_matrix["image"] |= {"frontend", "frontend_nginx"} + build_matrix["include"] = [includes[item] for item in build_matrix["image"]] for item in build_matrix["include"]: diff --git a/catalog/dags/database/delete_records/delete_records.py b/catalog/dags/database/delete_records/delete_records.py index 8cdc383f9b1..ba08db72543 100644 --- a/catalog/dags/database/delete_records/delete_records.py +++ b/catalog/dags/database/delete_records/delete_records.py @@ -7,7 +7,7 @@ from common import slack from common.constants import POSTGRES_CONN_ID from common.sql import RETURN_ROW_COUNT, PostgresHook -from common.storage.columns import DELETED_ON, Column, PROVIDER, FOREIGN_ID +from common.storage.columns import DELETED_ON, FOREIGN_ID, PROVIDER, Column from common.storage.db_columns import ( setup_db_columns_for_media_type, setup_deleted_db_columns_for_media_type, diff --git a/catalog/dags/elasticsearch_cluster/create_new_es_index/create_new_es_index_dag.py b/catalog/dags/elasticsearch_cluster/create_new_es_index/create_new_es_index_dag.py index 39f23f0d92d..ad4c3229c3a 100644 --- a/catalog/dags/elasticsearch_cluster/create_new_es_index/create_new_es_index_dag.py +++ b/catalog/dags/elasticsearch_cluster/create_new_es_index/create_new_es_index_dag.py @@ -110,6 +110,7 @@ CreateNewIndex, ) + logger = logging.getLogger(__name__) diff --git a/catalog/dags/popularity/popularity_refresh_dag_factory.py b/catalog/dags/popularity/popularity_refresh_dag_factory.py index ae7a11720dc..d8f05b4336e 100644 --- a/catalog/dags/popularity/popularity_refresh_dag_factory.py +++ b/catalog/dags/popularity/popularity_refresh_dag_factory.py @@ -28,16 +28,16 @@ from airflow import DAG from airflow.decorators import task from airflow.operators.trigger_dagrun import TriggerDagRunOperator + +from common import slack +from common.constants import DAG_DEFAULT_ARGS, POSTGRES_CONN_ID +from database.batched_update.constants import DAG_ID as BATCHED_UPDATE_DAG_ID from popularity import sql from popularity.popularity_refresh_types import ( POPULARITY_REFRESH_CONFIGS, PopularityRefresh, ) -from common import slack -from common.constants import DAG_DEFAULT_ARGS, POSTGRES_CONN_ID -from database.batched_update.constants import DAG_ID as BATCHED_UPDATE_DAG_ID - logger = logging.getLogger(__name__) diff --git a/catalog/dags/popularity/recreate_popularity_calculation_dag_factory.py b/catalog/dags/popularity/recreate_popularity_calculation_dag_factory.py index 31261ec38fc..f8662b06b02 100644 --- a/catalog/dags/popularity/recreate_popularity_calculation_dag_factory.py +++ b/catalog/dags/popularity/recreate_popularity_calculation_dag_factory.py @@ -13,14 +13,14 @@ SQL code is deployed for the calculation. """ from airflow import DAG + +from common.constants import DAG_DEFAULT_ARGS, POSTGRES_CONN_ID from popularity import sql from popularity.popularity_refresh_types import ( POPULARITY_REFRESH_CONFIGS, PopularityRefresh, ) -from common.constants import DAG_DEFAULT_ARGS, POSTGRES_CONN_ID - def create_recreate_popularity_calculation_dag(popularity_refresh: PopularityRefresh): media_type = popularity_refresh.media_type diff --git a/catalog/dags/popularity/sql.py b/catalog/dags/popularity/sql.py index bacf3bf6291..388bd02f92c 100644 --- a/catalog/dags/popularity/sql.py +++ b/catalog/dags/popularity/sql.py @@ -4,12 +4,12 @@ from airflow.decorators import task, task_group from airflow.models.abstractoperator import AbstractOperator -from popularity.popularity_refresh_types import PopularityRefresh from common.constants import DAG_DEFAULT_ARGS, SQLInfo from common.sql import PostgresHook, single_value from common.storage import columns as col from common.utils import setup_sql_info_for_media_type +from popularity.popularity_refresh_types import PopularityRefresh DEFAULT_PERCENTILE = 0.85 diff --git a/catalog/dags/providers/provider_api_scripts/inaturalist.py b/catalog/dags/providers/provider_api_scripts/inaturalist.py index 532ba0f92d5..81443cf2f6a 100644 --- a/catalog/dags/providers/provider_api_scripts/inaturalist.py +++ b/catalog/dags/providers/provider_api_scripts/inaturalist.py @@ -7,7 +7,7 @@ https://api.inaturalist.org/v1/docs/ But there is a full dump intended for sharing on S3. https://github.com/inaturalist/inaturalist-open-data/tree/documentation/Metadata - Because these are very large normalized tables, as opposed to more document + Because these are exceptionally large normalized tables, as opposed to more document oriented API responses, we found that bringing the data into postgres first was the most effective approach. More detail in slack here: https://wordpress.slack.com/archives/C02012JB00N/p1653145643080479?thread_ts=1653082292.714469&cid=C02012JB00N diff --git a/catalog/dags/providers/provider_dag_factory.py b/catalog/dags/providers/provider_dag_factory.py index 65f94b8078c..1e5a5d04068 100644 --- a/catalog/dags/providers/provider_dag_factory.py +++ b/catalog/dags/providers/provider_dag_factory.py @@ -76,9 +76,8 @@ from airflow.utils.task_group import TaskGroup from airflow.utils.trigger_rule import TriggerRule -from common.constants import AWS_CONN_ID, DAG_DEFAULT_ARGS +from common.constants import AWS_CONN_ID, DAG_DEFAULT_ARGS, XCOM_PULL_TEMPLATE from common.constants import POSTGRES_CONN_ID as DB_CONN_ID -from common.constants import XCOM_PULL_TEMPLATE from common.loader import loader, reporting, s3, sql from providers.factory_utils import date_partition_for_prefix, pull_media_wrapper from providers.provider_reingestion_workflows import ProviderReingestionWorkflow diff --git a/catalog/docs/data_models.md b/catalog/docs/data_models.md index cc1e78cf2b2..96d16085dc6 100644 --- a/catalog/docs/data_models.md +++ b/catalog/docs/data_models.md @@ -1,6 +1,8 @@ -__ +> **Note** +> +> This documentation is temporary and should be replaced by more thorough +> documentation of our DB fields in +> https://github.com/WordPress/openverse/issues/412. # Data Models diff --git a/catalog/docs/provider_data_ingester_faq.md b/catalog/docs/provider_data_ingester_faq.md index b6848faab7d..64a9ea541d3 100644 --- a/catalog/docs/provider_data_ingester_faq.md +++ b/catalog/docs/provider_data_ingester_faq.md @@ -63,8 +63,10 @@ def get_record_data(self, data: dict) -> dict | list[dict] | None: ... ``` -**NOTE**: When doing this, keep in mind that adding too many requests may slow -down ingestion. Be aware of rate limits from your provider API as well. +> **Note** +> +> When doing this, keep in mind that adding too many requests may slow down +> ingestion. Be aware of rate limits from your provider API as well. ## What if my API endpoint isn't static and needs to change from one request to another? diff --git a/catalog/justfile b/catalog/justfile index 5bf3859d913..c11f6bc2913 100644 --- a/catalog/justfile +++ b/catalog/justfile @@ -134,7 +134,7 @@ generate-dag-docs fail_on_diff="false": echo "Done!" if {{ fail_on_diff }}; then set +e - git diff --exit-code -- documentation/catalog/reference/DAGs.md + git diff --exit-code -- ../documentation/catalog/reference/DAGs.md if [ $? -ne 0 ]; then printf "\n\n\e[31m!! Changes found in DAG documentation, please run 'just generate-dag-docs' locally and commit difference !!\n\n" exit 1 diff --git a/catalog/requirements-dev.txt b/catalog/requirements-dev.txt index b84e71be18a..972be24b3c3 100644 --- a/catalog/requirements-dev.txt +++ b/catalog/requirements-dev.txt @@ -4,7 +4,7 @@ flaky==3.7.0 ipython -pook==1.1.1 +pook==1.4.0 pytest-env pytest-mock pytest-raises==0.11 diff --git a/docker-compose.yml b/docker-compose.yml index 4c40c6df731..7e87d00e6a5 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -186,7 +186,7 @@ services: cache: profiles: - api - image: docker.io/redis:7.2.3 + image: docker.io/redis:7.2.4 ports: - "50263:6379" diff --git a/documentation/api/guides/https.md b/documentation/api/guides/https.md index 13d4d3cd085..e23949fe393 100644 --- a/documentation/api/guides/https.md +++ b/documentation/api/guides/https.md @@ -18,8 +18,8 @@ Additionally, you will need to install 1. Create certificates for NGINX to use. - ```console - $ just docker/nginx/cert + ```bash + just docker/nginx/cert ``` This will create a certificate file `openversse.crt` and a key file @@ -28,8 +28,8 @@ Additionally, you will need to install 2. Bring the ingestion server and API up, along with all their dependent services. - ```console - $ just api/up + ```bash + just api/up ``` The `api/up` recipe orchestrates the following services: `cache`, `db`, @@ -40,8 +40,8 @@ Additionally, you will need to install 3. Make an API call over HTTPS. - ```console - $ just api/stats images https://localhost:50243 + ```bash + just api/stats images https://localhost:50243 just _curl-get "images/stats/" https://localhost:50243 curl "https://localhost:50243/v1/images/stats/" [{"source_name":"flickr","display_name":"Flickr","source_url":"https://www.flickr.com","logo_url":null,"media_count":2500},{"source_name":"stocksnap","display_name":"StockSnap","source_url":"https://stocksnap.io","logo_url":null,"media_count":2500}]% diff --git a/documentation/api/guides/quickstart.md b/documentation/api/guides/quickstart.md index 1efaf7de156..dbab0768ed5 100644 --- a/documentation/api/guides/quickstart.md +++ b/documentation/api/guides/quickstart.md @@ -17,25 +17,25 @@ you need to run this. 2. Clone the repository to your computer. Then switch to the cloned directory. If you're planning to contribute, fork the repo and clone your fork instead. - ```console - $ git clone https://github.com/WordPress/openverse.git # or your fork - $ cd openverse/ + ```bash + git clone https://github.com/WordPress/openverse.git # or your fork + cd openverse/ ``` If you followed the general setup guide and installed [GitHub CLI](/general/general_setup.md#github-cli), you can clone more simply using the `gh` command. - ```console - $ gh repo clone WordPress/openverse # or your fork - $ cd openverse/ + ```bash + gh repo clone WordPress/openverse # or your fork + cd openverse/ ``` 3. Bring the ingestion server and API up, along with all their dependent services. - ```console - $ just api/up + ```bash + just api/up ``` The `api/up` recipe orchestrates the following services: `cache`, `db`, @@ -49,24 +49,24 @@ you need to run this. 4. Load the sample data. This step can take a few minutes to complete. - ```console - $ just api/init + ```bash + just api/init ``` ````{admonition} Troubleshooting If this step fails, cleaning up and restarting usually fixes it. - ```console - $ just down -v - $ just api/init + ```bash + just down -v + just api/init ``` ```` 5. With the data loaded, the API can now return JSON responses to your HTTP requests. - ```console - $ just api/stats + ```bash + just api/stats just _curl-get "images/stats/" http://localhost:50280 curl "http://localhost:50280/v1/images/stats/" [{"source_name":"flickr","display_name":"Flickr","source_url":"https://www.flickr.com","logo_url":null,"media_count":2500},{"source_name":"stocksnap","display_name":"StockSnap","source_url":"https://stocksnap.io","logo_url":null,"media_count":2500}]% @@ -77,8 +77,8 @@ you need to run this. JSON data. If you have `jq` installed, you can pipe the response to it and transform it. - ```console - $ just api/stats | jq '.[0]' + ```bash + just api/stats | jq '.[0]' { "source_name": "flickr", "display_name": "Flickr", @@ -87,7 +87,7 @@ you need to run this. "media_count": 2500 } - $ just api/stats 'audio' | jq '[.[] | .source_name]' + just api/stats 'audio' | jq '[.[] | .source_name]' [ "freesound", "jamendo", diff --git a/documentation/api/guides/test.md b/documentation/api/guides/test.md index 1de1e46831e..b91480f7c85 100644 --- a/documentation/api/guides/test.md +++ b/documentation/api/guides/test.md @@ -9,8 +9,8 @@ Once you've made some changes to the codebase, it is important to run tests. 2. Run the tests. - ```console - $ just api/test + ```bash + just api/test ``` ```{note} diff --git a/documentation/api/reference/search_algorithm.md b/documentation/api/reference/search_algorithm.md index 1287be1c808..6358b2f33b7 100644 --- a/documentation/api/reference/search_algorithm.md +++ b/documentation/api/reference/search_algorithm.md @@ -1,12 +1,13 @@ # Search Algorithm Openverse currently uses a relatively simple and naïve search algorithm with -very limited options. The documentation on this page was written by referencing -the code in Openverse as well as parts of Openverse's historical development. -Parts of the story for how Openverse's indexes came to be configured as they are -today are likely missing. Future improvements to Openverse's indexing and search -will be more carefully documented here and in the code to ensure there is -greater longevity of understanding. +restricted modifications to the default Elasticsearch behaviour. The +documentation on this page was written by referencing the code in Openverse as +well as parts of Openverse's historical development. Parts of the story for how +Openverse's indexes came to be configured as they are today are likely missing. +Future improvements to Openverse's indexing and search will be more carefully +documented here and in the code to ensure there is greater longevitiy of +understanding. > **Note**: This document avoids covering details covered in the > [Openverse Search Guide](https://wordpress.org/openverse/search-help). @@ -176,7 +177,7 @@ aspects of a document: > to potentially change this fact. Of these, title is weighted 10000 times more heavily than the description and -tags. This makes searches that match a title very closely rise to the "top" of +tags. This makes works whose titles closely match the query rise to the "top" of the results, even if the same text is present word-for-word in a description. It also breaks ties between documents, if, for example, two documents are returned, one because the title matches and one because a tag matches, the title-matched diff --git a/documentation/automations/guides/quickstart.md b/documentation/automations/guides/quickstart.md index 59d287910c9..22a456ea6fe 100644 --- a/documentation/automations/guides/quickstart.md +++ b/documentation/automations/guides/quickstart.md @@ -26,8 +26,8 @@ If you wish to install only dependencies for automations, run the following: Run Python automation scripts using the `automations/python/run` just recipe. Ex.: -``` -$ just automations/python/run print_labels.py +```bash +just automations/python/run print_labels.py ``` The recipe is an alias for running `pipenv run diff --git a/frontend/src/components/VModal/meta/VModal.stories.mdx b/frontend/src/components/VModal/meta/VModal.stories.mdx index d2d22c60dd5..b3e725fb278 100644 --- a/frontend/src/components/VModal/meta/VModal.stories.mdx +++ b/frontend/src/components/VModal/meta/VModal.stories.mdx @@ -34,13 +34,13 @@ export const Template = (args) => ({ {{ visible ? 'Modal open' : 'Modal closed' }}
- This is some modal 1 content, blah blah blah. + This is some modal 1 content, blah etc.
- This is popover content! Woohoo! I'm inside a modal!!! Wow!!! + This is popover content! Woohoo! I'm inside a modal! Wow!
diff --git a/frontend/src/components/VPopover/VPopover.vue b/frontend/src/components/VPopover/VPopover.vue index 73c06be0f08..5c8873873cd 100644 --- a/frontend/src/components/VPopover/VPopover.vue +++ b/frontend/src/components/VPopover/VPopover.vue @@ -6,10 +6,6 @@ ref="triggerContainerRef" class="flex w-min items-stretch whitespace-nowrap" @click="onTriggerClick" - @mouseenter="onTriggerMouseEnter" - @focusin="onTriggerMouseEnter" - @mouseleave="onTriggerMouseLeave" - @focusout="onTriggerMouseLeave" > + +
+ + + + +
+
+ +
+
+ + + diff --git a/frontend/src/composables/use-floating-ui.ts b/frontend/src/composables/use-floating-ui.ts index 3c4c5811309..75ad4abb69d 100644 --- a/frontend/src/composables/use-floating-ui.ts +++ b/frontend/src/composables/use-floating-ui.ts @@ -12,24 +12,17 @@ import { Strategy, } from "@floating-ui/dom" -export type PopoverContentProps = { +export type UseFloatingProps = { visible: boolean - hide: () => void - hideOnEsc: boolean - hideOnClickOutside: boolean - autoFocusOnShow: boolean - autoFocusOnHide: boolean triggerElement: HTMLElement | null placement: Placement strategy: Strategy clippable: boolean - trapFocus: boolean - zIndex: number | string } type Props = { floatingElRef: Ref - floatingPropsRefs: ToRefs + floatingPropsRefs: ToRefs } // A constant offset to ensure there's a gap between diff --git a/frontend/src/composables/use-pages.ts b/frontend/src/composables/use-pages.ts index e4b4e5d120a..6406b98beb0 100644 --- a/frontend/src/composables/use-pages.ts +++ b/frontend/src/composables/use-pages.ts @@ -35,6 +35,11 @@ export default function usePages() { name: "navigation.api", link: "https://api.openverse.engineering/v1/", }, + { + id: "terms", + name: "navigation.terms", + link: "https://docs.openverse.org/terms_of_service.html", + }, { id: "privacy", name: "navigation.privacy", diff --git a/frontend/src/composables/use-popover-content.ts b/frontend/src/composables/use-popover-content.ts index f3d09d23788..accde7dac87 100644 --- a/frontend/src/composables/use-popover-content.ts +++ b/frontend/src/composables/use-popover-content.ts @@ -1,16 +1,28 @@ import { computed, ref } from "vue" -import { - PopoverContentProps, - useFloatingUi, -} from "~/composables/use-floating-ui" +import { useFloatingUi } from "~/composables/use-floating-ui" import { useDialogContent } from "~/composables/use-dialog-content" import type { Properties as CSSProperties } from "csstype" import type { Ref, ToRefs, SetupContext } from "vue" +import type { Placement, Strategy } from "@floating-ui/dom" +export type PopoverContentProps = { + visible: boolean + hide: () => void + hideOnEsc: boolean + hideOnClickOutside: boolean + autoFocusOnShow: boolean + autoFocusOnHide: boolean + triggerElement: HTMLElement | null + placement: Placement + strategy: Strategy + clippable: boolean + trapFocus: boolean + zIndex: number | string +} type Props = { popoverRef: Ref popoverPropsRefs: ToRefs diff --git a/frontend/src/locales/scripts/en.json5 b/frontend/src/locales/scripts/en.json5 index ba290436deb..73979693079 100644 --- a/frontend/src/locales/scripts/en.json5 +++ b/frontend/src/locales/scripts/en.json5 @@ -66,6 +66,7 @@ licenses: "Licenses", getInvolved: "Get involved", api: "API", + terms: "Terms", privacy: "Privacy", feedback: "Feedback", sources: "Sources", @@ -485,6 +486,8 @@ }, providerLabel: "Provider", sourceLabel: "Source", + providerDescription: "Website where the content is hosted", + sourceDescription: "Organization that created or owns the original content", loading: "Loading...", relatedError: "Error fetching related media", aria: { diff --git a/frontend/src/static/favicon.ico b/frontend/src/static/favicon.ico index 7d386b90c4f..9652ae3bcf0 100644 Binary files a/frontend/src/static/favicon.ico and b/frontend/src/static/favicon.ico differ diff --git a/frontend/src/static/favicon.svg b/frontend/src/static/favicon.svg new file mode 100644 index 00000000000..6f65e5f932d --- /dev/null +++ b/frontend/src/static/favicon.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + diff --git a/frontend/src/static/openverse-logo-180.png b/frontend/src/static/openverse-logo-180.png index 8ec35f5cc46..b6d938f8b43 100644 Binary files a/frontend/src/static/openverse-logo-180.png and b/frontend/src/static/openverse-logo-180.png differ diff --git a/frontend/src/static/openverse-logo.svg b/frontend/src/static/openverse-logo.svg index 70c7b6457c5..6f65e5f932d 100644 --- a/frontend/src/static/openverse-logo.svg +++ b/frontend/src/static/openverse-logo.svg @@ -1,18 +1,28 @@ - - - - - - - - + + + + + + + + + + + + + + + diff --git a/frontend/src/types/media.ts b/frontend/src/types/media.ts index 416ecd0c4b7..063f68cc26c 100644 --- a/frontend/src/types/media.ts +++ b/frontend/src/types/media.ts @@ -131,6 +131,7 @@ export const isMediaDetail = ( } export type Metadata = { + name?: string label: string url?: string value: string diff --git a/frontend/src/utils/metadata.ts b/frontend/src/utils/metadata.ts index acc9e869f48..f8b79a3ad2d 100644 --- a/frontend/src/utils/metadata.ts +++ b/frontend/src/utils/metadata.ts @@ -41,6 +41,7 @@ export const getMediaMetadata = ( const metadata: Metadata[] = [] if (media.source && media.providerName !== media.sourceName) { metadata.push({ + name: "provider", label: "mediaDetails.providerLabel", value: media.providerName || media.provider, }) @@ -51,6 +52,7 @@ export const getMediaMetadata = ( ) const sourceName = media.sourceName ?? media.providerName ?? media.provider metadata.push({ + name: "source", label: "mediaDetails.sourceLabel", source: media.source ?? media.provider, url: sourceUrl, diff --git a/frontend/test/locales/ar.json b/frontend/test/locales/ar.json index c1bdf3bd7ca..ca7963f616d 100644 --- a/frontend/test/locales/ar.json +++ b/frontend/test/locales/ar.json @@ -678,6 +678,7 @@ "licenses": "التراخيص", "getInvolved": "شارك", "api": "API", + "terms": "شروط", "privacy": "خصوصية", "feedback": "استجابة", "sources": "مصادر", diff --git a/frontend/test/playwright/e2e/sensitive-results.spec.ts b/frontend/test/playwright/e2e/sensitive-results.spec.ts index da48e36c997..f66f101c24e 100644 --- a/frontend/test/playwright/e2e/sensitive-results.spec.ts +++ b/frontend/test/playwright/e2e/sensitive-results.spec.ts @@ -6,12 +6,14 @@ import { preparePageForTests, } from "~~/test/playwright/utils/navigation" import { t } from "~~/test/playwright/utils/i18n" -import { getH1, getHomeLink } from "~~/test/playwright/utils/components" +import { getH1 } from "~~/test/playwright/utils/components" import { collectAnalyticsEvents, expectEventPayloadToMatch, } from "~~/test/playwright/utils/analytics" +import { INCLUDE_SENSITIVE_QUERY_PARAM } from "~/constants/content-safety" + test.describe.configure({ mode: "parallel" }) const getSensitiveToggle = (page: Page) => { @@ -42,12 +44,14 @@ test.describe("sensitive_results", () => { // Check the sensitive toggle on a search page await filters.open(page) - await getSensitiveToggle(page).click() - // Search from the home page - await getHomeLink(page).click() - await page.locator('main input[type="search"]').fill("cat") - await page.keyboard.press("Enter") + // Wait for the request that includes the sensitive query param + const requestPromise = page.waitForRequest((req) => { + return req.url().includes(INCLUDE_SENSITIVE_QUERY_PARAM) + }) + await getSensitiveToggle(page).click() + const request = await requestPromise + expect(request.url()).toContain("cat") // Check the sensitive media on the search page await expect(getH1(page, /cat/i)).toBeVisible() diff --git a/frontend/test/playwright/visual-regression/pages/errors.spec.ts-snapshots/search-result-audio-no-results-ltr-sm-linux.png b/frontend/test/playwright/visual-regression/pages/errors.spec.ts-snapshots/search-result-audio-no-results-ltr-sm-linux.png index 45113744767..b731f5daca4 100644 Binary files a/frontend/test/playwright/visual-regression/pages/errors.spec.ts-snapshots/search-result-audio-no-results-ltr-sm-linux.png and b/frontend/test/playwright/visual-regression/pages/errors.spec.ts-snapshots/search-result-audio-no-results-ltr-sm-linux.png differ diff --git a/frontend/test/playwright/visual-regression/pages/errors.spec.ts-snapshots/search-result-audio-no-results-rtl-sm-linux.png b/frontend/test/playwright/visual-regression/pages/errors.spec.ts-snapshots/search-result-audio-no-results-rtl-sm-linux.png index f7906440a8c..dce6025508c 100644 Binary files a/frontend/test/playwright/visual-regression/pages/errors.spec.ts-snapshots/search-result-audio-no-results-rtl-sm-linux.png and b/frontend/test/playwright/visual-regression/pages/errors.spec.ts-snapshots/search-result-audio-no-results-rtl-sm-linux.png differ diff --git a/frontend/test/playwright/visual-regression/pages/errors.spec.ts-snapshots/search-result-image-no-results-ltr-sm-linux.png b/frontend/test/playwright/visual-regression/pages/errors.spec.ts-snapshots/search-result-image-no-results-ltr-sm-linux.png index e9797c8569b..bcee4f495c3 100644 Binary files a/frontend/test/playwright/visual-regression/pages/errors.spec.ts-snapshots/search-result-image-no-results-ltr-sm-linux.png and b/frontend/test/playwright/visual-regression/pages/errors.spec.ts-snapshots/search-result-image-no-results-ltr-sm-linux.png differ diff --git a/frontend/test/playwright/visual-regression/pages/errors.spec.ts-snapshots/search-result-image-no-results-rtl-sm-linux.png b/frontend/test/playwright/visual-regression/pages/errors.spec.ts-snapshots/search-result-image-no-results-rtl-sm-linux.png index 030725e243a..86f0e1527ca 100644 Binary files a/frontend/test/playwright/visual-regression/pages/errors.spec.ts-snapshots/search-result-image-no-results-rtl-sm-linux.png and b/frontend/test/playwright/visual-regression/pages/errors.spec.ts-snapshots/search-result-image-no-results-rtl-sm-linux.png differ diff --git a/frontend/test/playwright/visual-regression/pages/errors.spec.ts-snapshots/search-result-timeout-ltr-sm-linux.png b/frontend/test/playwright/visual-regression/pages/errors.spec.ts-snapshots/search-result-timeout-ltr-sm-linux.png index 79f7784f0bf..c29800c5487 100644 Binary files a/frontend/test/playwright/visual-regression/pages/errors.spec.ts-snapshots/search-result-timeout-ltr-sm-linux.png and b/frontend/test/playwright/visual-regression/pages/errors.spec.ts-snapshots/search-result-timeout-ltr-sm-linux.png differ diff --git a/frontend/test/playwright/visual-regression/pages/errors.spec.ts-snapshots/search-result-timeout-rtl-sm-linux.png b/frontend/test/playwright/visual-regression/pages/errors.spec.ts-snapshots/search-result-timeout-rtl-sm-linux.png index ccfff4dccc0..6446fbf02f8 100644 Binary files a/frontend/test/playwright/visual-regression/pages/errors.spec.ts-snapshots/search-result-timeout-rtl-sm-linux.png and b/frontend/test/playwright/visual-regression/pages/errors.spec.ts-snapshots/search-result-timeout-rtl-sm-linux.png differ diff --git a/frontend/test/playwright/visual-regression/pages/pages-single-result.spec.ts-snapshots/ltr-full-page-report-xl-linux.png b/frontend/test/playwright/visual-regression/pages/pages-single-result.spec.ts-snapshots/ltr-full-page-report-xl-linux.png index 47b1403a481..7f3e25021ef 100644 Binary files a/frontend/test/playwright/visual-regression/pages/pages-single-result.spec.ts-snapshots/ltr-full-page-report-xl-linux.png and b/frontend/test/playwright/visual-regression/pages/pages-single-result.spec.ts-snapshots/ltr-full-page-report-xl-linux.png differ diff --git a/frontend/test/playwright/visual-regression/pages/pages-single-result.spec.ts-snapshots/rtl-full-page-report-xl-linux.png b/frontend/test/playwright/visual-regression/pages/pages-single-result.spec.ts-snapshots/rtl-full-page-report-xl-linux.png index a1cceafee3f..284f8d692f7 100644 Binary files a/frontend/test/playwright/visual-regression/pages/pages-single-result.spec.ts-snapshots/rtl-full-page-report-xl-linux.png and b/frontend/test/playwright/visual-regression/pages/pages-single-result.spec.ts-snapshots/rtl-full-page-report-xl-linux.png differ diff --git a/frontend/test/storybook/visual-regression/v-filter-button.spec.ts b/frontend/test/storybook/visual-regression/v-filter-button.spec.ts index eb9ad8e5dd6..afdd7bb44ad 100644 --- a/frontend/test/storybook/visual-regression/v-filter-button.spec.ts +++ b/frontend/test/storybook/visual-regression/v-filter-button.spec.ts @@ -2,6 +2,7 @@ import { test } from "@playwright/test" import breakpoints from "~~/test/playwright/utils/breakpoints" import { makeGotoWithArgs } from "~~/test/storybook/utils/args" +import { sleep } from "~~/test/playwright/utils/navigation" const gotoWithArgs = makeGotoWithArgs( "components-vheader-vfilterbutton--default-story" @@ -61,6 +62,7 @@ test.describe("VFilterButton", () => { appliedFilters: filterCount, pressed: true, }) + await sleep(500) await expectSnapshot( `filter-button-pressed-${filterCount}-checked`, page.locator(wrapper) diff --git a/frontend/test/storybook/visual-regression/v-footer.spec.ts-snapshots/footer-content-ltr-md-linux.png b/frontend/test/storybook/visual-regression/v-footer.spec.ts-snapshots/footer-content-ltr-md-linux.png index f92a1c0c781..2e4fb9399fb 100644 Binary files a/frontend/test/storybook/visual-regression/v-footer.spec.ts-snapshots/footer-content-ltr-md-linux.png and b/frontend/test/storybook/visual-regression/v-footer.spec.ts-snapshots/footer-content-ltr-md-linux.png differ diff --git a/frontend/test/storybook/visual-regression/v-footer.spec.ts-snapshots/footer-content-ltr-sm-linux.png b/frontend/test/storybook/visual-regression/v-footer.spec.ts-snapshots/footer-content-ltr-sm-linux.png index ef76a654b16..e342dee4691 100644 Binary files a/frontend/test/storybook/visual-regression/v-footer.spec.ts-snapshots/footer-content-ltr-sm-linux.png and b/frontend/test/storybook/visual-regression/v-footer.spec.ts-snapshots/footer-content-ltr-sm-linux.png differ diff --git a/frontend/test/storybook/visual-regression/v-footer.spec.ts-snapshots/footer-content-ltr-xs-linux.png b/frontend/test/storybook/visual-regression/v-footer.spec.ts-snapshots/footer-content-ltr-xs-linux.png index 4aa719feed9..8422c78c351 100644 Binary files a/frontend/test/storybook/visual-regression/v-footer.spec.ts-snapshots/footer-content-ltr-xs-linux.png and b/frontend/test/storybook/visual-regression/v-footer.spec.ts-snapshots/footer-content-ltr-xs-linux.png differ diff --git a/frontend/test/storybook/visual-regression/v-footer.spec.ts-snapshots/footer-content-rtl-md-linux.png b/frontend/test/storybook/visual-regression/v-footer.spec.ts-snapshots/footer-content-rtl-md-linux.png index e271f51e7eb..0beca9968d1 100644 Binary files a/frontend/test/storybook/visual-regression/v-footer.spec.ts-snapshots/footer-content-rtl-md-linux.png and b/frontend/test/storybook/visual-regression/v-footer.spec.ts-snapshots/footer-content-rtl-md-linux.png differ diff --git a/frontend/test/storybook/visual-regression/v-footer.spec.ts-snapshots/footer-content-rtl-sm-linux.png b/frontend/test/storybook/visual-regression/v-footer.spec.ts-snapshots/footer-content-rtl-sm-linux.png index ef05b8c9ba8..fc7ef182372 100644 Binary files a/frontend/test/storybook/visual-regression/v-footer.spec.ts-snapshots/footer-content-rtl-sm-linux.png and b/frontend/test/storybook/visual-regression/v-footer.spec.ts-snapshots/footer-content-rtl-sm-linux.png differ diff --git a/frontend/test/storybook/visual-regression/v-footer.spec.ts-snapshots/footer-content-rtl-xs-linux.png b/frontend/test/storybook/visual-regression/v-footer.spec.ts-snapshots/footer-content-rtl-xs-linux.png index 9e81c8f8072..e5b6dada5b9 100644 Binary files a/frontend/test/storybook/visual-regression/v-footer.spec.ts-snapshots/footer-content-rtl-xs-linux.png and b/frontend/test/storybook/visual-regression/v-footer.spec.ts-snapshots/footer-content-rtl-xs-linux.png differ diff --git a/frontend/test/storybook/visual-regression/v-header-internal.spec.ts b/frontend/test/storybook/visual-regression/v-header-internal.spec.ts index b4a24890395..8803c8fd26e 100644 --- a/frontend/test/storybook/visual-regression/v-header-internal.spec.ts +++ b/frontend/test/storybook/visual-regression/v-header-internal.spec.ts @@ -1,7 +1,6 @@ import { test } from "@playwright/test" import breakpoints from "~~/test/playwright/utils/breakpoints" -import { sleep } from "~~/test/playwright/utils/navigation" import { languageDirections } from "~~/test/playwright/utils/i18n" const headerSelector = ".main-header" @@ -35,12 +34,17 @@ test.describe("VHeaderInternal", () => { }) test(`mobile-header-internal-modal-${dir}`, async ({ page }) => { await page.goto(pageUrl(dir)) + + // Ensure fonts are loaded before taking the snapshot. + const requestPromise = page.waitForRequest((req) => + req.url().includes("var.woff2") + ) await page.locator('button[aria-haspopup="dialog"]').click() + await requestPromise // Mouse stays over the button, so the close button is hovered. // To prevent this, move the mouse away. await page.mouse.move(0, 0) - // Wait for the fonts to load. - await sleep(300) + await expectSnapshot(`mobile-header-internal-open-${dir}`, page) }) }) diff --git a/frontend/test/storybook/visual-regression/v-header-internal.spec.ts-snapshots/desktop-header-internal-ltr-2xl-linux.png b/frontend/test/storybook/visual-regression/v-header-internal.spec.ts-snapshots/desktop-header-internal-ltr-2xl-linux.png index 7b23166ab86..18befa1c5ca 100644 Binary files a/frontend/test/storybook/visual-regression/v-header-internal.spec.ts-snapshots/desktop-header-internal-ltr-2xl-linux.png and b/frontend/test/storybook/visual-regression/v-header-internal.spec.ts-snapshots/desktop-header-internal-ltr-2xl-linux.png differ diff --git a/frontend/test/storybook/visual-regression/v-header-internal.spec.ts-snapshots/desktop-header-internal-ltr-lg-linux.png b/frontend/test/storybook/visual-regression/v-header-internal.spec.ts-snapshots/desktop-header-internal-ltr-lg-linux.png index fb70ab1c0df..a5a3c369f6d 100644 Binary files a/frontend/test/storybook/visual-regression/v-header-internal.spec.ts-snapshots/desktop-header-internal-ltr-lg-linux.png and b/frontend/test/storybook/visual-regression/v-header-internal.spec.ts-snapshots/desktop-header-internal-ltr-lg-linux.png differ diff --git a/frontend/test/storybook/visual-regression/v-header-internal.spec.ts-snapshots/desktop-header-internal-ltr-xl-linux.png b/frontend/test/storybook/visual-regression/v-header-internal.spec.ts-snapshots/desktop-header-internal-ltr-xl-linux.png index a92f080c8a1..089973ba3b3 100644 Binary files a/frontend/test/storybook/visual-regression/v-header-internal.spec.ts-snapshots/desktop-header-internal-ltr-xl-linux.png and b/frontend/test/storybook/visual-regression/v-header-internal.spec.ts-snapshots/desktop-header-internal-ltr-xl-linux.png differ diff --git a/frontend/test/storybook/visual-regression/v-header-internal.spec.ts-snapshots/desktop-header-internal-rtl-2xl-linux.png b/frontend/test/storybook/visual-regression/v-header-internal.spec.ts-snapshots/desktop-header-internal-rtl-2xl-linux.png index 3aa1870ac83..2945079f5d9 100644 Binary files a/frontend/test/storybook/visual-regression/v-header-internal.spec.ts-snapshots/desktop-header-internal-rtl-2xl-linux.png and b/frontend/test/storybook/visual-regression/v-header-internal.spec.ts-snapshots/desktop-header-internal-rtl-2xl-linux.png differ diff --git a/frontend/test/storybook/visual-regression/v-header-internal.spec.ts-snapshots/desktop-header-internal-rtl-lg-linux.png b/frontend/test/storybook/visual-regression/v-header-internal.spec.ts-snapshots/desktop-header-internal-rtl-lg-linux.png index 232ec76edbb..cdaac968042 100644 Binary files a/frontend/test/storybook/visual-regression/v-header-internal.spec.ts-snapshots/desktop-header-internal-rtl-lg-linux.png and b/frontend/test/storybook/visual-regression/v-header-internal.spec.ts-snapshots/desktop-header-internal-rtl-lg-linux.png differ diff --git a/frontend/test/storybook/visual-regression/v-header-internal.spec.ts-snapshots/desktop-header-internal-rtl-xl-linux.png b/frontend/test/storybook/visual-regression/v-header-internal.spec.ts-snapshots/desktop-header-internal-rtl-xl-linux.png index b76b77b7302..058247e360b 100644 Binary files a/frontend/test/storybook/visual-regression/v-header-internal.spec.ts-snapshots/desktop-header-internal-rtl-xl-linux.png and b/frontend/test/storybook/visual-regression/v-header-internal.spec.ts-snapshots/desktop-header-internal-rtl-xl-linux.png differ diff --git a/frontend/test/storybook/visual-regression/v-image-cell.spec.ts-snapshots/v-image-cell-intrinsic-focused-xl-linux.png b/frontend/test/storybook/visual-regression/v-image-cell.spec.ts-snapshots/v-image-cell-intrinsic-focused-xl-linux.png index ec738dfbfd3..939f90cbc8c 100644 Binary files a/frontend/test/storybook/visual-regression/v-image-cell.spec.ts-snapshots/v-image-cell-intrinsic-focused-xl-linux.png and b/frontend/test/storybook/visual-regression/v-image-cell.spec.ts-snapshots/v-image-cell-intrinsic-focused-xl-linux.png differ diff --git a/ingestion_server/Pipfile b/ingestion_server/Pipfile index 74d6a186c2f..046a434d576 100644 --- a/ingestion_server/Pipfile +++ b/ingestion_server/Pipfile @@ -15,7 +15,7 @@ pook = "~=1.0" aws-requests-auth = "~=0.4" boto3 = "~=1.28" bottle = "~=0.12" -elasticsearch = "==8.11.1" +elasticsearch = "==8.12.0" elasticsearch-dsl = "~=8.9" falcon = "~=3.1" filelock = "~=3.13" diff --git a/ingestion_server/Pipfile.lock b/ingestion_server/Pipfile.lock index baad87f6f36..c519aa84079 100644 --- a/ingestion_server/Pipfile.lock +++ b/ingestion_server/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "97f9e25f04027699dae5bc04e31eafbf4a6734acafa86848bc56826fb1cafff0" + "sha256": "019c5ba70be1bfcd4ffb5f8750607120d331553c00889d1d14feb580b5bff9c7" }, "pipfile-spec": 6, "requires": { @@ -34,20 +34,20 @@ }, "boto3": { "hashes": [ - "sha256:1af021e0c6e3040e8de66d403e963566476235bb70f9a8e3f6784813ac2d8026", - "sha256:31c130a40ec0631059b77d7e87f67ad03ff1685a5b37638ac0c4687026a3259d" + "sha256:7bf924c942426839efd7fa5c2c4fe85dba208258393e8017a5ad327c30e5948d", + "sha256:9e62f42de2873baab96eb822386d6a3b1d77f6715cb9033d7b4e6e9ebb0cdbe7" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==1.34.11" + "version": "==1.34.32" }, "botocore": { "hashes": [ - "sha256:1ff1398b6ea670e1c01ac67a33af3da854f8e700d3528289c04f319c330d8250", - "sha256:51905c3d623c60df5dc5794387de7caf886d350180a01a3dfa762e903edb45a9" + "sha256:466aee158bd0429dbd567c4e2bdf7be9a0a5a74409f8b295c30f34d84c497f9c", + "sha256:aa26a74df83eed3db9542c1cf9108138794c344918b36a506c0723717f1acaab" ], "markers": "python_version >= '3.8'", - "version": "==1.34.11" + "version": "==1.34.32" }, "bottle": { "hashes": [ @@ -163,29 +163,29 @@ }, "elastic-transport": { "hashes": [ - "sha256:1a6ab59b2a6f6feeef20d254babb1b27fbf0b2bc8d3cf485f5211b422290dd4c", - "sha256:dfb5d8a0cb649c159ebf4d9b1f55b7c8d00bb65687c53060b54cc9b2a7c84344" + "sha256:48839b942fcce199eece1558ecea6272e116c58da87ca8d495ef12eb61effaf7", + "sha256:87d9dc9dee64a05235e7624ed7e6ab6e5ca16619aa7a6d22e853273b9f1cfbee" ], "markers": "python_version >= '3.7'", - "version": "==8.11.0" + "version": "==8.12.0" }, "elasticsearch": { "hashes": [ - "sha256:360b721324ce4bc7d554afb8acbf4942370e73c5ef8c4dad5f5ba3bb2a70eeae", - "sha256:a98309cee11fef8d6750f388683e9a8005da94bdfd940b36ef85cb6cc53186c7" + "sha256:58fd3876682f7529c33b9eeee701e71cfcc334bb45d725e315e22a0a5e2611fb", + "sha256:d394c5ce746bb8cb97827feae57759dae462bce34df221a6fdb6875c56476389" ], "index": "pypi", - "markers": "python_version >= '3.6'", - "version": "==8.11.1" + "markers": "python_version >= '3.7'", + "version": "==8.12.0" }, "elasticsearch-dsl": { "hashes": [ - "sha256:44af4fd7f62009bb19193b55e1c2143b6932517e4c0ec30107e7ff4d968a127e", - "sha256:61000f8ff5e9633d3381aea5a6dfba5c9c4505fe2e6c5cba6a17cd7debc890d9" + "sha256:2ea9e6ded64d21a8f1ef72477a4d116c6fbeea631ac32a2e2490b9c0d09a99a6", + "sha256:ce32b8529888a97be911531e7590816cf3b1f608263eff6fb75aa7106e233c88" ], "index": "pypi", "markers": "python_version >= '3.7'", - "version": "==8.11.0" + "version": "==8.12.0" }, "falcon": { "hashes": [ @@ -263,12 +263,12 @@ }, "jsonschema": { "hashes": [ - "sha256:4f614fd46d8d61258610998997743ec5492a648b33cf478c1ddc23ed4598a5fa", - "sha256:ed6231f0429ecf966f5bc8dfef245998220549cbbcf140f913b7464c52c3b6b3" + "sha256:7996507afae316306f9e2290407761157c6f78002dcf7419acb99822143d1c6f", + "sha256:85727c00279f5fa6bedbe6238d2aa6403bedd8b4864ab11207d07df3cc1b2ee5" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==4.20.0" + "version": "==4.21.1" }, "jsonschema-specifications": { "hashes": [ @@ -353,6 +353,7 @@ "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4", "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba", "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8", + "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef", "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5", "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd", "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3", @@ -375,16 +376,17 @@ "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d", "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f" ], + "index": "pypi", "markers": "python_version >= '3.6'", "version": "==6.0.1" }, "referencing": { "hashes": [ - "sha256:689e64fe121843dcfd57b71933318ef1f91188ffb45367332700a86ac8fd6161", - "sha256:bdcd3efb936f82ff86f993093f6da7435c7de69a3b3a5a06678a6050184bee99" + "sha256:39240f2ecc770258f28b642dd47fd74bc8b02484de54e1882b74b35ebd779bd5", + "sha256:c775fedf74bc0f9189c2a3be1c12fd03e8c23f4d371dce795df44e06c5b412f7" ], "markers": "python_version >= '3.8'", - "version": "==0.32.0" + "version": "==0.33.0" }, "requests": { "hashes": [ @@ -396,115 +398,115 @@ }, "requests-file": { "hashes": [ - "sha256:07d74208d3389d01c38ab89ef403af0cfec63957d53a0081d8eca738d0247d8e", - "sha256:dfe5dae75c12481f68ba353183c53a65e6044c923e64c24b2209f6c7570ca953" + "sha256:20c5931629c558fda566cacc10cfe2cd502433e628f568c34c80d96a0cc95972", + "sha256:3e493d390adb44aa102ebea827a48717336d5268968c370eaf19abaf5cae13bf" ], - "version": "==1.5.1" + "version": "==2.0.0" }, "rpds-py": { "hashes": [ - "sha256:0474df4ade9a3b4af96c3d36eb81856cb9462e4c6657d4caecfd840d2a13f3c9", - "sha256:071980663c273bf3d388fe5c794c547e6f35ba3335477072c713a3176bf14a60", - "sha256:07aab64e2808c3ebac2a44f67e9dc0543812b715126dfd6fe4264df527556cb6", - "sha256:088396c7c70e59872f67462fcac3ecbded5233385797021976a09ebd55961dfe", - "sha256:162d7cd9cd311c1b0ff1c55a024b8f38bd8aad1876b648821da08adc40e95734", - "sha256:19f00f57fdd38db4bb5ad09f9ead1b535332dbf624200e9029a45f1f35527ebb", - "sha256:1bdbc5fcb04a7309074de6b67fa9bc4b418ab3fc435fec1f2779a0eced688d04", - "sha256:1be2f033df1b8be8c3167ba3c29d5dca425592ee31e35eac52050623afba5772", - "sha256:24f7a2eb3866a9e91f4599851e0c8d39878a470044875c49bd528d2b9b88361c", - "sha256:290a81cfbe4673285cdf140ec5cd1658ffbf63ab359f2b352ebe172e7cfa5bf0", - "sha256:2946b120718eba9af2b4dd103affc1164a87b9e9ebff8c3e4c05d7b7a7e274e2", - "sha256:2bd82db36cd70b3628c0c57d81d2438e8dd4b7b32a6a9f25f24ab0e657cb6c4e", - "sha256:2ddef620e70eaffebed5932ce754d539c0930f676aae6212f8e16cd9743dd365", - "sha256:2e53b9b25cac9065328901713a7e9e3b12e4f57ef4280b370fbbf6fef2052eef", - "sha256:302bd4983bbd47063e452c38be66153760112f6d3635c7eeefc094299fa400a9", - "sha256:349cb40897fd529ca15317c22c0eab67f5ac5178b5bd2c6adc86172045210acc", - "sha256:358dafc89ce3894c7f486c615ba914609f38277ef67f566abc4c854d23b997fa", - "sha256:35953f4f2b3216421af86fd236b7c0c65935936a94ea83ddbd4904ba60757773", - "sha256:35ae5ece284cf36464eb160880018cf6088a9ac5ddc72292a6092b6ef3f4da53", - "sha256:3b811d182ad17ea294f2ec63c0621e7be92a1141e1012383461872cead87468f", - "sha256:3da5a4c56953bdbf6d04447c3410309616c54433146ccdb4a277b9cb499bc10e", - "sha256:3dc6a7620ba7639a3db6213da61312cb4aa9ac0ca6e00dc1cbbdc21c2aa6eb57", - "sha256:3f91df8e6dbb7360e176d1affd5fb0246d2b88d16aa5ebc7db94fd66b68b61da", - "sha256:4022b9dc620e14f30201a8a73898a873c8e910cb642bcd2f3411123bc527f6ac", - "sha256:413b9c17388bbd0d87a329d8e30c1a4c6e44e2bb25457f43725a8e6fe4161e9e", - "sha256:43d4dd5fb16eb3825742bad8339d454054261ab59fed2fbac84e1d84d5aae7ba", - "sha256:44627b6ca7308680a70766454db5249105fa6344853af6762eaad4158a2feebe", - "sha256:44a54e99a2b9693a37ebf245937fd6e9228b4cbd64b9cc961e1f3391ec6c7391", - "sha256:47713dc4fce213f5c74ca8a1f6a59b622fc1b90868deb8e8e4d993e421b4b39d", - "sha256:495a14b72bbe217f2695dcd9b5ab14d4f8066a00f5d209ed94f0aca307f85f6e", - "sha256:4c46ad6356e1561f2a54f08367d1d2e70a0a1bb2db2282d2c1972c1d38eafc3b", - "sha256:4d6a9f052e72d493efd92a77f861e45bab2f6be63e37fa8ecf0c6fd1a58fedb0", - "sha256:509b617ac787cd1149600e731db9274ebbef094503ca25158e6f23edaba1ca8f", - "sha256:5552f328eaef1a75ff129d4d0c437bf44e43f9436d3996e8eab623ea0f5fcf73", - "sha256:5a80e2f83391ad0808b4646732af2a7b67550b98f0cae056cb3b40622a83dbb3", - "sha256:5cf6af100ffb5c195beec11ffaa8cf8523057f123afa2944e6571d54da84cdc9", - "sha256:5e6caa3809e50690bd92fa490f5c38caa86082c8c3315aa438bce43786d5e90d", - "sha256:5ef00873303d678aaf8b0627e111fd434925ca01c657dbb2641410f1cdaef261", - "sha256:69ac7ea9897ec201ce68b48582f3eb34a3f9924488a5432a93f177bf76a82a7e", - "sha256:6a61226465bda9283686db8f17d02569a98e4b13c637be5a26d44aa1f1e361c2", - "sha256:6d904c5693e08bad240f16d79305edba78276be87061c872a4a15e2c301fa2c0", - "sha256:6dace7b26a13353e24613417ce2239491b40a6ad44e5776a18eaff7733488b44", - "sha256:6df15846ee3fb2e6397fe25d7ca6624af9f89587f3f259d177b556fed6bebe2c", - "sha256:703d95c75a72e902544fda08e965885525e297578317989fd15a6ce58414b41d", - "sha256:726ac36e8a3bb8daef2fd482534cabc5e17334052447008405daca7ca04a3108", - "sha256:781ef8bfc091b19960fc0142a23aedadafa826bc32b433fdfe6fd7f964d7ef44", - "sha256:80443fe2f7b3ea3934c5d75fb0e04a5dbb4a8e943e5ff2de0dec059202b70a8b", - "sha256:83640a5d7cd3bff694747d50436b8b541b5b9b9782b0c8c1688931d6ee1a1f2d", - "sha256:84c5a4d1f9dd7e2d2c44097fb09fffe728629bad31eb56caf97719e55575aa82", - "sha256:882ce6e25e585949c3d9f9abd29202367175e0aab3aba0c58c9abbb37d4982ff", - "sha256:888a97002e986eca10d8546e3c8b97da1d47ad8b69726dcfeb3e56348ebb28a3", - "sha256:8aad80645a011abae487d356e0ceb359f4938dfb6f7bcc410027ed7ae4f7bb8b", - "sha256:8cb6fe8ecdfffa0e711a75c931fb39f4ba382b4b3ccedeca43f18693864fe850", - "sha256:8d6b6937ae9eac6d6c0ca3c42774d89fa311f55adff3970fb364b34abde6ed3d", - "sha256:90123853fc8b1747f80b0d354be3d122b4365a93e50fc3aacc9fb4c2488845d6", - "sha256:96f957d6ab25a78b9e7fc9749d754b98eac825a112b4e666525ce89afcbd9ed5", - "sha256:981d135c7cdaf6cd8eadae1c950de43b976de8f09d8e800feed307140d3d6d00", - "sha256:9b32f742ce5b57201305f19c2ef7a184b52f6f9ba6871cc042c2a61f0d6b49b8", - "sha256:9f0350ef2fba5f34eb0c9000ea328e51b9572b403d2f7f3b19f24085f6f598e8", - "sha256:a297a4d08cc67c7466c873c78039d87840fb50d05473db0ec1b7b03d179bf322", - "sha256:a3d7e2ea25d3517c6d7e5a1cc3702cffa6bd18d9ef8d08d9af6717fc1c700eed", - "sha256:a4b682c5775d6a3d21e314c10124599976809455ee67020e8e72df1769b87bc3", - "sha256:a4ebb8b20bd09c5ce7884c8f0388801100f5e75e7f733b1b6613c713371feefc", - "sha256:a61f659665a39a4d17d699ab3593d7116d66e1e2e3f03ef3fb8f484e91908808", - "sha256:a9880b4656efe36ccad41edc66789e191e5ee19a1ea8811e0aed6f69851a82f4", - "sha256:ac08472f41ea77cd6a5dae36ae7d4ed3951d6602833af87532b556c1b4601d63", - "sha256:adc0c3d6fc6ae35fee3e4917628983f6ce630d513cbaad575b4517d47e81b4bb", - "sha256:af27423662f32d7501a00c5e7342f7dbd1e4a718aea7a239781357d15d437133", - "sha256:b2e75e17bd0bb66ee34a707da677e47c14ee51ccef78ed6a263a4cc965a072a1", - "sha256:b634c5ec0103c5cbebc24ebac4872b045cccb9456fc59efdcf6fe39775365bd2", - "sha256:b6f5549d6ed1da9bfe3631ca9483ae906f21410be2445b73443fa9f017601c6f", - "sha256:bd4b677d929cf1f6bac07ad76e0f2d5de367e6373351c01a9c0a39f6b21b4a8b", - "sha256:bf721ede3eb7b829e4a9b8142bd55db0bdc82902720548a703f7e601ee13bdc3", - "sha256:c647ca87fc0ebe808a41de912e9a1bfef9acb85257e5d63691364ac16b81c1f0", - "sha256:ca57468da2d9a660bcf8961637c85f2fbb2aa64d9bc3f9484e30c3f9f67b1dd7", - "sha256:cad0f59ee3dc35526039f4bc23642d52d5f6616b5f687d846bfc6d0d6d486db0", - "sha256:cc97f0640e91d7776530f06e6836c546c1c752a52de158720c4224c9e8053cad", - "sha256:ccd4e400309e1f34a5095bf9249d371f0fd60f8a3a5c4a791cad7b99ce1fd38d", - "sha256:cffa76b385dfe1e38527662a302b19ffb0e7f5cf7dd5e89186d2c94a22dd9d0c", - "sha256:d0dd7ed2f16df2e129496e7fbe59a34bc2d7fc8db443a606644d069eb69cbd45", - "sha256:d452817e0d9c749c431a1121d56a777bd7099b720b3d1c820f1725cb40928f58", - "sha256:d8dda2a806dfa4a9b795950c4f5cc56d6d6159f7d68080aedaff3bdc9b5032f5", - "sha256:dcbe1f8dd179e4d69b70b1f1d9bb6fd1e7e1bdc9c9aad345cdeb332e29d40748", - "sha256:e0441fb4fdd39a230477b2ca9be90868af64425bfe7b122b57e61e45737a653b", - "sha256:e04e56b4ca7a770593633556e8e9e46579d66ec2ada846b401252a2bdcf70a6d", - "sha256:e061de3b745fe611e23cd7318aec2c8b0e4153939c25c9202a5811ca911fd733", - "sha256:e93ec1b300acf89730cf27975ef574396bc04edecc358e9bd116fb387a123239", - "sha256:e9e557db6a177470316c82f023e5d571811c9a4422b5ea084c85da9aa3c035fc", - "sha256:eab36eae3f3e8e24b05748ec9acc66286662f5d25c52ad70cadab544e034536b", - "sha256:ec23fcad480e77ede06cf4127a25fc440f7489922e17fc058f426b5256ee0edb", - "sha256:ec2e1cf025b2c0f48ec17ff3e642661da7ee332d326f2e6619366ce8e221f018", - "sha256:ed99b4f7179d2111702020fd7d156e88acd533f5a7d3971353e568b6051d5c97", - "sha256:ee94cb58c0ba2c62ee108c2b7c9131b2c66a29e82746e8fa3aa1a1effbd3dcf1", - "sha256:f19afcfc0dd0dca35694df441e9b0f95bc231b512f51bded3c3d8ca32153ec19", - "sha256:f1b9d9260e06ea017feb7172976ab261e011c1dc2f8883c7c274f6b2aabfe01a", - "sha256:f28ac0e8e7242d140f99402a903a2c596ab71550272ae9247ad78f9a932b5698", - "sha256:f42e25c016927e2a6b1ce748112c3ab134261fc2ddc867e92d02006103e1b1b7", - "sha256:f4bd4578e44f26997e9e56c96dedc5f1af43cc9d16c4daa29c771a00b2a26851", - "sha256:f811771019f063bbd0aa7bb72c8a934bc13ebacb4672d712fc1639cfd314cccc" + "sha256:01f58a7306b64e0a4fe042047dd2b7d411ee82e54240284bab63e325762c1147", + "sha256:0210b2668f24c078307260bf88bdac9d6f1093635df5123789bfee4d8d7fc8e7", + "sha256:02866e060219514940342a1f84303a1ef7a1dad0ac311792fbbe19b521b489d2", + "sha256:0387ce69ba06e43df54e43968090f3626e231e4bc9150e4c3246947567695f68", + "sha256:060f412230d5f19fc8c8b75f315931b408d8ebf56aec33ef4168d1b9e54200b1", + "sha256:071bc28c589b86bc6351a339114fb7a029f5cddbaca34103aa573eba7b482382", + "sha256:0bfb09bf41fe7c51413f563373e5f537eaa653d7adc4830399d4e9bdc199959d", + "sha256:10162fe3f5f47c37ebf6d8ff5a2368508fe22007e3077bf25b9c7d803454d921", + "sha256:149c5cd24f729e3567b56e1795f74577aa3126c14c11e457bec1b1c90d212e38", + "sha256:1701fc54460ae2e5efc1dd6350eafd7a760f516df8dbe51d4a1c79d69472fbd4", + "sha256:1957a2ab607f9added64478a6982742eb29f109d89d065fa44e01691a20fc20a", + "sha256:1a746a6d49665058a5896000e8d9d2f1a6acba8a03b389c1e4c06e11e0b7f40d", + "sha256:1bfcad3109c1e5ba3cbe2f421614e70439f72897515a96c462ea657261b96518", + "sha256:1d36b2b59e8cc6e576f8f7b671e32f2ff43153f0ad6d0201250a7c07f25d570e", + "sha256:1db228102ab9d1ff4c64148c96320d0be7044fa28bd865a9ce628ce98da5973d", + "sha256:1dc29db3900cb1bb40353772417800f29c3d078dbc8024fd64655a04ee3c4bdf", + "sha256:1e626b365293a2142a62b9a614e1f8e331b28f3ca57b9f05ebbf4cf2a0f0bdc5", + "sha256:1f3c3461ebb4c4f1bbc70b15d20b565759f97a5aaf13af811fcefc892e9197ba", + "sha256:20de7b7179e2031a04042e85dc463a93a82bc177eeba5ddd13ff746325558aa6", + "sha256:24e4900a6643f87058a27320f81336d527ccfe503984528edde4bb660c8c8d59", + "sha256:2528ff96d09f12e638695f3a2e0c609c7b84c6df7c5ae9bfeb9252b6fa686253", + "sha256:25f071737dae674ca8937a73d0f43f5a52e92c2d178330b4c0bb6ab05586ffa6", + "sha256:270987bc22e7e5a962b1094953ae901395e8c1e1e83ad016c5cfcfff75a15a3f", + "sha256:292f7344a3301802e7c25c53792fae7d1593cb0e50964e7bcdcc5cf533d634e3", + "sha256:2953937f83820376b5979318840f3ee47477d94c17b940fe31d9458d79ae7eea", + "sha256:2a792b2e1d3038daa83fa474d559acfd6dc1e3650ee93b2662ddc17dbff20ad1", + "sha256:2a7b2f2f56a16a6d62e55354dd329d929560442bd92e87397b7a9586a32e3e76", + "sha256:2f4eb548daf4836e3b2c662033bfbfc551db58d30fd8fe660314f86bf8510b93", + "sha256:3664d126d3388a887db44c2e293f87d500c4184ec43d5d14d2d2babdb4c64cad", + "sha256:3677fcca7fb728c86a78660c7fb1b07b69b281964673f486ae72860e13f512ad", + "sha256:380e0df2e9d5d5d339803cfc6d183a5442ad7ab3c63c2a0982e8c824566c5ccc", + "sha256:3ac732390d529d8469b831949c78085b034bff67f584559340008d0f6041a049", + "sha256:4128980a14ed805e1b91a7ed551250282a8ddf8201a4e9f8f5b7e6225f54170d", + "sha256:4341bd7579611cf50e7b20bb8c2e23512a3dc79de987a1f411cb458ab670eb90", + "sha256:436474f17733c7dca0fbf096d36ae65277e8645039df12a0fa52445ca494729d", + "sha256:4dc889a9d8a34758d0fcc9ac86adb97bab3fb7f0c4d29794357eb147536483fd", + "sha256:4e21b76075c01d65d0f0f34302b5a7457d95721d5e0667aea65e5bb3ab415c25", + "sha256:516fb8c77805159e97a689e2f1c80655c7658f5af601c34ffdb916605598cda2", + "sha256:5576ee2f3a309d2bb403ec292d5958ce03953b0e57a11d224c1f134feaf8c40f", + "sha256:5a024fa96d541fd7edaa0e9d904601c6445e95a729a2900c5aec6555fe921ed6", + "sha256:5d0e8a6434a3fbf77d11448c9c25b2f25244226cfbec1a5159947cac5b8c5fa4", + "sha256:5e7d63ec01fe7c76c2dbb7e972fece45acbb8836e72682bde138e7e039906e2c", + "sha256:60e820ee1004327609b28db8307acc27f5f2e9a0b185b2064c5f23e815f248f8", + "sha256:637b802f3f069a64436d432117a7e58fab414b4e27a7e81049817ae94de45d8d", + "sha256:65dcf105c1943cba45d19207ef51b8bc46d232a381e94dd38719d52d3980015b", + "sha256:698ea95a60c8b16b58be9d854c9f993c639f5c214cf9ba782eca53a8789d6b19", + "sha256:70fcc6c2906cfa5c6a552ba7ae2ce64b6c32f437d8f3f8eea49925b278a61453", + "sha256:720215373a280f78a1814becb1312d4e4d1077b1202a56d2b0815e95ccb99ce9", + "sha256:7450dbd659fed6dd41d1a7d47ed767e893ba402af8ae664c157c255ec6067fde", + "sha256:7b7d9ca34542099b4e185b3c2a2b2eda2e318a7dbde0b0d83357a6d4421b5296", + "sha256:7fbd70cb8b54fe745301921b0816c08b6d917593429dfc437fd024b5ba713c58", + "sha256:81038ff87a4e04c22e1d81f947c6ac46f122e0c80460b9006e6517c4d842a6ec", + "sha256:810685321f4a304b2b55577c915bece4c4a06dfe38f6e62d9cc1d6ca8ee86b99", + "sha256:82ada4a8ed9e82e443fcef87e22a3eed3654dd3adf6e3b3a0deb70f03e86142a", + "sha256:841320e1841bb53fada91c9725e766bb25009cfd4144e92298db296fb6c894fb", + "sha256:8587fd64c2a91c33cdc39d0cebdaf30e79491cc029a37fcd458ba863f8815383", + "sha256:8ffe53e1d8ef2520ebcf0c9fec15bb721da59e8ef283b6ff3079613b1e30513d", + "sha256:9051e3d2af8f55b42061603e29e744724cb5f65b128a491446cc029b3e2ea896", + "sha256:91e5a8200e65aaac342a791272c564dffcf1281abd635d304d6c4e6b495f29dc", + "sha256:93432e747fb07fa567ad9cc7aaadd6e29710e515aabf939dfbed8046041346c6", + "sha256:938eab7323a736533f015e6069a7d53ef2dcc841e4e533b782c2bfb9fb12d84b", + "sha256:9584f8f52010295a4a417221861df9bea4c72d9632562b6e59b3c7b87a1522b7", + "sha256:9737bdaa0ad33d34c0efc718741abaafce62fadae72c8b251df9b0c823c63b22", + "sha256:99da0a4686ada4ed0f778120a0ea8d066de1a0a92ab0d13ae68492a437db78bf", + "sha256:99f567dae93e10be2daaa896e07513dd4bf9c2ecf0576e0533ac36ba3b1d5394", + "sha256:9bdf1303df671179eaf2cb41e8515a07fc78d9d00f111eadbe3e14262f59c3d0", + "sha256:9f0e4dc0f17dcea4ab9d13ac5c666b6b5337042b4d8f27e01b70fae41dd65c57", + "sha256:a000133a90eea274a6f28adc3084643263b1e7c1a5a66eb0a0a7a36aa757ed74", + "sha256:a3264e3e858de4fc601741498215835ff324ff2482fd4e4af61b46512dd7fc83", + "sha256:a71169d505af63bb4d20d23a8fbd4c6ce272e7bce6cc31f617152aa784436f29", + "sha256:a967dd6afda7715d911c25a6ba1517975acd8d1092b2f326718725461a3d33f9", + "sha256:aa5bfb13f1e89151ade0eb812f7b0d7a4d643406caaad65ce1cbabe0a66d695f", + "sha256:ae35e8e6801c5ab071b992cb2da958eee76340e6926ec693b5ff7d6381441745", + "sha256:b686f25377f9c006acbac63f61614416a6317133ab7fafe5de5f7dc8a06d42eb", + "sha256:b760a56e080a826c2e5af09002c1a037382ed21d03134eb6294812dda268c811", + "sha256:b86b21b348f7e5485fae740d845c65a880f5d1eda1e063bc59bef92d1f7d0c55", + "sha256:b9412abdf0ba70faa6e2ee6c0cc62a8defb772e78860cef419865917d86c7342", + "sha256:bd345a13ce06e94c753dab52f8e71e5252aec1e4f8022d24d56decd31e1b9b23", + "sha256:be22ae34d68544df293152b7e50895ba70d2a833ad9566932d750d3625918b82", + "sha256:bf046179d011e6114daf12a534d874958b039342b347348a78b7cdf0dd9d6041", + "sha256:c3d2010656999b63e628a3c694f23020322b4178c450dc478558a2b6ef3cb9bb", + "sha256:c64602e8be701c6cfe42064b71c84ce62ce66ddc6422c15463fd8127db3d8066", + "sha256:d65e6b4f1443048eb7e833c2accb4fa7ee67cc7d54f31b4f0555b474758bee55", + "sha256:d8bbd8e56f3ba25a7d0cf980fc42b34028848a53a0e36c9918550e0280b9d0b6", + "sha256:da1ead63368c04a9bded7904757dfcae01eba0e0f9bc41d3d7f57ebf1c04015a", + "sha256:dbbb95e6fc91ea3102505d111b327004d1c4ce98d56a4a02e82cd451f9f57140", + "sha256:dbc56680ecf585a384fbd93cd42bc82668b77cb525343170a2d86dafaed2a84b", + "sha256:df3b6f45ba4515632c5064e35ca7f31d51d13d1479673185ba8f9fefbbed58b9", + "sha256:dfe07308b311a8293a0d5ef4e61411c5c20f682db6b5e73de6c7c8824272c256", + "sha256:e796051f2070f47230c745d0a77a91088fbee2cc0502e9b796b9c6471983718c", + "sha256:efa767c220d94aa4ac3a6dd3aeb986e9f229eaf5bce92d8b1b3018d06bed3772", + "sha256:f0b8bf5b8db49d8fd40f54772a1dcf262e8be0ad2ab0206b5a2ec109c176c0a4", + "sha256:f175e95a197f6a4059b50757a3dca33b32b61691bdbd22c29e8a8d21d3914cae", + "sha256:f2f3b28b40fddcb6c1f1f6c88c6f3769cd933fa493ceb79da45968a21dccc920", + "sha256:f6c43b6f97209e370124baf2bf40bb1e8edc25311a158867eb1c3a5d449ebc7a", + "sha256:f7f4cb1f173385e8a39c29510dd11a78bf44e360fb75610594973f5ea141028b", + "sha256:fad059a4bd14c45776600d223ec194e77db6c20255578bb5bcdd7c18fd169361", + "sha256:ff1dcb8e8bc2261a088821b2595ef031c91d499a0c1b031c152d43fe0a6ecec8", + "sha256:ffee088ea9b593cc6160518ba9bd319b5475e5f3e578e4552d63818773c6f56a" ], "markers": "python_version >= '3.8'", - "version": "==0.16.2" + "version": "==0.17.1" }, "s3transfer": { "hashes": [ @@ -519,10 +521,10 @@ "falcon" ], "hashes": [ - "sha256:320a55cdf9da9097a0bead239c35b7e61f53660ef9878861824fd6d9b2eaf3b5", - "sha256:81b5b9ffdd1a374e9eb0c053b5d2012155db9cbe76393a8585677b753bd5fdc1" + "sha256:34ad8cfc9b877aaa2a8eb86bfe5296a467fffe0619b931a05b181c45f6da59bf", + "sha256:78575620331186d32f34b7ece6edea97ce751f58df822547d3ab85517881a27a" ], - "version": "==1.39.1" + "version": "==1.40.0" }, "six": { "hashes": [ @@ -599,12 +601,12 @@ }, "ipython": { "hashes": [ - "sha256:2f55d59370f59d0d2b2212109fe0e6035cfea436b1c0e6150ad2244746272ec5", - "sha256:ac4da4ecf0042fb4e0ce57c60430c2db3c719fa8bdf92f8631d6bd8a5785d1f0" + "sha256:1050a3ab8473488d7eee163796b02e511d0735cf43a04ba2a8348bd0f2eaf8a5", + "sha256:48fbc236fbe0e138b88773fa0437751f14c3645fb483f1d4c5dee58b37e5ce73" ], "index": "pypi", "markers": "python_version >= '3.10'", - "version": "==8.19.0" + "version": "==8.21.0" }, "jedi": { "hashes": [ @@ -616,12 +618,12 @@ }, "jsonschema": { "hashes": [ - "sha256:4f614fd46d8d61258610998997743ec5492a648b33cf478c1ddc23ed4598a5fa", - "sha256:ed6231f0429ecf966f5bc8dfef245998220549cbbcf140f913b7464c52c3b6b3" + "sha256:7996507afae316306f9e2290407761157c6f78002dcf7419acb99822143d1c6f", + "sha256:85727c00279f5fa6bedbe6238d2aa6403bedd8b4864ab11207d07df3cc1b2ee5" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==4.20.0" + "version": "==4.21.1" }, "jsonschema-specifications": { "hashes": [ @@ -672,11 +674,11 @@ }, "pluggy": { "hashes": [ - "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12", - "sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7" + "sha256:7db9f7b503d67d1c5b95f59773ebb58a8c1c288129a88665838012cfb07b8981", + "sha256:8c85c2876142a764e5b7548e7d9a0e0ddb46f5185161049a79b7e974454223be" ], "markers": "python_version >= '3.8'", - "version": "==1.3.0" + "version": "==1.4.0" }, "pook": { "hashes": [ @@ -745,11 +747,11 @@ }, "referencing": { "hashes": [ - "sha256:689e64fe121843dcfd57b71933318ef1f91188ffb45367332700a86ac8fd6161", - "sha256:bdcd3efb936f82ff86f993093f6da7435c7de69a3b3a5a06678a6050184bee99" + "sha256:39240f2ecc770258f28b642dd47fd74bc8b02484de54e1882b74b35ebd779bd5", + "sha256:c775fedf74bc0f9189c2a3be1c12fd03e8c23f4d371dce795df44e06c5b412f7" ], "markers": "python_version >= '3.8'", - "version": "==0.32.0" + "version": "==0.33.0" }, "remote-pdb": { "hashes": [ @@ -762,108 +764,108 @@ }, "rpds-py": { "hashes": [ - "sha256:0474df4ade9a3b4af96c3d36eb81856cb9462e4c6657d4caecfd840d2a13f3c9", - "sha256:071980663c273bf3d388fe5c794c547e6f35ba3335477072c713a3176bf14a60", - "sha256:07aab64e2808c3ebac2a44f67e9dc0543812b715126dfd6fe4264df527556cb6", - "sha256:088396c7c70e59872f67462fcac3ecbded5233385797021976a09ebd55961dfe", - "sha256:162d7cd9cd311c1b0ff1c55a024b8f38bd8aad1876b648821da08adc40e95734", - "sha256:19f00f57fdd38db4bb5ad09f9ead1b535332dbf624200e9029a45f1f35527ebb", - "sha256:1bdbc5fcb04a7309074de6b67fa9bc4b418ab3fc435fec1f2779a0eced688d04", - "sha256:1be2f033df1b8be8c3167ba3c29d5dca425592ee31e35eac52050623afba5772", - "sha256:24f7a2eb3866a9e91f4599851e0c8d39878a470044875c49bd528d2b9b88361c", - "sha256:290a81cfbe4673285cdf140ec5cd1658ffbf63ab359f2b352ebe172e7cfa5bf0", - "sha256:2946b120718eba9af2b4dd103affc1164a87b9e9ebff8c3e4c05d7b7a7e274e2", - "sha256:2bd82db36cd70b3628c0c57d81d2438e8dd4b7b32a6a9f25f24ab0e657cb6c4e", - "sha256:2ddef620e70eaffebed5932ce754d539c0930f676aae6212f8e16cd9743dd365", - "sha256:2e53b9b25cac9065328901713a7e9e3b12e4f57ef4280b370fbbf6fef2052eef", - "sha256:302bd4983bbd47063e452c38be66153760112f6d3635c7eeefc094299fa400a9", - "sha256:349cb40897fd529ca15317c22c0eab67f5ac5178b5bd2c6adc86172045210acc", - "sha256:358dafc89ce3894c7f486c615ba914609f38277ef67f566abc4c854d23b997fa", - "sha256:35953f4f2b3216421af86fd236b7c0c65935936a94ea83ddbd4904ba60757773", - "sha256:35ae5ece284cf36464eb160880018cf6088a9ac5ddc72292a6092b6ef3f4da53", - "sha256:3b811d182ad17ea294f2ec63c0621e7be92a1141e1012383461872cead87468f", - "sha256:3da5a4c56953bdbf6d04447c3410309616c54433146ccdb4a277b9cb499bc10e", - "sha256:3dc6a7620ba7639a3db6213da61312cb4aa9ac0ca6e00dc1cbbdc21c2aa6eb57", - "sha256:3f91df8e6dbb7360e176d1affd5fb0246d2b88d16aa5ebc7db94fd66b68b61da", - "sha256:4022b9dc620e14f30201a8a73898a873c8e910cb642bcd2f3411123bc527f6ac", - "sha256:413b9c17388bbd0d87a329d8e30c1a4c6e44e2bb25457f43725a8e6fe4161e9e", - "sha256:43d4dd5fb16eb3825742bad8339d454054261ab59fed2fbac84e1d84d5aae7ba", - "sha256:44627b6ca7308680a70766454db5249105fa6344853af6762eaad4158a2feebe", - "sha256:44a54e99a2b9693a37ebf245937fd6e9228b4cbd64b9cc961e1f3391ec6c7391", - "sha256:47713dc4fce213f5c74ca8a1f6a59b622fc1b90868deb8e8e4d993e421b4b39d", - "sha256:495a14b72bbe217f2695dcd9b5ab14d4f8066a00f5d209ed94f0aca307f85f6e", - "sha256:4c46ad6356e1561f2a54f08367d1d2e70a0a1bb2db2282d2c1972c1d38eafc3b", - "sha256:4d6a9f052e72d493efd92a77f861e45bab2f6be63e37fa8ecf0c6fd1a58fedb0", - "sha256:509b617ac787cd1149600e731db9274ebbef094503ca25158e6f23edaba1ca8f", - "sha256:5552f328eaef1a75ff129d4d0c437bf44e43f9436d3996e8eab623ea0f5fcf73", - "sha256:5a80e2f83391ad0808b4646732af2a7b67550b98f0cae056cb3b40622a83dbb3", - "sha256:5cf6af100ffb5c195beec11ffaa8cf8523057f123afa2944e6571d54da84cdc9", - "sha256:5e6caa3809e50690bd92fa490f5c38caa86082c8c3315aa438bce43786d5e90d", - "sha256:5ef00873303d678aaf8b0627e111fd434925ca01c657dbb2641410f1cdaef261", - "sha256:69ac7ea9897ec201ce68b48582f3eb34a3f9924488a5432a93f177bf76a82a7e", - "sha256:6a61226465bda9283686db8f17d02569a98e4b13c637be5a26d44aa1f1e361c2", - "sha256:6d904c5693e08bad240f16d79305edba78276be87061c872a4a15e2c301fa2c0", - "sha256:6dace7b26a13353e24613417ce2239491b40a6ad44e5776a18eaff7733488b44", - "sha256:6df15846ee3fb2e6397fe25d7ca6624af9f89587f3f259d177b556fed6bebe2c", - "sha256:703d95c75a72e902544fda08e965885525e297578317989fd15a6ce58414b41d", - "sha256:726ac36e8a3bb8daef2fd482534cabc5e17334052447008405daca7ca04a3108", - "sha256:781ef8bfc091b19960fc0142a23aedadafa826bc32b433fdfe6fd7f964d7ef44", - "sha256:80443fe2f7b3ea3934c5d75fb0e04a5dbb4a8e943e5ff2de0dec059202b70a8b", - "sha256:83640a5d7cd3bff694747d50436b8b541b5b9b9782b0c8c1688931d6ee1a1f2d", - "sha256:84c5a4d1f9dd7e2d2c44097fb09fffe728629bad31eb56caf97719e55575aa82", - "sha256:882ce6e25e585949c3d9f9abd29202367175e0aab3aba0c58c9abbb37d4982ff", - "sha256:888a97002e986eca10d8546e3c8b97da1d47ad8b69726dcfeb3e56348ebb28a3", - "sha256:8aad80645a011abae487d356e0ceb359f4938dfb6f7bcc410027ed7ae4f7bb8b", - "sha256:8cb6fe8ecdfffa0e711a75c931fb39f4ba382b4b3ccedeca43f18693864fe850", - "sha256:8d6b6937ae9eac6d6c0ca3c42774d89fa311f55adff3970fb364b34abde6ed3d", - "sha256:90123853fc8b1747f80b0d354be3d122b4365a93e50fc3aacc9fb4c2488845d6", - "sha256:96f957d6ab25a78b9e7fc9749d754b98eac825a112b4e666525ce89afcbd9ed5", - "sha256:981d135c7cdaf6cd8eadae1c950de43b976de8f09d8e800feed307140d3d6d00", - "sha256:9b32f742ce5b57201305f19c2ef7a184b52f6f9ba6871cc042c2a61f0d6b49b8", - "sha256:9f0350ef2fba5f34eb0c9000ea328e51b9572b403d2f7f3b19f24085f6f598e8", - "sha256:a297a4d08cc67c7466c873c78039d87840fb50d05473db0ec1b7b03d179bf322", - "sha256:a3d7e2ea25d3517c6d7e5a1cc3702cffa6bd18d9ef8d08d9af6717fc1c700eed", - "sha256:a4b682c5775d6a3d21e314c10124599976809455ee67020e8e72df1769b87bc3", - "sha256:a4ebb8b20bd09c5ce7884c8f0388801100f5e75e7f733b1b6613c713371feefc", - "sha256:a61f659665a39a4d17d699ab3593d7116d66e1e2e3f03ef3fb8f484e91908808", - "sha256:a9880b4656efe36ccad41edc66789e191e5ee19a1ea8811e0aed6f69851a82f4", - "sha256:ac08472f41ea77cd6a5dae36ae7d4ed3951d6602833af87532b556c1b4601d63", - "sha256:adc0c3d6fc6ae35fee3e4917628983f6ce630d513cbaad575b4517d47e81b4bb", - "sha256:af27423662f32d7501a00c5e7342f7dbd1e4a718aea7a239781357d15d437133", - "sha256:b2e75e17bd0bb66ee34a707da677e47c14ee51ccef78ed6a263a4cc965a072a1", - "sha256:b634c5ec0103c5cbebc24ebac4872b045cccb9456fc59efdcf6fe39775365bd2", - "sha256:b6f5549d6ed1da9bfe3631ca9483ae906f21410be2445b73443fa9f017601c6f", - "sha256:bd4b677d929cf1f6bac07ad76e0f2d5de367e6373351c01a9c0a39f6b21b4a8b", - "sha256:bf721ede3eb7b829e4a9b8142bd55db0bdc82902720548a703f7e601ee13bdc3", - "sha256:c647ca87fc0ebe808a41de912e9a1bfef9acb85257e5d63691364ac16b81c1f0", - "sha256:ca57468da2d9a660bcf8961637c85f2fbb2aa64d9bc3f9484e30c3f9f67b1dd7", - "sha256:cad0f59ee3dc35526039f4bc23642d52d5f6616b5f687d846bfc6d0d6d486db0", - "sha256:cc97f0640e91d7776530f06e6836c546c1c752a52de158720c4224c9e8053cad", - "sha256:ccd4e400309e1f34a5095bf9249d371f0fd60f8a3a5c4a791cad7b99ce1fd38d", - "sha256:cffa76b385dfe1e38527662a302b19ffb0e7f5cf7dd5e89186d2c94a22dd9d0c", - "sha256:d0dd7ed2f16df2e129496e7fbe59a34bc2d7fc8db443a606644d069eb69cbd45", - "sha256:d452817e0d9c749c431a1121d56a777bd7099b720b3d1c820f1725cb40928f58", - "sha256:d8dda2a806dfa4a9b795950c4f5cc56d6d6159f7d68080aedaff3bdc9b5032f5", - "sha256:dcbe1f8dd179e4d69b70b1f1d9bb6fd1e7e1bdc9c9aad345cdeb332e29d40748", - "sha256:e0441fb4fdd39a230477b2ca9be90868af64425bfe7b122b57e61e45737a653b", - "sha256:e04e56b4ca7a770593633556e8e9e46579d66ec2ada846b401252a2bdcf70a6d", - "sha256:e061de3b745fe611e23cd7318aec2c8b0e4153939c25c9202a5811ca911fd733", - "sha256:e93ec1b300acf89730cf27975ef574396bc04edecc358e9bd116fb387a123239", - "sha256:e9e557db6a177470316c82f023e5d571811c9a4422b5ea084c85da9aa3c035fc", - "sha256:eab36eae3f3e8e24b05748ec9acc66286662f5d25c52ad70cadab544e034536b", - "sha256:ec23fcad480e77ede06cf4127a25fc440f7489922e17fc058f426b5256ee0edb", - "sha256:ec2e1cf025b2c0f48ec17ff3e642661da7ee332d326f2e6619366ce8e221f018", - "sha256:ed99b4f7179d2111702020fd7d156e88acd533f5a7d3971353e568b6051d5c97", - "sha256:ee94cb58c0ba2c62ee108c2b7c9131b2c66a29e82746e8fa3aa1a1effbd3dcf1", - "sha256:f19afcfc0dd0dca35694df441e9b0f95bc231b512f51bded3c3d8ca32153ec19", - "sha256:f1b9d9260e06ea017feb7172976ab261e011c1dc2f8883c7c274f6b2aabfe01a", - "sha256:f28ac0e8e7242d140f99402a903a2c596ab71550272ae9247ad78f9a932b5698", - "sha256:f42e25c016927e2a6b1ce748112c3ab134261fc2ddc867e92d02006103e1b1b7", - "sha256:f4bd4578e44f26997e9e56c96dedc5f1af43cc9d16c4daa29c771a00b2a26851", - "sha256:f811771019f063bbd0aa7bb72c8a934bc13ebacb4672d712fc1639cfd314cccc" + "sha256:01f58a7306b64e0a4fe042047dd2b7d411ee82e54240284bab63e325762c1147", + "sha256:0210b2668f24c078307260bf88bdac9d6f1093635df5123789bfee4d8d7fc8e7", + "sha256:02866e060219514940342a1f84303a1ef7a1dad0ac311792fbbe19b521b489d2", + "sha256:0387ce69ba06e43df54e43968090f3626e231e4bc9150e4c3246947567695f68", + "sha256:060f412230d5f19fc8c8b75f315931b408d8ebf56aec33ef4168d1b9e54200b1", + "sha256:071bc28c589b86bc6351a339114fb7a029f5cddbaca34103aa573eba7b482382", + "sha256:0bfb09bf41fe7c51413f563373e5f537eaa653d7adc4830399d4e9bdc199959d", + "sha256:10162fe3f5f47c37ebf6d8ff5a2368508fe22007e3077bf25b9c7d803454d921", + "sha256:149c5cd24f729e3567b56e1795f74577aa3126c14c11e457bec1b1c90d212e38", + "sha256:1701fc54460ae2e5efc1dd6350eafd7a760f516df8dbe51d4a1c79d69472fbd4", + "sha256:1957a2ab607f9added64478a6982742eb29f109d89d065fa44e01691a20fc20a", + "sha256:1a746a6d49665058a5896000e8d9d2f1a6acba8a03b389c1e4c06e11e0b7f40d", + "sha256:1bfcad3109c1e5ba3cbe2f421614e70439f72897515a96c462ea657261b96518", + "sha256:1d36b2b59e8cc6e576f8f7b671e32f2ff43153f0ad6d0201250a7c07f25d570e", + "sha256:1db228102ab9d1ff4c64148c96320d0be7044fa28bd865a9ce628ce98da5973d", + "sha256:1dc29db3900cb1bb40353772417800f29c3d078dbc8024fd64655a04ee3c4bdf", + "sha256:1e626b365293a2142a62b9a614e1f8e331b28f3ca57b9f05ebbf4cf2a0f0bdc5", + "sha256:1f3c3461ebb4c4f1bbc70b15d20b565759f97a5aaf13af811fcefc892e9197ba", + "sha256:20de7b7179e2031a04042e85dc463a93a82bc177eeba5ddd13ff746325558aa6", + "sha256:24e4900a6643f87058a27320f81336d527ccfe503984528edde4bb660c8c8d59", + "sha256:2528ff96d09f12e638695f3a2e0c609c7b84c6df7c5ae9bfeb9252b6fa686253", + "sha256:25f071737dae674ca8937a73d0f43f5a52e92c2d178330b4c0bb6ab05586ffa6", + "sha256:270987bc22e7e5a962b1094953ae901395e8c1e1e83ad016c5cfcfff75a15a3f", + "sha256:292f7344a3301802e7c25c53792fae7d1593cb0e50964e7bcdcc5cf533d634e3", + "sha256:2953937f83820376b5979318840f3ee47477d94c17b940fe31d9458d79ae7eea", + "sha256:2a792b2e1d3038daa83fa474d559acfd6dc1e3650ee93b2662ddc17dbff20ad1", + "sha256:2a7b2f2f56a16a6d62e55354dd329d929560442bd92e87397b7a9586a32e3e76", + "sha256:2f4eb548daf4836e3b2c662033bfbfc551db58d30fd8fe660314f86bf8510b93", + "sha256:3664d126d3388a887db44c2e293f87d500c4184ec43d5d14d2d2babdb4c64cad", + "sha256:3677fcca7fb728c86a78660c7fb1b07b69b281964673f486ae72860e13f512ad", + "sha256:380e0df2e9d5d5d339803cfc6d183a5442ad7ab3c63c2a0982e8c824566c5ccc", + "sha256:3ac732390d529d8469b831949c78085b034bff67f584559340008d0f6041a049", + "sha256:4128980a14ed805e1b91a7ed551250282a8ddf8201a4e9f8f5b7e6225f54170d", + "sha256:4341bd7579611cf50e7b20bb8c2e23512a3dc79de987a1f411cb458ab670eb90", + "sha256:436474f17733c7dca0fbf096d36ae65277e8645039df12a0fa52445ca494729d", + "sha256:4dc889a9d8a34758d0fcc9ac86adb97bab3fb7f0c4d29794357eb147536483fd", + "sha256:4e21b76075c01d65d0f0f34302b5a7457d95721d5e0667aea65e5bb3ab415c25", + "sha256:516fb8c77805159e97a689e2f1c80655c7658f5af601c34ffdb916605598cda2", + "sha256:5576ee2f3a309d2bb403ec292d5958ce03953b0e57a11d224c1f134feaf8c40f", + "sha256:5a024fa96d541fd7edaa0e9d904601c6445e95a729a2900c5aec6555fe921ed6", + "sha256:5d0e8a6434a3fbf77d11448c9c25b2f25244226cfbec1a5159947cac5b8c5fa4", + "sha256:5e7d63ec01fe7c76c2dbb7e972fece45acbb8836e72682bde138e7e039906e2c", + "sha256:60e820ee1004327609b28db8307acc27f5f2e9a0b185b2064c5f23e815f248f8", + "sha256:637b802f3f069a64436d432117a7e58fab414b4e27a7e81049817ae94de45d8d", + "sha256:65dcf105c1943cba45d19207ef51b8bc46d232a381e94dd38719d52d3980015b", + "sha256:698ea95a60c8b16b58be9d854c9f993c639f5c214cf9ba782eca53a8789d6b19", + "sha256:70fcc6c2906cfa5c6a552ba7ae2ce64b6c32f437d8f3f8eea49925b278a61453", + "sha256:720215373a280f78a1814becb1312d4e4d1077b1202a56d2b0815e95ccb99ce9", + "sha256:7450dbd659fed6dd41d1a7d47ed767e893ba402af8ae664c157c255ec6067fde", + "sha256:7b7d9ca34542099b4e185b3c2a2b2eda2e318a7dbde0b0d83357a6d4421b5296", + "sha256:7fbd70cb8b54fe745301921b0816c08b6d917593429dfc437fd024b5ba713c58", + "sha256:81038ff87a4e04c22e1d81f947c6ac46f122e0c80460b9006e6517c4d842a6ec", + "sha256:810685321f4a304b2b55577c915bece4c4a06dfe38f6e62d9cc1d6ca8ee86b99", + "sha256:82ada4a8ed9e82e443fcef87e22a3eed3654dd3adf6e3b3a0deb70f03e86142a", + "sha256:841320e1841bb53fada91c9725e766bb25009cfd4144e92298db296fb6c894fb", + "sha256:8587fd64c2a91c33cdc39d0cebdaf30e79491cc029a37fcd458ba863f8815383", + "sha256:8ffe53e1d8ef2520ebcf0c9fec15bb721da59e8ef283b6ff3079613b1e30513d", + "sha256:9051e3d2af8f55b42061603e29e744724cb5f65b128a491446cc029b3e2ea896", + "sha256:91e5a8200e65aaac342a791272c564dffcf1281abd635d304d6c4e6b495f29dc", + "sha256:93432e747fb07fa567ad9cc7aaadd6e29710e515aabf939dfbed8046041346c6", + "sha256:938eab7323a736533f015e6069a7d53ef2dcc841e4e533b782c2bfb9fb12d84b", + "sha256:9584f8f52010295a4a417221861df9bea4c72d9632562b6e59b3c7b87a1522b7", + "sha256:9737bdaa0ad33d34c0efc718741abaafce62fadae72c8b251df9b0c823c63b22", + "sha256:99da0a4686ada4ed0f778120a0ea8d066de1a0a92ab0d13ae68492a437db78bf", + "sha256:99f567dae93e10be2daaa896e07513dd4bf9c2ecf0576e0533ac36ba3b1d5394", + "sha256:9bdf1303df671179eaf2cb41e8515a07fc78d9d00f111eadbe3e14262f59c3d0", + "sha256:9f0e4dc0f17dcea4ab9d13ac5c666b6b5337042b4d8f27e01b70fae41dd65c57", + "sha256:a000133a90eea274a6f28adc3084643263b1e7c1a5a66eb0a0a7a36aa757ed74", + "sha256:a3264e3e858de4fc601741498215835ff324ff2482fd4e4af61b46512dd7fc83", + "sha256:a71169d505af63bb4d20d23a8fbd4c6ce272e7bce6cc31f617152aa784436f29", + "sha256:a967dd6afda7715d911c25a6ba1517975acd8d1092b2f326718725461a3d33f9", + "sha256:aa5bfb13f1e89151ade0eb812f7b0d7a4d643406caaad65ce1cbabe0a66d695f", + "sha256:ae35e8e6801c5ab071b992cb2da958eee76340e6926ec693b5ff7d6381441745", + "sha256:b686f25377f9c006acbac63f61614416a6317133ab7fafe5de5f7dc8a06d42eb", + "sha256:b760a56e080a826c2e5af09002c1a037382ed21d03134eb6294812dda268c811", + "sha256:b86b21b348f7e5485fae740d845c65a880f5d1eda1e063bc59bef92d1f7d0c55", + "sha256:b9412abdf0ba70faa6e2ee6c0cc62a8defb772e78860cef419865917d86c7342", + "sha256:bd345a13ce06e94c753dab52f8e71e5252aec1e4f8022d24d56decd31e1b9b23", + "sha256:be22ae34d68544df293152b7e50895ba70d2a833ad9566932d750d3625918b82", + "sha256:bf046179d011e6114daf12a534d874958b039342b347348a78b7cdf0dd9d6041", + "sha256:c3d2010656999b63e628a3c694f23020322b4178c450dc478558a2b6ef3cb9bb", + "sha256:c64602e8be701c6cfe42064b71c84ce62ce66ddc6422c15463fd8127db3d8066", + "sha256:d65e6b4f1443048eb7e833c2accb4fa7ee67cc7d54f31b4f0555b474758bee55", + "sha256:d8bbd8e56f3ba25a7d0cf980fc42b34028848a53a0e36c9918550e0280b9d0b6", + "sha256:da1ead63368c04a9bded7904757dfcae01eba0e0f9bc41d3d7f57ebf1c04015a", + "sha256:dbbb95e6fc91ea3102505d111b327004d1c4ce98d56a4a02e82cd451f9f57140", + "sha256:dbc56680ecf585a384fbd93cd42bc82668b77cb525343170a2d86dafaed2a84b", + "sha256:df3b6f45ba4515632c5064e35ca7f31d51d13d1479673185ba8f9fefbbed58b9", + "sha256:dfe07308b311a8293a0d5ef4e61411c5c20f682db6b5e73de6c7c8824272c256", + "sha256:e796051f2070f47230c745d0a77a91088fbee2cc0502e9b796b9c6471983718c", + "sha256:efa767c220d94aa4ac3a6dd3aeb986e9f229eaf5bce92d8b1b3018d06bed3772", + "sha256:f0b8bf5b8db49d8fd40f54772a1dcf262e8be0ad2ab0206b5a2ec109c176c0a4", + "sha256:f175e95a197f6a4059b50757a3dca33b32b61691bdbd22c29e8a8d21d3914cae", + "sha256:f2f3b28b40fddcb6c1f1f6c88c6f3769cd933fa493ceb79da45968a21dccc920", + "sha256:f6c43b6f97209e370124baf2bf40bb1e8edc25311a158867eb1c3a5d449ebc7a", + "sha256:f7f4cb1f173385e8a39c29510dd11a78bf44e360fb75610594973f5ea141028b", + "sha256:fad059a4bd14c45776600d223ec194e77db6c20255578bb5bcdd7c18fd169361", + "sha256:ff1dcb8e8bc2261a088821b2595ef031c91d499a0c1b031c152d43fe0a6ecec8", + "sha256:ffee088ea9b593cc6160518ba9bd319b5475e5f3e578e4552d63818773c6f56a" ], "markers": "python_version >= '3.8'", - "version": "==0.16.2" + "version": "==0.17.1" }, "six": { "hashes": [ @@ -890,18 +892,18 @@ }, "traitlets": { "hashes": [ - "sha256:f14949d23829023013c47df20b4a76ccd1a85effb786dc060f34de7948361b33", - "sha256:fcdaa8ac49c04dfa0ed3ee3384ef6dfdb5d6f3741502be247279407679296772" + "sha256:2e5a030e6eff91737c643231bfcf04a65b0132078dad75e4936700b213652e74", + "sha256:8585105b371a04b8316a43d5ce29c098575c2e477850b62b848b964f1444527e" ], "markers": "python_version >= '3.8'", - "version": "==5.14.0" + "version": "==5.14.1" }, "wcwidth": { "hashes": [ - "sha256:f01c104efdf57971bcb756f054dd58ddec5204dd15fa31d6503ea57947d97c02", - "sha256:f26ec43d96c8cbfed76a5075dac87680124fa84e0855195a6184da9c187f133c" + "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859", + "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5" ], - "version": "==0.2.12" + "version": "==0.2.13" }, "xmltodict": { "hashes": [ diff --git a/ingestion_server/ingestion_server/api.py b/ingestion_server/ingestion_server/api.py index dc004a8674a..7285fc695d6 100644 --- a/ingestion_server/ingestion_server/api.py +++ b/ingestion_server/ingestion_server/api.py @@ -1,10 +1,9 @@ """A small RPC API server for scheduling data refresh and indexing tasks.""" -from collections import defaultdict - import logging import os import time import uuid +from collections import defaultdict from multiprocessing import Process, Value from pathlib import Path from urllib.parse import urlparse @@ -17,8 +16,8 @@ from ingestion_server import slack from ingestion_server.constants.media_types import MEDIA_TYPES, MediaType from ingestion_server.db_helpers import ( - DB_UPSTREAM_CONFIG, DB_API_CONFIG, + DB_UPSTREAM_CONFIG, database_connect, ) from ingestion_server.es_helpers import elasticsearch_connect, get_stat diff --git a/ingestion_server/ingestion_server/cleanup.py b/ingestion_server/ingestion_server/cleanup.py index e7a5dfa3058..23f69f84390 100644 --- a/ingestion_server/ingestion_server/cleanup.py +++ b/ingestion_server/ingestion_server/cleanup.py @@ -14,8 +14,9 @@ import tldextract from psycopg2.extras import DictCursor, Json -from ingestion_server.indexer import DB_BUFFER_SIZE from ingestion_server.db_helpers import database_connect +from ingestion_server.indexer import DB_BUFFER_SIZE + # Number of records to buffer in memory at once CLEANUP_BUFFER_SIZE = DB_BUFFER_SIZE diff --git a/ingestion_server/ingestion_server/distributed_reindex_scheduler.py b/ingestion_server/ingestion_server/distributed_reindex_scheduler.py index 9bd3eb4919e..c17b0143bf3 100644 --- a/ingestion_server/ingestion_server/distributed_reindex_scheduler.py +++ b/ingestion_server/ingestion_server/distributed_reindex_scheduler.py @@ -50,11 +50,17 @@ def _assign_work(db_conn, workers, model_name, table_name, target_index): worker_url_template = "http://{}:8002" # Wait for the workers to start. + failures = [] for worker in workers: worker_url = worker_url_template.format(worker) succeeded = _wait_for_healthcheck(f"{worker_url}/healthcheck") if not succeeded: - return False + failures.append(worker) + if failures: + raise ValueError( + f"Some workers didn't respond to health check: {','.join(failures)}" + ) + for idx, worker in enumerate(workers): worker_url = worker_url_template.format(worker) params = { diff --git a/ingestion_server/ingestion_server/ingest.py b/ingestion_server/ingestion_server/ingest.py index f400f10ffd0..dacd7395d07 100644 --- a/ingestion_server/ingestion_server/ingest.py +++ b/ingestion_server/ingestion_server/ingest.py @@ -26,7 +26,7 @@ from ingestion_server import slack from ingestion_server.cleanup import clean_image_data from ingestion_server.constants.internal_types import ApproachType -from ingestion_server.db_helpers import database_connect, DB_UPSTREAM_CONFIG +from ingestion_server.db_helpers import DB_UPSTREAM_CONFIG, database_connect from ingestion_server.queries import ( get_copy_data_query, get_create_ext_query, diff --git a/ingestion_server/justfile b/ingestion_server/justfile index fda1656fce8..10c082f67bf 100644 --- a/ingestion_server/justfile +++ b/ingestion_server/justfile @@ -99,6 +99,9 @@ create-and-populate-filtered-index model="image" destination_suffix="init": # Run ingestion-server tests locally test-local *args: + # populate the tldextract cache before running tests to prevent unnecessary network requests during tests + # and from needing to mock essentially unmockable responses + pipenv run tldextract --update pipenv run pytest {{ args }} {{ if IS_CI == "" { "just test-logs > test/ingestion_logs.txt && just test-clean-dc" } else { "" } }} diff --git a/ingestion_server/test/unit_tests/test_cleanup.py b/ingestion_server/test/unit_tests/test_cleanup.py index 8e6daa2c766..696a873c065 100644 --- a/ingestion_server/test/unit_tests/test_cleanup.py +++ b/ingestion_server/test/unit_tests/test_cleanup.py @@ -1,9 +1,8 @@ -from test.unit_tests.conftest import create_mock_image -from unittest.mock import MagicMock - +import pook from psycopg2._json import Json -from ingestion_server.cleanup import CleanupFunctions, TlsTest +from ingestion_server.cleanup import CleanupFunctions +from test.unit_tests.conftest import create_mock_image class TestCleanup: @@ -42,14 +41,16 @@ def test_accuracy_filter(): assert result == expected @staticmethod + @pook.on def test_url_protocol_fix(): bad_url = "flickr.com" tls_support_cache = {} + pook.get("https://flickr.com").reply(200) result = CleanupFunctions.cleanup_url(bad_url, tls_support_cache) expected = "'https://flickr.com'" bad_http = "neverssl.com" - TlsTest.test_tls_supported = MagicMock(return_value=False) + pook.get("https://neverssl.com").reply(500) result_http = CleanupFunctions.cleanup_url(bad_http, tls_support_cache) expected_http = "'http://neverssl.com'" assert result == expected diff --git a/ingestion_server/test/unit_tests/test_distributed_reindex_scheduler.py b/ingestion_server/test/unit_tests/test_distributed_reindex_scheduler.py new file mode 100644 index 00000000000..5f875a447d6 --- /dev/null +++ b/ingestion_server/test/unit_tests/test_distributed_reindex_scheduler.py @@ -0,0 +1,83 @@ +from unittest import mock + +import pook +import pytest + +from ingestion_server import distributed_reindex_scheduler + + +@pytest.mark.parametrize( + "estimated_records, record_limit, workers, expected_ranges", + [ + # One worker + (100, 1000, ["worker1"], [(0, 100)]), + # Multiple workers, even split + (100, 1000, ["worker1", "worker2"], [(0, 50), (50, 100)]), + # Multiple workers, uneven split + # NOTE: records get dropped in this case + (100, 1000, ["worker1", "worker2", "worker3"], [(0, 33), (33, 66), (66, 99)]), + # One worker, limited + (100, 55, ["worker1"], [(0, 55)]), + # Two workers, limited + (100, 50, ["worker1", "worker2"], [(0, 25), (25, 50)]), + ], +) +def test_assign_work(estimated_records, record_limit, workers, expected_ranges): + # Checks for the parameters + assert len(workers) == len( + expected_ranges + ), "Number of workers and expected ranges do not match, correct the test parameters" + # Set up database mock response + mock_db = mock.MagicMock() + mock_db.cursor.return_value.__enter__.return_value.fetchone.return_value = [ + estimated_records + ] + # Enable pook & mock other internal functions + with pook.use(), mock.patch( + "ingestion_server.distributed_reindex_scheduler.get_record_limit" + ) as mock_get_record_limit, mock.patch( + "ingestion_server.distributed_reindex_scheduler._wait_for_healthcheck" + ) as mock_wait_for_healthcheck: + mock_wait_for_healthcheck.return_value = True + mock_get_record_limit.return_value = record_limit + + # Set up pook matches + for worker, (start_id, end_id) in zip(workers, expected_ranges): + pook.post(f"http://{worker}:8002/indexing_task").json( + { + "model_name": "sample_model", + "table_name": "sample_table", + "target_index": "sample_index", + "start_id": start_id, + "end_id": end_id, + } + ) + + distributed_reindex_scheduler._assign_work( + mock_db, + workers, + "sample_model", + "sample_table", + "sample_index", + ) + + # Raise an exception to ensure all pook requests were matched + assert pook.isdone() + + +def test_assign_work_workers_fail(): + mock_db = mock.MagicMock() + mock_db.cursor.return_value.__enter__.return_value.fetchone.return_value = [100] + with mock.patch( + "ingestion_server.distributed_reindex_scheduler._wait_for_healthcheck" + ) as mock_wait_for_healthcheck, pook.use(False): + mock_wait_for_healthcheck.return_value = False + + with pytest.raises(ValueError, match="Some workers didn't respond"): + distributed_reindex_scheduler._assign_work( + mock_db, + ["worker"] * 6, + "fake-model", + "fake-table", + "target-index", + ) diff --git a/ingestion_server/test/unit_tests/test_es_image_model.py b/ingestion_server/test/unit_tests/test_es_image_model.py index ad79c950cc0..940261a85c6 100644 --- a/ingestion_server/test/unit_tests/test_es_image_model.py +++ b/ingestion_server/test/unit_tests/test_es_image_model.py @@ -1,6 +1,5 @@ -from test.unit_tests.conftest import create_mock_image - from ingestion_server.elasticsearch_models import Image +from test.unit_tests.conftest import create_mock_image class TestImage: diff --git a/justfile b/justfile index 9f9cfe63f22..d5f584b7940 100644 --- a/justfile +++ b/justfile @@ -23,6 +23,7 @@ DC_USER := env_var_or_default("DC_USER", "opener") cd automations/python && just cd automations/js && just cd documentation && just + cd .vale && just printf "\nTo run a nested recipe, add the folder path before it, like \`just frontend/install\`.\n" ########### @@ -91,6 +92,17 @@ precommit: lint hook="" *files="": precommit python3 pre-commit.pyz run {{ hook }} {{ if files == "" { "--all-files" } else { "--files" } }} {{ files }} +# Run codeowners validator locally. Only enable experimental hooks if there are no uncommitted changes. +lint-codeowners checks="stable": + docker run --rm \ + -u 1000:1000 \ + -v $PWD:/src:rw,Z \ + --workdir=/src \ + -e REPOSITORY_PATH="." \ + -e CHECKS="files,duppaterns,syntax" \ + {{ if checks != "stable" { "-e EXPERIMENTAL_CHECKS='notowned,avoid-shadowing'" } else { "" } }} \ + ghcr.io/mszostok/codeowners-validator:v0.7.4 + ######## # Init # ######## diff --git a/package.json b/package.json index 7da3e57e519..392d7df448c 100644 --- a/package.json +++ b/package.json @@ -9,8 +9,8 @@ }, "author": "Openverse ", "scripts": { - "postinstall": "pnpm --filter ./packages/* run build", - "preeslint": "pnpm --filter eslint-plugin run build", + "postinstall": "pnpm --filter './packages/*' run build", + "preeslint": "pnpm --filter '@openverse/eslint-plugin' run build", "eslint": "eslint --ext .js,.ts,.vue,.json,.json5 --ignore-path .gitignore --ignore-path .eslintignore --max-warnings=0 frontend automations/js packages .pnpmfile.cjs .eslintrc.js prettier.config.js tsconfig.base.json" }, "packageManager": "pnpm@8.12.1", diff --git a/packages/eslint-plugin/package.json b/packages/eslint-plugin/package.json index e26f78b8b88..ec2586a94d2 100644 --- a/packages/eslint-plugin/package.json +++ b/packages/eslint-plugin/package.json @@ -5,7 +5,7 @@ "version": "0.0.0", "main": "dist/index.js", "scripts": { - "build": "swc ./src -d ./dist", + "build": "swc ./src -d ./dist --strip-leading-paths --delete-dir-on-start", "test:unit": "pnpm run build && jest", "types": "tsc -p ." }, @@ -20,7 +20,7 @@ "eslint-plugin-eslint-comments": "^3.2.0", "eslint-plugin-import": "^2.28.1", "eslint-plugin-jest": "^27.2.3", - "eslint-plugin-playwright": "^0.21.0", + "eslint-plugin-playwright": "^0.22.0", "eslint-plugin-tsdoc": "^0.2.17", "eslint-plugin-unicorn": "^48.0.1", "eslint-plugin-vue": "^9.17.0", @@ -30,7 +30,7 @@ }, "devDependencies": { "@eslint/eslintrc": "^2.1.2", - "@swc/cli": "^0.1.62", + "@swc/cli": "^0.3.0", "@swc/core": "^1.3.82", "@swc/jest": "^0.2.29", "@typescript-eslint/rule-tester": "^6.5.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b2d72b6a0ee..f78e2cad6a0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -191,8 +191,8 @@ importers: specifier: ^0.1.0 version: 0.1.3(pinia@2.0.33)(vue@2.7.15) '@playwright/test': - specifier: 1.40.1 - version: 1.40.1 + specifier: 1.41.2 + version: 1.41.2 '@tailwindcss/typography': specifier: ^0.5.10 version: 0.5.10(tailwindcss@3.3.5) @@ -215,8 +215,8 @@ importers: specifier: ^29.5.4 version: 29.5.4 '@types/node': - specifier: 18.19.4 - version: 18.19.4 + specifier: 18.19.14 + version: 18.19.14 '@types/throttle-debounce': specifier: ^5.0.0 version: 5.0.0 @@ -262,9 +262,9 @@ importers: jest-transform-stub: specifier: ^2.0.0 version: 2.0.0 - npm-run-all: - specifier: ^4.1.5 - version: 4.1.5 + npm-run-all2: + specifier: ^6.1.2 + version: 6.1.2 postcss: specifier: ^8.4.31 version: 8.4.31 @@ -282,7 +282,7 @@ importers: version: 3.0.1 ts-node: specifier: ^10.9.1 - version: 10.9.1(@types/node@18.19.4)(typescript@5.2.2) + version: 10.9.1(@types/node@18.19.14)(typescript@5.2.2) typescript: specifier: ^5.2.2 version: 5.2.2 @@ -344,8 +344,8 @@ importers: specifier: ^27.2.3 version: 27.2.3(@typescript-eslint/eslint-plugin@6.5.0)(eslint@8.48.0)(jest@29.6.4)(typescript@5.2.2) eslint-plugin-playwright: - specifier: ^0.21.0 - version: 0.21.0(eslint-plugin-jest@27.2.3)(eslint@8.48.0) + specifier: ^0.22.0 + version: 0.22.2(eslint-plugin-jest@27.2.3)(eslint@8.48.0) eslint-plugin-tsdoc: specifier: ^0.2.17 version: 0.2.17 @@ -369,8 +369,8 @@ importers: specifier: ^2.1.2 version: 2.1.2 '@swc/cli': - specifier: ^0.1.62 - version: 0.1.62(@swc/core@1.3.82) + specifier: ^0.3.0 + version: 0.3.9(@swc/core@1.3.82) '@swc/core': specifier: ^1.3.82 version: 1.3.82 @@ -439,7 +439,7 @@ packages: resolution: {integrity: sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==} engines: {node: '>=6.9.0'} dependencies: - '@babel/highlight': 7.18.6 + '@babel/highlight': 7.22.20 dev: true /@babel/code-frame@7.22.10: @@ -475,7 +475,7 @@ packages: resolution: {integrity: sha512-gTXYh3M5wb7FRXQy+FErKFAv90BnlOuNn1QkCK2lREoPAjrQCO49+HVSrFoe5uakFAF5eenS75KbO2vQiLrTMQ==} engines: {node: '>=6.9.0'} dependencies: - '@babel/code-frame': 7.22.5 + '@babel/code-frame': 7.22.13 '@babel/generator': 7.22.5 '@babel/helper-module-transforms': 7.22.5 '@babel/helpers': 7.22.5 @@ -1089,15 +1089,6 @@ packages: - supports-color dev: false - /@babel/highlight@7.18.6: - resolution: {integrity: sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/helper-validator-identifier': 7.22.20 - chalk: 2.4.2 - js-tokens: 4.0.0 - dev: true - /@babel/highlight@7.22.10: resolution: {integrity: sha512-78aUtVcT7MUscr0K5mIEnkwxPE0MaxkR5RxRwuHaQ+JuU5AmTPhY+do2mdzVTnIJJpyBglql2pehuBIWHug+WQ==} engines: {node: '>=6.9.0'} @@ -3453,7 +3444,7 @@ packages: resolution: {integrity: sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/code-frame': 7.22.5 + '@babel/code-frame': 7.22.13 '@babel/parser': 7.23.0 '@babel/types': 7.22.5 @@ -3461,7 +3452,7 @@ packages: resolution: {integrity: sha512-7DuIjPgERaNo6r+PZwItpjCZEa5vyw4eJGufeLxrPdBXBoLcCJCIasvK6pK/9DVNrLZTLFhUGqaC6X/PA007TQ==} engines: {node: '>=6.9.0'} dependencies: - '@babel/code-frame': 7.22.5 + '@babel/code-frame': 7.22.13 '@babel/generator': 7.22.5 '@babel/helper-environment-visitor': 7.22.5 '@babel/helper-function-name': 7.22.5 @@ -3946,7 +3937,7 @@ packages: ajv: 6.12.6 debug: 4.3.4 espree: 9.6.1 - globals: 13.21.0 + globals: 13.24.0 ignore: 5.2.4 import-fresh: 3.3.0 js-yaml: 4.1.0 @@ -4127,7 +4118,7 @@ packages: engines: {node: '>= 10.14.2'} dependencies: '@jest/types': 26.6.2 - '@types/node': 18.19.4 + '@types/node': 18.19.14 chalk: 4.1.2 jest-message-util: 26.6.2 jest-util: 26.6.2 @@ -4139,7 +4130,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/types': 29.6.3 - '@types/node': 18.19.4 + '@types/node': 18.19.14 chalk: 4.1.2 jest-message-util: 29.6.3 jest-util: 29.6.3 @@ -4154,7 +4145,7 @@ packages: '@jest/test-result': 26.6.2 '@jest/transform': 26.6.2 '@jest/types': 26.6.2 - '@types/node': 18.19.4 + '@types/node': 18.19.14 ansi-escapes: 4.3.2 chalk: 4.1.2 exit: 0.1.2 @@ -4199,14 +4190,14 @@ packages: '@jest/test-result': 29.6.4 '@jest/transform': 29.6.4 '@jest/types': 29.6.3 - '@types/node': 18.19.4 + '@types/node': 18.19.14 ansi-escapes: 4.3.2 chalk: 4.1.2 ci-info: 3.8.0 exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 29.6.3 - jest-config: 29.6.4(@types/node@18.19.4) + jest-config: 29.6.4(@types/node@18.19.14) jest-haste-map: 29.6.4 jest-message-util: 29.6.3 jest-regex-util: 29.6.3 @@ -4240,7 +4231,7 @@ packages: dependencies: '@jest/fake-timers': 26.6.2 '@jest/types': 26.6.2 - '@types/node': 18.19.4 + '@types/node': 18.19.14 jest-mock: 26.6.2 dev: true @@ -4250,7 +4241,7 @@ packages: dependencies: '@jest/fake-timers': 29.6.4 '@jest/types': 29.6.3 - '@types/node': 18.19.4 + '@types/node': 18.19.14 jest-mock: 29.6.3 /@jest/expect-utils@29.6.4: @@ -4274,7 +4265,7 @@ packages: dependencies: '@jest/types': 26.6.2 '@sinonjs/fake-timers': 6.0.1 - '@types/node': 18.19.4 + '@types/node': 18.19.14 jest-message-util: 26.6.2 jest-mock: 26.6.2 jest-util: 26.6.2 @@ -4286,7 +4277,7 @@ packages: dependencies: '@jest/types': 29.6.3 '@sinonjs/fake-timers': 10.3.0 - '@types/node': 18.19.4 + '@types/node': 18.19.14 jest-message-util: 29.6.3 jest-mock: 29.6.3 jest-util: 29.6.3 @@ -4360,7 +4351,7 @@ packages: '@jest/transform': 29.6.4 '@jest/types': 29.6.3 '@jridgewell/trace-mapping': 0.3.18 - '@types/node': 18.19.4 + '@types/node': 18.19.14 chalk: 4.1.2 collect-v8-coverage: 1.0.1 exit: 0.1.2 @@ -4500,7 +4491,7 @@ packages: dependencies: '@types/istanbul-lib-coverage': 2.0.3 '@types/istanbul-reports': 3.0.1 - '@types/node': 18.19.4 + '@types/node': 18.19.14 '@types/yargs': 15.0.14 chalk: 4.1.2 dev: true @@ -4511,7 +4502,7 @@ packages: dependencies: '@types/istanbul-lib-coverage': 2.0.3 '@types/istanbul-reports': 3.0.1 - '@types/node': 18.19.4 + '@types/node': 18.19.14 '@types/yargs': 16.0.4 chalk: 4.1.2 dev: true @@ -4522,7 +4513,7 @@ packages: dependencies: '@types/istanbul-lib-coverage': 2.0.3 '@types/istanbul-reports': 3.0.1 - '@types/node': 18.19.4 + '@types/node': 18.19.14 '@types/yargs': 16.0.4 chalk: 4.1.2 dev: true @@ -4534,7 +4525,7 @@ packages: '@jest/schemas': 29.6.3 '@types/istanbul-lib-coverage': 2.0.3 '@types/istanbul-reports': 3.0.1 - '@types/node': 18.19.4 + '@types/node': 18.19.14 '@types/yargs': 17.0.24 chalk: 4.1.2 @@ -5685,12 +5676,12 @@ packages: - vue dev: true - /@playwright/test@1.40.1: - resolution: {integrity: sha512-EaaawMTOeEItCRvfmkI9v6rBkF1svM8wjl/YPRrg2N2Wmp+4qJYkWtJsbew1szfKKDm6fPLy4YAanBhIlf9dWw==} + /@playwright/test@1.41.2: + resolution: {integrity: sha512-qQB9h7KbibJzrDpkXkYvsmiDJK14FULCCZgEcoe2AvFAS64oCirWTwzTlAYEbKaRxWs5TFesE1Na6izMv3HfGg==} engines: {node: '>=16'} hasBin: true dependencies: - playwright: 1.40.1 + playwright: 1.41.2 dev: true /@polka/url@1.0.0-next.21: @@ -7022,9 +7013,9 @@ packages: - webpack-command dev: true - /@swc/cli@0.1.62(@swc/core@1.3.82): - resolution: {integrity: sha512-kOFLjKY3XH1DWLfXL1/B5MizeNorHR8wHKEi92S/Zi9Md/AK17KSqR8MgyRJ6C1fhKHvbBCl8wboyKAFXStkYw==} - engines: {node: '>= 12.13'} + /@swc/cli@0.3.9(@swc/core@1.3.82): + resolution: {integrity: sha512-e5grxGEyNT0fYZEFmhSrRYL1kFAZAXlv+WjfQ35J6J9Hl0EtrMVymAEbGabetg2Q/2FX6HiRcjgc9LrdUCBk4A==} + engines: {node: '>= 16.14.0'} hasBin: true peerDependencies: '@swc/core': ^1.2.66 @@ -7035,8 +7026,11 @@ packages: dependencies: '@mole-inc/bin-wrapper': 8.0.1 '@swc/core': 1.3.82 + '@swc/counter': 0.1.3 commander: 7.2.0 fast-glob: 3.3.1 + minimatch: 9.0.3 + piscina: 4.3.1 semver: 7.5.4 slash: 3.0.0 source-map: 0.7.3 @@ -7156,6 +7150,10 @@ packages: '@swc/core-win32-x64-msvc': 1.3.82 dev: true + /@swc/counter@0.1.3: + resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} + dev: true + /@swc/jest@0.2.29(@swc/core@1.3.82): resolution: {integrity: sha512-8reh5RvHBsSikDC3WGCd5ZTd2BXKkyOdK7QwynrCH58jk2cQFhhHhFBg/jvnWZehUQe/EoOImLENc9/DwbBFow==} engines: {npm: '>= 7.0.0'} @@ -7335,7 +7333,7 @@ packages: resolution: {integrity: sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==} dependencies: '@types/connect': 3.4.37 - '@types/node': 18.19.4 + '@types/node': 18.19.14 dev: true /@types/cacheable-request@6.0.3: @@ -7343,14 +7341,14 @@ packages: dependencies: '@types/http-cache-semantics': 4.0.1 '@types/keyv': 3.1.4 - '@types/node': 18.19.4 + '@types/node': 18.19.14 '@types/responselike': 1.0.0 dev: true /@types/clean-css@4.2.5: resolution: {integrity: sha512-NEzjkGGpbs9S9fgC4abuBvTpVwE3i+Acu9BBod3PUyjDVZcNsGx61b8r2PphR61QGPnn0JHVs5ey6/I4eTrkxw==} dependencies: - '@types/node': 18.19.4 + '@types/node': 18.19.14 source-map: 0.6.1 dev: true @@ -7363,7 +7361,7 @@ packages: /@types/connect@3.4.37: resolution: {integrity: sha512-zBUSRqkfZ59OcwXon4HVxhx5oWCJmc0OtBTK05M+p0dYjgN6iTwIL2T/WbsQZrEsdnwaF9cWQ+azOnpPvIqY3Q==} dependencies: - '@types/node': 18.19.4 + '@types/node': 18.19.14 dev: true /@types/cookie@0.3.3: @@ -7373,13 +7371,13 @@ packages: /@types/etag@1.8.2: resolution: {integrity: sha512-z8Pbo2e+EZWMpuRPYSjhSivp2OEkqrMZBUfEAWlJC31WUCKveZ8ioWXHAC5BXRZfwxCBfYRhPij1YJHK1W6oDA==} dependencies: - '@types/node': 18.19.4 + '@types/node': 18.19.14 dev: true /@types/express-serve-static-core@4.17.26: resolution: {integrity: sha512-zeu3tpouA043RHxW0gzRxwCHchMgftE8GArRsvYT0ByDMbn19olQHx5jLue0LxWY6iYtXb7rXmuVtSkhy9YZvQ==} dependencies: - '@types/node': 18.19.4 + '@types/node': 18.19.14 '@types/qs': 6.9.7 '@types/range-parser': 1.2.4 dev: true @@ -7409,13 +7407,13 @@ packages: resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==} dependencies: '@types/minimatch': 3.0.5 - '@types/node': 18.19.4 + '@types/node': 18.19.14 dev: true /@types/graceful-fs@4.1.5: resolution: {integrity: sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==} dependencies: - '@types/node': 18.19.4 + '@types/node': 18.19.14 /@types/hast@2.3.4: resolution: {integrity: sha512-wLEm0QvaoawEDoTRwzTXp4b4jpwiJDvR5KMnFnVodm3scufTlBOWRD6N1OBf9TZMhjlNsSfcO5V+7AF4+Vy+9g==} @@ -7445,7 +7443,7 @@ packages: /@types/http-proxy@1.17.10: resolution: {integrity: sha512-Qs5aULi+zV1bwKAg5z1PWnDXWmsn+LxIvUGv6E2+OOMYhclZMO+OXd9pYVf2gLykf2I7IV2u7oTHwChPNsvJ7g==} dependencies: - '@types/node': 18.19.4 + '@types/node': 18.19.14 dev: false /@types/is-function@1.0.1: @@ -7488,7 +7486,7 @@ packages: /@types/keyv@3.1.4: resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} dependencies: - '@types/node': 18.19.4 + '@types/node': 18.19.14 dev: true /@types/less@3.0.5: @@ -7516,7 +7514,7 @@ packages: /@types/node-fetch@2.6.1: resolution: {integrity: sha512-oMqjURCaxoSIsHSr1E47QHzbmzNR5rK8McHuNb11BOM9cHcIK3Avy0s/b2JlXHoQGTYS3NsvWzV1M0iK7l0wbA==} dependencies: - '@types/node': 18.19.4 + '@types/node': 18.19.14 form-data: 3.0.1 dev: true @@ -7528,8 +7526,8 @@ packages: resolution: {integrity: sha512-ZOzvDRWp8dCVBmgnkIqYCArgdFOO9YzocZp8Ra25N/RStKiWvMOXHMz+GjSeVNe5TstaTmTWPucGJkDw0XXJWA==} dev: true - /@types/node@18.19.4: - resolution: {integrity: sha512-xNzlUhzoHotIsnFoXmJB+yWmBvFZgKCI9TtPIEdYIMM1KWfwuY8zh7wvc1u1OAXlC7dlf6mZVx/s+Y5KfFz19A==} + /@types/node@18.19.14: + resolution: {integrity: sha512-EnQ4Us2rmOS64nHDWr0XqAD8DsO6f3XR6lf9UIIrZQpUzPVdN/oPuEzfDWNHSyXLvoGgjuEm/sPwFGSSs35Wtg==} dependencies: undici-types: 5.26.5 @@ -7584,13 +7582,13 @@ packages: /@types/responselike@1.0.0: resolution: {integrity: sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==} dependencies: - '@types/node': 18.19.4 + '@types/node': 18.19.14 dev: true /@types/sax@1.2.3: resolution: {integrity: sha512-+QSw6Tqvs/KQpZX8DvIl3hZSjNFLW/OqE5nlyHXtTwODaJvioN2rOWpBNEWZp2HZUFhOh+VohmJku/WxEXU2XA==} dependencies: - '@types/node': 18.19.4 + '@types/node': 18.19.14 dev: false /@types/semver@7.5.0: @@ -7600,7 +7598,7 @@ packages: resolution: {integrity: sha512-NUo5XNiAdULrJENtJXZZ3fHtfMolzZwczzBbnAeBbqBwG+LaG6YaJtuwzwGSQZ2wsCrxjEhNNjAkKigy3n8teQ==} dependencies: '@types/mime': 1.3.2 - '@types/node': 18.19.4 + '@types/node': 18.19.14 dev: true /@types/serve-static@1.15.4: @@ -7608,7 +7606,7 @@ packages: dependencies: '@types/http-errors': 2.0.3 '@types/mime': 1.3.2 - '@types/node': 18.19.4 + '@types/node': 18.19.14 dev: true /@types/source-list-map@0.1.2: @@ -7682,14 +7680,14 @@ packages: /@types/webpack-sources@3.2.0: resolution: {integrity: sha512-Ft7YH3lEVRQ6ls8k4Ff1oB4jN6oy/XmU6tQISKdhfh+1mR+viZFphS6WL0IrtDOzvefmJg5a0s7ZQoRXwqTEFg==} dependencies: - '@types/node': 18.19.4 + '@types/node': 18.19.14 '@types/source-list-map': 0.1.2 source-map: 0.7.3 /@types/webpack@4.41.35: resolution: {integrity: sha512-XRC6HLGHtNfN8/xWeu1YUQV1GSE+28q8lSqvcJ+0xt/zW9Wmn4j9pCSvaXPyRlCKrl5OuqECQNEJUy2vo8oWqg==} dependencies: - '@types/node': 18.19.4 + '@types/node': 18.19.14 '@types/tapable': 1.0.8 '@types/uglify-js': 3.13.1 '@types/webpack-sources': 3.2.0 @@ -8646,6 +8644,11 @@ packages: resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} engines: {node: '>=10'} + /ansi-styles@6.2.1: + resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} + engines: {node: '>=12'} + dev: true + /ansi-to-html@0.6.15: resolution: {integrity: sha512-28ijx2aHJGdzbs+O5SNQF65r6rrKYnkuwTYm8lZlChuoJ9P1vVzIpWO20sQTqTPDXYp6NFwk326vApTtLVFXpQ==} engines: {node: '>=8.0.0'} @@ -11915,8 +11918,8 @@ packages: natural-compare: 1.4.0 dev: true - /eslint-plugin-playwright@0.21.0(eslint-plugin-jest@27.2.3)(eslint@8.48.0): - resolution: {integrity: sha512-Y6qwguE9L6LB1JCsnPKaHbo+Z4X8/MngD82N0NkwiZ0ch0UVc4Oc2ZqmxanFxftIddnvwtNNlzUezglLlzUzKA==} + /eslint-plugin-playwright@0.22.2(eslint-plugin-jest@27.2.3)(eslint@8.48.0): + resolution: {integrity: sha512-LtOB9myIX1O7HHqg9vtvBLjvXq1MXKuXIcD1nS+qZiMUJV6s9HBdilURAr9pIFc9kEelbVF54hOJ8pMxHvJP7g==} peerDependencies: eslint: '>=7' eslint-plugin-jest: '>=25' @@ -14301,7 +14304,7 @@ packages: '@jest/expect': 29.6.4 '@jest/test-result': 29.6.4 '@jest/types': 29.6.3 - '@types/node': 18.19.4 + '@types/node': 18.19.14 chalk: 4.1.2 co: 4.6.0 dedent: 1.5.1 @@ -14364,7 +14367,7 @@ packages: exit: 0.1.2 graceful-fs: 4.2.11 import-local: 3.0.3 - jest-config: 29.6.4(@types/node@18.19.4) + jest-config: 29.6.4(@types/node@18.19.14) jest-util: 29.6.3 jest-validate: 29.6.3 prompts: 2.4.2 @@ -14402,7 +14405,7 @@ packages: jest-validate: 26.6.2 micromatch: 4.0.5 pretty-format: 26.6.2 - ts-node: 10.9.1(@types/node@18.19.4)(typescript@5.2.2) + ts-node: 10.9.1(@types/node@18.19.14)(typescript@5.2.2) transitivePeerDependencies: - bufferutil - canvas @@ -14410,7 +14413,7 @@ packages: - utf-8-validate dev: true - /jest-config@29.6.4(@types/node@18.19.4): + /jest-config@29.6.4(@types/node@18.19.14): resolution: {integrity: sha512-JWohr3i9m2cVpBumQFv2akMEnFEPVOh+9L2xIBJhJ0zOaci2ZXuKJj0tgMKQCBZAKA09H049IR4HVS/43Qb19A==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} peerDependencies: @@ -14425,7 +14428,7 @@ packages: '@babel/core': 7.22.5 '@jest/test-sequencer': 29.6.4 '@jest/types': 29.6.3 - '@types/node': 18.19.4 + '@types/node': 18.19.14 babel-jest: 29.6.4(@babel/core@7.22.5) chalk: 4.1.2 ci-info: 3.8.0 @@ -14509,7 +14512,7 @@ packages: '@jest/environment': 26.6.2 '@jest/fake-timers': 26.6.2 '@jest/types': 26.6.2 - '@types/node': 18.19.4 + '@types/node': 18.19.14 jest-mock: 26.6.2 jest-util: 26.6.2 jsdom: 16.7.0 @@ -14527,7 +14530,7 @@ packages: '@jest/environment': 26.6.2 '@jest/fake-timers': 26.6.2 '@jest/types': 26.6.2 - '@types/node': 18.19.4 + '@types/node': 18.19.14 jest-mock: 26.6.2 jest-util: 26.6.2 dev: true @@ -14539,7 +14542,7 @@ packages: '@jest/environment': 29.6.4 '@jest/fake-timers': 29.6.4 '@jest/types': 29.6.3 - '@types/node': 18.19.4 + '@types/node': 18.19.14 jest-mock: 29.6.3 jest-util: 29.6.3 @@ -14564,7 +14567,7 @@ packages: dependencies: '@jest/types': 26.6.2 '@types/graceful-fs': 4.1.5 - '@types/node': 18.19.4 + '@types/node': 18.19.14 anymatch: 3.1.3 fb-watchman: 2.0.1 graceful-fs: 4.2.11 @@ -14587,7 +14590,7 @@ packages: dependencies: '@jest/types': 29.6.3 '@types/graceful-fs': 4.1.5 - '@types/node': 18.19.4 + '@types/node': 18.19.14 anymatch: 3.1.3 fb-watchman: 2.0.1 graceful-fs: 4.2.11 @@ -14608,7 +14611,7 @@ packages: '@jest/source-map': 26.6.2 '@jest/test-result': 26.6.2 '@jest/types': 26.6.2 - '@types/node': 18.19.4 + '@types/node': 18.19.14 chalk: 4.1.2 co: 4.6.0 expect: 26.6.2 @@ -14667,7 +14670,7 @@ packages: resolution: {integrity: sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA==} engines: {node: '>= 10.14.2'} dependencies: - '@babel/code-frame': 7.22.5 + '@babel/code-frame': 7.22.13 '@jest/types': 26.6.2 '@types/stack-utils': 2.0.1 chalk: 4.1.2 @@ -14697,7 +14700,7 @@ packages: engines: {node: '>= 10.14.2'} dependencies: '@jest/types': 26.6.2 - '@types/node': 18.19.4 + '@types/node': 18.19.14 dev: true /jest-mock@29.6.3: @@ -14705,7 +14708,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/types': 29.6.3 - '@types/node': 18.19.4 + '@types/node': 18.19.14 jest-util: 29.6.3 /jest-pnp-resolver@1.2.2(jest-resolve@26.6.2): @@ -14796,7 +14799,7 @@ packages: '@jest/environment': 26.6.2 '@jest/test-result': 26.6.2 '@jest/types': 26.6.2 - '@types/node': 18.19.4 + '@types/node': 18.19.14 chalk: 4.1.2 emittery: 0.7.2 exit: 0.1.2 @@ -14829,7 +14832,7 @@ packages: '@jest/test-result': 29.6.4 '@jest/transform': 29.6.4 '@jest/types': 29.6.3 - '@types/node': 18.19.4 + '@types/node': 18.19.14 chalk: 4.1.2 emittery: 0.13.1 graceful-fs: 4.2.11 @@ -14899,7 +14902,7 @@ packages: '@jest/test-result': 29.6.4 '@jest/transform': 29.6.4 '@jest/types': 29.6.3 - '@types/node': 18.19.4 + '@types/node': 18.19.14 chalk: 4.1.2 cjs-module-lexer: 1.2.3 collect-v8-coverage: 1.0.1 @@ -14921,7 +14924,7 @@ packages: resolution: {integrity: sha512-S5wqyz0DXnNJPd/xfIzZ5Xnp1HrJWBczg8mMfMpN78OJ5eDxXyf+Ygld9wX1DnUWbIbhM1YDY95NjR4CBXkb2g==} engines: {node: '>= 10.14.2'} dependencies: - '@types/node': 18.19.4 + '@types/node': 18.19.14 graceful-fs: 4.2.11 dev: true @@ -14985,7 +14988,7 @@ packages: engines: {node: '>= 10.14.2'} dependencies: '@jest/types': 26.6.2 - '@types/node': 18.19.4 + '@types/node': 18.19.14 chalk: 4.1.2 graceful-fs: 4.2.11 is-ci: 2.0.0 @@ -14997,7 +15000,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/types': 29.6.3 - '@types/node': 18.19.4 + '@types/node': 18.19.14 chalk: 4.1.2 ci-info: 3.8.0 graceful-fs: 4.2.11 @@ -15032,7 +15035,7 @@ packages: dependencies: '@jest/test-result': 26.6.2 '@jest/types': 26.6.2 - '@types/node': 18.19.4 + '@types/node': 18.19.14 ansi-escapes: 4.3.2 chalk: 4.1.2 jest-util: 26.6.2 @@ -15045,7 +15048,7 @@ packages: dependencies: '@jest/test-result': 29.6.4 '@jest/types': 29.6.3 - '@types/node': 18.19.4 + '@types/node': 18.19.14 ansi-escapes: 4.3.2 chalk: 4.1.2 emittery: 0.13.1 @@ -15056,7 +15059,7 @@ packages: resolution: {integrity: sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==} engines: {node: '>= 10.13.0'} dependencies: - '@types/node': 18.19.4 + '@types/node': 18.19.14 merge-stream: 2.0.0 supports-color: 7.2.0 @@ -15064,7 +15067,7 @@ packages: resolution: {integrity: sha512-6dpvFV4WjcWbDVGgHTWo/aupl8/LbBx2NSKfiwqf79xC/yeJjKHT1+StcKy/2KTmW16hE68ccKVOtXf+WZGz7Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@types/node': 18.19.4 + '@types/node': 18.19.14 jest-util: 29.6.3 merge-stream: 2.0.0 supports-color: 8.1.1 @@ -15255,6 +15258,11 @@ packages: /json-parse-even-better-errors@2.3.1: resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + /json-parse-even-better-errors@3.0.1: + resolution: {integrity: sha512-aatBvbL26wVUCLmbWdCpeu9iF5wOyWpagiKkInA+kfws3sWdBrTnsvN2CKcyCYyUrc7rebNBlK6+kteg7ksecg==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dev: true + /json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} @@ -16194,6 +16202,16 @@ packages: resolution: {integrity: sha512-AO81vsIO1k1sM4Zrd6Hu7regmJN1NSiAja10gc4bX3F0wd+9rQmcuHQaHVQCYIEC8iFXnE+mavh23GOt7wBgug==} dev: true + /nice-napi@1.0.2: + resolution: {integrity: sha512-px/KnJAJZf5RuBGcfD+Sp2pAKq0ytz8j+1NehvgIGFkvtvFrDM3T8E4x/JJODXK9WZow8RRGrbA9QQ3hs+pDhA==} + os: ['!win32'] + requiresBuild: true + dependencies: + node-addon-api: 3.2.1 + node-gyp-build: 4.8.0 + dev: true + optional: true + /nice-try@1.0.5: resolution: {integrity: sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==} dev: true @@ -16214,6 +16232,12 @@ packages: resolution: {integrity: sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==} dev: true + /node-addon-api@3.2.1: + resolution: {integrity: sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==} + requiresBuild: true + dev: true + optional: true + /node-cache@4.2.1: resolution: {integrity: sha512-BOb67bWg2dTyax5kdef5WfU3X8xu4wPg+zHzkvls0Q/QpYycIFRLEEIdAx9Wma43DxG6Qzn4illdZoYseKWa4A==} engines: {node: '>= 0.4.6'} @@ -16244,6 +16268,13 @@ packages: dependencies: whatwg-url: 5.0.0 + /node-gyp-build@4.8.0: + resolution: {integrity: sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og==} + hasBin: true + requiresBuild: true + dev: true + optional: true + /node-html-parser@5.3.3: resolution: {integrity: sha512-ncg1033CaX9UexbyA7e1N0aAoAYRDiV8jkTvzEnfd1GDvzFdrsXLzR4p4ik8mwLgnaKP/jyUFWDy9q3jvRT2Jw==} dependencies: @@ -16364,20 +16395,23 @@ packages: resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==} engines: {node: '>=10'} - /npm-run-all@4.1.5: - resolution: {integrity: sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==} - engines: {node: '>= 4'} + /npm-normalize-package-bin@3.0.1: + resolution: {integrity: sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dev: true + + /npm-run-all2@6.1.2: + resolution: {integrity: sha512-WwwnS8Ft+RpXve6T2EIEVpFLSqN+ORHRvgNk3H9N62SZXjmzKoRhMFg3I17TK3oMaAEr+XFbRirWS2Fn3BCPSg==} + engines: {node: ^14.18.0 || >=16.0.0, npm: '>= 8'} hasBin: true dependencies: - ansi-styles: 3.2.1 - chalk: 2.4.2 - cross-spawn: 6.0.5 + ansi-styles: 6.2.1 + cross-spawn: 7.0.3 memorystream: 0.3.1 - minimatch: 3.1.2 - pidtree: 0.3.1 - read-pkg: 3.0.0 - shell-quote: 1.7.3 - string.prototype.padend: 3.1.3 + minimatch: 9.0.3 + pidtree: 0.6.0 + read-package-json-fast: 3.0.2 + shell-quote: 1.8.1 dev: true /npm-run-path@2.0.2: @@ -16900,7 +16934,7 @@ packages: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} dependencies: - '@babel/code-frame': 7.22.10 + '@babel/code-frame': 7.22.13 error-ex: 1.3.2 json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 @@ -17043,8 +17077,8 @@ packages: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} - /pidtree@0.3.1: - resolution: {integrity: sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==} + /pidtree@0.6.0: + resolution: {integrity: sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==} engines: {node: '>=0.10'} hasBin: true dev: true @@ -17103,6 +17137,12 @@ packages: resolution: {integrity: sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==} engines: {node: '>= 6'} + /piscina@4.3.1: + resolution: {integrity: sha512-MBj0QYm3hJQ/C/wIXTN1OCYC8uQ4BBJ4LVele2P4ZwVQAH04vkk8E1SpDbuemLAL1dZorbuOob9rYqJeWCcCRg==} + optionalDependencies: + nice-napi: 1.0.2 + dev: true + /pkg-dir@3.0.0: resolution: {integrity: sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==} engines: {node: '>=6'} @@ -17142,18 +17182,18 @@ packages: engines: {node: '>=10'} dev: false - /playwright-core@1.40.1: - resolution: {integrity: sha512-+hkOycxPiV534c4HhpfX6yrlawqVUzITRKwHAmYfmsVreltEl6fAZJ3DPfLMOODw0H3s1Itd6MDCWmP1fl/QvQ==} + /playwright-core@1.41.2: + resolution: {integrity: sha512-VaTvwCA4Y8kxEe+kfm2+uUUw5Lubf38RxF7FpBxLPmGe5sdNkSg5e3ChEigaGrX7qdqT3pt2m/98LiyvU2x6CA==} engines: {node: '>=16'} hasBin: true dev: true - /playwright@1.40.1: - resolution: {integrity: sha512-2eHI7IioIpQ0bS1Ovg/HszsN/XKNwEG1kbzSDDmADpclKc7CyqkHw7Mg2JCz/bbCxg25QUPcjksoMW7JcIFQmw==} + /playwright@1.41.2: + resolution: {integrity: sha512-v0bOa6H2GJChDL8pAeLa/LZC4feoAMbSQm1/jF/ySsWWoaNItvrMP7GEkvEEFyCTUYKMxjQKaTSg5up7nR6/8A==} engines: {node: '>=16'} hasBin: true dependencies: - playwright-core: 1.40.1 + playwright-core: 1.41.2 optionalDependencies: fsevents: 2.3.2 dev: true @@ -17581,7 +17621,7 @@ packages: dependencies: lilconfig: 2.1.0 postcss: 8.4.31 - ts-node: 10.9.1(@types/node@18.19.4)(typescript@5.2.2) + ts-node: 10.9.1(@types/node@18.19.14)(typescript@5.2.2) yaml: 2.3.1 dev: true @@ -18891,6 +18931,14 @@ packages: dependencies: pify: 2.3.0 + /read-package-json-fast@3.0.2: + resolution: {integrity: sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dependencies: + json-parse-even-better-errors: 3.0.1 + npm-normalize-package-bin: 3.0.1 + dev: true + /read-pkg-up@1.0.1: resolution: {integrity: sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A==} engines: {node: '>=0.10.0'} @@ -19700,13 +19748,8 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} - /shell-quote@1.7.3: - resolution: {integrity: sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw==} - dev: true - /shell-quote@1.8.1: resolution: {integrity: sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==} - dev: false /shellwords@0.1.1: resolution: {integrity: sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==} @@ -20797,7 +20840,7 @@ packages: resolution: {integrity: sha512-vDWbsl26LIcPGmDpoVzjEP6+hvHZkBkLW7JpvwbCv/5IYPJlsbzCVXY3wsCeAxAUeTclNOUZxnLdGh3VBD/J6w==} dev: true - /ts-node@10.9.1(@types/node@18.19.4)(typescript@5.2.2): + /ts-node@10.9.1(@types/node@18.19.14)(typescript@5.2.2): resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==} hasBin: true peerDependencies: @@ -20816,7 +20859,7 @@ packages: '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 - '@types/node': 18.19.4 + '@types/node': 18.19.14 acorn: 8.10.0 acorn-walk: 8.2.0 arg: 4.1.3 @@ -22169,7 +22212,7 @@ packages: dependencies: imurmurhash: 0.1.4 is-typedarray: 1.0.0 - signal-exit: 3.0.6 + signal-exit: 3.0.7 typedarray-to-buffer: 3.1.5 dev: true diff --git a/pyproject.toml b/pyproject.toml index 3263fb57a41..cc0d058069a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,8 +10,9 @@ ignore-words = ".codespell/ignore_words.txt" # Default for `select` is ["E4", "E7", "E9", "F"] # All additional rules must be added using `extend-select`. extend-select = [ - "UP", + "UP", # pyupgrade, https://docs.astral.sh/ruff/rules/#pyupgrade-up "D", # pydocstyle, https://docs.astral.sh/ruff/rules/#pydocstyle-d + "I", # isort, https://docs.astral.sh/ruff/rules/#isort-i ] ignore = [ "D1", # D1xx: we do not want to force contributors to write redundant or useless docstrings @@ -45,10 +46,12 @@ known-first-party = [ "common", "data_refresh", "database", + "elasticsearch_cluster", "maintenance", "oauth2", "providers", "retired", + "test", ] [tool.ruff.lint.isort.sections] diff --git a/sample_data/sample_image.csv b/sample_data/sample_image.csv index bf160e8031e..095e73a5c68 100644 --- a/sample_data/sample_image.csv +++ b/sample_data/sample_image.csv @@ -324,7 +324,7 @@ cf77d94f-269c-49a9-b3ac-44e2a4381fd2,2022-08-27 09:36:29.000000+00,2022-08-27 09 31132cd9-a281-42fc-91bb-64d9a95f9227,2022-10-04 19:58:50.000000+00,2022-10-04 19:58:50.000000+00,provider_api,flickr,flickr,51745760139,https://www.flickr.com/photos/194609181@N03/51745760139,https://live.staticflickr.com/65535/51745760139_4b96dbc9c9_b.jpg,https://live.staticflickr.com/65535/51745760139_4b96dbc9c9_m.jpg,1024,576,72218,by-nc-sa,2.0,p-games,https://www.flickr.com/photos/194609181@N03,P1000765,"{""views"": ""40"", ""pub_date"": ""1639440849"", ""date_taken"": ""2021-12-04 20:51:35"", ""license_url"": ""https://creativecommons.org/licenses/by-nc-sa/2.0/"", ""raw_license_url"": null}",,f,2021-12-15 20:49:19.976193+00,f,jpg,photograph, c474de50-85b5-4811-b3a5-6cfc6c2ed9d5,2022-06-03 10:10:37.000000+00,2022-06-03 10:10:37.000000+00,provider_api,flickr,flickr,51745357723,https://www.flickr.com/photos/194609181@N03/51745357723,https://live.staticflickr.com/65535/51745357723_be8a7c7752_b.jpg,https://live.staticflickr.com/65535/51745357723_be8a7c7752_m.jpg,1024,576,95968,by-nc-sa,2.0,p-games,https://www.flickr.com/photos/194609181@N03,P1000758,"{""views"": ""40"", ""pub_date"": ""1639440852"", ""date_taken"": ""2021-12-04 20:43:14"", ""license_url"": ""https://creativecommons.org/licenses/by-nc-sa/2.0/"", ""raw_license_url"": null}",,f,2021-12-15 20:49:19.976193+00,f,jpg,photograph, 79ff3390-1b8a-4b15-a6b5-fb9e43f0ba80,2022-05-01 02:21:12.000000+00,2022-05-01 02:21:12.000000+00,provider_api,flickr,flickr,51747500143,https://www.flickr.com/photos/128831778@N05/51747500143,https://live.staticflickr.com/65535/51747500143_3b6e462ae8_b.jpg,https://live.staticflickr.com/65535/51747500143_3b6e462ae8_m.jpg,1024,816,298340,by-nc-sa,2.0,Laurentrekk Photographies,https://www.flickr.com/photos/128831778@N05,Roller Derby - Anglet - Salle du Pignada - 'Valient Bitchiz' du Anglet Roller Derby & 'Kontra Bandista' du Euskal Roller Derby de Bayonne - 2021.12.05,"{""views"": ""40"", ""pub_date"": ""1639527045"", ""date_taken"": ""2021-12-05 15:30:32"", ""license_url"": ""https://creativecommons.org/licenses/by-nc-sa/2.0/""}","[{""name"": ""anglet"", ""provider"": ""flickr""}, {""name"": ""bandista"", ""provider"": ""flickr""}, {""name"": ""bayonne"", ""provider"": ""flickr""}, {""name"": ""bitchiz"", ""provider"": ""flickr""}, {""name"": ""kontra"", ""provider"": ""flickr""}, {""name"": ""kontrabandista"", ""provider"": ""flickr""}, {""name"": ""photo"", ""provider"": ""flickr""}, {""name"": ""photographer"", ""provider"": ""flickr""}, {""name"": ""photos"", ""provider"": ""flickr""}, {""name"": ""photosports"", ""provider"": ""flickr""}, {""name"": ""pictures"", ""provider"": ""flickr""}, {""name"": ""roller"", ""provider"": ""flickr""}, {""name"": ""rollerstadium"", ""provider"": ""flickr""}, {""name"": ""sport"", ""provider"": ""flickr""}, {""name"": ""sportphoto"", ""provider"": ""flickr""}, {""name"": ""sportpics"", ""provider"": ""flickr""}, {""name"": ""sports"", ""provider"": ""flickr""}, {""name"": ""sportspics"", ""provider"": ""flickr""}, {""name"": ""valient"", ""provider"": ""flickr""}, {""name"": ""valientbitchiz"", ""provider"": ""flickr""}]",f,2021-12-15 22:19:02.971943+00,f,jpg,photograph, -027e86f8-ab89-4634-84ed-fb17bfdb0342,2022-08-28 13:46:12.000000+00,2022-08-28 13:46:12.000000+00,provider_api,flickr,flickr,51747299011,https://www.flickr.com/photos/89165847@N00/51747299011,https://live.staticflickr.com/65535/51747299011_182253e920_b.jpg,https://live.staticflickr.com/65535/51747299011_182253e920_m.jpg,1024,768,185539,by-sa,2.0,mikecogh,https://www.flickr.com/photos/89165847@N00,Big CAT on the Beach,"{""views"": ""40"", ""pub_date"": ""1639527329"", ""date_taken"": ""2021-07-04 11:43:05"", ""license_url"": ""https://creativecommons.org/licenses/by-sa/2.0/""}","[{""name"": ""3290"", ""provider"": ""flickr""}, {""name"": ""adelaide"", ""provider"": ""flickr""}, {""name"": ""beach"", ""provider"": ""flickr""}, {""name"": ""brand"", ""provider"": ""flickr""}, {""name"": ""cat"", ""provider"": ""flickr""}, {""name"": ""caterpillar"", ""provider"": ""flickr""}, {""name"": ""digger"", ""provider"": ""flickr""}, {""name"": ""dunes"", ""provider"": ""flickr""}, {""name"": ""earthmover"", ""provider"": ""flickr""}, {""name"": ""excavator"", ""provider"": ""flickr""}, {""name"": ""glenelg"", ""provider"": ""flickr""}, {""name"": ""jetty"", ""provider"": ""flickr""}, {""name"": ""sandcarting"", ""provider"": ""flickr""}]",f,2021-12-15 22:16:03.237644+00,f,jpg,photograph, +027e86f8-ab89-4634-84ed-fb17bfdb0342,2022-08-28 13:46:12.000000+00,2022-08-28 13:46:12.000000+00,provider_api,flickr,flickr,51747299011,https://www.flickr.com/photos/89165847@N00/51747299011,https://live.staticflickr.com/65535/51747299011_182253e920_b.jpg,https://live.staticflickr.com/65535/51747299011_182253e920_m.jpg,1024,768,185539,by-sa,2.0,mikecogh,https://www.flickr.com/photos/89165847@N00,Big CAT on the Beach,"{""views"": ""40"", ""pub_date"": ""1639527329"", ""date_taken"": ""2021-07-04 11:43:05"", ""license_url"": ""https://creativecommons.org/licenses/by-sa/2.0/""}","[{""name"": ""3290"", ""provider"": ""flickr""}, {""name"": ""adelaide"", ""provider"": ""flickr""}, {""name"": ""beach"", ""provider"": ""flickr""}, {""name"": ""brand"", ""provider"": ""flickr""}, {""name"": ""CAT"", ""provider"": ""flickr""}, {""name"": ""caterpillar"", ""provider"": ""flickr""}, {""name"": ""digger"", ""provider"": ""flickr""}, {""name"": ""dunes"", ""provider"": ""flickr""}, {""name"": ""earthmover"", ""provider"": ""flickr""}, {""name"": ""excavator"", ""provider"": ""flickr""}, {""name"": ""glenelg"", ""provider"": ""flickr""}, {""name"": ""jetty"", ""provider"": ""flickr""}, {""name"": ""sandcarting"", ""provider"": ""flickr""}]",f,2021-12-15 22:16:03.237644+00,f,jpg,photograph, a88169b9-3669-4316-82ee-70467f822c04,2022-09-26 16:53:27.000000+00,2022-09-26 16:53:27.000000+00,provider_api,flickr,flickr,51748177460,https://www.flickr.com/photos/31582298@N08/51748177460,https://live.staticflickr.com/65535/51748177460_79e389dea6_b.jpg,https://live.staticflickr.com/65535/51748177460_79e389dea6_m.jpg,1024,624,67917,by-sa,2.0,Asamblea Nacional del Ecuador,https://www.flickr.com/photos/31582298@N08,"COMISIÓN DE JUSTICIA, ECUADOR, 14 DE DICIEMBRE DEL 2021","{""views"": ""40"", ""pub_date"": ""1639527306"", ""date_taken"": ""2021-12-14 18:44:18"", ""description"": ""Ecuador, 14 de Diciembre del 2021.- Análisis y discusión del nudo crítico de la temporalidad identificado en el proyecto de Ley Orgánica para garantizar el derecho a la interrupción voluntaria del embarazo en caso de violación, para cuyo debate recibiremos en el Pleno de esta Mesa Parlamentaria los aportes y observaciones de varios profesionales y expertos en la materia. Fotos: Fernando Lagla / Asamblea Nacional"", ""license_url"": ""https://creativecommons.org/licenses/by-sa/2.0/""}","[{""name"": ""alejandrojaramillo"", ""provider"": ""flickr""}, {""name"": ""asambleaecuador"", ""provider"": ""flickr""}, {""name"": ""asambleanacional"", ""provider"": ""flickr""}, {""name"": ""comisióndejusticia"", ""provider"": ""flickr""}]",f,2021-12-15 22:14:02.778385+00,f,jpg,photograph, 971ec387-5111-445d-8f86-9fe53a0285a2,2022-10-26 03:46:10.000000+00,2022-10-26 03:46:10.000000+00,provider_api,flickr,flickr,51747301301,https://www.flickr.com/photos/31582298@N08/51747301301,https://live.staticflickr.com/65535/51747301301_7a8b5af017_b.jpg,https://live.staticflickr.com/65535/51747301301_7a8b5af017_m.jpg,1024,640,83985,by-sa,2.0,Asamblea Nacional del Ecuador,https://www.flickr.com/photos/31582298@N08,"COMISIÓN DE JUSTICIA, ECUADOR, 14 DE DICIEMBRE DEL 2021","{""views"": ""40"", ""pub_date"": ""1639527305"", ""date_taken"": ""2021-12-14 18:44:19"", ""description"": ""Ecuador, 14 de Diciembre del 2021.- Análisis y discusión del nudo crítico de la temporalidad identificado en el proyecto de Ley Orgánica para garantizar el derecho a la interrupción voluntaria del embarazo en caso de violación, para cuyo debate recibiremos en el Pleno de esta Mesa Parlamentaria los aportes y observaciones de varios profesionales y expertos en la materia. Fotos: Fernando Lagla / Asamblea Nacional"", ""license_url"": ""https://creativecommons.org/licenses/by-sa/2.0/""}","[{""name"": ""alejandrojaramillo"", ""provider"": ""flickr""}, {""name"": ""asambleaecuador"", ""provider"": ""flickr""}, {""name"": ""asambleanacional"", ""provider"": ""flickr""}, {""name"": ""comisióndejusticia"", ""provider"": ""flickr""}]",f,2021-12-15 22:14:02.778385+00,f,jpg,photograph, 25ce5783-af6f-475a-911f-aebb96722a46,2022-01-18 10:59:47.000000+00,2022-01-18 10:59:47.000000+00,provider_api,flickr,flickr,51748138325,https://www.flickr.com/photos/128831778@N05/51748138325,https://live.staticflickr.com/65535/51748138325_a1222eb21a_b.jpg,https://live.staticflickr.com/65535/51748138325_a1222eb21a_m.jpg,1024,748,308082,by-nc-sa,2.0,Laurentrekk Photographies,https://www.flickr.com/photos/128831778@N05,Roller Derby - Anglet - Salle du Pignada - 'Valient Bitchiz' du Anglet Roller Derby & 'Kontra Bandista' du Euskal Roller Derby de Bayonne - 2021.12.05,"{""views"": ""40"", ""pub_date"": ""1639527045"", ""date_taken"": ""2021-12-05 15:29:38"", ""license_url"": ""https://creativecommons.org/licenses/by-nc-sa/2.0/""}","[{""name"": ""anglet"", ""provider"": ""flickr""}, {""name"": ""bandista"", ""provider"": ""flickr""}, {""name"": ""bayonne"", ""provider"": ""flickr""}, {""name"": ""bitchiz"", ""provider"": ""flickr""}, {""name"": ""kontra"", ""provider"": ""flickr""}, {""name"": ""kontrabandista"", ""provider"": ""flickr""}, {""name"": ""photo"", ""provider"": ""flickr""}, {""name"": ""photographer"", ""provider"": ""flickr""}, {""name"": ""photos"", ""provider"": ""flickr""}, {""name"": ""photosports"", ""provider"": ""flickr""}, {""name"": ""pictures"", ""provider"": ""flickr""}, {""name"": ""roller"", ""provider"": ""flickr""}, {""name"": ""rollerstadium"", ""provider"": ""flickr""}, {""name"": ""sport"", ""provider"": ""flickr""}, {""name"": ""sportphoto"", ""provider"": ""flickr""}, {""name"": ""sportpics"", ""provider"": ""flickr""}, {""name"": ""sports"", ""provider"": ""flickr""}, {""name"": ""sportspics"", ""provider"": ""flickr""}, {""name"": ""valient"", ""provider"": ""flickr""}, {""name"": ""valientbitchiz"", ""provider"": ""flickr""}]",f,2021-12-15 22:19:02.971943+00,f,jpg,photograph, @@ -2506,7 +2506,7 @@ ba65f751-e7ac-469d-95d6-c121d73be2eb,2022-09-22 07:30:29.000000+00,2022-09-22 07 cab58c39-985e-4871-97b7-34c582336afb,2022-11-18 05:04:27.000000+00,2022-11-18 05:04:27.000000+00,provider_api,stocksnap,stocksnap,HNM0EAC9LW,https://stocksnap.io/photo/HNM0EAC9LW,https://cdn.stocksnap.io/img-thumbs/960w/HNM0EAC9LW.jpg,https://cdn.stocksnap.io/img-thumbs/280h/HNM0EAC9LW.jpg,5472,3648,439331,cc0,1.0,HD Wallpapers,https://stocksnap.io/author/126244,Abstract Defocused Photo,"{""license_url"": ""https://creativecommons.org/publicdomain/zero/1.0/"", ""downloads_raw"": ""1220"", ""favorites_raw"": ""14"", ""page_views_raw"": ""5730"", ""raw_license_url"": ""https://creativecommons.org/publicdomain/zero/1.0/""}","[{""name"": ""abstract"", ""provider"": ""stocksnap""}, {""name"": ""defocused"", ""provider"": ""stocksnap""}, {""name"": ""bright"", ""provider"": ""stocksnap""}, {""name"": ""color"", ""provider"": ""stocksnap""}, {""name"": ""design"", ""provider"": ""stocksnap""}, {""name"": ""pattern"", ""provider"": ""stocksnap""}, {""name"": ""background"", ""provider"": ""stocksnap""}, {""name"": ""blur"", ""provider"": ""stocksnap""}, {""name"": ""defocus"", ""provider"": ""stocksnap""}, {""name"": ""effect"", ""provider"": ""stocksnap""}, {""name"": ""wallpaper"", ""provider"": ""stocksnap""}, {""name"": ""backdrop"", ""provider"": ""stocksnap""}, {""name"": ""blurred"", ""provider"": ""stocksnap""}, {""name"": ""colorful"", ""provider"": ""stocksnap""}, {""name"": ""decoration"", ""provider"": ""stocksnap""}, {""name"": ""shapes"", ""provider"": ""stocksnap""}, {""name"": ""motion"", ""provider"": ""stocksnap""}, {""name"": ""energy"", ""provider"": ""stocksnap""}, {""name"": ""hdwallpaper"", ""provider"": ""stocksnap""}]",f,2021-12-15 21:23:03.199486+00,f,jpg,photograph, 981dd255-b8e2-4e70-8f58-b3156de02f23,2022-02-20 04:18:16.000000+00,2022-02-20 04:18:16.000000+00,provider_api,stocksnap,stocksnap,0YEQU9SK3P,https://stocksnap.io/photo/0YEQU9SK3P,https://cdn.stocksnap.io/img-thumbs/960w/0YEQU9SK3P.jpg,https://cdn.stocksnap.io/img-thumbs/280h/0YEQU9SK3P.jpg,5215,3536,674404,cc0,1.0,Macro Mama,https://stocksnap.io/author/125683,Flower Bloom Photo,"{""license_url"": ""https://creativecommons.org/publicdomain/zero/1.0/"", ""downloads_raw"": ""1170"", ""favorites_raw"": ""6"", ""page_views_raw"": ""4845"", ""raw_license_url"": ""https://creativecommons.org/publicdomain/zero/1.0/""}","[{""name"": ""flower"", ""provider"": ""stocksnap""}, {""name"": ""bloom"", ""provider"": ""stocksnap""}, {""name"": ""closeup"", ""provider"": ""stocksnap""}, {""name"": ""blossom"", ""provider"": ""stocksnap""}, {""name"": ""macro"", ""provider"": ""stocksnap""}, {""name"": ""nature"", ""provider"": ""stocksnap""}, {""name"": ""petal"", ""provider"": ""stocksnap""}, {""name"": ""flora"", ""provider"": ""stocksnap""}, {""name"": ""floral"", ""provider"": ""stocksnap""}, {""name"": ""colorful"", ""provider"": ""stocksnap""}, {""name"": ""background"", ""provider"": ""stocksnap""}, {""name"": ""natural"", ""provider"": ""stocksnap""}, {""name"": ""detail"", ""provider"": ""stocksnap""}, {""name"": ""wallpaper"", ""provider"": ""stocksnap""}, {""name"": ""bright"", ""provider"": ""stocksnap""}, {""name"": ""fresh"", ""provider"": ""stocksnap""}, {""name"": ""spring"", ""provider"": ""stocksnap""}, {""name"": ""summer"", ""provider"": ""stocksnap""}, {""name"": ""hdwallpaper"", ""provider"": ""stocksnap""}, {""name"": ""beauty"", ""provider"": ""stocksnap""}, {""name"": ""grow"", ""provider"": ""stocksnap""}, {""name"": ""copyspace"", ""provider"": ""stocksnap""}, {""name"": ""bud"", ""provider"": ""stocksnap""}, {""name"": ""bug"", ""provider"": ""stocksnap""}, {""name"": ""insect"", ""provider"": ""stocksnap""}, {""name"": ""bee"", ""provider"": ""stocksnap""}]",f,2021-12-15 21:21:02.972883+00,f,jpg,photograph, 9faadb5b-997a-40fe-b255-4ee8ec4f0ccf,2022-07-29 02:07:35.000000+00,2022-07-29 02:07:35.000000+00,provider_api,stocksnap,stocksnap,DBUU6N5YUY,https://stocksnap.io/photo/DBUU6N5YUY,https://cdn.stocksnap.io/img-thumbs/960w/DBUU6N5YUY.jpg,https://cdn.stocksnap.io/img-thumbs/280h/DBUU6N5YUY.jpg,5472,3648,588132,cc0,1.0,Free Nature Stock,https://freenaturestock.com,Blue Night Photo,"{""license_url"": ""https://creativecommons.org/publicdomain/zero/1.0/"", ""downloads_raw"": ""1080"", ""favorites_raw"": ""17"", ""page_views_raw"": ""4625"", ""raw_license_url"": ""https://creativecommons.org/publicdomain/zero/1.0/""}","[{""name"": ""blue"", ""provider"": ""stocksnap""}, {""name"": ""night"", ""provider"": ""stocksnap""}, {""name"": ""sky"", ""provider"": ""stocksnap""}, {""name"": ""stars"", ""provider"": ""stocksnap""}, {""name"": ""universe"", ""provider"": ""stocksnap""}, {""name"": ""space"", ""provider"": ""stocksnap""}, {""name"": ""astrology"", ""provider"": ""stocksnap""}, {""name"": ""nature"", ""provider"": ""stocksnap""}, {""name"": ""astrophotography"", ""provider"": ""stocksnap""}, {""name"": ""astronomy"", ""provider"": ""stocksnap""}, {""name"": ""galaxy"", ""provider"": ""stocksnap""}, {""name"": ""wallpaper"", ""provider"": ""stocksnap""}, {""name"": ""virtual"", ""provider"": ""stocksnap""}, {""name"": ""background"", ""provider"": ""stocksnap""}, {""name"": ""clouds"", ""provider"": ""stocksnap""}, {""name"": ""milky"", ""provider"": ""stocksnap""}, {""name"": ""way"", ""provider"": ""stocksnap""}, {""name"": ""hdwallpaper"", ""provider"": ""stocksnap""}, {""name"": ""zoombackground"", ""provider"": ""stocksnap""}]",f,2021-12-15 21:21:02.972883+00,f,jpg,photograph, -fb18c299-2be0-4ddb-b6d8-e890eec3da1c,2022-07-06 23:43:25.000000+00,2022-07-06 23:43:25.000000+00,provider_api,stocksnap,stocksnap,R7RWYRIPB0,https://stocksnap.io/photo/R7RWYRIPB0,https://cdn.stocksnap.io/img-thumbs/960w/R7RWYRIPB0.jpg,https://cdn.stocksnap.io/img-thumbs/280h/R7RWYRIPB0.jpg,6000,4000,678636,cc0,1.0,Travel Photographer,https://stocksnap.io,Christmas Background Photo,"{""license_url"": ""https://creativecommons.org/publicdomain/zero/1.0/"", ""downloads_raw"": ""960"", ""favorites_raw"": ""5"", ""page_views_raw"": ""875"", ""raw_license_url"": ""https://creativecommons.org/publicdomain/zero/1.0/""}","[{""name"": ""christmas"", ""provider"": ""stocksnap""}, {""name"": ""background"", ""provider"": ""stocksnap""}, {""name"": ""holiday"", ""provider"": ""stocksnap""}, {""name"": ""xmas"", ""provider"": ""stocksnap""}, {""name"": ""tree"", ""provider"": ""stocksnap""}, {""name"": ""lights"", ""provider"": ""stocksnap""}, {""name"": ""fireplace"", ""provider"": ""stocksnap""}, {""name"": ""seasonal"", ""provider"": ""stocksnap""}, {""name"": ""home"", ""provider"": ""stocksnap""}, {""name"": ""indoors"", ""provider"": ""stocksnap""}, {""name"": ""decoration"", ""provider"": ""stocksnap""}, {""name"": ""decor"", ""provider"": ""stocksnap""}, {""name"": ""ornaments"", ""provider"": ""stocksnap""}, {""name"": ""festive"", ""provider"": ""stocksnap""}, {""name"": ""glowing"", ""provider"": ""stocksnap""}, {""name"": ""cat"", ""provider"": ""stocksnap""}, {""name"": ""pet"", ""provider"": ""stocksnap""}, {""name"": ""cozy"", ""provider"": ""stocksnap""}]",f,2021-12-15 21:30:02.827184+00,f,jpg,photograph, +fb18c299-2be0-4ddb-b6d8-e890eec3da1c,2022-07-06 23:43:25.000000+00,2022-07-06 23:43:25.000000+00,provider_api,stocksnap,stocksnap,R7RWYRIPB0,https://stocksnap.io/photo/R7RWYRIPB0,https://cdn.stocksnap.io/img-thumbs/960w/R7RWYRIPB0.jpg,https://cdn.stocksnap.io/img-thumbs/280h/R7RWYRIPB0.jpg,6000,4000,678636,cc0,1.0,Travel Photographer,https://stocksnap.io,Christmas Background Photo,"{""license_url"": ""https://creativecommons.org/publicdomain/zero/1.0/"", ""downloads_raw"": ""960"", ""favorites_raw"": ""5"", ""page_views_raw"": ""875"", ""raw_license_url"": ""https://creativecommons.org/publicdomain/zero/1.0/""}","[{""name"": ""christmas"", ""provider"": ""stocksnap""}, {""name"": ""background"", ""provider"": ""stocksnap""}, {""name"": ""holiday"", ""provider"": ""stocksnap""}, {""name"": ""xmas"", ""provider"": ""stocksnap""}, {""name"": ""tree"", ""provider"": ""stocksnap""}, {""name"": ""lights"", ""provider"": ""stocksnap""}, {""name"": ""fireplace"", ""provider"": ""stocksnap""}, {""name"": ""seasonal"", ""provider"": ""stocksnap""}, {""name"": ""home"", ""provider"": ""stocksnap""}, {""name"": ""indoors"", ""provider"": ""stocksnap""}, {""name"": ""decoration"", ""provider"": ""stocksnap""}, {""name"": ""decor"", ""provider"": ""stocksnap""}, {""name"": ""ornaments"", ""provider"": ""stocksnap""}, {""name"": ""festive"", ""provider"": ""stocksnap""}, {""name"": ""glowing"", ""provider"": ""stocksnap""}, {""name"": ""Cat"", ""provider"": ""stocksnap""}, {""name"": ""pet"", ""provider"": ""stocksnap""}, {""name"": ""cozy"", ""provider"": ""stocksnap""}]",f,2021-12-15 21:30:02.827184+00,f,jpg,photograph, 78a8e8e9-5b9e-4869-b296-e2975cb09bde,2022-07-01 19:17:44.000000+00,2022-07-01 19:17:44.000000+00,provider_api,stocksnap,stocksnap,UXDHJEAXYA,https://stocksnap.io/photo/UXDHJEAXYA,https://cdn.stocksnap.io/img-thumbs/960w/UXDHJEAXYA.jpg,https://cdn.stocksnap.io/img-thumbs/280h/UXDHJEAXYA.jpg,6720,4480,264652,cc0,1.0,Stephen Rahn,https://www.flickr.com/photos/srahn,Crescent Moon Photo,"{""license_url"": ""https://creativecommons.org/publicdomain/zero/1.0/"", ""downloads_raw"": ""900"", ""favorites_raw"": ""13"", ""page_views_raw"": ""3935"", ""raw_license_url"": ""https://creativecommons.org/publicdomain/zero/1.0/""}","[{""name"": ""crescent"", ""provider"": ""stocksnap""}, {""name"": ""moon"", ""provider"": ""stocksnap""}, {""name"": ""sky"", ""provider"": ""stocksnap""}, {""name"": ""night"", ""provider"": ""stocksnap""}, {""name"": ""nature"", ""provider"": ""stocksnap""}, {""name"": ""astronomy"", ""provider"": ""stocksnap""}, {""name"": ""blue"", ""provider"": ""stocksnap""}, {""name"": ""astrology"", ""provider"": ""stocksnap""}, {""name"": ""tranquility"", ""provider"": ""stocksnap""}, {""name"": ""eclipse"", ""provider"": ""stocksnap""}, {""name"": ""illuminated"", ""provider"": ""stocksnap""}, {""name"": ""background"", ""provider"": ""stocksnap""}, {""name"": ""minimal"", ""provider"": ""stocksnap""}, {""name"": ""space"", ""provider"": ""stocksnap""}, {""name"": ""evening"", ""provider"": ""stocksnap""}, {""name"": ""wallpaper"", ""provider"": ""stocksnap""}, {""name"": ""sphere"", ""provider"": ""stocksnap""}, {""name"": ""hdwallpaper"", ""provider"": ""stocksnap""}, {""name"": ""copyspace"", ""provider"": ""stocksnap""}, {""name"": ""stars"", ""provider"": ""stocksnap""}]",f,2021-12-15 21:21:02.972883+00,f,jpg,photograph, e35703e0-5005-4e7e-8727-924ad2da1a65,2022-07-28 16:47:07.000000+00,2022-07-28 16:47:07.000000+00,provider_api,stocksnap,stocksnap,ZRHJGSLPMZ,https://stocksnap.io/photo/ZRHJGSLPMZ,https://cdn.stocksnap.io/img-thumbs/960w/ZRHJGSLPMZ.jpg,https://cdn.stocksnap.io/img-thumbs/280h/ZRHJGSLPMZ.jpg,6016,4016,576666,cc0,1.0,Tim Sullivan,https://www.secretagencygroup.com,Diamond Plate Photo,"{""license_url"": ""https://creativecommons.org/publicdomain/zero/1.0/"", ""downloads_raw"": ""890"", ""favorites_raw"": ""8"", ""page_views_raw"": ""4205"", ""raw_license_url"": ""https://creativecommons.org/publicdomain/zero/1.0/""}","[{""name"": ""diamond"", ""provider"": ""stocksnap""}, {""name"": ""plate"", ""provider"": ""stocksnap""}, {""name"": ""background"", ""provider"": ""stocksnap""}, {""name"": ""grunge"", ""provider"": ""stocksnap""}, {""name"": ""pattern"", ""provider"": ""stocksnap""}, {""name"": ""texture"", ""provider"": ""stocksnap""}, {""name"": ""floor"", ""provider"": ""stocksnap""}, {""name"": ""abstract"", ""provider"": ""stocksnap""}, {""name"": ""industrial"", ""provider"": ""stocksnap""}, {""name"": ""surface"", ""provider"": ""stocksnap""}, {""name"": ""safety"", ""provider"": ""stocksnap""}, {""name"": ""dark"", ""provider"": ""stocksnap""}, {""name"": ""closeup"", ""provider"": ""stocksnap""}, {""name"": ""material"", ""provider"": ""stocksnap""}, {""name"": ""metal"", ""provider"": ""stocksnap""}, {""name"": ""steel"", ""provider"": ""stocksnap""}, {""name"": ""rubber"", ""provider"": ""stocksnap""}, {""name"": ""tile"", ""provider"": ""stocksnap""}, {""name"": ""hdwallpaper"", ""provider"": ""stocksnap""}, {""name"": ""copyspace"", ""provider"": ""stocksnap""}, {""name"": ""wallpaper"", ""provider"": ""stocksnap""}]",f,2021-12-15 21:21:02.972883+00,f,jpg,photograph, 6bb34fac-fa04-4e40-a99f-c09e63e998d2,2022-01-30 11:37:38.000000+00,2022-01-30 11:37:38.000000+00,provider_api,stocksnap,stocksnap,AS7IXHU7KI,https://stocksnap.io/photo/AS7IXHU7KI,https://cdn.stocksnap.io/img-thumbs/960w/AS7IXHU7KI.jpg,https://cdn.stocksnap.io/img-thumbs/280h/AS7IXHU7KI.jpg,4766,3177,505206,cc0,1.0,Kelly Ishmael,http://mindingmynest.com,Macro Flower Photo,"{""license_url"": ""https://creativecommons.org/publicdomain/zero/1.0/"", ""downloads_raw"": ""775"", ""favorites_raw"": ""8"", ""page_views_raw"": ""3625"", ""raw_license_url"": ""https://creativecommons.org/publicdomain/zero/1.0/""}","[{""name"": ""macro"", ""provider"": ""stocksnap""}, {""name"": ""flower"", ""provider"": ""stocksnap""}, {""name"": ""background"", ""provider"": ""stocksnap""}, {""name"": ""floral"", ""provider"": ""stocksnap""}, {""name"": ""closeup"", ""provider"": ""stocksnap""}, {""name"": ""petals"", ""provider"": ""stocksnap""}, {""name"": ""colorful"", ""provider"": ""stocksnap""}, {""name"": ""daisy"", ""provider"": ""stocksnap""}, {""name"": ""plant"", ""provider"": ""stocksnap""}, {""name"": ""bloom"", ""provider"": ""stocksnap""}, {""name"": ""blossom"", ""provider"": ""stocksnap""}, {""name"": ""wallpaper"", ""provider"": ""stocksnap""}, {""name"": ""botany"", ""provider"": ""stocksnap""}, {""name"": ""vibrant"", ""provider"": ""stocksnap""}, {""name"": ""bright"", ""provider"": ""stocksnap""}, {""name"": ""flora"", ""provider"": ""stocksnap""}, {""name"": ""texture"", ""provider"": ""stocksnap""}, {""name"": ""nature"", ""provider"": ""stocksnap""}, {""name"": ""natural"", ""provider"": ""stocksnap""}, {""name"": ""hdwallpaper"", ""provider"": ""stocksnap""}, {""name"": ""garden"", ""provider"": ""stocksnap""}]",f,2021-12-15 20:48:57.914727+00,f,jpg,photograph,