From c03374d6df49b7f7a1f2d77c03f79761912c2f1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20B=C3=BChler?= Date: Fri, 28 Apr 2023 19:44:13 +0200 Subject: [PATCH] move argument/column handling to decoder (prepare for more post-processing in decoder) --- src/ldaptool/_utils/argclasses.py | 3 ++ src/ldaptool/decode/arguments.py | 61 ++++++++++++++++++++----------- src/ldaptool/search/arguments.py | 39 +------------------- 3 files changed, 44 insertions(+), 59 deletions(-) diff --git a/src/ldaptool/_utils/argclasses.py b/src/ldaptool/_utils/argclasses.py index 7c65fb4..14356fa 100644 --- a/src/ldaptool/_utils/argclasses.py +++ b/src/ldaptool/_utils/argclasses.py @@ -74,6 +74,9 @@ _TArgs = typing.TypeVar("_TArgs", bound="BaseArguments") @dataclasses.dataclass(slots=True, kw_only=True) class BaseArguments: + def __post_init__(self) -> None: + pass + @classmethod def add_fields_to_parser( cls: type[_TArgs], diff --git a/src/ldaptool/decode/arguments.py b/src/ldaptool/decode/arguments.py index f1e44aa..c4ea92e 100644 --- a/src/ldaptool/decode/arguments.py +++ b/src/ldaptool/decode/arguments.py @@ -1,12 +1,28 @@ from __future__ import annotations +import argparse import dataclasses from ldaptool._utils import argclasses +def _parser_add_attributes(parser: argparse.ArgumentParser, dest: str) -> None: + parser.add_argument( + metavar="attributes", + dest=dest, + nargs="*", + help=""" + Attributes to lookup (and columns to display in tables). + Fake attributes `dndomain`, `dnpath` an `dnfullpath` are available (created from dn). + """, + ) + + @dataclasses.dataclass(slots=True, kw_only=True) class Arguments(argclasses.BaseArguments): + columns: list[str] = dataclasses.field(default_factory=list, metadata=argclasses.manual(_parser_add_attributes)) + attributes: list[str] = dataclasses.field(default_factory=list) + json: bool = dataclasses.field( default=False, metadata=argclasses.arg(help="Use full json output"), @@ -19,29 +35,30 @@ class Arguments(argclasses.BaseArguments): default=", ", metadata=argclasses.arg(help="Separator to join multiple values of one attribute with (default: %(default)r)"), ) + dateonly: bool = dataclasses.field( default=True, metadata=argclasses.arg(help="Use only date part of decoded timestamps"), ) - dndomain: bool = dataclasses.field( - default=False, - metadata=argclasses.arg(help="Whether to export a virtual dndomain attribute (DNS domain from dn)"), - ) - dnpath: bool = dataclasses.field( - default=False, - metadata=argclasses.arg( - help=""" - Whether to export a virtual dnpath attribute - ('/' joined values of reversed DN without DNS labels) - """ - ), - ) - dnfullpath: bool = dataclasses.field( - default=False, - metadata=argclasses.arg( - help=""" - Whether to export a virtual dnfullpath attribute - ('/' joined values of reversed DN; DNS domain as first label) - """ - ), - ) + + dndomain: bool = False + dnpath: bool = False + dnfullpath: bool = False + + def __post_init__(self) -> None: + super(Arguments, self).__post_init__() # super() not working here, unclear why. + + # extract special attribute names + attributes_set: dict[str, str] = {arg.lower(): arg for arg in self.columns} # index by lowercase name + # create fake attributes on demand + if attributes_set.pop("dndomain", ""): + self.dndomain = True + if attributes_set.pop("dnpath", ""): + self.dnpath = True + if attributes_set.pop("dnfullpath", ""): + self.dnfullpath = True + # store remaining attributes (with original case) + self.attributes = list(attributes_set.values()) + if self.columns and not self.attributes: + # if we only wanted fake attributes, make sure we only request 'dn' - empty list would query all attributes + self.attributes = ["dn"] diff --git a/src/ldaptool/search/arguments.py b/src/ldaptool/search/arguments.py index 1eef170..8dc3ffb 100644 --- a/src/ldaptool/search/arguments.py +++ b/src/ldaptool/search/arguments.py @@ -1,6 +1,5 @@ from __future__ import annotations -import argparse import dataclasses import typing @@ -8,28 +7,8 @@ import ldaptool.decode.arguments from ldaptool._utils import argclasses -def _parser_add_attributes(parser: argparse.ArgumentParser, dest: str) -> None: - parser.add_argument( - metavar="attributes", - dest=dest, - nargs="*", - help=""" - Attributes to lookup (and columns to display in tables). - Fake attributes `dndomain`, `dnpath` an `dnfullpath` are available (created from dn). - """, - ) - - @dataclasses.dataclass(slots=True, kw_only=True) class Arguments(ldaptool.decode.arguments.Arguments): - # overwrite fields for fake attributes to remove them from argparse; - # we enable those based on the attribute list - dndomain: bool = False - dnpath: bool = False - dnfullpath: bool = False - - attributes: list[str] = dataclasses.field(default_factory=list, metadata=argclasses.manual(_parser_add_attributes)) - columns: list[str] = dataclasses.field(default_factory=list) filter: typing.Optional[str] = dataclasses.field(default=None, metadata=argclasses.arg(help="LDAP query filter")) find: typing.Optional[str] = dataclasses.field( default=None, @@ -75,6 +54,8 @@ class Arguments(ldaptool.decode.arguments.Arguments): ) def __post_init__(self) -> None: + super(Arguments, self).__post_init__() # super() not working here, unclear why. + if not self.filter is None: if not self.find is None: raise SystemExit("Can't use both --find and --filter") @@ -86,19 +67,3 @@ class Arguments(ldaptool.decode.arguments.Arguments): else: # probably doesn't like empty filter? self.filter = "(objectClass=*)" - - # extract special attribute names - self.columns = self.attributes # use all names for columns (headings and their order) - attributes_set: dict[str, str] = {arg.lower(): arg for arg in self.attributes} # index by lowercase name - # create fake attributes on demand - if attributes_set.pop("dndomain", ""): - self.dndomain = True - if attributes_set.pop("dnpath", ""): - self.dnpath = True - if attributes_set.pop("dnfullpath", ""): - self.dnfullpath = True - # store remaining attributes (with original case) - self.attributes = list(attributes_set.values()) - if self.columns and not self.attributes: - # if we only wanted fake attributes, make sure we only request 'dn' - empty list would query all attributes - self.attributes = ["dn"]