Skip to content

Commit e965c17

Browse files
committed
Replace deprecated optparse dependency [RHELDST-34542]
1 parent eec6a3d commit e965c17

File tree

5 files changed

+176
-76
lines changed

5 files changed

+176
-76
lines changed

kobo/cli.py

Lines changed: 87 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -22,18 +22,18 @@ def __init__(self, *args, **kwargs):
2222
--------------------------
2323
# It usually makes sense to inherit directly from Command class.
2424
# All common methods and attributes should be in the container.
25-
# Specify any OptionParser options in options() method.
26-
# OptionParser.parse_args() result is automatically passed to run(*args, **kwargs) method.
27-
# A OptionParser instance os available in self.parser attribute.
25+
# Specify command arguments in the options() method using add_argument().
26+
# ArgumentParser.parse_args() result is automatically passed to run(*args, **kwargs) method.
27+
# An ArgumentParser instance is available in self.parser attribute.
2828
2929
class Make_Dirs(Command):
3030
'''create directories'''
3131
enabled = True
3232
admin = False
3333
3434
def options(self):
35-
self.parser.usage = "%%prog %s [options] <user>" % self.normalized_name
36-
self.parser.add_option("-m", "--mode", help="set directory perms (0xxx)")
35+
self.parser.usage = "%(prog)s %s [options] <user>" % self.normalized_name
36+
self.parser.add_argument("-m", "--mode", help="set directory perms (0xxx)")
3737
3838
def run(self, *args, **kwargs):
3939
if len(args) < 1:
@@ -68,9 +68,8 @@ def run(self, *args, **kwargs):
6868

6969
from __future__ import print_function
7070
import sys
71-
import optparse
71+
import argparse
7272
import datetime
73-
from optparse import Option
7473
from six.moves.xmlrpc_client import Fault
7574

7675
from kobo.plugins import Plugin, PluginContainer
@@ -183,32 +182,41 @@ def normalize_name(cls, name):
183182
return name.lower().replace('_', '-').replace(' ', '-')
184183

185184

186-
class CommandOptionParser(optparse.OptionParser):
185+
class CommandOptionParser(argparse.ArgumentParser):
187186
"""Enhanced OptionParser with plugin support."""
188187
def __init__(self,
189188
usage=None,
190-
option_list=None,
191-
option_class=Option,
192189
version=None,
193190
conflict_handler="error",
194191
description=None,
195-
formatter=None,
196-
add_help_option=True,
192+
formatter_class=None,
193+
add_help=True,
197194
prog=None,
198195
command_container=None,
199196
default_command="help",
200197
add_username_password_options=False,
201198
add_hub_option=False,
202199
default_profile="",
203200
configuration_directory="/etc"):
204-
205-
usage = usage or "%prog <command> [args] [--help]"
201+
usage = usage or "%(prog)s <command> [args] [--help]"
206202
self.container = command_container
207203
self.default_command = default_command
208204
self.command = None
209-
formatter = formatter or optparse.IndentedHelpFormatter(max_help_position=33)
210-
211-
optparse.OptionParser.__init__(self, usage, option_list, option_class, version, conflict_handler, description, formatter, add_help_option, prog)
205+
formatter_class = formatter_class or argparse.RawTextHelpFormatter
206+
207+
# Initialize the argument parser
208+
super(CommandOptionParser, self).__init__(
209+
prog=prog,
210+
usage=usage,
211+
description=description,
212+
conflict_handler=conflict_handler,
213+
add_help=add_help,
214+
formatter_class=formatter_class,
215+
)
216+
217+
# Add version argument if provided
218+
if version:
219+
self.add_argument('--version', action='version', version=version)
212220

213221
if add_username_password_options:
214222
self._add_opts(
@@ -263,7 +271,7 @@ def format_help_commands(self, admin=False):
263271

264272
def parse_args(self, args=None, values=None):
265273
"""return (command_instance, opts, args)"""
266-
args = self._get_args(args)
274+
args = args if args is not None else sys.argv[1:]
267275
command = None
268276

269277
if len(args) > 0 and not args[0].startswith("-"):
@@ -281,25 +289,37 @@ def parse_args(self, args=None, values=None):
281289
if self.command != cmd.normalized_name:
282290
self.command = cmd.normalized_name
283291
cmd.options()
284-
cmd_opts, cmd_args = optparse.OptionParser.parse_args(self, args, values)
285-
return (cmd, cmd_opts, cmd_args)
286292

287-
def run(self, args=None, values=None):
293+
# Parse arguments using argparse
294+
parsed_args = super(CommandOptionParser, self).parse_args(args)
295+
296+
# Get remaining positional arguments (if any)
297+
remaining_args = getattr(parsed_args, 'args', [])
298+
299+
return (cmd, parsed_args, remaining_args)
300+
301+
def run(self, args=None):
288302
"""parse arguments and run a command"""
289-
cmd, cmd_opts, cmd_args = self.parse_args(args, values)
290-
cmd_kwargs = cmd_opts.__dict__
303+
# Get command instance and parsed arguments
304+
cmd, parsed_args, remaining_args = self.parse_args(args)
305+
306+
# Convert Namespace to dictionary for kwargs
307+
cmd_kwargs = vars(parsed_args)
291308

292-
# this block should only be evaluated if default_profile has been set at instantiation
309+
# Handle profile if specified
293310
if self.default_profile and 'profile' in cmd_kwargs:
294-
self._load_profile(cmd_kwargs['profile'])
311+
self._load_profile(cmd_kwargs['profile'])
295312

296-
cmd.run(*cmd_args, **cmd_kwargs)
313+
# Run command with positional args and keyword args
314+
cmd.run(*remaining_args, **cmd_kwargs)
297315

298316
def _add_opts(self, *args):
299317
"""populates one or more options with their respective help texts"""
300-
option_list = [optparse.Option(option, help=help_text) for option, help_text in args]
301318

302-
self._populate_option_list(option_list=option_list, add_help=False)
319+
for option, help_text in args:
320+
# Strip leading dashes and use as destination
321+
dest = option.lstrip('-').replace('-', '_')
322+
self.add_argument(option, dest=dest, help=help_text)
303323

304324
def _load_profile(self, profile):
305325
"""load configuration file under location <CONFIGURATION_DIRECTORY>/<PROFILE>.conf"""
@@ -326,9 +346,12 @@ class Help_Admin(Command):
326346

327347
def options(self):
328348
# override default --help option
329-
opt = self.parser.get_option("--help")
330-
opt.action = "store_true"
331-
opt.dest = "help"
349+
self.parser.add_argument(
350+
"--help",
351+
action="store_true",
352+
dest="help",
353+
help="show help message and exit"
354+
)
332355

333356
def run(self, *args, **kwargs):
334357
self.parser.print_help(admin=True)
@@ -366,12 +389,14 @@ def run(self, *args, **kwargs):
366389
print("--------")
367390

368391
for command_name, CommandClass in sorted(self.parser.container.plugins.items()):
369-
parser = optparse.OptionParser(usage=self.parser.usage)
392+
parser = argparse.ArgumentParser(
393+
usage=self.parser.usage,
394+
formatter_class=argparse.RawTextHelpFormatter
395+
)
370396
cmd = CommandClass(parser)
371397
cmd.normalized_name = command_name
372398
cmd.options()
373399
cmd.container = self.parser.container
374-
cmd_opts, cmd_args = parser.parse_args()
375400

376401
print(command_name)
377402
print("-" * len(command_name))
@@ -380,24 +405,39 @@ def run(self, *args, **kwargs):
380405
print("[ADMIN ONLY]", end=' ')
381406

382407
print(cmd.__doc__.strip(), end="\n\n")
383-
usage = parser.get_usage().strip().replace("Usage: ", "**Usage:** ", 1)
408+
409+
# Get formatted usage
410+
usage = parser.format_usage()
384411
if usage:
385-
print(usage, end="\n\n")
412+
print(usage.replace("usage: ", "**Usage:** "), end="\n\n")
386413

387-
for opt in sorted(parser.option_list, key=str):
388-
if "-h/--help" in str(opt):
414+
# Process and display arguments
415+
for action in parser._actions:
416+
# Skip help action
417+
if action.dest == 'help':
389418
continue
390-
if opt.nargs:
391-
metavar = opt.metavar or opt.dest.upper()
392-
opt_list = []
393-
for opt_str in opt._short_opts + opt._long_opts:
394-
if opt.nargs is not None:
395-
opt_list.append("%s=%s" % (opt_str, metavar))
419+
420+
# Format option strings
421+
opts = []
422+
for opt_str in action.option_strings:
423+
if action.metavar:
424+
opts.append(f"{opt_str}={action.metavar}")
425+
elif action.nargs:
426+
opts.append(f"{opt_str}={action.dest.upper()}")
396427
else:
397-
opt_list.append(opt_str)
398-
print("/".join(opt_list))
399-
print(" %s" % opt.help)
400-
if opt.action == "append":
428+
opts.append(opt_str)
429+
430+
if opts: # Optional arguments
431+
print("/".join(opts))
432+
elif action.dest != 'help': # Positional arguments
433+
print(action.dest)
434+
435+
# Print help text
436+
if action.help:
437+
print(f" {action.help}")
438+
439+
# Show if argument can be specified multiple times
440+
if action.nargs in ('+', '*', argparse.REMAINDER):
401441
print("\n This option can be specified multiple times")
402442
print()
403443
print()

kobo/notification.py

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
import smtplib
1111
import sys
12-
import optparse
12+
import argparse
1313

1414
import kobo.shortcuts
1515
import six
@@ -54,44 +54,49 @@ def send(self, from_addr, recipients, subject, body, reply_to=None, xheaders=Non
5454

5555
def main(argv):
5656
"""Main function for command line usage"""
57-
parser = optparse.OptionParser("usage: %prog <options> <to_addr> [to_addr]...")
58-
parser.add_option(
57+
parser = argparse.ArgumentParser(description="Send email notifications")
58+
parser.add_argument(
5959
"--server",
6060
help="specify SMTP server address"
6161
)
62-
parser.add_option(
62+
parser.add_argument(
6363
"-f",
6464
"--from",
6565
dest="from_addr",
6666
help="set the From address"
6767
)
68-
parser.add_option(
68+
parser.add_argument(
6969
"-s",
7070
"--subject",
7171
help="set email Subject"
7272
)
73-
parser.add_option(
73+
parser.add_argument(
7474
"-r",
7575
"--reply-to",
7676
help="set the Reply-To address"
7777
)
78-
parser.add_option(
78+
parser.add_argument(
7979
"-x",
8080
"--xheader",
8181
nargs=2,
8282
dest="xheaders",
8383
action="append",
8484
help="set X-Headers; takes two arguments (-x X-Spam eggs)"
8585
)
86+
parser.add_argument(
87+
"recipients",
88+
nargs="+",
89+
help="recipient email addresses"
90+
)
8691

87-
(opts, args) = parser.parse_args(argv)
92+
args = parser.parse_args(argv)
8893

89-
server = opts.server
90-
from_addr = opts.from_addr
91-
subject = opts.subject
92-
reply_to = opts.reply_to
93-
xheaders = opts.xheaders and dict(opts.xheaders) or {}
94-
recipients = args
94+
server = args.server
95+
from_addr = args.from_addr
96+
subject = args.subject
97+
reply_to = args.reply_to
98+
xheaders = args.xheaders and dict(args.xheaders) or {}
99+
recipients = args.recipients
95100

96101
if not server:
97102
parser.error("SMTP server address required")

kobo/worker/main.py

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import os
55
import sys
66
import signal
7-
import optparse
7+
import argparse
88
import logging
99

1010
# IMPORTANT: import taskd first to set os.environ["PROJECT_DEFAULT_CONFIG_FILE"]
@@ -100,38 +100,36 @@ def sighup_handler(*_):
100100

101101

102102
def main(conf, argv=None, task_manager_class=None):
103-
parser = optparse.OptionParser()
104-
parser.add_option(
103+
parser = argparse.ArgumentParser()
104+
parser.add_argument(
105105
"-f", "--foreground",
106106
default=False,
107107
action="store_true",
108108
help="run in foreground (do not spawn a daemon)",
109109
)
110-
parser.add_option(
110+
parser.add_argument(
111111
"-k", "--kill",
112112
default=False,
113113
action="store_true",
114114
help="kill the daemon",
115115
)
116-
parser.add_option(
116+
parser.add_argument(
117117
"-p", "--pid-file",
118118
help="specify a pid file",
119119
)
120-
opts, args = parser.parse_args(argv)
120+
args = parser.parse_args(argv)
121121

122-
pid_file = opts.pid_file
123-
if pid_file is None:
124-
pid_file = conf.get("PID_FILE")
122+
pid_file = args.pid_file or conf.get("PID_FILE")
125123

126124
if pid_file is None:
127125
parser.error("No pid file specified.")
128126

129-
if opts.kill:
127+
if args.kill:
130128
pid = open(pid_file, "r").read()
131129
os.kill(int(pid), 15)
132130
sys.exit(0)
133131

134-
if opts.foreground:
132+
if args.foreground:
135133
main_loop(conf, foreground=True, task_manager_class=task_manager_class)
136134
else:
137135
kobo.process.daemonize(

0 commit comments

Comments
 (0)