Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
15 changes: 10 additions & 5 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -81,13 +81,18 @@ select = [
"E",
# Pyflakes
"F",
# TODO: enable these at some point?
# pyupgrade
# "UP",
"UP",
# flake8-bugbear
#"B",
"B",
# isort
"I",
# TODO: enable these at some point?
# flake8-simplify
#"SIM",
# isort
# "I",
]
ignore = [
# yatiml requires Dict, List, etc.
"UP006",
"UP035",
]
3 changes: 1 addition & 2 deletions ymmsl/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,13 @@
"""
from importlib.metadata import version as package_version

from ymmsl.conversion.converter import convert_to, DowngradeError
from ymmsl.conversion.converter import DowngradeError, convert_to
from ymmsl.document import Document
from ymmsl.io import dump, load, load_as, save

# For backwards compatibility of programs
from ymmsl.v0_2 import Operator, Settings


__version__ = package_version("ymmsl")
__author__ = 'Lourens Veen'
__email__ = 'l.veen@esciencecenter.nl'
Expand Down
9 changes: 5 additions & 4 deletions ymmsl/command_line.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import click
import os
import warnings
from shutil import copyfile
from typing import Dict, Optional, TextIO, Type, Union
import warnings

import click

import ymmsl.v0_1 as v0_1
import ymmsl.v0_2 as v0_2
from ymmsl.conversion.converter import DowngradeError
from ymmsl.document import Document
from ymmsl.io import load_as, save
import ymmsl.v0_1 as v0_1
import ymmsl.v0_2 as v0_2


def showwarning(
Expand Down
23 changes: 13 additions & 10 deletions ymmsl/conversion/convert_v0_1_to_v0_2.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import warnings
from copy import deepcopy
from typing import Dict, List, MutableMapping, Optional
import warnings

import ymmsl.v0_1 as v0_1
import ymmsl.v0_2 as v0_2
Expand All @@ -24,19 +24,22 @@ def convert_v0_1_to_v0_2(config: v0_1.PartialConfiguration) -> v0_2.Configuratio
convert_implementation(impl) for impl in config.implementations.values()]
if programs:
warnings.warn(
'In yMMSL v0.2 implementations have become programs, and you can now'
' specify the ports of a program in the yMMSL description. If your'
' program has fixed ports then you should do this, because it will make'
' incorrect wiring easier to debug. While there, add a description too!'
)
'In yMMSL v0.2 implementations have become programs, and you can now'
' specify the ports of a program in the yMMSL description. If your'
' program has fixed ports then you should do this, because it will make'
' incorrect wiring easier to debug. While there, add a description too!',
stacklevel=2,
)

resources = convert_resources(config.resources, models)
checkpoints = deepcopy(config.checkpoints)
resume = deepcopy(config.resume)

warnings.warn(
'Comments can unfortunately not be read by this converter, and so have been'
' ignored. Please copy them into an appropriate description field.')
'Comments can unfortunately not be read by this converter, and so have been'
' ignored. Please copy them into an appropriate description field.',
stacklevel=2,
)

return v0_2.Configuration(
description, None, models, None, settings, programs, resources, checkpoints,
Expand Down Expand Up @@ -94,7 +97,7 @@ def infer_ports(components: List[v0_2.Component], conduits: List[v0_2.Conduit])
' been added based on the connected conduits. THIS MAY BE WRONG,'
' because the operators have all been set to F_INIT and O_F, while they'
' may really be O_I or S. Please check these components and adjust'
f' as needed: {ch_comp_list}')
f' as needed: {ch_comp_list}', stacklevel=4)


def convert_model(model: v0_1.ModelReference) -> v0_2.Model:
Expand Down Expand Up @@ -174,7 +177,7 @@ def convert_resources(
' prefixed with the name of the top (outermost) model, e.g. as'
' my_model.my_component rather than just my_component. This file'
' does not contain a model, so its name cannot be added automatically.'
' Please add the model name yourself.')
' Please add the model name yourself.', stacklevel=3)
return deepcopy(resources)
else:
mname = models[0].name
Expand Down
6 changes: 3 additions & 3 deletions ymmsl/conversion/converter.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
from typing import Callable, cast, Dict, Type, TypeVar
from typing import Callable, Dict, Type, TypeVar, cast

from ymmsl.conversion.convert_v0_1_to_v0_2 import convert_v0_1_to_v0_2
from ymmsl.document import Document
import ymmsl.v0_1 as v0_1
import ymmsl.v0_2 as v0_2
from ymmsl.conversion.convert_v0_1_to_v0_2 import convert_v0_1_to_v0_2
from ymmsl.document import Document


class DowngradeError(RuntimeError):
Expand Down
4 changes: 1 addition & 3 deletions ymmsl/conversion/tests/test_convert_v0_1_to_v0_2.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,9 @@

import pytest

from ymmsl.conversion.convert_v0_1_to_v0_2 import convert_v0_1_to_v0_2

import ymmsl.v0_1 as v0_1
import ymmsl.v0_2 as v0_2

from ymmsl.conversion.convert_v0_1_to_v0_2 import convert_v0_1_to_v0_2

Ref1 = v0_1.Reference

Expand Down
3 changes: 1 addition & 2 deletions ymmsl/conversion/tests/test_converter.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import pytest

from ymmsl.conversion.converter import convert_to

import ymmsl.v0_1 as v0_1
import ymmsl.v0_2 as v0_2
from ymmsl.conversion.converter import convert_to


def test_convert_to_no_change(full_config: v0_1.PartialConfiguration) -> None:
Expand Down
4 changes: 3 additions & 1 deletion ymmsl/document.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
from abc import ABC
from abc import ABC, abstractmethod


class Document(ABC):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Document used to be non-abstract, but that ended up giving confusing error messages if the ymmsl version tag was wrong. For example, if you put ymmsl_version: v0_2 in the document, then neither v0_1.Document nor v0_2.Document would match, and yatiml would try to match ymmsl.Document, which doesn't have any keys, and you get something like this:

        ymmsl_version: v0_2
        ^
    Found a key "ymmsl_version", which is not allowed here. Maybe it was indented incorrectly? For reference, no other keys are allowed, but "ymmsl_version", "description" and "models" were given.

It's pretty easy to overlook the actual problem, especially if the error message points you in the wrong direction.

The problem there is that yatiml considers ymmsl.Document something that could be what the user intended, while it's really a base class that's only there to provide a single type that can represent any kind of ymmsl document. It really is abstract, and so it should really be declared abstract, and yatiml understands that concept and then produces a good error message:

Multiple things are allowed here, but none of them were recognised correctly. At least one of these errors should apply to what you want to do; please solve that one and ignore the others.
  in "<unicode string>", line 1, column 1:
    ymmsl_version: v0_2
    ^
Incorrect attribute value v0_2 where v0.1 was required

  in "<unicode string>", line 1, column 1:
    ymmsl_version: v0_2
    ^
Incorrect attribute value v0_2 where v0.2 was required

and now it's obvious what the problem is. So this needs to be solved differently. I'll see if I can find some other way of making ruff and mypy happy.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for clarifying, I wasn't aware of this!
Agreed with your solution to ignore the mypy error 👍

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I've been thinking about how that should have been documented, or whether me having a vague memory of a problem with this and a private notes file from last year that I found using grep is a good enough way of preventing regressions. I could have added a test that checked for an error containing Incorrect attribute value v0_2, but I figured this wouldn't regress anyway...

"""Base class for ymmsl documents of all versions"""

@abstractmethod
def __init__(self) -> None:
pass
11 changes: 4 additions & 7 deletions ymmsl/io.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,17 @@
"""Loading and saving functions."""
from pathlib import Path
from typing import Any, IO, Type, TypeVar, Union
from typing import IO, Any, Type, TypeVar, Union

import yatiml

import ymmsl.v0_1 as v0_1
import ymmsl.v0_2 as v0_2
from ymmsl.conversion.converter import convert_to
from ymmsl.document import Document

import ymmsl.v0_1 as v0_1
from ymmsl.v0_1.document import Document as v0_1_Document
from ymmsl.v0_1.model import MulticastConduit as v0_1_MulticastConduit

import ymmsl.v0_2 as v0_2
from ymmsl.v0_2.model import MulticastConduit as v0_2_MulticastConduit


_classes = (
Document,
v0_1.BaseEnv, v0_1.CheckpointRangeRule, v0_1.CheckpointAtRule,
Expand All @@ -34,7 +31,7 @@
v0_2.SupportedSetting, v0_2.SupportedSettings, v0_2.ThreadedResReq)


_load = yatiml.load_function(*_classes)
_load = yatiml.load_function(*_classes) # type: ignore


def load(source: Union[str, Path, IO[Any]]) -> Document:
Expand Down
24 changes: 19 additions & 5 deletions ymmsl/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,27 @@
import pytest

from ymmsl.v0_1 import (
BaseEnv, Component, Conduit, Configuration, ExecutionModel, Implementation,
CheckpointRangeRule, CheckpointAtRule, Checkpoints, KeepsStateForNextUse,
Model, MPICoresResReq, MPINodesResReq,
PartialConfiguration, Ports, Reference, Settings, ThreadedResReq)
BaseEnv,
CheckpointAtRule,
CheckpointRangeRule,
Checkpoints,
Component,
Conduit,
Configuration,
ExecutionModel,
Implementation,
KeepsStateForNextUse,
Model,
MPICoresResReq,
MPINodesResReq,
PartialConfiguration,
Ports,
Reference,
Settings,
ThreadedResReq,
)
from ymmsl.v0_1.model import ModelReference


Ref = Reference


Expand Down
4 changes: 2 additions & 2 deletions ymmsl/tests/test_examples.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from pathlib import Path

from ymmsl import load_as
from ymmsl.v0_2 import Configuration

from pathlib import Path


def test_load_examples() -> None:
doc_dir = Path(__file__).parents[2] / 'docs'
Expand Down
6 changes: 3 additions & 3 deletions ymmsl/tests/test_io.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import ymmsl
from ymmsl import v0_2
import pytest
import yatiml

import pytest
import ymmsl
from ymmsl import v0_2


def test_invalid_version() -> None:
Expand Down
18 changes: 13 additions & 5 deletions ymmsl/tests/test_io_v0_1.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,22 @@
from typing import Any, cast

import pytest

from yatiml import RecognitionError

from ymmsl.io import dump, load, save
from ymmsl.v0_1 import (
Configuration, ExecutionModel, KeepsStateForNextUse, Model, ModelReference,
MPICoresResReq, MPINodesResReq, PartialConfiguration, Reference,
ThreadedResReq, CheckpointRangeRule)

CheckpointRangeRule,
Configuration,
ExecutionModel,
KeepsStateForNextUse,
Model,
ModelReference,
MPICoresResReq,
MPINodesResReq,
PartialConfiguration,
Reference,
ThreadedResReq,
)

Ref = Reference

Expand Down
8 changes: 4 additions & 4 deletions ymmsl/tests/test_load_as.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
from typing import cast, List
from typing import List, cast

import pytest

from ymmsl.io import load_as
import ymmsl.v0_1 as v0_1
import ymmsl.v0_2 as v0_2

import pytest
from ymmsl.io import load_as


def test_load_as_v0_1(test_yaml1: str) -> None:
Expand Down
21 changes: 15 additions & 6 deletions ymmsl/v0_1/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,26 @@
"""

from ymmsl.v0_1.checkpoint import (
CheckpointRule, CheckpointRangeRule, CheckpointAtRule, Checkpoints)
CheckpointAtRule,
CheckpointRangeRule,
CheckpointRule,
Checkpoints,
)
from ymmsl.v0_1.component import Component, Operator, Port, Ports
from ymmsl.v0_1.configuration import Configuration, PartialConfiguration
from ymmsl.v0_1.execution import (
BaseEnv, ExecutionModel, Implementation, MPICoresResReq,
MPINodesResReq, ResourceRequirements, ThreadedResReq,
KeepsStateForNextUse)
from ymmsl.v0_1.settings import Settings, SettingValue
BaseEnv,
ExecutionModel,
Implementation,
KeepsStateForNextUse,
MPICoresResReq,
MPINodesResReq,
ResourceRequirements,
ThreadedResReq,
)
from ymmsl.v0_1.identity import Identifier, Reference
from ymmsl.v0_1.model import Conduit, Model, ModelReference

from ymmsl.v0_1.settings import Settings, SettingValue

__all__ = [
'BaseEnv', 'CheckpointRule', 'CheckpointRangeRule', 'CheckpointAtRule',
Expand Down
23 changes: 13 additions & 10 deletions ymmsl/v0_1/component.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
"""Definitions for describing simulation components."""
import logging
from collections import OrderedDict
from enum import Enum
import logging
from typing import Dict # noqa: F401
from typing import Iterable, List, Optional, Union
from typing import (
Dict, # noqa: F401
Iterable,
List,
Optional,
Union,
)

import yaml
import yatiml

from ymmsl.v0_1.identity import Identifier, Reference


_logger = logging.getLogger(__name__)


Expand Down Expand Up @@ -153,7 +157,7 @@ def operator(self, port_name: Identifier) -> Operator:
if port_name in self.o_f:
return Operator.O_F

raise KeyError('No port named "{}" was found'.format(port_name))
raise KeyError(f'No port named "{port_name}" was found')

_yatiml_defaults: dict[str, Optional[list[str]]] = {
'f_init': [],
Expand Down Expand Up @@ -209,9 +213,8 @@ def __init__(self, name: str, implementation: Optional[str] = None,
self.implementation = Reference(implementation)
for part in self.implementation:
if isinstance(part, int):
raise ValueError('Component implementation {} contains a'
' subscript, which is not'
' allowed.'.format(self.name))
raise ValueError(f"Component implementation {self.name} contains a"
" subscript, which is not allowed.")

if multiplicity is None:
self.multiplicity = list()
Expand All @@ -226,12 +229,12 @@ def __str__(self) -> str:
"""Returns a string representation of the object."""
result = str(self.name)
for dim in self.multiplicity:
result += '[0:{}]'.format(dim)
result += f"[0:{dim}]"
return result

def __repr__(self) -> str:
"""Returns a string representation of the object."""
return 'Component({})'.format(self.name)
return f"Component({self.name})"

def instances(self) -> List[Reference]:
"""Creates a list of instances needed.
Expand Down
Loading