Skip to content

Commit

Permalink
Add support for multiple scenarios in a single file (#6)
Browse files Browse the repository at this point in the history
- Allows multiple scenarios in a file via `[...]`
- Make it easier to list leaf versions (can use an empty `{}`)
- Add more "requires a version that does not exist" scenarios
  • Loading branch information
zanieb authored Dec 13, 2023
1 parent ce17c32 commit 7400d41
Show file tree
Hide file tree
Showing 6 changed files with 510 additions and 57 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,4 +76,6 @@ pip install -i https://test.pypi.org/simple/ <scenario>-<package>==1.0.0

### Writing new scenarios

**Not yet written**
Scenario files may contain one or more scenarios written in JSON.

**Documentation not yet written**
100 changes: 87 additions & 13 deletions scenarios/requires-does-not-exist.json
Original file line number Diff line number Diff line change
@@ -1,17 +1,91 @@
{
"name": "requires-does-not-exist",
"description": "Package `a` requires any version of package `b` which does not exist",
"root": "a",
"packages": {
"a": {
"versions": {
"1.0.0": {
"requires_python": ">=3.7",
"requires": [
"b"
]
[
{
"name": "requires-package-does-not-exist",
"description": "Package `a` requires any version of package `b` which does not exist",
"root": "a",
"packages": {
"a": {
"versions": {
"1.0.0": {
"requires_python": ">=3.7",
"requires": [
"b"
]
}
}
}
}
},
{
"name": "requires-exact-version-does-not-exist",
"description": "Package `a` requires an exact version of package `b` but only other versions exist",
"root": "a",
"packages": {
"a": {
"versions": {
"1.0.0": {
"requires_python": ">=3.7",
"requires": [
"b==2.0.0"
]
}
}
},
"b": {
"versions": {
"1.0.0": {
"requires_python": ">=3.7",
"requires": []
}
}
}
}
},
{
"name": "requires-greater-version-does-not-exist",
"description": "Package `a` requires a version of `b` greater than `1.0.0` but only smaller versions exist",
"root": "a",
"packages": {
"a": {
"versions": {
"1.0.0": {
"requires_python": ">=3.7",
"requires": [
"b>1.0.0"
]
}
}
},
"b": {
"versions": {
"0.1.0": {},
"1.0.0": {}
}
}
}
},
{
"name": "requires-less-version-does-not-exist",
"description": "Package `a` requires a version of `b` less than `1.0.0` but only larger versions exist",
"root": "a",
"packages": {
"a": {
"versions": {
"1.0.0": {
"requires_python": ">=3.7",
"requires": [
"b<2.0.0"
]
}
}
},
"b": {
"versions": {
"2.0.0": {},
"3.0.0": {},
"4.0.0": {}
}
}
}
}
}
]
16 changes: 9 additions & 7 deletions src/packse/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,36 +14,38 @@
InvalidScenario,
ScenarioNotFound,
)
from packse.scenario import Package, Scenario, load_scenario, scenario_prefix
from packse.scenario import Package, Scenario, load_scenarios, scenario_prefix
from packse.template import create_from_template

logger = logging.getLogger(__name__)


def build(targets: list[Path], rm_destination: bool):
# Validate all targets first
# Validate and collect all targets first
scenarios = []

for target in targets:
if not target.exists():
raise ScenarioNotFound(target)

try:
load_scenario(target)
logger.debug("Loading %s", target)
scenarios.extend(load_scenarios(target))
except Exception as exc:
raise InvalidScenario(target, reason=str(exc)) from exc

# Then build each one
for target in targets:
result = build_scenario(target, rm_destination)
for scenario in scenarios:
result = build_scenario(scenario, rm_destination)
print(result)


def build_scenario(target: Path, rm_destination: bool) -> str:
def build_scenario(scenario: Scenario, rm_destination: bool) -> str:
"""
Build the scenario defined at the given path.
Returns the scenario's root package name.
"""
scenario = load_scenario(target)
prefix = scenario_prefix(scenario)

work_dir = Path.cwd()
Expand Down
23 changes: 20 additions & 3 deletions src/packse/scenario.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@


class PackageVersion(msgspec.Struct):
requires_python: str | None
requires: list[str]
requires_python: str | None = ">=3.7"
requires: list[str] = []

def hash(self) -> str:
"""
Expand Down Expand Up @@ -77,11 +77,28 @@ def hash(self) -> str:

def load_scenario(target: Path) -> Scenario:
"""
Loads a scenario, including a hash of its contents
Loads a scenario
"""
return msgspec.json.decode(target.read_text(), type=Scenario)


def load_many_scenarios(target: Path) -> list[Scenario]:
"""
Loads a file with many scenarios
"""
return msgspec.json.decode(target.read_text(), type=list[Scenario])


def load_scenarios(target: Path) -> list[Scenario]:
# Guess if the file contains one or many scenario
with target.open() as buffer:
many = buffer.readline().lstrip().startswith("[")
if many:
return load_many_scenarios(target)
else:
return [load_scenario(target)]


def scenario_version(scenario: Scenario) -> str:
"""
Generate a unique version for a scenario based on its contents.
Expand Down
19 changes: 10 additions & 9 deletions src/packse/view.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,31 +7,32 @@
from packaging.requirements import Requirement

from packse.error import InvalidScenario, ScenarioNotFound
from packse.scenario import Scenario, load_scenario, scenario_prefix
from packse.scenario import Scenario, load_scenarios, scenario_prefix

logger = logging.getLogger(__name__)


def view(targets: list[Path]):
# Validate all targets first
scenarios = []

# Validate and collect all targets first
for target in targets:
if not target.exists():
raise ScenarioNotFound(target)

try:
load_scenario(target)
logger.debug("Loading %s", target)
scenarios.extend(load_scenarios(target))
except Exception as exc:
raise InvalidScenario(target, reason=str(exc)) from exc

# Then view each one
for target in targets:
view_scenario(target)

for scenario in scenarios:
logging.debug("Viewing %s", scenario.name)
view_scenario(scenario)

def view_scenario(target: Path):
logging.debug("Viewing %s", target)

scenario = load_scenario(target)
def view_scenario(scenario: Scenario):
prefix = scenario_prefix(scenario)

print(prefix)
Expand Down
Loading

0 comments on commit 7400d41

Please sign in to comment.