Passed
Push — dependabot/pip/regex-2021.9.24 ( 3b76a8...31bdd5 )
by
unknown
02:00
created

mandos.entry._arg_utils.ArgUtils.parse_taxa()   B

Complexity

Conditions 6

Size

Total Lines 23
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 22
nop 4
dl 0
loc 23
rs 8.4186
c 0
b 0
f 0
1
from __future__ import annotations
0 ignored issues
show
introduced by
Missing module docstring
Loading history...
2
import os
3
from dataclasses import dataclass
4
from inspect import cleandoc
5
from pathlib import Path
6
from typing import (
7
    AbstractSet,
8
    Any,
9
    Callable,
10
    Iterable,
11
    Mapping,
12
    Optional,
13
    Sequence,
14
    Set,
15
    Tuple,
16
    TypeVar,
17
    Union,
18
)
19
20
import typer
0 ignored issues
show
introduced by
Unable to import 'typer'
Loading history...
21
from pocketutils.core.exceptions import PathExistsError, XTypeError, XValueError
0 ignored issues
show
introduced by
Unable to import 'pocketutils.core.exceptions'
Loading history...
22
from regex import regex
0 ignored issues
show
introduced by
Unable to import 'regex'
Loading history...
23
from typeddfs.df_errors import FilenameSuffixError
0 ignored issues
show
introduced by
Unable to import 'typeddfs.df_errors'
Loading history...
24
25
from mandos.model.apis.chembl_support.chembl_targets import TargetType
26
from mandos.model.apis.pubchem_support.pubchem_models import ClinicalTrialsGovUtils
27
from mandos.model.settings import SETTINGS, Globals
28
from mandos.model.taxonomy import Taxonomy
29
from mandos.model.taxonomy_caches import TaxonomyFactories
30
from mandos.model.utils.setup import logger
31
32
T = TypeVar("T", covariant=True)
0 ignored issues
show
Coding Style Naming introduced by
Class name "T" doesn't conform to PascalCase naming style ('[^\\W\\da-z][^\\W_]+$' pattern)

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
33
34
35
@dataclass(frozen=True, repr=True, order=True)
0 ignored issues
show
introduced by
Missing class docstring
Loading history...
36
class ParsedTaxa:
37
    source: str
38
    allow: Sequence[Union[int, str]]
39
    forbid: Sequence[Union[int, str]]
40
    ancestors: Sequence[Union[int, str]]
41
42
    @classmethod
43
    def empty(cls) -> ParsedTaxa:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
44
        return ParsedTaxa("", [], [], [])
45
46
47
class _Args:
48
    @staticmethod
49
    def _arg(doc: str, *names, default: Optional[T] = None, req: bool = False, **kwargs):
50
        kwargs = dict(
51
            help=cleandoc(doc),
52
            **kwargs,
53
            allow_dash=True,
54
        )
55
        if req:
0 ignored issues
show
unused-code introduced by
Unnecessary "else" after "return"
Loading history...
56
            return typer.Argument(default, **kwargs)
57
        else:
58
            return typer.Option(default, *names, **kwargs)
59
60
    @staticmethod
61
    def _path(
62
        doc: str, *names, default: Optional[str], f: bool, d: bool, out: bool, req: bool, **kwargs
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
Coding Style Naming introduced by
Variable name "f" doesn't conform to snake_case naming style ('([^\\W\\dA-Z][^\\WA-Z]2,|_[^\\WA-Z]*|__[^\\WA-Z\\d_][^\\WA-Z]+__)$' pattern)

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
Coding Style Naming introduced by
Variable name "d" doesn't conform to snake_case naming style ('([^\\W\\dA-Z][^\\WA-Z]2,|_[^\\WA-Z]*|__[^\\WA-Z\\d_][^\\WA-Z]+__)$' pattern)

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
63
    ):
64
        # if it's None, we're going to have a special default set afterward, so we'll explain it in the doc
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (107/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
65
        if out and default is None:
66
            kwargs = dict(show_default=False, **kwargs)
67
        kwargs = {
68
            **dict(
69
                exists=not out,
70
                dir_okay=d,
71
                file_okay=f,
72
                readable=out,
73
                writable=not out,
74
            ),
75
            **kwargs,
76
        }
77
        return _Args._arg(doc, *names, default=default, req=req, **kwargs)
78
79
80
class Arg(_Args):
0 ignored issues
show
introduced by
Missing class docstring
Loading history...
81
    @staticmethod
82
    def out_file(doc: str, *names, default: Optional[str] = None, **kwargs):
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
83
        return _Args._path(
84
            doc, *names, default=default, f=True, d=False, out=True, req=True, **kwargs
85
        )
86
87
    @staticmethod
88
    def out_dir(doc: str, *names, default: Optional[str] = None, **kwargs):
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
89
        return _Args._path(
90
            doc, *names, default=default, f=True, d=True, out=True, req=True, **kwargs
91
        )
92
93
    @staticmethod
94
    def out_path(doc: str, *names, default: Optional[str] = None, **kwargs):
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
95
        return _Args._path(
96
            doc, *names, default=default, f=True, d=True, out=False, req=True, **kwargs
97
        )
98
99
    @staticmethod
100
    def in_file(doc: str, *names, default: Optional[str] = None, **kwargs):
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
101
        return _Args._path(
102
            doc, *names, default=default, f=True, d=False, out=False, req=True, **kwargs
103
        )
104
105
    @staticmethod
106
    def in_dir(doc: str, *names, default: Optional[str] = None, **kwargs):
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
107
        return _Args._path(
108
            doc, *names, default=default, f=False, d=True, out=False, req=True, **kwargs
109
        )
110
111
    @staticmethod
112
    def in_path(doc: str, *names, default: Optional[str] = None, **kwargs):
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
113
        return _Args._path(
114
            doc, *names, default=default, f=True, d=True, out=False, req=True, **kwargs
115
        )
116
117
    @staticmethod
118
    def val(doc: str, *names, default: Optional[T] = None, **kwargs):
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
119
        return _Args._arg(doc, *names, default=default, req=True, **kwargs)
120
121
122
class Opt(_Args):
0 ignored issues
show
introduced by
Missing class docstring
Loading history...
123
    @staticmethod
124
    def out_file(doc: str, *names, default: Optional[str] = None, **kwargs):
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
125
        return _Args._path(
126
            doc, *names, default=default, f=True, d=False, out=True, req=False, **kwargs
127
        )
128
129
    @staticmethod
130
    def out_dir(doc: str, *names, default: Optional[str] = None, **kwargs):
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
131
        return _Args._path(
132
            doc, *names, default=default, f=True, d=True, out=True, req=False, **kwargs
133
        )
134
135
    @staticmethod
136
    def out_path(doc: str, *names, default: Optional[str] = None, **kwargs):
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
137
        return _Args._path(
138
            doc,
139
            *names,
140
            default=default,
141
            f=True,
142
            d=True,
143
            out=False,
144
            req=False,
145
            exists=False,
146
            **kwargs,
147
        )
148
149
    @staticmethod
150
    def in_file(doc: str, *names, default: Optional[str] = None, **kwargs):
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
151
        return _Args._path(
152
            doc, *names, default=default, f=True, d=False, out=False, req=False, **kwargs
153
        )
154
155
    @staticmethod
156
    def in_dir(doc: str, *names, default: Optional[str] = None, **kwargs):
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
157
        return _Args._path(
158
            doc, *names, default=default, f=False, d=True, out=False, req=False, **kwargs
159
        )
160
161
    @staticmethod
162
    def in_path(doc: str, *names, default: Optional[str] = None, **kwargs):
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
163
        return _Args._path(
164
            doc,
165
            *names,
166
            default=default,
167
            f=True,
168
            d=True,
169
            out=False,
170
            req=False,
171
            exists=False,
172
            **kwargs,
173
        )
174
175
    @staticmethod
176
    def val(doc: str, *names, default: Optional[T] = None, **kwargs):
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
177
        return _Args._arg(doc, *names, default=default, req=False, **kwargs)
178
179
    @staticmethod
180
    def flag(doc: str, *names, **kwargs):
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
181
        return _Args._arg(doc, *names, default=False, req=False, **kwargs)
182
183
184
class ArgUtils:
0 ignored issues
show
introduced by
Missing class docstring
Loading history...
185
    @classmethod
186
    def definition_bullets(cls, dct: Mapping[Any, Any], colon: str = ": ", indent: int = 12) -> str:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
187
        joiner = os.linesep * 2 + " " * indent
188
        jesus = [f" - {k}{colon}{v}" for k, v in dct.items()]
189
        return joiner.join(jesus)
190
191
    @classmethod
192
    def definition_list(cls, dct: Mapping[Any, Any], colon: str = ": ", sep: str = "; ") -> str:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
193
        jesus = [f"{k}{colon}{v}" for k, v in dct.items()]
194
        return sep.join(jesus)
195
196
    @classmethod
197
    def list(
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
198
        cls,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
199
        lst: Iterable[Any],
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
200
        *,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
201
        attr: Union[None, str, Callable[[Any], Any]] = None,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
202
        sep: str = ", ",
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
203
    ) -> str:
204
        x = []
0 ignored issues
show
Coding Style Naming introduced by
Variable name "x" doesn't conform to snake_case naming style ('([^\\W\\dA-Z][^\\WA-Z]2,|_[^\\WA-Z]*|__[^\\WA-Z\\d_][^\\WA-Z]+__)$' pattern)

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
205
        for v in lst:
0 ignored issues
show
Coding Style Naming introduced by
Variable name "v" doesn't conform to snake_case naming style ('([^\\W\\dA-Z][^\\WA-Z]2,|_[^\\WA-Z]*|__[^\\WA-Z\\d_][^\\WA-Z]+__)$' pattern)

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
206
            if attr is None and hasattr(v, "name"):
207
                x += [v.name]
0 ignored issues
show
Coding Style Naming introduced by
Variable name "x" doesn't conform to snake_case naming style ('([^\\W\\dA-Z][^\\WA-Z]2,|_[^\\WA-Z]*|__[^\\WA-Z\\d_][^\\WA-Z]+__)$' pattern)

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
208
            elif attr is None:
209
                x += [str(v)]
0 ignored issues
show
Coding Style Naming introduced by
Variable name "x" doesn't conform to snake_case naming style ('([^\\W\\dA-Z][^\\WA-Z]2,|_[^\\WA-Z]*|__[^\\WA-Z\\d_][^\\WA-Z]+__)$' pattern)

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
210
            elif isinstance(attr, str):
211
                x += [str(getattr(v, attr))]
0 ignored issues
show
Coding Style Naming introduced by
Variable name "x" doesn't conform to snake_case naming style ('([^\\W\\dA-Z][^\\WA-Z]2,|_[^\\WA-Z]*|__[^\\WA-Z\\d_][^\\WA-Z]+__)$' pattern)

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
212
            else:
213
                x += [str(attr(v))]
0 ignored issues
show
Coding Style Naming introduced by
Variable name "x" doesn't conform to snake_case naming style ('([^\\W\\dA-Z][^\\WA-Z]2,|_[^\\WA-Z]*|__[^\\WA-Z\\d_][^\\WA-Z]+__)$' pattern)

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
214
        return sep.join(x)
215
216
    @classmethod
217
    def get_taxonomy(
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
218
        cls,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
219
        taxa: Optional[str],
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
220
        *,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
221
        local_only: bool = False,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
222
        allow_forbid: bool = True,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
223
    ) -> Optional[Taxonomy]:
224
        if taxa is None or len(taxa) == 0:
225
            return None
226
        allow, forbid, ancestors = cls.parse_taxa(taxa, allow_forbid=allow_forbid)
0 ignored issues
show
introduced by
Attempting to unpack a non-sequence defined at line 35
Loading history...
227
        return TaxonomyFactories.get_smart_taxonomy(
228
            allow=allow,
229
            forbid=forbid,
230
            ancestors=cls.parse_taxa_ids(ancestors),
231
            local_only=local_only,
232
        )
233
234
    @classmethod
235
    def parse_taxa(
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
236
        cls,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
237
        taxa: Optional[str],
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
238
        *,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
239
        allow_forbid: bool = True,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
240
    ) -> ParsedTaxa:
241
        if taxa is None or taxa == "":
242
            return ParsedTaxa.empty()
243
        ancestors = f"{Globals.cellular_taxon},{Globals.viral_taxon}"
244
        if ":" in taxa:
245
            ancestors = taxa.split(":", 1)[1]
246
            taxa = taxa.split(":", 1)[0]
247
        taxa_objs = [t.strip() for t in taxa.split(",") if len(t.strip()) > 0]
248
        allow = [t.strip().lstrip("+") for t in taxa_objs if not t.startswith("-")]
249
        forbid = [t.strip().lstrip("-") for t in taxa_objs if t.startswith("-")]
250
        if not allow_forbid and len(forbid) > 0:
251
            raise XValueError(f"Cannot use '-' in {taxa}")
252
        return ParsedTaxa(
253
            source=taxa,
254
            allow=[ArgUtils.parse_taxon(t, id_only=False) for t in allow],
255
            forbid=[ArgUtils.parse_taxon(t, id_only=False) for t in forbid],
256
            ancestors=[ArgUtils.parse_taxon(t, id_only=True) for t in ancestors],
257
        )
258
259
    @classmethod
260
    def parse_taxa_ids(cls, taxa: str) -> Sequence[int]:
261
        """
262
        Does not allow negatives.
263
        """
264
        if taxa is None or taxa == "":
265
            return []
266
        taxa = [t.strip() for t in taxa.split(",") if len(t.strip()) > 0]
267
        return [ArgUtils.parse_taxon(t, id_only=True) for t in taxa]
268
269
    @classmethod
270
    def parse_taxon(cls, taxon: Union[int, str], *, id_only: bool = False) -> Union[int, str]:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
271
        std = cls._get_std_taxon(taxon)
272
        if isinstance(taxon, str) and taxon in std:
273
            return std
274
        if isinstance(taxon, str) and not id_only:
0 ignored issues
show
unused-code introduced by
Unnecessary "elif" after "return"
Loading history...
275
            return taxon
276
        elif isinstance(taxon, str) and taxon.isdigit():
277
            return int(taxon)
278
        if id_only:
279
            raise XTypeError(f"Taxon {taxon} must be an ID")
280
        raise XTypeError(f"Taxon {taxon} must be an ID or name")
281
282
    @classmethod
283
    def _get_std_taxon(cls, taxa: str) -> str:
284
        x = dict(
0 ignored issues
show
Coding Style Naming introduced by
Variable name "x" doesn't conform to snake_case naming style ('([^\\W\\dA-Z][^\\WA-Z]2,|_[^\\WA-Z]*|__[^\\WA-Z\\d_][^\\WA-Z]+__)$' pattern)

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
285
            vertebrata=Globals.vertebrata,
286
            vertebrate=Globals.vertebrata,
287
            vertebrates=Globals.vertebrata,
288
            cellular=Globals.cellular_taxon,
289
            cell=Globals.cellular_taxon,
290
            cells=Globals.cellular_taxon,
291
            viral=Globals.viral_taxon,
292
            virus=Globals.viral_taxon,
293
            viruses=Globals.viral_taxon,
294
            all=f"{Globals.cellular_taxon},{Globals.viral_taxon}",
295
        ).get(taxa)
296
        return taxa if x is None else str(x)
297
298
    @staticmethod
299
    def get_trial_statuses(st: str) -> Set[str]:
0 ignored issues
show
Coding Style Naming introduced by
Argument name "st" doesn't conform to snake_case naming style ('([^\\W\\dA-Z][^\\WA-Z]2,|_[^\\WA-Z]*|__[^\\WA-Z\\d_][^\\WA-Z]+__)$' pattern)

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
introduced by
Missing function or method docstring
Loading history...
300
        return ClinicalTrialsGovUtils.resolve_statuses(st)
301
302
    @staticmethod
303
    def get_target_types(st: str) -> Set[str]:
0 ignored issues
show
Coding Style Naming introduced by
Argument name "st" doesn't conform to snake_case naming style ('([^\\W\\dA-Z][^\\WA-Z]2,|_[^\\WA-Z]*|__[^\\WA-Z\\d_][^\\WA-Z]+__)$' pattern)

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
introduced by
Missing function or method docstring
Loading history...
304
        return {s.name for s in TargetType.resolve(st)}
305
306
307
class EntryUtils:
0 ignored issues
show
introduced by
Missing class docstring
Loading history...
308
    @classmethod
309
    def adjust_filename(
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
Coding Style Naming introduced by
Argument name "to" doesn't conform to snake_case naming style ('([^\\W\\dA-Z][^\\WA-Z]2,|_[^\\WA-Z]*|__[^\\WA-Z\\d_][^\\WA-Z]+__)$' pattern)

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
310
        cls,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
311
        to: Optional[Path],
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
312
        default: Union[str, Path],
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
313
        replace: bool,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
314
        *,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
315
        suffixes: Union[None, AbstractSet[str], Callable[[Union[Path, str]], Any]] = None,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
316
    ) -> Path:
317
        if to is None:
318
            path = Path(default)
319
        elif str(to).startswith("."):
320
            path = Path(default).with_suffix(str(to))
321
        elif str(to).startswith("*."):
322
            path = Path(default).with_suffix(str(to)[1:])
323
        elif to.is_dir() or to.suffix == "":
324
            path = to / default
325
        else:
326
            path = Path(to)
327
        if (
328
            path.exists()
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
329
            and not path.is_file()
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
330
            and not path.is_socket()
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
331
            and not path.is_char_device()
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
332
        ):
333
            raise PathExistsError(f"Path {path} exists and is not a file")
334
        if path.exists() and not replace:
335
            raise PathExistsError(f"File {path} already exists")
336
        cls._check_suffix(path.suffix, suffixes)
337
        if path.exists() and replace:
338
            logger.info(f"Overwriting existing file {path}.")
339
        return path
340
341
    @classmethod
342
    def adjust_dir_name(
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
Coding Style Naming introduced by
Argument name "to" doesn't conform to snake_case naming style ('([^\\W\\dA-Z][^\\WA-Z]2,|_[^\\WA-Z]*|__[^\\WA-Z\\d_][^\\WA-Z]+__)$' pattern)

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
343
        cls,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
344
        to: Optional[Path],
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
345
        default: Union[str, Path],
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
346
        *,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
347
        suffixes: Union[None, AbstractSet[str], Callable[[Union[Path, str]], Any]] = None,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
348
    ) -> Tuple[Path, str]:
349
        out_dir = Path(default)
350
        suffix = SETTINGS.table_suffix
351
        if to is not None:
352
            pat = regex.compile(r"([^\*]*)(?:\*(\..+))", flags=regex.V1)
353
            m: regex.Match = pat.fullmatch(to)
0 ignored issues
show
Coding Style Naming introduced by
Variable name "m" doesn't conform to snake_case naming style ('([^\\W\\dA-Z][^\\WA-Z]2,|_[^\\WA-Z]*|__[^\\WA-Z\\d_][^\\WA-Z]+__)$' pattern)

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
354
            out_dir = default if m.group(1) == "" else m.group(1)
355
            suffix = SETTINGS.table_suffix if m.group(2) == "" else m.group(2)
356
            if out_dir.startswith("."):
357
                logger.warning(f"Writing to {out_dir} - was it meant as a suffix instead?")
358
            out_dir = Path(out_dir)
359
        if out_dir.exists() and not out_dir.is_dir():
360
            raise PathExistsError(f"Path {out_dir} already exists but and is not a directory")
361
        cls._check_suffix(suffix, suffixes)
362
        if out_dir.exists():
363
            n_files = len(list(out_dir.iterdir()))
364
            if n_files > 0:
365
                logger.debug(f"Directory {out_dir} is non-emtpy")
366
        return out_dir, suffix
367
368
    @classmethod
369
    def _check_suffix(cls, suffix, suffixes):
370
        if suffixes is not None and callable(suffixes):
371
            try:
372
                suffixes(suffix)  # make sure it's ok
373
            except FilenameSuffixError:
374
                raise XValueError(f"Unsupported file format {suffix}")
375
        elif suffixes is not None:
376
            if suffix not in suffixes:
377
                raise XValueError(f"Unsupported file format {suffix}")
378
379
380
__all__ = ["Arg", "Opt", "ArgUtils", "EntryUtils"]
381