Source code for meta_package_manager.tables

# Copyright Kevin Deldycke <kevin@deldycke.com> and contributors.
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
"""Table-output vocabulary and rendering plumbing shared by the subcommands.

The {command}`mpm` subcommands render heterogeneous tables (different columns per
command) but share the same output machinery. This module owns all of it:

- {class}`SortableField`, the vocabulary of the global `mpm --sort-by`
  selector. The selector itself is click-extra's field-vocabulary
  {class}`~click_extra.table.SortByOption`, and the per-table resolution (sort
  by the selected fields the table carries, keep the original row order when it
  carries none) happens inside {func}`click_extra.table.print_table`, from the
  field each header pairs with its column in the registries below.
- The per-command **column registries**, each pairing a click-extra
  {class}`~click_extra.table.ColumnSpec` (whose ID addresses the column from
  `--columns`) with the {class}`SortableField` the column carries (`None`
  for a column that cannot drive the sort). A registry is the single source of
  truth for its command: the same tuple feeds the `@columns_option` declaration
  (which validates the user selection) and {func}`print_projected_table`
  (which projects headers and rows before rendering).
- {func}`print_projected_table` and {func}`print_serialized_and_exit`, the
  human-friendly and machine-friendly rendering paths every table-producing
  subcommand goes through.

```{note}
The registry pairs' second element is annotated `str | None` rather than
`SortableField | None`: on Python 3.10, {class}`SortableField` extends
`backports.strenum.StrEnum`, whose stubs type the members as plain
{class}`str`, so the tighter annotation only checks under 3.11+.
`StrEnum` members being {class}`str` subclasses, the wider annotation is
accurate on every supported version.
```
"""

from __future__ import annotations

import sys

from click_extra.context import COLUMNS, TABLE_FORMAT
from click_extra.table import (
    SERIALIZATION_FORMATS,
    ColumnSpec,
    print_data,
    select_columns,
    select_row,
)

if sys.version_info >= (3, 11):
    from enum import StrEnum
else:
    from backports.strenum import StrEnum  # type: ignore[import-not-found]

TYPE_CHECKING = False
if TYPE_CHECKING:
    from collections.abc import Iterable, Sequence

    from click_extra import Context


[docs] class SortableField(StrEnum): """Fields IDs allowed to be sorted.""" MANAGER_ID = "manager_id" MANAGER_NAME = "manager_name" PACKAGE_ID = "package_id" PACKAGE_NAME = "package_name" VERSION = "version"
MANAGERS_COLUMNS: tuple[tuple[ColumnSpec, str | None], ...] = ( ( ColumnSpec("manager_id", "Manager ID", "Manager's identifier."), SortableField.MANAGER_ID, ), ( ColumnSpec("manager_name", "Name", "Manager's common name."), SortableField.MANAGER_NAME, ), ( ColumnSpec("supported", "Supported", "Support status on the current platform."), None, ), ( ColumnSpec("cli", "CLI", "Location of the manager's binary on the system."), None, ), ( ColumnSpec("executable", "Executable", "Whether the binary is executable."), None, ), ( ColumnSpec( "version", "Version", "Manager's self-reported version, and the unsatisfied requirement " "when stale.", ), SortableField.VERSION, ), ) """Columns of the `mpm managers` table.""" INSTALLED_COLUMNS: tuple[tuple[ColumnSpec, str | None], ...] = ( ( ColumnSpec("package_id", "Package ID", "Package's identifier."), SortableField.PACKAGE_ID, ), ( ColumnSpec("package_name", "Name", "Package's common name."), SortableField.PACKAGE_NAME, ), ( ColumnSpec("manager_id", "Manager", "Manager reporting the package."), SortableField.MANAGER_ID, ), ( ColumnSpec( "installed_version", "Installed version", "Version currently installed." ), SortableField.VERSION, ), ) """Columns of the `mpm installed` table.""" OUTDATED_COLUMNS: tuple[tuple[ColumnSpec, str | None], ...] = ( *INSTALLED_COLUMNS, ( ColumnSpec( "latest_version", "Latest version", "Version available for upgrade." ), None, ), ) """Columns of the `mpm outdated` table.""" SEARCH_COLUMNS: tuple[tuple[ColumnSpec, str | None], ...] = ( ( ColumnSpec("package_id", "Package ID", "Package's identifier."), SortableField.PACKAGE_ID, ), ( ColumnSpec("package_name", "Name", "Package's common name."), SortableField.PACKAGE_NAME, ), ( ColumnSpec("manager_id", "Manager", "Manager reporting the match."), SortableField.MANAGER_ID, ), ( ColumnSpec("latest_version", "Latest version", "Latest version available."), SortableField.VERSION, ), ( ColumnSpec( "description", "Description", "Package description, for managers that provide one. Out of the " "default selection: select it explicitly or pass --description.", ), None, ), ) """Columns of the `mpm search` table. The `description` column exists in the registry (so `--columns` can select it) but stays out of the default selection unless `--description` (or `--extended`, which searches descriptions) is passed. """ WHICH_COLUMNS: tuple[tuple[ColumnSpec, str | None], ...] = ( ( ColumnSpec( "manager_id", "Manager ID", "Manager whose search path found the binary." ), SortableField.MANAGER_ID, ), ( ColumnSpec( "priority", "Priority", "Rank of the match in the manager's search path." ), None, ), ( ColumnSpec("cli_path", "CLI path", "Location of the matched binary."), None, ), ( ColumnSpec( "symlink", "Symlink destination", "Resolved target when the match is a symlink.", ), None, ), ) """Columns of the `mpm which` table."""
[docs] def column_specs( columns: Sequence[tuple[ColumnSpec, str | None]], ) -> tuple[ColumnSpec, ...]: """Extract the bare {class}`~click_extra.table.ColumnSpec` tuple from a column registry.""" return tuple(spec for spec, _ in columns)