Skip to content

Commit 436a8a6

Browse files
authored
Merge pull request #15 from bernt-matthias/topic/guess-in-or-out
Guess if files/dirs are inputs or outputs
2 parents 097113d + 40fbc68 commit 436a8a6

3 files changed

Lines changed: 98 additions & 16 deletions

File tree

acclimatise/cli_types.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,19 @@ class CliBoolean(CliType):
7474

7575

7676
@dataclass(unsafe_hash=True)
77-
class CliDir(CliType):
77+
class CliFileSystemType(CliType):
78+
"""
79+
Takes a directory / file path
80+
"""
81+
82+
output: bool = False
83+
"""
84+
Indicator if it is input or output
85+
"""
86+
87+
88+
@dataclass(unsafe_hash=True)
89+
class CliDir(CliFileSystemType):
7890
"""
7991
Takes a directory path
8092
"""
@@ -83,7 +95,7 @@ class CliDir(CliType):
8395

8496

8597
@dataclass(unsafe_hash=True)
86-
class CliFile(CliType):
98+
class CliFile(CliFileSystemType):
8799
"""
88100
Takes a file path
89101
"""

acclimatise/model.py

Lines changed: 42 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -370,31 +370,59 @@ def capital(self):
370370
)
371371

372372

373-
int_re = re.compile("(int(eger)?)|size|length|max|min", flags=re.IGNORECASE)
374-
str_re = re.compile("str(ing)?", flags=re.IGNORECASE)
375-
float_re = re.compile("float|decimal", flags=re.IGNORECASE)
376-
bool_re = re.compile("bool(ean)?", flags=re.IGNORECASE)
377-
file_re = re.compile("file|path", flags=re.IGNORECASE)
378-
dir_re = re.compile("folder|directory", flags=re.IGNORECASE)
373+
int_re = re.compile(
374+
r"\b((int(eger)?)|size|length|max|min|(num(ber)?))\b", flags=re.IGNORECASE
375+
)
376+
str_re = re.compile(r"\bstr(ing)?\b", flags=re.IGNORECASE)
377+
float_re = re.compile(r"\b(float|decimal)\b", flags=re.IGNORECASE)
378+
bool_re = re.compile(r"\bbool(ean)?\b", flags=re.IGNORECASE)
379+
file_re = re.compile(r"\b(file|path)\b", flags=re.IGNORECASE)
380+
input_re = re.compile(r"input", flags=re.IGNORECASE)
381+
output_re = re.compile(r"output", flags=re.IGNORECASE)
382+
dir_re = re.compile(r"\b(folder|directory)\b", flags=re.IGNORECASE)
383+
384+
float_num_re = re.compile(
385+
r"[+-]?(([0-9]*\.[0-9]+)|((?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)))",
386+
flags=re.IGNORECASE,
387+
)
388+
int_num_re = re.compile(r"([+-]?[0-9]+)", flags=re.IGNORECASE)
389+
390+
391+
def distinguish_inout(
392+
string, cls: typing.Type[cli_types.CliFileSystemType]
393+
) -> cli_types.CliFileSystemType:
394+
"""
395+
distinguish input/output files/directories given a string
396+
"""
397+
im = input_re.search(string)
398+
om = output_re.search(string)
399+
if not im and om:
400+
return cls(output=True)
401+
else:
402+
return cls(output=False)
379403

380404

381405
def infer_type(string) -> typing.Optional[cli_types.CliType]:
382406
"""
383407
Reads a string (argument description etc) to find hints about what type this argument might be. This is
384408
generally called by the get_type() methods
385409
"""
386-
if bool_re.match(string):
410+
if bool_re.search(string):
387411
return cli_types.CliBoolean()
388-
elif float_re.match(string):
412+
elif float_re.search(string):
389413
return cli_types.CliFloat()
390-
elif int_re.match(string):
414+
elif int_re.search(string):
391415
return cli_types.CliInteger()
392-
elif file_re.match(string):
393-
return cli_types.CliFile()
394-
elif dir_re.match(string):
395-
return cli_types.CliDir()
396-
elif str_re.match(string):
416+
elif file_re.search(string):
417+
return distinguish_inout(string, cli_types.CliFile)
418+
elif dir_re.search(string):
419+
return distinguish_inout(string, cli_types.CliDir)
420+
elif str_re.search(string):
397421
return cli_types.CliString()
422+
elif float_num_re.search(string):
423+
return cli_types.CliFloat()
424+
elif int_num_re.search(string):
425+
return cli_types.CliInteger()
398426
else:
399427
return None
400428

test/test_type_inference.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import pytest
2+
3+
from acclimatise.cli_types import (
4+
CliBoolean,
5+
CliDir,
6+
CliFile,
7+
CliFloat,
8+
CliInteger,
9+
CliString,
10+
)
11+
from acclimatise.model import infer_type
12+
13+
14+
@pytest.mark.parametrize(
15+
"string,typ",
16+
[
17+
("", None),
18+
("int", CliInteger()),
19+
("size", CliInteger()),
20+
("length", CliInteger()),
21+
("max", CliInteger()),
22+
("min", CliInteger()),
23+
("str", CliString()),
24+
("float", CliFloat()),
25+
("decimal", CliFloat()),
26+
("bool", CliBoolean()),
27+
("file", CliFile()),
28+
("path", CliFile()),
29+
("input file", CliFile(output=False)),
30+
("output file", CliFile(output=True)),
31+
("folder", CliDir()),
32+
("directory", CliDir()),
33+
("output directory", CliDir(output=True)),
34+
("blah 23 blub", CliInteger()),
35+
("nonsense 23.42", CliFloat()),
36+
(".42 gibberish", CliFloat()),
37+
("1E-5", CliFloat()),
38+
],
39+
)
40+
def test_type_inference(string, typ):
41+
inferred_type = infer_type(string)
42+
assert inferred_type == typ

0 commit comments

Comments
 (0)