[SCM] Samba Shared Repository - branch master updated

Andrew Bartlett abartlet at samba.org
Wed Oct 25 00:32:02 UTC 2023


The branch, master has been updated
       via  50b8a2de2aa python: getopt: HostOptions and other option groups inherit from samba OptionGroup class
       via  7c389e19212 netcmd: auth policy: add OptionGroup classes for user, service and computer options
       via  0667708cef2 python: netcmd: make use of HostOptions for claims and sites commands
       via  e1244ba304a python: getopt: Add HostOptions to avoid need to manually add -H
       via  0f3d6d80dab python: netcmd: make use of required flag on Option for claims commands
       via  e60f3afcc5f python: getopt: implement required flag on options and OptionParser
       via  837e1d9fdad python: getopt: subclass OptionParser to populate option_class
       via  6943a58bff3 netcmd: tests: stop checking for ERROR prefix from CommandError
       via  fb058e7f2ce python: netcmd: remove OptionError alias to OptionValueError
       via  14b21298687 python: netcmd: catch parent exception class OptParseError instead
       via  f77064c8225 python: getopt: rename SambaOption to Option
       via  d54f52b847f python: netcmd: parser class in getSamDB should set option_class
       via  b7a1946d8b7 python: netcmd: fix import grouping and sorting in base first
       via  5f8c46d1dec python: netcmd: remove redundant Option subclass
       via  32032937ed9 python: netcmd: SUPPRESS_HELP constant has no effect here
       via  a930456f0c9 python: netcmd: dbcheck: fix import grouping and order
       via  3a5a5cae3a6 python: netcmd: ntacl: fix import grouping and order
       via  90f7ad08b53 python: tests: fix some hidden tab characters in tests.py
       via  0f93e1d17f8 python: add docstrings to Validator and ValidationError
       via  dc513a82a6a python: move Validator base class and ValidationError to getopt
       via  29c9991594f python: getopt: move validators logic to parent class
       via  bdad257a312 netcmd: don't turn exception into CommandError in run_validators
       via  99c93c1e89e netcmd: PEP8: minor whitespace fix, file did not pass PEP8
       via  c3876242fdf netcmd: move comment above class to docstring
       via  8b575612975 netcmd: correctly pass Samba option class to OptionParser
       via  96959b72679 python: getopt: move SambaOption to the top of the file
       via  c688e73358c python: getopt: correctly group and sort imports
       via  1f8b4913c60 python: getopt: update super calls to python3 style
       via  e209b8d79c2 python: move comment for check_bytes to docstring
       via  22316fea335 python: PEP8 fixup whitespace in getopt.py first
       via  029e0457ccc netcmd: tests: make check_run and related methods classmethod for consistency
       via  b543874abc3 tests: minor indentation and whitespace fixes
      from  7c8dea14da6 smbtorture: add test for fruit:validate_afpinfo option

https://git.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 50b8a2de2aadd94386fb0525bfc741867121c929
Author: Rob van der Linde <rob at catalyst.net.nz>
Date:   Fri Oct 20 14:46:40 2023 +1300

    python: getopt: HostOptions and other option groups inherit from samba OptionGroup class
    
    Signed-off-by: Rob van der Linde <rob at catalyst.net.nz>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    
    Autobuild-User(master): Andrew Bartlett <abartlet at samba.org>
    Autobuild-Date(master): Wed Oct 25 00:31:37 UTC 2023 on atb-devel-224

commit 7c389e19212f76aaf9cba8ac8315742c7294e2c8
Author: Rob van der Linde <rob at catalyst.net.nz>
Date:   Tue Oct 10 23:31:33 2023 +1300

    netcmd: auth policy: add OptionGroup classes for user, service and computer options
    
    Signed-off-by: Rob van der Linde <rob at catalyst.net.nz>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 0667708cef2e4375552860ae67ac24e6b0f593d0
Author: Rob van der Linde <rob at catalyst.net.nz>
Date:   Fri Oct 6 15:49:27 2023 +1300

    python: netcmd: make use of HostOptions for claims and sites commands
    
    Signed-off-by: Rob van der Linde <rob at catalyst.net.nz>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit e1244ba304a2de598779f9fcf1307244f333ab65
Author: Rob van der Linde <rob at catalyst.net.nz>
Date:   Fri Oct 6 15:47:43 2023 +1300

    python: getopt: Add HostOptions to avoid need to manually add -H
    
    Signed-off-by: Rob van der Linde <rob at catalyst.net.nz>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 0f3d6d80dab0be046663e8bac2357b20520c70e3
Author: Rob van der Linde <rob at catalyst.net.nz>
Date:   Fri Oct 6 14:50:32 2023 +1300

    python: netcmd: make use of required flag on Option for claims commands
    
    Signed-off-by: Rob van der Linde <rob at catalyst.net.nz>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit e60f3afcc5fca7ec1d8aacfc7abf19009b3d831c
Author: Rob van der Linde <rob at catalyst.net.nz>
Date:   Fri Oct 6 12:58:46 2023 +1300

    python: getopt: implement required flag on options and OptionParser
    
    Signed-off-by: Rob van der Linde <rob at catalyst.net.nz>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 837e1d9fdad79ea3a7fdce1232d8dd834f181a63
Author: Rob van der Linde <rob at catalyst.net.nz>
Date:   Thu Oct 19 15:05:56 2023 +1300

    python: getopt: subclass OptionParser to populate option_class
    
    The option_class needs to be set correctly for OptionGroups that use self.add_option
    
    Override OptionParser `__init__` to change the default Option class to the samba one.
    
    Signed-off-by: Rob van der Linde <rob at catalyst.net.nz>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 6943a58bff37c815aa993f74fbbbe2587a21202b
Author: Rob van der Linde <rob at catalyst.net.nz>
Date:   Thu Oct 19 14:26:46 2023 +1300

    netcmd: tests: stop checking for ERROR prefix from CommandError
    
    Signed-off-by: Rob van der Linde <rob at catalyst.net.nz>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit fb058e7f2ce3878713af959e8e35d1991bde24ee
Author: Rob van der Linde <rob at catalyst.net.nz>
Date:   Fri Oct 6 12:45:35 2023 +1300

    python: netcmd: remove OptionError alias to OptionValueError
    
    The other methods in this file already raise optparse.OptionValueError
    directly, except for two older ones.
    
    They are using an alias which changes the name to OptionError, the
    confusing part about this is that optparse.OptionError actually does
    exist, so the incorrect alias needs to be removed.
    
    Signed-off-by: Rob van der Linde <rob at catalyst.net.nz>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 14b2129868748d3732d5361e2b34f3a5a0a66ff2
Author: Rob van der Linde <rob at catalyst.net.nz>
Date:   Fri Oct 6 12:39:30 2023 +1300

    python: netcmd: catch parent exception class OptParseError instead
    
    This covers both OptionError and OptionValueError
    
    Signed-off-by: Rob van der Linde <rob at catalyst.net.nz>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit f77064c8225c79d137e225e962d885e83e113d85
Author: Rob van der Linde <rob at catalyst.net.nz>
Date:   Thu Oct 5 16:26:40 2023 +1300

    python: getopt: rename SambaOption to Option
    
     * Nothing uses SambaOption directly, everything imports it through samba.netcmd.Option
     * Avoid an unnecessary rename on import
    
    Signed-off-by: Rob van der Linde <rob at catalyst.net.nz>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit d54f52b847fe03b9e3946f25db51e4cc980bedfa
Author: Rob van der Linde <rob at catalyst.net.nz>
Date:   Thu Oct 5 16:00:36 2023 +1300

    python: netcmd: parser class in getSamDB should set option_class
    
    Signed-off-by: Rob van der Linde <rob at catalyst.net.nz>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit b7a1946d8b750ed1fdd888317798d476be145051
Author: Rob van der Linde <rob at catalyst.net.nz>
Date:   Thu Oct 5 15:52:54 2023 +1300

    python: netcmd: fix import grouping and sorting in base first
    
    Signed-off-by: Rob van der Linde <rob at catalyst.net.nz>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 5f8c46d1decd8aea12713cb471db25a7932706d8
Author: Rob van der Linde <rob at catalyst.net.nz>
Date:   Thu Oct 5 15:22:58 2023 +1300

    python: netcmd: remove redundant Option subclass
    
    Instead, just import SambaOption as Option, so all the existing commands don't need changing.
    
    Signed-off-by: Rob van der Linde <rob at catalyst.net.nz>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 32032937ed905d5f5b9ac8ba94381e7cb03f443c
Author: Rob van der Linde <rob at catalyst.net.nz>
Date:   Thu Oct 5 15:18:32 2023 +1300

    python: netcmd: SUPPRESS_HELP constant has no effect here
    
    Where it is used, on a few options, the constant should be used
    directly instead.
    
    This means that in the following commit, the Option subclass of
    SambaOption can be removed, as it will become redundant.
    
    Signed-off-by: Rob van der Linde <rob at catalyst.net.nz>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit a930456f0c9043ddfed216c0726046fb1ff8da43
Author: Rob van der Linde <rob at catalyst.net.nz>
Date:   Thu Oct 5 15:13:45 2023 +1300

    python: netcmd: dbcheck: fix import grouping and order
    
    Signed-off-by: Rob van der Linde <rob at catalyst.net.nz>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 3a5a5cae3a688c0276ae1a50113907afff2e6b31
Author: Rob van der Linde <rob at catalyst.net.nz>
Date:   Thu Oct 5 15:10:06 2023 +1300

    python: netcmd: ntacl: fix import grouping and order
    
    Signed-off-by: Rob van der Linde <rob at catalyst.net.nz>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 90f7ad08b536a47c9b35b238ab4eaeab0dd76681
Author: Rob van der Linde <rob at catalyst.net.nz>
Date:   Thu Oct 5 14:47:46 2023 +1300

    python: tests: fix some hidden tab characters in tests.py
    
    Signed-off-by: Rob van der Linde <rob at catalyst.net.nz>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 0f93e1d17f8130180e039fcd1230737308a962ce
Author: Rob van der Linde <rob at catalyst.net.nz>
Date:   Thu Oct 5 14:33:32 2023 +1300

    python: add docstrings to Validator and ValidationError
    
    Signed-off-by: Rob van der Linde <rob at catalyst.net.nz>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit dc513a82a6a2795b22820146ca583cbe169a7499
Author: Rob van der Linde <rob at catalyst.net.nz>
Date:   Thu Oct 5 14:30:20 2023 +1300

    python: move Validator base class and ValidationError to getopt
    
    It makes more sense for these to exist in the top package, because they are used by SambaOption.
    
    validators.py can still exist in netcmd, just not the base class and exception.
    
    Signed-off-by: Rob van der Linde <rob at catalyst.net.nz>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 29c9991594f71c4fecc04f3d7701ab93e92ec7ab
Author: Rob van der Linde <rob at catalyst.net.nz>
Date:   Thu Oct 5 14:17:01 2023 +1300

    python: getopt: move validators logic to parent class
    
    Signed-off-by: Rob van der Linde <rob at catalyst.net.nz>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit bdad257a31210e7d6195212bd051f1136854ce6f
Author: Rob van der Linde <rob at catalyst.net.nz>
Date:   Thu Oct 5 14:03:14 2023 +1300

    netcmd: don't turn exception into CommandError in run_validators
    
    It's the wrong place to do it.
    
    Instead, let it raise the original exception, capture it in _run, and
    call existing show_command_error method.
    
    Signed-off-by: Rob van der Linde <rob at catalyst.net.nz>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 99c93c1e89e974e12793f305dc4f8f7812bf2574
Author: Rob van der Linde <rob at catalyst.net.nz>
Date:   Thu Oct 5 13:47:11 2023 +1300

    netcmd: PEP8: minor whitespace fix, file did not pass PEP8
    
    Signed-off-by: Rob van der Linde <rob at catalyst.net.nz>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit c3876242fdf56f1edfda790e1f52589bf95c0c24
Author: Rob van der Linde <rob at catalyst.net.nz>
Date:   Thu Oct 5 13:42:14 2023 +1300

    netcmd: move comment above class to docstring
    
    Signed-off-by: Rob van der Linde <rob at catalyst.net.nz>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 8b575612975df853cf7718fb2c9dea3bbf064508
Author: Rob van der Linde <rob at catalyst.net.nz>
Date:   Thu Oct 5 12:05:17 2023 +1300

    netcmd: correctly pass Samba option class to OptionParser
    
    On OptionGroups it will set option_class and then this gets used by self.add_option
    
    Signed-off-by: Rob van der Linde <rob at catalyst.net.nz>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 96959b72679f4a5cac1c5d300bb4013bd100fcfe
Author: Rob van der Linde <rob at catalyst.net.nz>
Date:   Thu Oct 5 11:32:30 2023 +1300

    python: getopt: move SambaOption to the top of the file
    
    This is needed for the next commit
    
    Signed-off-by: Rob van der Linde <rob at catalyst.net.nz>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit c688e73358c465bdb44b36fbba2953bfa7931640
Author: Rob van der Linde <rob at catalyst.net.nz>
Date:   Thu Oct 5 11:50:22 2023 +1300

    python: getopt: correctly group and sort imports
    
    Signed-off-by: Rob van der Linde <rob at catalyst.net.nz>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 1f8b4913c60efaa97bb56d97ab1fca0d2627ef3e
Author: Rob van der Linde <rob at catalyst.net.nz>
Date:   Thu Oct 5 11:48:14 2023 +1300

    python: getopt: update super calls to python3 style
    
    Signed-off-by: Rob van der Linde <rob at catalyst.net.nz>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit e209b8d79c2f232ba668bfff79c8bda951895084
Author: Rob van der Linde <rob at catalyst.net.nz>
Date:   Thu Oct 5 11:29:59 2023 +1300

    python: move comment for check_bytes to docstring
    
    Signed-off-by: Rob van der Linde <rob at catalyst.net.nz>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 22316fea3359a808031a550c6612811f3f816f80
Author: Rob van der Linde <rob at catalyst.net.nz>
Date:   Thu Oct 5 11:27:40 2023 +1300

    python: PEP8 fixup whitespace in getopt.py first
    
    Signed-off-by: Rob van der Linde <rob at catalyst.net.nz>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 029e0457ccc78b0b9de01ede16c39c29d26a26b0
Author: Rob van der Linde <rob at catalyst.net.nz>
Date:   Mon Oct 2 18:32:29 2023 +1300

    netcmd: tests: make check_run and related methods classmethod for consistency
    
    Before that only run_command was turned into a @classmethod, but not
    the other related methods which were left unchanged, this made it
    inconsistent.
    
    Some of these methods need to be called from setUpTestData so they
    really need to be @classmethod anyway.
    
    Signed-off-by: Rob van der Linde <rob at catalyst.net.nz>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit b543874abc30e9c8dc042d70e29ab6598968bebd
Author: Rob van der Linde <rob at catalyst.net.nz>
Date:   Mon Oct 2 18:27:39 2023 +1300

    tests: minor indentation and whitespace fixes
    
    Signed-off-by: Rob van der Linde <rob at catalyst.net.nz>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

-----------------------------------------------------------------------

Summary of changes:
 python/samba/getopt.py                             | 244 +++++++++++++-----
 python/samba/netcmd/__init__.py                    |  62 ++---
 python/samba/netcmd/dbcheck.py                     |  17 +-
 python/samba/netcmd/domain/auth/policy.py          | 278 ++++++++++-----------
 python/samba/netcmd/domain/auth/silo.py            |  53 ++--
 python/samba/netcmd/domain/auth/silo_member.py     |  44 ++--
 python/samba/netcmd/domain/claim/claim_type.py     |  59 ++---
 python/samba/netcmd/domain/claim/value_type.py     |  19 +-
 python/samba/netcmd/ntacl.py                       |  25 +-
 python/samba/netcmd/sites.py                       |  84 ++-----
 python/samba/netcmd/validators.py                  |  13 +-
 python/samba/tests/__init__.py                     |  35 +--
 python/samba/tests/samba_tool/base.py              |  17 +-
 .../samba/tests/samba_tool/domain_auth_policy.py   | 146 +++++------
 python/samba/tests/samba_tool/domain_auth_silo.py  |  14 +-
 python/samba/tests/samba_tool/domain_claim.py      |  16 +-
 source4/selftest/tests.py                          |   8 +-
 17 files changed, 555 insertions(+), 579 deletions(-)


Changeset truncated at 500 lines:

diff --git a/python/samba/getopt.py b/python/samba/getopt.py
index e9ff3de5b34..0935ed00d40 100644
--- a/python/samba/getopt.py
+++ b/python/samba/getopt.py
@@ -20,21 +20,181 @@
 __docformat__ = "restructuredText"
 
 import optparse
-from copy import copy
 import os
+import sys
+from abc import ABCMeta, abstractmethod
+from copy import copy
+
 from samba.credentials import (
     Credentials,
     AUTO_USE_KERBEROS,
     DONT_USE_KERBEROS,
     MUST_USE_KERBEROS,
 )
-import sys
 from samba._glue import get_burnt_commandline
 
-OptionError = optparse.OptionValueError
+
+def check_bytes(option, opt, value):
+    """Custom option type to allow the input of sizes using byte, kb, mb ...
+
+    units, e.g. 2Gb, 4KiB ...
+       e.g. Option("--size", type="bytes", metavar="SIZE")
+    """
+
+    multipliers = {"B": 1,
+                   "KB": 1024,
+                   "MB": 1024 * 1024,
+                   "GB": 1024 * 1024 * 1024}
+
+    # strip out any spaces
+    v = value.replace(" ", "")
+
+    # extract the numeric prefix
+    digits = ""
+    while v and v[0:1].isdigit() or v[0:1] == '.':
+        digits += v[0]
+        v = v[1:]
+
+    try:
+        m = float(digits)
+    except ValueError:
+        msg = ("{0} option requires a numeric value, "
+               "with an optional unit suffix").format(opt)
+        raise optparse.OptionValueError(msg)
+
+    # strip out the 'i' and convert to upper case so
+    # kib Kib kb KB are all equivalent
+    suffix = v.upper().replace("I", "")
+    try:
+        return m * multipliers[suffix]
+    except KeyError as k:
+        msg = ("{0} invalid suffix '{1}', "
+               "should be B, Kb, Mb or Gb").format(opt, v)
+        raise optparse.OptionValueError(msg)
+
+
+class OptionMissingError(optparse.OptionValueError):
+    """One or more Options with required=True is missing."""
+
+    def __init__(self, options):
+        """Raised when required Options are missing from the command line.
+
+        :param options: list of 1 or more option
+        """
+        self.options = options
+
+    def __str__(self):
+        if len(self.options) == 1:
+            missing = self.options[0]
+            return f"Argument {missing} is required."
+        else:
+            options = sorted([str(option) for option in self.options])
+            missing = ", ".join(options)
+            return f"The arguments {missing} are required."
+
+
+class ValidationError(Exception):
+    """ValidationError is the exception raised by validators.
+
+    Should be raised from the __call__ method of the Validator subclass.
+    """
+    pass
+
+
+class Validator(metaclass=ABCMeta):
+    """Base class for Validators used by SambaOption.
+
+    Subclass this to make custom validators and implement __call__.
+    """
+
+    @abstractmethod
+    def __call__(self, field, value):
+        pass
 
 
-class SambaOptions(optparse.OptionGroup):
+class Option(optparse.Option):
+    ATTRS = optparse.Option.ATTRS + ["required", "validators"]
+    TYPES = optparse.Option.TYPES + ("bytes",)
+    TYPE_CHECKER = copy(optparse.Option.TYPE_CHECKER)
+    TYPE_CHECKER["bytes"] = check_bytes
+
+    def run_validators(self, opt, value):
+        """Runs the list of validators on the current option."""
+        validators = getattr(self, "validators") or []
+        for validator in validators:
+            validator(opt, value)
+
+    def convert_value(self, opt, value):
+        """Override convert_value to run validators just after.
+
+        This can also be done in process() but there we would have to
+        replace the entire method.
+        """
+        value = super().convert_value(opt, value)
+        self.run_validators(opt, value)
+        return value
+
+
+class OptionParser(optparse.OptionParser):
+    """Samba OptionParser, adding support for required=True on Options."""
+
+    def __init__(self,
+                 usage=None,
+                 option_list=None,
+                 option_class=Option,
+                 version=None,
+                 conflict_handler="error",
+                 description=None,
+                 formatter=None,
+                 add_help_option=True,
+                 prog=None,
+                 epilog=None):
+        """
+        Ensure that option_class defaults to the Samba one.
+        """
+        super().__init__(usage, option_list, option_class, version,
+                         conflict_handler, description, formatter,
+                         add_help_option, prog, epilog)
+
+    def check_values(self, values, args):
+        """Loop through required options if value is missing raise exception."""
+        missing = []
+        for option in self._get_all_options():
+            if option.required:
+                value = getattr(values, option.dest)
+                if value is None:
+                    missing.append(option)
+
+        if missing:
+            raise OptionMissingError(missing)
+
+        return super().check_values(values, args)
+
+
+class OptionGroup(optparse.OptionGroup):
+    """Samba OptionGroup base class.
+
+    Provides a generic set_option method to be used as Option callback,
+    so that one doesn't need to be created for every available Option.
+
+    Also overrides the add_option method, so it correctly initialises
+    the defaults on the OptionGroup.
+    """
+
+    def add_option(self, *args, **kwargs):
+        """Override add_option so it applies defaults during constructor."""
+        opt = super().add_option(*args, **kwargs)
+        default = None if opt.default == optparse.NO_DEFAULT else opt.default
+        self.set_option(opt, opt.get_opt_string(), default, self.parser)
+        return opt
+
+    def set_option(self, option, opt_str, arg, parser):
+        """Callback to set the attribute based on the Option dest name."""
+        dest = option.dest or option._long_opts[0][2:].replace("-", "_")
+        setattr(self, dest, arg)
+
+
+class SambaOptions(OptionGroup):
     """General Samba-related command line options."""
 
     def __init__(self, parser):
@@ -60,7 +220,7 @@ class SambaOptions(optparse.OptionGroup):
                 sys.stderr.flush()
 
         from samba.param import LoadParm
-        optparse.OptionGroup.__init__(self, parser, "Samba Common Options")
+        super().__init__(parser, "Samba Common Options")
         self.add_option("-s", "--configfile", action="callback",
                         type=str, metavar="FILE", help="Configuration file",
                         callback=self._load_configfile)
@@ -89,14 +249,16 @@ class SambaOptions(optparse.OptionGroup):
         try:
             self._lp.set('debug level', arg)
         except RuntimeError:
-            raise OptionError(f"invalid -d/--debug value: '{arg}'")
+            raise optparse.OptionValueError(
+                f"invalid -d/--debug value: '{arg}'")
         parser.values.debuglevel = arg
 
     def _set_realm(self, option, opt_str, arg, parser):
         try:
             self._lp.set('realm', arg)
         except RuntimeError:
-            raise OptionError(f"invalid --realm value: '{arg}'")
+            raise optparse.OptionValueError(
+                f"invalid --realm value: '{arg}'")
         self.realm = arg
 
     def _set_option(self, option, opt_str, arg, parser):
@@ -125,15 +287,27 @@ class Samba3Options(SambaOptions):
     """General Samba-related command line options with an s3 param."""
 
     def __init__(self, parser):
-        SambaOptions.__init__(self, parser)
+        super().__init__(parser)
         from samba.samba3 import param as s3param
         self._lp = s3param.get_context()
 
 
-class VersionOptions(optparse.OptionGroup):
+class HostOptions(OptionGroup):
+    """Command line options for connecting to target host or database."""
+
+    def __init__(self, parser):
+        super().__init__(parser, "Host Options")
+
+        self.add_option("-H", "--URL",
+                        help="LDB URL for database or target server",
+                        type=str, metavar="URL", action="callback",
+                        callback=self.set_option, dest="H")
+
+
+class VersionOptions(OptionGroup):
     """Command line option for printing Samba version."""
     def __init__(self, parser):
-        optparse.OptionGroup.__init__(self, parser, "Version Options")
+        super().__init__(parser, "Version Options")
         self.add_option("-V", "--version", action="callback",
                         callback=self._display_version,
                         help="Display version number")
@@ -168,7 +342,7 @@ def parse_kerberos_arg(arg, opt_str):
                                         (opt_str, arg))
 
 
-class CredentialsOptions(optparse.OptionGroup):
+class CredentialsOptions(OptionGroup):
     """Command line options for specifying credentials."""
 
     def __init__(self, parser, special_name=None):
@@ -181,7 +355,7 @@ class CredentialsOptions(optparse.OptionGroup):
         self.ask_for_password = True
         self.ipaddress = None
         self.machine_pass = False
-        optparse.OptionGroup.__init__(self, parser, self.section)
+        super().__init__(parser, self.section)
         self._add_option("--simple-bind-dn", metavar="DN", action="callback",
                          callback=self._set_simple_bind_dn, type=str,
                          help="DN to use for a simple bind")
@@ -301,7 +475,7 @@ class CredentialsOptionsDouble(CredentialsOptions):
     """Command line options for specifying credentials of two servers."""
 
     def __init__(self, parser):
-        CredentialsOptions.__init__(self, parser)
+        super().__init__(parser)
         self.no_pass2 = True
         self.add_option("--simple-bind-dn2", metavar="DN2", action="callback",
                         callback=self._set_simple_bind_dn2, type=str,
@@ -363,47 +537,3 @@ class CredentialsOptionsDouble(CredentialsOptions):
         if self.no_pass2:
             self.creds2.set_cmdline_callbacks()
         return self.creds2
-
-# Custom option type to allow the input of sizes using byte, kb, mb ...
-# units, e.g. 2Gb, 4KiB ...
-#    e.g. Option("--size", type="bytes", metavar="SIZE")
-#
-def check_bytes(option, opt, value):
-
-    multipliers = {
-            "B"  : 1,
-            "KB" : 1024,
-            "MB" : 1024 * 1024,
-            "GB" : 1024 * 1024 * 1024}
-
-    # strip out any spaces
-    v = value.replace(" ", "")
-
-    # extract the numeric prefix
-    digits = ""
-    while v and v[0:1].isdigit() or v[0:1] == '.':
-        digits += v[0]
-        v = v[1:]
-
-    try:
-        m = float(digits)
-    except ValueError:
-        msg = ("{0} option requires a numeric value, "
-               "with an optional unit suffix").format(opt)
-        raise optparse.OptionValueError(msg)
-
-
-    # strip out the 'i' and convert to upper case so
-    # kib Kib kb KB are all equivalent
-    suffix = v.upper().replace("I", "")
-    try:
-        return m * multipliers[suffix]
-    except KeyError as k:
-        msg = ("{0} invalid suffix '{1}', "
-               "should be B, Kb, Mb or Gb").format(opt, v)
-        raise optparse.OptionValueError(msg)
-
-class SambaOption(optparse.Option):
-    TYPES = optparse.Option.TYPES + ("bytes",)
-    TYPE_CHECKER = copy(optparse.Option.TYPE_CHECKER)
-    TYPE_CHECKER["bytes"] = check_bytes
diff --git a/python/samba/netcmd/__init__.py b/python/samba/netcmd/__init__.py
index bb3736e2117..31541a98347 100644
--- a/python/samba/netcmd/__init__.py
+++ b/python/samba/netcmd/__init__.py
@@ -26,47 +26,16 @@ import samba
 from ldb import ERR_INVALID_CREDENTIALS, LdbError
 from samba import colour
 from samba.auth import system_session
-from samba.getopt import SambaOption, OptionError
+from samba.getopt import Option, OptionParser
 from samba.logger import get_samba_logger
 from samba.samdb import SamDB
 
 from .encoders import JSONEncoder
-from .validators import ValidationError
-
-
-class Option(SambaOption):
-    ATTRS = SambaOption.ATTRS + ["validators"]
-    SUPPRESS_HELP = optparse.SUPPRESS_HELP
-
-    def run_validators(self, opt, value):
-        """Runs the list of validators on the current option.
-
-        If the validator raises ValidationError, turn that into CommandError
-        which gives nicer output.
-        """
-        validators = getattr(self, "validators") or []
-
-        for validator in validators:
-            try:
-                validator(opt, value)
-            except ValidationError as e:
-                raise CommandError(e)
-
-    def convert_value(self, opt, value):
-        """Override convert_value to run validators just after.
-
-        This can also be done in process() but there we would have to
-        replace the entire method.
-        """
-        value = super().convert_value(opt, value)
-        self.run_validators(opt, value)
-        return value
-
-
-# This help formatter does text wrapping and preserves newlines
 
 
 class PlainHelpFormatter(optparse.IndentedHelpFormatter):
+    """This help formatter does text wrapping and preserves newlines."""
+
     def format_description(self, description=""):
         desc_width = self.width - self.current_indent
         indent = " " * self.current_indent
@@ -146,11 +115,11 @@ class Command(object):
         else:
             print(f"{err}{klass}: {msg} - {evalue}", file=self.errf)
 
-    def ldb_connect(self, ldap_url, sambaopts, credopts):
+    def ldb_connect(self, hostopts, sambaopts, credopts):
         """Helper to connect to Ldb database using command line opts."""
         lp = sambaopts.get_loadparm()
         creds = credopts.get_credentials(lp)
-        return SamDB(ldap_url, credentials=creds,
+        return SamDB(hostopts.H, credentials=creds,
                      session_info=system_session(lp), lp=lp)
 
     def print_json(self, data):
@@ -175,7 +144,7 @@ class Command(object):
             message = "uncaught exception"
             force_traceback = True
 
-        if isinstance(e, OptionError):
+        if isinstance(e, optparse.OptParseError):
             print(evalue, file=self.errf)
             self.usage()
             force_traceback = False
@@ -211,11 +180,13 @@ class Command(object):
             traceback.print_tb(etraceback, file=self.errf)
 
     def _create_parser(self, prog=None, epilog=None):
-        parser = optparse.OptionParser(
+        parser = OptionParser(
             usage=self.synopsis,
             description=self.full_description,
             formatter=PlainHelpFormatter(),
-            prog=prog, epilog=epilog)
+            prog=prog,
+            epilog=epilog,
+            option_class=Option)
         parser.add_options(self.takes_options)
         optiongroups = {}
         for name in sorted(self.takes_optiongroups.keys()):
@@ -241,12 +212,19 @@ class Command(object):
 
     def _run(self, *argv):
         parser, optiongroups = self._create_parser(self.command_name)
-        opts, args = parser.parse_args(list(argv))
+
+        # Handle possible validation errors raised by parser
+        try:
+            opts, args = parser.parse_args(list(argv))
+        except Exception as e:
+            self.show_command_error(e)
+            return -1
+
         # Filter out options from option groups
         kwargs = dict(opts.__dict__)
         for option_group in parser.option_groups:
             for option in option_group.option_list:
-                if option.dest is not None:
+                if option.dest is not None and option.dest in kwargs:
                     del kwargs[option.dest]
         kwargs.update(optiongroups)
 
@@ -338,7 +316,7 @@ class SuperCommand(Command):
                 sub = self.subcommands[a]
                 return sub._resolve(sub_path, *sub_args, outf=outf, errf=errf)
 
-            elif a in [ '--help', 'help', None, '-h', '-V', '--version' ]:
+            elif a in ['--help', 'help', None, '-h', '-V', '--version']:
                 # we pass these to the leaf node.
                 if a == 'help':
                     a = '--help'
diff --git a/python/samba/netcmd/dbcheck.py b/python/samba/netcmd/dbcheck.py
index 4d5c79ff11b..657881b5eea 100644
--- a/python/samba/netcmd/dbcheck.py
+++ b/python/samba/netcmd/dbcheck.py
@@ -16,18 +16,17 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #
 
-import ldb
+import optparse
 import sys
+
+import ldb
 import samba.getopt as options
+from samba import colour
 from samba.auth import system_session
-from samba.samdb import SamDB
-from samba.netcmd import (
-    Command,
-    CommandError,
-    Option
-)
 from samba.dbchecker import dbcheck
-from samba import colour
+from samba.samdb import SamDB
+
+from . import Command, CommandError, Option
 
 
 class cmd_dbcheck(Command):
@@ -86,7 +85,7 @@ class cmd_dbcheck(Command):
                type=str, metavar="URL", dest="H"),
         Option("--selftest-check-expired-tombstones",
                dest="selftest_check_expired_tombstones", default=False, action="store_true",
-               help=Option.SUPPRESS_HELP), # This is only used by tests
+               help=optparse.SUPPRESS_HELP),  # This is only used by tests
     ]
 
     def run(self, DN=None, H=None, verbose=False, fix=False, yes=False,
diff --git a/python/samba/netcmd/domain/auth/policy.py b/python/samba/netcmd/domain/auth/policy.py
index faf81cca616..6ee85602907 100644
--- a/python/samba/netcmd/domain/auth/policy.py
+++ b/python/samba/netcmd/domain/auth/policy.py
@@ -29,6 +29,75 @@ from samba.netcmd.domain.models.exceptions import ModelError
 from samba.netcmd.validators import Range
 
 
+class UserOptions(options.OptionGroup):
+    """User options used by policy create and policy modify commands."""
+
+    def __init__(self, parser):


-- 
Samba Shared Repository



More information about the samba-cvs mailing list