Skip to content

Commit

Permalink
refactor: update docstrings for clarity and consistency
Browse files Browse the repository at this point in the history
  • Loading branch information
pivoshenko committed Feb 8, 2025
1 parent 9511c1f commit cefb1e8
Show file tree
Hide file tree
Showing 7 changed files with 47 additions and 48 deletions.
18 changes: 9 additions & 9 deletions src/poetry_plugin_dotenv/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,18 @@

@dataclasses.dataclass
class _Config:
"""Defines the data schema and defaults used for plugin configuration."""
"""Defines the schema and default values for the plugin configuration."""

ignore: bool = False
location: str = ""


# TODO(pivoshenko): this configuration loader is a "quick patch" solution
# TODO(pivoshenko): this configuration loader is a "quick patch" solution and needs refinement
class Config(_Config):
"""Configuration loader."""
"""Configuration loader for the plugin."""

def __init__(self, working_dir: str) -> None:
"""Initialize and load configuration from sources."""
"""Initialize and load configuration from the defined sources."""

super().__init__()

Expand All @@ -62,7 +62,7 @@ def __init__(self, working_dir: str) -> None:
self._apply_source_config(source_config)

def _apply_source_config(self, source_config: dict[str, str | bool | None]) -> None:
"""Apply source configuration to the instance."""
"""Apply the loaded configuration to the instance variables."""

for field in self.__dataclass_fields__.values():
source_value = source_config.get(field.name)
Expand All @@ -79,7 +79,7 @@ def _apply_source_config(self, source_config: dict[str, str | bool | None]) -> N


def _load_config_from_toml(filepath: str, section: str) -> dict[str, str | bool | None]:
"""Load configuration from the TOML file."""
"""Load configuration from a TOML file."""

if not os.path.exists(filepath):
return {}
Expand All @@ -94,7 +94,7 @@ def _load_config_from_toml(filepath: str, section: str) -> dict[str, str | bool


def _load_config_from_os(section: str) -> dict[str, str | bool | None]:
"""Load configuration from the OS environment variables."""
"""Load configuration from OS environment variables."""

return {
key[len(section) :].lower(): value
Expand All @@ -104,9 +104,9 @@ def _load_config_from_os(section: str) -> dict[str, str | bool | None]:


def _as_bool(value: str) -> bool:
"""Convert a string value to a Boolean equivalent.
"""Convert a string value to its Boolean equivalent.
Heavily inspired from ``distutils strtobool``.
This function is inspired by ``distutils strtobool``.
"""

try:
Expand Down
4 changes: 2 additions & 2 deletions src/poetry_plugin_dotenv/dotenv/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def __init__(
self._dict: OrderedDict[str, str] | None = None

def dict(self) -> OrderedDict[str, str]:
"""Return content of a dotenv file."""
"""Get content of a dotenv file."""

if self._dict:
return self._dict
Expand All @@ -65,7 +65,7 @@ def parse(self) -> Iterator[tuple[str, str]]:
yield mapping.key, mapping.value # type: ignore[misc]

def set_as_environment_variables(self) -> bool:
"""Load current dotenv as a system environment variable."""
"""Load current dotenv as system environment variables."""

if self.dict():
for key, value in self.dict().items():
Expand Down
41 changes: 20 additions & 21 deletions src/poetry_plugin_dotenv/dotenv/parsers.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,15 @@ def make_regex(string: str, extra_flags: int = 0) -> re.Pattern[str]:

@dataclasses.dataclass(frozen=True)
class Original:
"""Position of the original string in the file."""
"""Represents the position of the original string in the file."""

string: str
line: int


@dataclasses.dataclass(frozen=True)
class Binding:
"""Binding of a key and a value."""
"""Represents a key-value pair from a dotenv file."""

key: str | None
value: str | None
Expand All @@ -59,65 +59,65 @@ class Binding:

@dataclasses.dataclass
class Position:
"""Model of a cursor position."""
"""Model representing the cursor's position in the file."""

chars: int
line: int

@classmethod
def start(cls) -> Position:
"""Get a start position."""
"""Get the starting position (line 1, character 0)."""

return cls(chars=0, line=1)

def set(self, other: Position) -> None:
"""Set a position."""
"""Set the current position to another position."""

self.chars = other.chars
self.line = other.line

def advance(self, string: str) -> None:
"""Update a position."""
"""Advance the position by the length of the given string."""

self.chars += len(string)
self.line += len(re.findall(_newline, string))


class Reader:
"""Dotenv reader."""
"""Reader for processing a dotenv file stream."""

def __init__(self, stream: IO[str]) -> None:
"""Initialize."""
"""Initialize the reader with a stream of data."""

self.string = stream.read()
self.position = Position.start()
self.mark = Position.start()

def has_next(self) -> bool:
"""Check if a dotenv has the next position."""
"""Check if there are more characters to read."""

return self.position.chars < len(self.string)

def set_mark(self) -> None:
"""Set a mark."""
"""Set a mark at the current position."""

self.mark.set(self.position)

def get_marked(self) -> Original:
"""Get a mark."""
"""Get the portion of the string marked between the current position and the mark."""

return Original(
string=self.string[self.mark.chars : self.position.chars],
line=self.mark.line,
)

def peek(self, count: int) -> str:
"""Peek a dotenv."""
"""Peek ahead in the string without advancing the cursor."""

return self.string[self.position.chars : self.position.chars + count]

def read_regex(self, regex: re.Pattern[str]) -> tuple[str, ...]:
"""Read a dotenv with a regex."""
"""Match and read a portion of the string using the given regex."""

match = regex.match(self.string, self.position.chars)

Expand All @@ -126,25 +126,24 @@ def read_regex(self, regex: re.Pattern[str]) -> tuple[str, ...]:
raise PoetryPluginDotenvPatternError(msg)

matched = self.string[match.start() : match.end()]

self.position.advance(matched)
return match.groups()


def decode_match(match: re.Match[str]) -> str:
"""Decode matches."""
"""Decode a match using unicode escapes."""

return codecs.decode(match.group(0), "unicode-escape")


def decode_escapes(regex: re.Pattern[str], string: str) -> str:
"""Decode escape symbols."""
"""Decode escape sequences in the string using the provided regex."""

return regex.sub(decode_match, string)


def parse_key(reader: Reader) -> str | None:
"""Parse a dotenv key."""
"""Parse the key part of a dotenv binding."""

char = reader.peek(1)

Expand All @@ -161,14 +160,14 @@ def parse_key(reader: Reader) -> str | None:


def parse_unquoted_value(reader: Reader) -> str:
"""Parse an unquoted dotenv value."""
"""Parse a value that is not quoted."""

(part,) = reader.read_regex(_unquoted_value)
return re.sub(r"\s+#.*", "", part).rstrip()


def parse_value(reader: Reader) -> str:
"""Parse a dotenv value."""
"""Parse a value from a dotenv binding."""

char = reader.peek(1)

Expand All @@ -187,7 +186,7 @@ def parse_value(reader: Reader) -> str:


def parse_binding(reader: Reader) -> Binding:
"""Parse a dotenv binding."""
"""Parse a single dotenv binding (key-value pair)."""

reader.set_mark()

Expand Down Expand Up @@ -234,7 +233,7 @@ def parse_binding(reader: Reader) -> Binding:


def parse_stream(stream: IO[str]) -> Iterator[Binding]:
"""Parse a dotenv stream."""
"""Parse a dotenv stream and yield key-value bindings."""

reader = Reader(stream)

Expand Down
10 changes: 5 additions & 5 deletions src/poetry_plugin_dotenv/dotenv/variables.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""Module that contains models of the dotenv variables/literals."""
"""Module that contains models of the dotenv variables and literals."""

from __future__ import annotations

Expand Down Expand Up @@ -28,7 +28,7 @@

@dataclasses.dataclass(frozen=True)
class Literal:
"""Model of a literal."""
"""Represents a literal value."""

value: str

Expand All @@ -40,19 +40,19 @@ def resolve(self, *args, **kwargs) -> str: # type: ignore[no-untyped-def]

@dataclasses.dataclass(frozen=True)
class Variable:
"""Model of a variable."""
"""Represents a variable with an optional default value."""

name: str
default: str | None = None

def resolve(self, env: OrderedDict[str, str], *args, **kwargs) -> str: # type: ignore[no-untyped-def]
"""Get a variable value."""
"""Resolve the variable value from the environment or use the default."""

return env.get(self.name, self.default) or "" # type: ignore[arg-type]


def parse(value: str) -> Iterator[Literal | Variable]:
"""Parse values."""
"""Parse a string and yield literals and variables."""

cursor = 0
value_length = len(value)
Expand Down
2 changes: 1 addition & 1 deletion src/poetry_plugin_dotenv/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""Module defines custom exceptions that are used across plugin."""
"""Module that contains custom exceptions that are used across plugin."""

from __future__ import annotations

Expand Down
10 changes: 5 additions & 5 deletions src/poetry_plugin_dotenv/logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class Style(enum.Enum):
ERROR = "<error>{0!s}</error>"

def __call__(self, text: str) -> str:
"""Apply a style to the text."""
"""Apply the style to the text."""

return self.value.format(text)

Expand All @@ -33,18 +33,18 @@ class Logger:
Notes
-----
Because this logger is used for the plugin that are running before the main command,
all the messages will be logged only in the debug mode.
Since this logger is used by a plugin that runs before the main command,
all messages are logged only in debug mode.
"""

def __init__(self, event: ConsoleCommandEvent) -> None:
"""Initialize."""
"""Initialize the logger."""

self.write_line = partial(event.io.write_line, verbosity=Verbosity.DEBUG)

def info(self, msg: str) -> None:
"""Log an info message."""
"""Log an informational message."""

self._log(Style.INFO, msg)

Expand Down
10 changes: 5 additions & 5 deletions src/poetry_plugin_dotenv/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
class DotenvPlugin(ApplicationPlugin):
"""Plugin that automatically loads environment variables from a dotenv file.
Plugin that automatically loads environment variables from a dotenv file into the environment
before ``poetry`` commands are run.
This plugin automatically loads environment variables from a dotenv file into the environment
before the `poetry` commands are executed.
"""

def activate(self, application: Application) -> None: # pragma: no cover
Expand All @@ -33,7 +33,7 @@ def activate(self, application: Application) -> None: # pragma: no cover
application.event_dispatcher.add_listener(COMMAND, listener=self.load) # type: ignore[union-attr, arg-type]

def load(self, event: ConsoleCommandEvent, *args, **kwargs) -> None: # type: ignore[no-untyped-def]
"""Load a dotenv file based on the provided configuration."""
"""Load a dotenv file according to the provided configuration."""

working_dir = event.io.input.option("directory") or os.path.curdir

Expand All @@ -44,13 +44,13 @@ def load(self, event: ConsoleCommandEvent, *args, **kwargs) -> None: # type: ig
return # pragma: nocover

if config.ignore:
logger.warning("Not loading environment variables")
logger.warning("Not loading environment variables. Ignored by configuration")
return

filepath = self._determine_filepath(config, working_dir)

if filepath == "":
logger.warning("Not loading environment variables")
logger.warning("Not loading environment variables. No valid filepath")
return

if os.path.isfile(filepath):
Expand Down

0 comments on commit cefb1e8

Please sign in to comment.