Skip to content

yore ¤

yore package.

Manage legacy code with comments.

Classes:

  • CommandCheck

    Command to check Yore comments.

  • CommandDiff

    Command to diff Yore comments.

  • CommandFix

    Command to fix Yore comments.

  • CommandMain

    Command to manage legacy code in your code base with YORE comments.

  • Config

    Configuration for the insiders project.

  • Unset

    A sentinel value for unset configuration options.

  • YoreComment

    A Yore comment.

Functions:

Attributes:

COMMENT_PATTERN module-attribute ¤

COMMENT_PATTERN: str = "\n    (?P<kind>bol|bump|eol)\\ (?P<version>[^:]+):\\ (?:\n        remove\\ (?P<remove>block|file|line)\n        |\n        replace\\ (?P<replace>block|file|line)\\ with\\ (?:\n            line\\ (?P<line>\\d+)\n            |\n            lines\\ (?P<lines>[\\d, -]+)\n            |\n            `(?P<string>.+)`\n        )\n        |\n        (?P<regex>regex-)?replace\\ `(?P<pattern1>.+)`\\ with\\ `(?P<pattern2>.*)`\\ within\\ (?P<within>block|file|line)\n    )\n"

The Yore comment pattern, as a regular expression.

COMMENT_PREFIXES module-attribute ¤

COMMENT_PREFIXES: set[str] = {
    "\\#\\ ",
    "//\\ ",
    "--\\ ",
    ";",
    "%\\ ",
    "'\\ ?",
    "/\\*\\ ",
    "<!--\\ ",
    "\\{\\#-?\\ ",
    "\\(\\*\\ ",
}

The supported comment prefixes.

DEFAULT_EXCLUDE module-attribute ¤

DEFAULT_EXCLUDE = ['.*', '__py*', 'build', 'dist']

The default patterns to exclude when scanning directories.

DEFAULT_PREFIX module-attribute ¤

DEFAULT_PREFIX = 'YORE'

Scope module-attribute ¤

Scope = Literal['block', 'file', 'line']

The scope of a comment.

YoreKind module-attribute ¤

YoreKind = Literal['bump', 'eol', 'bol']

The supported kinds of Yore comments.

python_dates module-attribute ¤

python_dates = _LazyPythonDates()

A dictionary of Python versions and their Beginning/End of Life dates.

CommandCheck dataclass ¤

CommandCheck(
    paths: list[Path] = list(),
    bump: str | None = None,
    eol_within: timedelta | None = None,
    bol_within: timedelta | None = None,
    prefix: str = DEFAULT_PREFIX,
)

Command to check Yore comments.

Methods:

Attributes:

  • bol_within (timedelta | None) –

    The time delta to start checking before the Beginning of Life of a Python version.

  • bump (str | None) –

    The next version of your project.

  • eol_within (timedelta | None) –

    The time delta to start checking before the End of Life of a Python version.

  • paths (list[Path]) –

    Path to files or directories to check.

  • prefix (str) –

    The prefix for Yore comments.

bol_within class-attribute instance-attribute ¤

bol_within: timedelta | None = None

The time delta to start checking before the Beginning of Life of a Python version. It is provided in a human-readable format, like 2 weeks or 1 month. Spaces are optional, and the unit can be shortened to a single letter: d for days, w for weeks, m for months, and y for years.

bump class-attribute instance-attribute ¤

bump: str | None = None

The next version of your project.

eol_within class-attribute instance-attribute ¤

eol_within: timedelta | None = None

The time delta to start checking before the End of Life of a Python version. It is provided in a human-readable format, like 2 weeks or 1 month. Spaces are optional, and the unit can be shortened to a single letter: d for days, w for weeks, m for months, and y for years.

paths class-attribute instance-attribute ¤

paths: list[Path] = field(default_factory=list)

Path to files or directories to check.

prefix class-attribute instance-attribute ¤

prefix: str = DEFAULT_PREFIX

The prefix for Yore comments.

__call__ ¤

__call__() -> int

Check Yore comments.

Source code in src/yore/_internal/cli.py
135
136
137
138
139
140
141
142
def __call__(self) -> int:
    """Check Yore comments."""
    ok = True
    paths = self.paths or [Path(".")]
    for path in paths:
        for comment in yield_path_comments(path, prefix=self.prefix):
            ok &= comment.check(bump=self.bump, eol_within=self.eol_within, bol_within=self.bol_within)
    return 0 if ok else 1

CommandDiff dataclass ¤

CommandDiff(
    paths: list[Path] = list(),
    bump: str | None = None,
    eol_within: timedelta | None = None,
    bol_within: timedelta | None = None,
    highlight: str | None = None,
    prefix: str = DEFAULT_PREFIX,
)

Command to diff Yore comments.

Methods:

Attributes:

  • bol_within (timedelta | None) –

    The time delta to start diffing before the Beginning of Life of a Python version.

  • bump (str | None) –

    The next version of your project.

  • eol_within (timedelta | None) –

    The time delta to start diffing before the End of Life of a Python version.

  • highlight (str | None) –

    The command to highlight diffs.

  • paths (list[Path]) –

    Path to files or directories to diff.

  • prefix (str) –

    The prefix for Yore comments.

bol_within class-attribute instance-attribute ¤

bol_within: timedelta | None = None

The time delta to start diffing before the Beginning of Life of a Python version. It is provided in a human-readable format, like 2 weeks or 1 month. Spaces are optional, and the unit can be shortened to a single letter: d for days, w for weeks, m for months, and y for years.

bump class-attribute instance-attribute ¤

bump: str | None = None

The next version of your project.

eol_within class-attribute instance-attribute ¤

eol_within: timedelta | None = None

The time delta to start diffing before the End of Life of a Python version. It is provided in a human-readable format, like 2 weeks or 1 month. Spaces are optional, and the unit can be shortened to a single letter: d for days, w for weeks, m for months, and y for years.

highlight class-attribute instance-attribute ¤

highlight: str | None = None

The command to highlight diffs.

paths class-attribute instance-attribute ¤

paths: list[Path] = field(default_factory=list)

Path to files or directories to diff.

prefix class-attribute instance-attribute ¤

prefix: str = DEFAULT_PREFIX

The prefix for Yore comments.

__call__ ¤

__call__() -> int

Diff Yore comments.

Source code in src/yore/_internal/cli.py
254
255
256
257
258
259
260
261
262
263
264
265
266
def __call__(self) -> int:
    """Diff Yore comments."""
    lines = self._diff_paths(self.paths or [Path(".")])
    if self.highlight:
        process = subprocess.Popen(self.highlight, shell=True, text=True, stdin=subprocess.PIPE)  # noqa: S602
        for line in lines:
            process.stdin.write(line)  # type: ignore[union-attr]
        process.stdin.close()  # type: ignore[union-attr]
        process.wait()
        return int(process.returncode)
    for line in lines:
        print(line, end="")
    return 0

CommandFix dataclass ¤

CommandFix(
    paths: list[Path] = list(),
    bump: str | None = None,
    eol_within: timedelta | None = None,
    bol_within: timedelta | None = None,
    prefix: str = DEFAULT_PREFIX,
)

Command to fix Yore comments.

Methods:

Attributes:

  • bol_within (timedelta | None) –

    The time delta to start fixing before the Beginning of Life of a Python version.

  • bump (str | None) –

    The next version of your project.

  • eol_within (timedelta | None) –

    The time delta to start fixing before the End of Life of a Python version.

  • paths (list[Path]) –

    Path to files or directories to fix.

  • prefix (str) –

    The prefix for Yore comments.

bol_within class-attribute instance-attribute ¤

bol_within: timedelta | None = None

The time delta to start fixing before the Beginning of Life of a Python version. It is provided in a human-readable format, like 2 weeks or 1 month. Spaces are optional, and the unit can be shortened to a single letter: d for days, w for weeks, m for months, and y for years.

bump class-attribute instance-attribute ¤

bump: str | None = None

The next version of your project.

eol_within class-attribute instance-attribute ¤

eol_within: timedelta | None = None

The time delta to start fixing before the End of Life of a Python version. It is provided in a human-readable format, like 2 weeks or 1 month. Spaces are optional, and the unit can be shortened to a single letter: d for days, w for weeks, m for months, and y for years.

paths class-attribute instance-attribute ¤

paths: list[Path] = field(default_factory=list)

Path to files or directories to fix.

prefix class-attribute instance-attribute ¤

prefix: str = DEFAULT_PREFIX

The prefix for Yore comments.

__call__ ¤

__call__() -> int

Fix Yore comments.

Source code in src/yore/_internal/cli.py
357
358
359
360
361
362
363
364
365
366
def __call__(self) -> int:
    """Fix Yore comments."""
    paths = self.paths or [Path(".")]
    for path in paths:
        if path.is_file():
            self._fix(path)
        else:
            for file in yield_files(path):
                self._fix(file)
    return 0

CommandMain dataclass ¤

CommandMain(
    subcommand: Subcommands[
        CommandCheck | CommandDiff | CommandFix
    ],
    config: Config = _load_config(),
    version: bool = False,
    debug_info: bool = False,
)

Command to manage legacy code in your code base with YORE comments.

Attributes:

config class-attribute instance-attribute ¤

config: Config = field(default_factory=_load_config)

Path to the configuration file.

debug_info class-attribute instance-attribute ¤

debug_info: bool = False

Print debug information.

subcommand instance-attribute ¤

subcommand: Subcommands[
    CommandCheck | CommandDiff | CommandFix
]

The selected subcommand.

version class-attribute instance-attribute ¤

version: bool = False

Version CLI option.

Config dataclass ¤

Config(
    prefix: list[str] | Unset = config_field("prefix"),
    diff_highlight: str | Unset = config_field(
        "diff.highlight"
    ),
)

Configuration for the insiders project.

Methods:

Attributes:

diff_highlight class-attribute instance-attribute ¤

diff_highlight: str | Unset = config_field("diff.highlight")

The command to highlight diffs.

prefix class-attribute instance-attribute ¤

prefix: list[str] | Unset = config_field('prefix')

The prefix for Yore comments.

from_data classmethod ¤

from_data(data: Mapping[str, Any]) -> Config

Load configuration from data.

Parameters:

Returns:

  • Config

    Loaded configuration.

Source code in src/yore/_internal/config.py
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
@classmethod
def from_data(
    cls,
    data: An[Mapping[str, Any], Doc("Data to load configuration from.")],
) -> An[Config, Doc("Loaded configuration.")]:
    """Load configuration from data."""
    # Check for unknown configuration keys.
    field_keys = [field.default.key for field in fields(cls)]  # type: ignore[union-attr]
    unknown_keys = []
    for top_level_key, top_level_value in data.items():
        if isinstance(top_level_value, dict):
            for key in top_level_value.keys():  # noqa: SIM118
                final_key = f"{top_level_key}.{key}"
                if final_key not in field_keys:
                    unknown_keys.append(final_key)
        elif top_level_key not in field_keys:
            unknown_keys.append(top_level_key)
    if unknown_keys:
        _logger.warning(f"Unknown configuration keys: {', '.join(unknown_keys)}")

    # Create a configuration instance.
    return cls(
        **{
            field.name: cls._get(
                data,
                *field.default.key.split("."),  # type: ignore[union-attr]
                default=field.default,  # type: ignore[arg-type]
                transform=getattr(cls, field.default.transform or "", None),  # type: ignore[union-attr]
            )
            for field in fields(cls)
        },
    )

from_default_locations classmethod ¤

from_default_locations() -> Config

Load configuration from the default locations.

Returns:

  • Config

    Loaded configuration.

Source code in src/yore/_internal/config.py
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
@classmethod
def from_default_locations(cls) -> An[Config, Doc("Loaded configuration.")]:
    """Load configuration from the default locations."""
    paths = ("config/yore.toml", "yore.toml", "pyproject.toml")
    cwd = Path.cwd()
    while True:
        for path in paths:
            if (cwd / path).exists():
                if path == "pyproject.toml":
                    return cls.from_pyproject(cwd / path)
                return cls.from_file(cwd / path)
        if cwd == cwd.parent:
            break
        cwd = cwd.parent
    return cls()

from_file classmethod ¤

from_file(path: str | Path) -> Config

Load configuration from a file.

Parameters:

  • path ¤

    (str | Path) –

    Path to the configuration file.

Returns:

  • Config

    Loaded configuration.

Source code in src/yore/_internal/config.py
122
123
124
125
126
127
128
129
@classmethod
def from_file(
    cls,
    path: An[str | Path, Doc("Path to the configuration file.")],
) -> An[Config, Doc("Loaded configuration.")]:
    """Load configuration from a file."""
    with open(path, "rb") as file:
        return cls.from_data(tomllib.load(file))

from_pyproject classmethod ¤

from_pyproject(path: str | Path) -> Config

Load configuration from pyproject.toml.

Parameters:

  • path ¤

    (str | Path) –

    Path to the pyproject.toml file.

Returns:

  • Config

    Loaded configuration.

Source code in src/yore/_internal/config.py
131
132
133
134
135
136
137
138
@classmethod
def from_pyproject(
    cls,
    path: An[str | Path, Doc("Path to the pyproject.toml file.")],
) -> An[Config, Doc("Loaded configuration.")]:
    """Load configuration from pyproject.toml."""
    with open(path, "rb") as file:
        return cls.from_data(tomllib.load(file).get("tool", {}).get("yore", {}))

Unset ¤

Unset(key: str, transform: str | None = None)

A sentinel value for unset configuration options.

Parameters:

  • key ¤

    (str) –

    TOML key.

  • transform ¤

    (str | None, default: None ) –

    Name of the method to call to transform the config value.

Methods:

  • __bool__

    An unset value always evaluates to False.

Attributes:

  • key (str) –

    TOML key.

  • name (str) –

    Transformed key name.

  • transform (str | None) –

    Name of the method to call to transform the config value.

Source code in src/yore/_internal/config.py
29
30
31
32
33
34
35
36
def __init__(
    self,
    key: An[str, Doc("TOML key.")],
    transform: An[str | None, Doc("Name of the method to call to transform the config value.")] = None,
) -> None:
    self.key: An[str, Doc("TOML key.")] = key
    self.name: An[str, Doc("Transformed key name.")] = key.replace("-", "_").replace(".", "_")
    self.transform: An[str | None, Doc("Name of the method to call to transform the config value.")] = transform

key instance-attribute ¤

key: str = key

TOML key.

name instance-attribute ¤

name: str = replace('.', '_')

Transformed key name.

transform instance-attribute ¤

transform: str | None = transform

Name of the method to call to transform the config value.

__bool__ ¤

__bool__() -> bool

An unset value always evaluates to False.

Source code in src/yore/_internal/config.py
38
39
40
def __bool__(self) -> bool:
    """An unset value always evaluates to False."""
    return False

YoreComment dataclass ¤

YoreComment(
    file: Path,
    lineno: int,
    raw: str,
    prefix: str,
    suffix: str,
    kind: YoreKind,
    version: str,
    remove: Scope | None = None,
    replace: Scope | None = None,
    line: int | None = None,
    lines: list[int] | None = None,
    string: str | None = None,
    regex: bool = False,
    pattern1: str | None = None,
    pattern2: str | None = None,
    within: Scope | None = None,
)

A Yore comment.

Methods:

  • check

    Check the comment.

  • fix

    Fix the comment and code below it.

Attributes:

  • bol (date) –

    The Beginning of Life date for the Python version.

  • comment (str) –

    The comment without the prefix.

  • eol (date) –

    The End of Life date for the Python version.

  • file (Path) –

    The file containing comment.

  • is_bol (bool) –

    Whether the comment is an End of Life comment.

  • is_bump (bool) –

    Whether the comment is a bump comment.

  • is_eol (bool) –

    Whether the comment is an End of Life comment.

  • kind (YoreKind) –

    The kind of comment.

  • line (int | None) –

    The line to replace.

  • lineno (int) –

    The line number of the comment.

  • lines (list[int] | None) –

    The lines to replace.

  • pattern1 (str | None) –

    The pattern to replace.

  • pattern2 (str | None) –

    The replacement pattern.

  • prefix (str) –

    The prefix of the comment.

  • raw (str) –

    The raw comment.

  • regex (bool) –

    Whether to use regex for replacement.

  • remove (Scope | None) –

    The removal scope.

  • replace (Scope | None) –

    The replacement scope.

  • string (str | None) –

    The string to replace.

  • suffix (str) –

    The suffix of the comment.

  • version (str) –

    The EOL/bump version.

  • within (Scope | None) –

    The scope to replace within.

bol property ¤

bol: date

The Beginning of Life date for the Python version.

comment property ¤

comment: str

The comment without the prefix.

eol property ¤

eol: date

The End of Life date for the Python version.

file instance-attribute ¤

file: Path

The file containing comment.

is_bol property ¤

is_bol: bool

Whether the comment is an End of Life comment.

is_bump property ¤

is_bump: bool

Whether the comment is a bump comment.

is_eol property ¤

is_eol: bool

Whether the comment is an End of Life comment.

kind instance-attribute ¤

kind: YoreKind

The kind of comment.

line class-attribute instance-attribute ¤

line: int | None = None

The line to replace.

lineno instance-attribute ¤

lineno: int

The line number of the comment.

lines class-attribute instance-attribute ¤

lines: list[int] | None = None

The lines to replace.

pattern1 class-attribute instance-attribute ¤

pattern1: str | None = None

The pattern to replace.

pattern2 class-attribute instance-attribute ¤

pattern2: str | None = None

The replacement pattern.

prefix instance-attribute ¤

prefix: str

The prefix of the comment.

raw instance-attribute ¤

raw: str

The raw comment.

regex class-attribute instance-attribute ¤

regex: bool = False

Whether to use regex for replacement.

remove class-attribute instance-attribute ¤

remove: Scope | None = None

The removal scope.

replace class-attribute instance-attribute ¤

replace: Scope | None = None

The replacement scope.

string class-attribute instance-attribute ¤

string: str | None = None

The string to replace.

suffix instance-attribute ¤

suffix: str

The suffix of the comment.

version instance-attribute ¤

version: str

The EOL/bump version.

within class-attribute instance-attribute ¤

within: Scope | None = None

The scope to replace within.

check ¤

check(
    *,
    bump: str | None = None,
    eol_within: timedelta | None = None,
    bol_within: timedelta | None = None,
) -> bool

Check the comment.

Parameters:

  • bump ¤

    (str | None, default: None ) –

    The next version of the project.

  • eol_within ¤

    (timedelta | None, default: None ) –

    The time delta to start warning before the End of Life of a Python version.

  • bol_within ¤

    (timedelta | None, default: None ) –

    The time delta to start warning before the Beginning of Life of a Python version.

Returns:

  • bool

    True when there is nothing to do, False otherwise.

Source code in src/yore/_internal/lib.py
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
def check(
    self,
    *,
    bump: str | None = None,
    eol_within: TimeDelta | None = None,
    bol_within: TimeDelta | None = None,
) -> bool:
    """Check the comment.

    Parameters:
        bump: The next version of the project.
        eol_within: The time delta to start warning before the End of Life of a Python version.
        bol_within: The time delta to start warning before the Beginning of Life of a Python version.

    Returns:
        True when there is nothing to do, False otherwise.
    """
    msg_location = f"{self.file}:{self.lineno}:"
    if self.is_eol:
        if eol_within and _within(eol_within, self.eol):
            delta = f"since {self.eol}" if _past(self.eol) else f"in ~{naturaldelta(_delta(self.eol))}"
            _logger.warning(f"{msg_location} {delta} {self.comment}")
        elif _within(TimeDelta(days=0), self.eol):
            _logger.error(f"{msg_location} since {self.eol} {self.comment}")
        else:
            return True
    elif self.is_bol:
        if bol_within and _within(bol_within, self.bol):
            delta = f"since {self.eol}" if _past(self.eol) else f"in ~{naturaldelta(_delta(self.eol))}"
            _logger.warning(f"{msg_location} {delta} {self.comment}")
        elif _within(TimeDelta(days=0), self.bol):
            _logger.error(f"{msg_location} since {self.bol} {self.comment}")
        else:
            return True
    elif self.is_bump and bump and Version(bump) >= Version(self.version):
        _logger.error(f"{msg_location} version {self.version} >= {self.comment}")
    else:
        return True
    return False

fix ¤

fix(
    buffer: list[str] | None = None,
    *,
    bump: str | None = None,
    eol_within: timedelta | None = None,
    bol_within: timedelta | None = None,
) -> bool

Fix the comment and code below it.

Parameters:

  • buffer ¤

    (list[str] | None, default: None ) –

    The buffer to fix. If not provided, read from and write to the file.

  • bump ¤

    (str | None, default: None ) –

    The next version of the project.

  • eol_within ¤

    (timedelta | None, default: None ) –

    The time delta to start fixing before the End of Life of a Python version.

  • bol_within ¤

    (timedelta | None, default: None ) –

    The time delta to start fixing before the Beginning of Life of a Python version.

Returns:

  • bool

    Whether the comment was fixed.

Source code in src/yore/_internal/lib.py
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
def fix(
    self,
    buffer: list[str] | None = None,
    *,
    bump: str | None = None,
    eol_within: TimeDelta | None = None,
    bol_within: TimeDelta | None = None,
) -> bool:
    """Fix the comment and code below it.

    Parameters:
        buffer: The buffer to fix. If not provided, read from and write to the file.
        bump: The next version of the project.
        eol_within: The time delta to start fixing before the End of Life of a Python version.
        bol_within: The time delta to start fixing before the Beginning of Life of a Python version.

    Returns:
        Whether the comment was fixed.
    """
    write = buffer is None
    buffer = buffer or self.file.read_text().splitlines(keepends=True)

    # Check if the fix should be applied.
    if (
        (self.is_eol and ((eol_within and _within(eol_within, self.eol)) or _within(TimeDelta(days=0), self.eol)))
        or (
            self.is_bol and ((bol_within and _within(bol_within, self.bol)) or _within(TimeDelta(days=0), self.bol))
        )
        or (self.is_bump and bump and Version(bump) >= Version(self.version))
    ):
        # Start at the commnent line, immediately remove it.
        start = self.lineno - 1
        del buffer[start]

        if self.remove:
            start, end = _scope_range(self.remove, buffer, start)
            del buffer[start:end]
            if write and self.remove == "file":
                self.file.unlink()

        elif self.replace:
            # Line numbers/ranges are relative to block starts, absolute for the "file" scope.
            start, end = _scope_range(self.replace, buffer, start)
            if self.line:
                replacement = [buffer[start + self.line - 1]]
            elif self.lines:
                replacement = [buffer[start + line] for line in self.lines]
            elif self.string:
                replacement = [self.string + "\n"]
            else:
                raise RuntimeError("No replacement specified")
            replacement = _reindent(replacement, _indent(buffer[start]))
            buffer[start:end] = replacement

        elif self.within:
            # Line numbers/ranges are relative to block starts, absolute for the "file" scope.
            start, end = _scope_range(self.within, buffer, start)
            block = buffer[start:end]
            if self.regex:
                pattern1: Pattern = re.compile(self.pattern1)
                replacement = [pattern1.sub(self.pattern2, line) for line in block]
            else:
                replacement = [line.replace(self.pattern1, self.pattern2) for line in block]  # type: ignore[arg-type]
            replacement = _reindent(replacement, _indent(buffer[start]))
            buffer[start:end] = replacement

        if write and buffer:
            self.file.write_text("".join(buffer))

        return True
    return False

config_field ¤

config_field(
    key: str, transform: str | None = None
) -> Unset

Create a dataclass field with a TOML key.

Parameters:

  • key ¤

    (str) –

    Key within the config file.

  • transform ¤

    (str | None, default: None ) –

    Name of transformation method to apply.

Returns:

  • Unset

    Configuration field.

Source code in src/yore/_internal/config.py
50
51
52
53
54
55
def config_field(
    key: An[str, Doc("Key within the config file.")],
    transform: An[str | None, Doc("Name of transformation method to apply.")] = None,
) -> An[Unset, Doc("Configuration field.")]:
    """Create a dataclass field with a TOML key."""
    return dataclass_field(default=Unset(key, transform=transform))

get_pattern cached ¤

get_pattern(prefix: str = DEFAULT_PREFIX) -> Pattern

Get the Yore comment pattern with a specific prefix.

Parameters:

Returns:

  • Pattern

    The Yore comment pattern.

Source code in src/yore/_internal/lib.py
354
355
356
357
358
359
360
361
362
363
364
365
366
367
@cache
def get_pattern(prefix: str = DEFAULT_PREFIX) -> Pattern:
    """Get the Yore comment pattern with a specific prefix.

    Parameters:
        prefix: The prefix to use in the pattern.

    Returns:
        The Yore comment pattern.
    """
    return re.compile(
        _PATTERN_PREFIX.replace("PREFIX", prefix) + COMMENT_PATTERN + _PATTERN_SUFFIX,
        re.VERBOSE | re.IGNORECASE,
    )

main ¤

main(args: list[str] | None = None) -> int

Run the main program.

This function is executed when you type yore or python -m yore.

Parameters:

  • args ¤

    (list[str] | None, default: None ) –

    Arguments passed from the command line.

Returns:

  • int

    An exit code.

Source code in src/yore/_internal/cli.py
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
def main(
    args: An[list[str] | None, Doc("Arguments passed from the command line.")] = None,
) -> An[int, Doc("An exit code.")]:
    """Run the main program.

    This function is executed when you type `yore` or `python -m yore`.
    """
    logging.basicConfig(level=logging.INFO, format="%(message)s")
    output = cappa.Output(error_format=f"[bold]{_NAME}[/]: [bold red]error[/]: {{message}}")
    completion_option: cappa.Arg = cappa.Arg(
        long=True,
        action=cappa.ArgAction.completion,
        choices=["complete", "generate"],
        help="Print shell-specific completion source.",
    )
    help_option: cappa.Arg = cappa.Arg(
        short="-h",
        long=True,
        action=cappa.ArgAction.help,
        help="Print the program help and exit.",
    )
    help_formatter = cappa.HelpFormatter(default_format="Default: {default}.")

    try:
        return cappa.invoke(
            CommandMain,
            argv=args,
            output=output,
            help=help_option,
            completion=completion_option,
            help_formatter=help_formatter,
        )
    except cappa.Exit as exit:
        return int(1 if exit.code is None else exit.code)

yield_buffer_comments ¤

yield_buffer_comments(
    file: Path,
    lines: list[str],
    *,
    prefix: str = DEFAULT_PREFIX,
) -> Iterator[YoreComment]

Yield all Yore comments in a buffer.

Parameters:

  • file ¤

    (Path) –

    The file to check.

  • lines ¤

    (list[str]) –

    The buffer to check (pre-read lines).

  • prefix ¤

    (str, default: DEFAULT_PREFIX ) –

    The prefix to look for in the comments.

Yields:

Source code in src/yore/_internal/lib.py
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
def yield_buffer_comments(file: Path, lines: list[str], *, prefix: str = DEFAULT_PREFIX) -> Iterator[YoreComment]:
    """Yield all Yore comments in a buffer.

    Parameters:
        file: The file to check.
        lines: The buffer to check (pre-read lines).
        prefix: The prefix to look for in the comments.

    Yields:
        Yore comments.
    """
    prepattern = _get_prematching_pattern(prefix)
    pattern = get_pattern(prefix)
    for lineno, line in enumerate(lines, 1):
        if prepattern.match(line):
            if match := pattern.match(line):
                yield _match_to_comment(match, file, lineno)
            else:
                _logger.error(f"{file}:{lineno}: invalid Yore comment")

yield_directory_comments ¤

yield_directory_comments(
    directory: Path, *, prefix: str = DEFAULT_PREFIX
) -> Iterator[YoreComment]

Yield all Yore comments in a directory.

Parameters:

  • directory ¤

    (Path) –

    The directory to check.

  • prefix ¤

    (str, default: DEFAULT_PREFIX ) –

    The prefix to look for in the comments.

Yields:

Source code in src/yore/_internal/lib.py
436
437
438
439
440
441
442
443
444
445
446
447
def yield_directory_comments(directory: Path, *, prefix: str = DEFAULT_PREFIX) -> Iterator[YoreComment]:
    """Yield all Yore comments in a directory.

    Parameters:
        directory: The directory to check.
        prefix: The prefix to look for in the comments.

    Yields:
        Yore comments.
    """
    for file in yield_files(directory):
        yield from yield_file_comments(file, prefix=prefix)

yield_file_comments ¤

yield_file_comments(
    file: Path, *, prefix: str = DEFAULT_PREFIX
) -> Iterator[YoreComment]

Yield all Yore comments in a file.

Parameters:

  • file ¤

    (Path) –

    The file to check.

  • prefix ¤

    (str, default: DEFAULT_PREFIX ) –

    The prefix to look for in the comments.

Yields:

Source code in src/yore/_internal/lib.py
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
def yield_file_comments(file: Path, *, prefix: str = DEFAULT_PREFIX) -> Iterator[YoreComment]:
    """Yield all Yore comments in a file.

    Parameters:
        file: The file to check.
        prefix: The prefix to look for in the comments.

    Yields:
        Yore comments.
    """
    try:
        lines = file.read_text().splitlines()
    except (OSError, UnicodeDecodeError):
        return
    yield from yield_buffer_comments(file, lines, prefix=prefix)

yield_files ¤

yield_files(
    directory: Path, exclude: list[str] | None = None
) -> Iterator[Path]

Yield all files in a directory.

Source code in src/yore/_internal/lib.py
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
def yield_files(directory: Path, exclude: list[str] | None = None) -> Iterator[Path]:
    """Yield all files in a directory."""
    exclude = DEFAULT_EXCLUDE if exclude is None else exclude
    _logger.debug(f"{directory}: scanning...")
    try:
        git_files = subprocess.run(  # noqa: S603
            ["git", "ls-files", "-z"],  # noqa: S607
            capture_output=True,
            cwd=directory,
            text=True,
            check=False,
        ).stdout
    except (FileNotFoundError, subprocess.CalledProcessError):
        for path in directory.iterdir():
            if path.is_file():
                yield path
            elif path.is_dir() and not any(path.match(pattern) for pattern in exclude):
                yield from yield_files(path, exclude=exclude)
    else:
        for filepath in git_files.strip("\0").split("\0"):
            yield directory / filepath

yield_path_comments ¤

yield_path_comments(
    path: Path, *, prefix: str = DEFAULT_PREFIX
) -> Iterator[YoreComment]

Yield all Yore comments in a file or directory.

Parameters:

  • path ¤

    (Path) –

    The file or directory to check.

  • prefix ¤

    (str, default: DEFAULT_PREFIX ) –

    The prefix to look for in the comments.

Yields:

Source code in src/yore/_internal/lib.py
450
451
452
453
454
455
456
457
458
459
460
461
462
463
def yield_path_comments(path: Path, *, prefix: str = DEFAULT_PREFIX) -> Iterator[YoreComment]:
    """Yield all Yore comments in a file or directory.

    Parameters:
        path: The file or directory to check.
        prefix: The prefix to look for in the comments.

    Yields:
        Yore comments.
    """
    if path.is_dir():
        yield from yield_directory_comments(path, prefix=prefix)
    else:
        yield from yield_file_comments(path, prefix=prefix)