Skip to content

Commit f946943

Browse files
authored
Merge pull request #72 from aCLImatise/attrs
Replace dataclasses with attrs throughout
2 parents 53879d2 + df901b8 commit f946943

File tree

13 files changed

+75
-59
lines changed

13 files changed

+75
-59
lines changed

.isort.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
[settings]
2-
known_third_party = WDL,click,cwl_utils,cwltool,dataclasses,inflection,pkg_resources,pyhash,pyparsing,pytest,ruamel,setuptools,spacy,wdlgen,wordsegment,regex,num2words,word2number,psutil,packaging,docker,attr
2+
known_third_party = WDL,click,cwl_utils,cwltool,inflection,pkg_resources,pyhash,pyparsing,pytest,ruamel,setuptools,spacy,wdlgen,wordsegment,regex,num2words,word2number,psutil,packaging,docker,attr

.pre-commit-config.yaml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@ repos:
1010
- "--force-grid-wrap=0"
1111
- "--use-parentheses"
1212
- "--line-width=88"
13-
- "--thirdparty"
14-
- "dataclasses"
1513

1614
- repo: https://github.com/psf/black
1715
rev: 20.8b1

aclimatise/cli_types.py

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@
44
import typing
55
from enum import Enum
66

7-
from dataclasses import dataclass
7+
import attr
88

9+
from aclimatise.yaml import AttrYamlMixin
910

10-
@dataclass(unsafe_hash=True)
11-
class CliType:
11+
12+
@attr.s(auto_attribs=True, frozen=True)
13+
class CliType(AttrYamlMixin):
1214
"""
1315
A data type used in the command-line
1416
"""
@@ -55,7 +57,7 @@ def representable(self) -> set:
5557
_representable = set()
5658

5759

58-
@dataclass(unsafe_hash=True)
60+
@attr.s(auto_attribs=True, frozen=True)
5961
class CliEnum(CliType):
6062
"""
6163
One of a list of possible options
@@ -67,7 +69,7 @@ class CliEnum(CliType):
6769
"""
6870

6971

70-
@dataclass(unsafe_hash=True)
72+
@attr.s(auto_attribs=True, frozen=True)
7173
class CliFloat(CliType):
7274
"""
7375
Takes a floating-point value
@@ -76,7 +78,7 @@ class CliFloat(CliType):
7678
pass
7779

7880

79-
@dataclass(unsafe_hash=True)
81+
@attr.s(auto_attribs=True, frozen=True)
8082
class CliInteger(CliType):
8183
"""
8284
Takes an integer value
@@ -85,7 +87,7 @@ class CliInteger(CliType):
8587
_representable = {CliFloat}
8688

8789

88-
@dataclass(unsafe_hash=True)
90+
@attr.s(auto_attribs=True, frozen=True)
8991
class CliString(CliType):
9092
"""
9193
Takes a string value
@@ -94,7 +96,7 @@ class CliString(CliType):
9496
pass
9597

9698

97-
@dataclass(unsafe_hash=True)
99+
@attr.s(auto_attribs=True, frozen=True)
98100
class CliBoolean(CliType):
99101
"""
100102
Takes a boolean value
@@ -103,7 +105,7 @@ class CliBoolean(CliType):
103105
pass
104106

105107

106-
@dataclass(unsafe_hash=True)
108+
@attr.s(auto_attribs=True, frozen=True)
107109
class CliFileSystemType(CliType):
108110
"""
109111
Takes a directory / file path
@@ -115,7 +117,7 @@ class CliFileSystemType(CliType):
115117
"""
116118

117119

118-
@dataclass(unsafe_hash=True)
120+
@attr.s(auto_attribs=True, frozen=True)
119121
class CliDir(CliFileSystemType):
120122
"""
121123
Takes a directory path
@@ -124,7 +126,7 @@ class CliDir(CliFileSystemType):
124126
pass
125127

126128

127-
@dataclass(unsafe_hash=True)
129+
@attr.s(auto_attribs=True, frozen=True)
128130
class CliFile(CliFileSystemType):
129131
"""
130132
Takes a file path
@@ -133,7 +135,7 @@ class CliFile(CliFileSystemType):
133135
pass
134136

135137

136-
@dataclass(unsafe_hash=True)
138+
@attr.s(auto_attribs=True, frozen=True)
137139
class CliDict(CliType):
138140
"""
139141
Takes a dictionary value
@@ -150,7 +152,7 @@ class CliDict(CliType):
150152
"""
151153

152154

153-
@dataclass(unsafe_hash=True)
155+
@attr.s(auto_attribs=True, frozen=True)
154156
class CliList(CliType):
155157
"""
156158
Takes a list value
@@ -162,7 +164,7 @@ class CliList(CliType):
162164
"""
163165

164166

165-
@dataclass(unsafe_hash=True)
167+
@attr.s(auto_attribs=True, frozen=True)
166168
class CliTuple(CliType):
167169
"""
168170
Takes a list of values with a fixed length, possibly each with different types

aclimatise/converter/__init__.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from pathlib import Path
55
from typing import Generator, Iterable, List, Set, TextIO, Tuple, Type
66

7-
from dataclasses import dataclass
7+
import attr
88

99
from aclimatise.model import CliArgument, Command, Flag
1010
from aclimatise.name_generation import (
@@ -16,16 +16,21 @@
1616
name_to_camel,
1717
name_to_snake,
1818
)
19+
from aclimatise.yaml import AttrYamlMixin
1920

2021

21-
@dataclass
22-
class NamedArgument:
22+
@attr.s(
23+
auto_attribs=True,
24+
)
25+
class NamedArgument(AttrYamlMixin):
2326
arg: CliArgument
2427
name: str
2528

2629

27-
@dataclass
28-
class WrapperGenerator:
30+
@attr.s(
31+
auto_attribs=True,
32+
)
33+
class WrapperGenerator(AttrYamlMixin):
2934
"""
3035
Abstract base class for a class that converts a Command object into a string that defines a tool
3136
wrapper in a certain workflow language

aclimatise/converter/cwl.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from pathlib import Path
33
from typing import List
44

5+
import attr
56
from cwl_utils.parser_v1_1 import (
67
CommandInputParameter,
78
CommandLineBinding,
@@ -10,7 +11,6 @@
1011
CommandOutputParameter,
1112
DockerRequirement,
1213
)
13-
from dataclasses import dataclass
1414

1515
from aclimatise import cli_types
1616
from aclimatise.cli_types import CliType
@@ -19,7 +19,7 @@
1919
from aclimatise.yaml import yaml
2020

2121

22-
@dataclass
22+
@attr.s(auto_attribs=True)
2323
class CwlGenerator(WrapperGenerator):
2424
case = "snake"
2525

aclimatise/converter/yml.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33
from pathlib import Path
44
from typing import Generator, List
55

6-
from dataclasses import dataclass
6+
import attr
77

88
from aclimatise.converter import WrapperGenerator
99
from aclimatise.model import Command
1010
from aclimatise.yaml import yaml
1111

1212

13-
@dataclass
13+
@attr.s(auto_attribs=True)
1414
class YmlGenerator(WrapperGenerator):
1515
"""
1616
Internal YML format

aclimatise/integration.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import typing
22

3-
import dataclasses
3+
import attr
44

55
from aclimatise.flag_parser.parser import CliParser
66
from aclimatise.model import Command, Flag
@@ -32,7 +32,7 @@ def parse_help(cmd: typing.Collection[str], text: str, max_length=1000) -> Comma
3232
# Combine the flags from both help and usage
3333
named=list(Flag.combine([help_command.named, usage_command.named])),
3434
)
35-
for field in dataclasses.fields(Command):
35+
for field in attr.fields(Command):
3636
fields[field.name] = (
3737
fields.get(field.name)
3838
or getattr(help_command, field.name)

aclimatise/model.py

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
from operator import attrgetter
1212

1313
import attr
14-
from dataclasses import dataclass, field
1514
from ruamel.yaml import yaml_object
1615
from word2number import w2n
1716

@@ -21,7 +20,7 @@
2120
from aclimatise.name_generation import segment_string
2221
from aclimatise.nlp import wordsegment
2322
from aclimatise.usage_parser.model import UsageInstance
24-
from aclimatise.yaml import yaml
23+
from aclimatise.yaml import AttrYamlMixin, yaml
2524

2625

2726
def first(lst: typing.List, default):
@@ -50,13 +49,15 @@ def useless_name(name: typing.List[str]):
5049

5150

5251
@yaml_object(yaml)
53-
@dataclass
54-
class Command:
52+
@attr.s(
53+
auto_attribs=True,
54+
)
55+
class Command(AttrYamlMixin):
5556
"""
5657
Class representing an entire command or subcommand, e.g. `bwa mem` or `grep`
5758
"""
5859

59-
def __post_init__(self):
60+
def __attrs_post_init__(self):
6061
# Store certain special flags in their own fields
6162
if self.help_flag is None:
6263
for flag in self.named:
@@ -235,12 +236,12 @@ def command_tree(self) -> typing.Generator["Command", None, None]:
235236
The command line used to invoke this command, e.g. ["bwa", "mem"]
236237
"""
237238

238-
positional: typing.List["Positional"] = field(default_factory=list)
239+
positional: typing.List["Positional"] = attr.ib(factory=list)
239240
"""
240241
All positional arguments supported by this command
241242
"""
242243

243-
named: typing.List["Flag"] = field(default_factory=list)
244+
named: typing.List["Flag"] = attr.ib(factory=list)
244245
"""
245246
All named arguments (flags) supported by this command
246247
"""
@@ -250,12 +251,12 @@ def command_tree(self) -> typing.Generator["Command", None, None]:
250251
The parent command, if this is a subcommand
251252
"""
252253

253-
subcommands: typing.List["Command"] = field(default_factory=list)
254+
subcommands: typing.List["Command"] = attr.ib(factory=list)
254255
"""
255256
A list of subcommands of this command, e.g. "bwa" has the subcommand "bwa mem"
256257
"""
257258

258-
usage: typing.List["UsageInstance"] = field(default_factory=list)
259+
usage: typing.List["UsageInstance"] = attr.ib(factory=list)
259260
"""
260261
Different usage examples provided by the help
261262
"""
@@ -293,7 +294,7 @@ def command_tree(self) -> typing.Generator["Command", None, None]:
293294

294295
@yaml_object(yaml)
295296
@attr.s(auto_attribs=True)
296-
class CliArgument:
297+
class CliArgument(AttrYamlMixin):
297298
"""
298299
A generic parent class for both named and positional CLI arguments
299300
"""
@@ -428,11 +429,10 @@ class Flag(CliArgument):
428429
Describes the arguments to this flag, e.g. ``-n 1`` has a single numeric argument
429430
"""
430431

431-
def __post_init__(self):
432+
def __attrs_post_init__(self):
432433
if self.optional is None:
433434
# Flags are optional by default
434435
self.optional = True
435-
super().__post_init__()
436436

437437
@staticmethod
438438
def deduplicate(flags: typing.Collection["Flag"]) -> typing.List["Flag"]:
@@ -595,8 +595,8 @@ def shortest_synonym(self) -> str:
595595

596596

597597
@yaml_object(yaml)
598-
@dataclass
599-
class FlagSynonym:
598+
@attr.s(auto_attribs=True)
599+
class FlagSynonym(AttrYamlMixin):
600600
"""
601601
Internal class for storing the arguments for a single synonym
602602
"""
@@ -679,8 +679,8 @@ def infer_type(string) -> typing.Optional[cli_types.CliType]:
679679

680680

681681
@yaml_object(yaml)
682-
@dataclass
683-
class FlagArg(abc.ABC):
682+
@attr.s(auto_attribs=True)
683+
class FlagArg(abc.ABC, AttrYamlMixin):
684684
"""
685685
The data model for the argument or arguments for a flag, for example a flag might have no arguments, it might have
686686
one argument, it might accept one option from a list of options, or it might accept an arbitrary number of inputs
@@ -709,7 +709,7 @@ def num_args(self) -> int:
709709

710710

711711
@yaml_object(yaml)
712-
@dataclass
712+
@attr.s(auto_attribs=True)
713713
class EmptyFlagArg(FlagArg):
714714
"""
715715
A flag that has no arguments, e.g. `--quiet` that is either present or not present
@@ -723,7 +723,7 @@ def get_type(self):
723723

724724

725725
@yaml_object(yaml)
726-
@dataclass
726+
@attr.s(auto_attribs=True)
727727
class OptionalFlagArg(FlagArg):
728728
"""
729729
When the flag has multiple arguments, some of which are optional, e.g.
@@ -757,7 +757,7 @@ def get_type(self):
757757

758758

759759
@yaml_object(yaml)
760-
@dataclass
760+
@attr.s(auto_attribs=True)
761761
class SimpleFlagArg(FlagArg):
762762
"""
763763
When a flag has one single argument, e.g. `-e PATTERN`, where PATTERN is the argument
@@ -779,7 +779,7 @@ def get_type(self):
779779

780780

781781
@yaml_object(yaml)
782-
@dataclass
782+
@attr.s(auto_attribs=True)
783783
class RepeatFlagArg(FlagArg):
784784
"""
785785
When a flag accepts 1 or more arguments, e.g. `--samout SAMOUTS [SAMOUTS ...]`
@@ -805,7 +805,7 @@ def get_type(self):
805805

806806

807807
@yaml_object(yaml)
808-
@dataclass
808+
@attr.s(auto_attribs=True)
809809
class ChoiceFlagArg(FlagArg):
810810
"""
811811
When a flag accepts one option from a list of options, e.g. `-s {yes,no,reverse}`

0 commit comments

Comments
 (0)