Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,12 @@ Test fixtures for use by clients are available for each release on the [Github r

#### `fill`

- 🐞 Fix `DeprecationWarning: Pickle, copy, and deepcopy support will be removed from itertools in Python 3.14.` by avoiding use `itertools` object in the spec `BaseTest` pydantic model ([#1414](https://github.com/ethereum/execution-spec-tests/pull/1414)).
- ✨ The `static_filler` plug-in now has support for static state tests (from [GeneralStateTests](https://github.com/ethereum/tests/tree/develop/src/GeneralStateTestsFiller)) ([#1362](https://github.com/ethereum/execution-spec-tests/pull/1362)).
- 🐞 Fix `DeprecationWarning: Pickle, copy, and deepcopy support will be removed from itertools in Python 3.14.` by avoiding use `itertools` object in the spec `BaseTest` pydantic model ([#1414](https://github.com/ethereum/execution-spec-tests/pull/1414)).

#### `consume`

- 🐞 Fix fixture tarball downloading with regular, non-Github release URLS and with numerical versions in regular release specs, e.g., `[email protected]` ([#1437](https://github.com/ethereum/execution-spec-tests/pull/1437)).

### 📋 Misc

Expand Down
42 changes: 29 additions & 13 deletions src/pytest_plugins/consume/consume.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
from ethereum_test_forks import get_forks, get_relative_fork_markers, get_transition_forks
from ethereum_test_tools.utility.versioning import get_current_commit_hash_or_tag

from .releases import ReleaseTag, get_release_page_url, get_release_url
from .releases import ReleaseTag, get_release_page_url, get_release_url, is_release_url, is_url

CACHED_DOWNLOADS_DIRECTORY = (
Path(platformdirs.user_cache_dir("ethereum-execution-spec-tests")) / "cached_downloads"
Expand Down Expand Up @@ -50,10 +50,16 @@ def __init__(self, url: str, base_directory: Path): # noqa: D107
self.url = url
self.base_directory = base_directory
self.parsed_url = urlparse(url)
self.org_repo = self.extract_github_repo()
self.version = Path(self.parsed_url.path).parts[-2]
self.archive_name = self.strip_archive_extension(Path(self.parsed_url.path).name)
self.extract_to = base_directory / self.org_repo / self.version / self.archive_name

@property
def extract_to(self) -> Path:
"""Path to the directory where the archive will be extracted."""
if is_release_url(self.url):
version = Path(self.parsed_url.path).parts[-2]
self.org_repo = self.extract_github_repo()
return self.base_directory / self.org_repo / version / self.archive_name
return self.base_directory / "other" / self.archive_name

def download_and_extract(self) -> Tuple[bool, Path]:
"""Download the URL and extract it locally if it hasn't already been downloaded."""
Expand Down Expand Up @@ -91,7 +97,7 @@ def detect_extracted_directory(self) -> Path:
"""
Detect a single top-level dir within the extracted archive, otherwise return extract_to.
""" # noqa: D200
extracted_dirs = [d for d in self.extract_to.iterdir() if d.is_dir()]
extracted_dirs = [d for d in self.extract_to.iterdir() if d.is_dir() and d.name != ".meta"]
return extracted_dirs[0] if len(extracted_dirs) == 1 else self.extract_to


Expand All @@ -112,15 +118,17 @@ def from_input(cls, input_source: str) -> "FixturesSource":
"""Determine the fixture source type and return an instance."""
if input_source == "stdin":
return cls(input_option=input_source, path=Path(), is_local=False, is_stdin=True)
if is_release_url(input_source):
return cls.from_release_url(input_source)
if is_url(input_source):
return cls.from_url(input_source)
if ReleaseTag.is_release_string(input_source):
return cls.from_release_spec(input_source)
return cls.validate_local_path(Path(input_source))

@classmethod
def from_url(cls, url: str) -> "FixturesSource":
"""Create a fixture source from a direct URL."""
def from_release_url(cls, url: str) -> "FixturesSource":
"""Create a fixture source from a support github repo release URL."""
release_page = get_release_page_url(url)
downloader = FixtureDownloader(url, CACHED_DOWNLOADS_DIRECTORY)
was_cached, path = downloader.download_and_extract()
Expand All @@ -133,6 +141,20 @@ def from_url(cls, url: str) -> "FixturesSource":
was_cached=was_cached,
)

@classmethod
def from_url(cls, url: str) -> "FixturesSource":
"""Create a fixture source from a direct URL."""
downloader = FixtureDownloader(url, CACHED_DOWNLOADS_DIRECTORY)
was_cached, path = downloader.download_and_extract()
return cls(
input_option=url,
path=path,
url=url,
release_page="",
is_local=False,
was_cached=was_cached,
)

@classmethod
def from_release_spec(cls, spec: str) -> "FixturesSource":
"""Create a fixture source from a release spec (e.g., develop@latest)."""
Expand All @@ -159,12 +181,6 @@ def validate_local_path(path: Path) -> "FixturesSource":
return FixturesSource(input_option=str(path), path=path)


def is_url(string: str) -> bool:
"""Check if a string is a remote URL."""
result = urlparse(string)
return all([result.scheme, result.netloc])


class SimLimitBehavior:
"""Represents options derived from the `--sim.limit` argument."""

Expand Down
22 changes: 21 additions & 1 deletion src/pytest_plugins/consume/releases.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from datetime import datetime
from pathlib import Path
from typing import List
from urllib.parse import urlparse

import platformdirs
import requests
Expand Down Expand Up @@ -72,7 +73,11 @@ def __eq__(self, value) -> bool:
"""
assert isinstance(value, str), f"Expected a string, but got: {value}"
if self.version is not None:
return value == f"{self.tag_name}@{self.version}"
# normal release, e.g., [email protected]
normal_release_match = value == self.version
# pre release, e.g., [email protected]
pre_release_match = value == f"{self.tag_name}@{self.version}"
return normal_release_match or pre_release_match
return value.startswith(self.tag_name)

@property
Expand Down Expand Up @@ -140,6 +145,21 @@ def is_docker_or_ci() -> bool:
return "GITHUB_ACTIONS" in os.environ or Path("/.dockerenv").exists()


def is_url(string: str) -> bool:
"""Check if a string is a remote URL."""
result = urlparse(string)
return all([result.scheme, result.netloc])


def is_release_url(input_str: str) -> bool:
"""Check if the release string is a URL."""
if not is_url(input_str):
return False
repo_pattern = "|".join(re.escape(repo) for repo in SUPPORTED_REPOS)
regex_pattern = rf"https://github\.com/({repo_pattern})/releases/download/"
return re.match(regex_pattern, input_str) is not None


def parse_release_information(release_information: List) -> List[ReleaseInformation]:
"""Parse the release information from the Github API."""
return Releases.model_validate(release_information).root # type: ignore
Expand Down
Loading