Commit Graph

354 Commits

Author SHA1 Message Date
Benjamin A. Beasley 156e1eb0b9 Use importlib.metadata on Python 3.10+
Favor importlib.metadata.packages_distributions() over
importlib_metadata.packages_distributions() where it is available, i.e.,
on Python 3.10 and later.

Depend on PyPI importlib_metadata only on Python 3.9 and older:
conditionalize the requirements.txt entry on Python version.

Change-Id: I624fc0059057de05bb2bacd9c1238cba71ebad2a
2023-11-29 22:13:41 +09:00
Zuul 3ee0725a09 Merge "Handle complex objects in yaml formatter better" 2023-09-11 09:24:42 +00:00
Zuul 76b5df665b Merge "Autofit table output if stdout is a tty" 2023-09-11 09:24:41 +00:00
Zuul a907200768 Merge "Clarification of the algorithm used" 2023-09-11 08:49:56 +00:00
Pavlo Shchelokovskyy 606644c13a Handle complex objects in yaml formatter better
this patch adds special handling of objects that have either 'toDict'
or 'to_dict' method, converting those to dictionary before passing
them to pyYaml.

The main immediate aim is to support instances of
openstack.utils.Munch class in the YAML output.

Story: 2010906
Task: 48728
Change-Id: If3718477533987b6b88b27ac639c6689a2e4b327
2023-09-05 14:31:40 +00:00
Pavlo Shchelokovskyy e02f89cd69 Autofit table output if stdout is a tty
nobody enjoys reading mangled tables in the terminal.

Be smart and auto-enable "fit width" if the output is a tty,
while still printing full lines when output is redirected (e.g. pipe)
so that e.g. grep and friends continue to work as before.

Unfortunately, tty detection is not reliable enough on Windows,
so this feature is not enabled there.

Change-Id: I46137d16ea3054a43de4a9f76477bda59ebacf10
2023-08-29 13:00:36 +00:00
Pavlo Shchelokovskyy 6096869f70 Fix flake8 violation E721
use isinstance for type check instead of type(..) ==

Change-Id: I062f9423f418caee33ab892b8b499ea22d4be38a
2023-08-29 13:00:36 +00:00
Jiri Podivin 72e81d7d84 Removing helper functions providing Python < 3.3 compatibility
Functions used for deriving terminal width are no longer
necessary, as Python 3.3 introduced[0] built in solution.

Remaining helper function `utils.terminal_width` received docstring
explaining return parameters.

Method `_assign_max_widths` of the `TableFormatter` class was refactored
to no longer use the `stdout` argument. Uses of the method were adjusted accordingly.
Method now also has minimal docstring. Minor adjustment was made to inline comments
to more closely reflect functionality of the code.

[0]https://docs.python.org/3.8/library/os.html?highlight=get_terminal_size#os.get_terminal_size

Signed-off-by: Jiri Podivin <jpodivin@redhat.com>
Change-Id: I2898f099227e8c97aef6492c60f2f99038aa1357
2023-03-01 09:18:15 +01:00
Stephen Finucane fb9a3a9b2d Strip trailing periods when getting description
This yields slightly prettier output.

Change-Id: Ibec7cd861eacc3630182d6a782ffaf361f449aa6
Signed-off-by: Stephen Finucane <sfinucan@redhat.com>
2022-12-12 18:14:52 +00:00
Jiri Podivin f2215ba0e7 Clarification of the algorithm used
Link was pointing to a wrong wikipedia page, we are using
Damerau-Levenshtein metric, which allows for additional "swap"
operation. A subtle but important distinction.

Signed-off-by: Jiri Podivin <jpodivin@redhat.com>
Change-Id: I6cc2499c371b86aaf6636d7a46416bc947c11bb2
2022-10-27 10:47:05 +02:00
Zuul 91c62985fb Merge "columns: Useful __str__, __repr__ implementation" 2022-10-04 18:15:39 +00:00
Stephen Finucane 67217b0e56 columns: Useful __str__, __repr__ implementation
The default implementations for __str__ and __repr__ are rubbish.

  >>> from osc_lib.cli import format_columns
  >>> str(format_columns.DictColumn({'foo': 'bar'}))
  '<osc_lib.cli.format_columns.DictColumn object at 0x7f6e26771e40>'
  >>> repr(format_columns.DictColumn({'foo': 'bar'}))
  '<osc_lib.cli.format_columns.DictColumn object at 0x7f6e26b57ac0>'

Make it useful.

  >>> from osc_lib.cli import format_columns
  >>> str(format_columns.DictColumn({'foo': 'bar'}))
  "foo='bar'"
  >>> repr(format_columns.DictColumn({'foo': 'bar'}))
  "DictColumn({'foo': 'bar'})"

This helps when testing as the reason for mismatches will be more
obvious.

Change-Id: I8b8598875f896cb3dbf417515d377e7758b3b98b
Signed-off-by: Stephen Finucane <sfinucan@redhat.com>
2022-10-03 14:23:47 +01:00
Zuul 58c853d101 Merge "Removing brackets around tested conditional" 2022-08-04 18:00:46 +00:00
Jiri Podivin 56b700afca Removing brackets around tested conditional
While permissible syntactically, using brackets to wrap tested conditional is unnecessary
and potentially confusing. As without inserted whitspace the code may look as a function
call, rather than a statement and expression.

The construct is also considered erroneous by linters.

Closes-Bug: 1983593

Signed-off-by: Jiri Podivin <jpodivin@redhat.com>
Change-Id: I0a086a8349e2a72cae024857e148fddc3556c319
2022-08-04 16:32:44 +02:00
ljhuang 4ba0a97f85 Replace abc.abstractproperty with property and abc.abstractmethod
Replace abc.abstractproperty with property and abc.abstractmethod,
as abc.abstractproperty has been deprecated since python3.3[1]

[1]https://docs.python.org/3.8/whatsnew/3.3.html?highlight=deprecated#abc

Change-Id: I5e86211323c5e08553a5c777c0b6d1d85f95e1a9
2022-08-04 13:03:13 +08:00
Stephen Finucane 86061ad87d Remove final use of pkg_resources
'pkg_resources' is slow, while 'importlib.metadata' is the new shiny and
is *much* faster. Recent version of 'importlib.metadata' - namely those
found in Python 3.10 or provided by the 4.4 'importlib-metadata'
backport - now provide the last bit of functionality we were missing to
remove 'pkg_resources' entirely, namely the ability to map package names
to modules. This is used for generating epilogs.

The benefits of this are huge, yielding a near 40% decrease in runtime
for the cliffdemo app (100mS after compared to 160mS) before.

Change-Id: I934d8a196d76622671781643f36bdb8a07d2f319
Signed-off-by: Stephen Finucane <sfinucan@redhat.com>
2022-07-15 16:08:26 +01:00
Stephen Finucane 3e0eed49c5 Defer loading PyYAML
Yet another library that's slow to import and is totally optional. Defer
loading this one also and speed up initial start time.

Change-Id: Ic694b4d36dbf7ce87bc8fe9a2f8b0597719418a1
Signed-off-by: Stephen Finucane <sfinucan@redhat.com>
2022-05-25 17:09:04 +01:00
Stephen Finucane 6811218817 Defer loading cmd2
We were importing cmd2 purely so we could do some exception
transformation. However, this is only needed if we're in interactive
mode. Avoid both the import of cmd2 and the transformation of the
exceptions unless this is the case. This speeds up import time by ~30%
for the demoapp on my machine (~160mS after compared to ~210mS before)

Change-Id: I2356dc9803b4d0eef3528c6d057207509932e6b2
Signed-off-by: Stephen Finucane <sfinucan@redhat.com>
2022-05-25 17:09:04 +01:00
Zuul 78dea943d7 Merge "Automatically page interactive root help output" 2021-09-20 22:58:33 +00:00
Zuul 734bc0c5da Merge "Colourise and automatically page help output" 2021-08-06 18:29:46 +00:00
Zuul 865ab44713 Merge "Update unit test to satisfy python3.10+" 2021-08-06 18:03:40 +00:00
Zuul b171761821 Merge "Add conflict_handler parameter as attribut in Command class" 2021-07-20 17:06:26 +00:00
Zane Bitter 4e7c882c3c Automatically page interactive root help output
The previous commit already ensures that the interactive help for
individual commands is sent to a pager. This does the same for the
'help' command with no arguments.

Change-Id: If5e38421d21e09f88a572dbb508b1997381bdb87
2021-07-12 21:03:39 -04:00
Zane Bitter 8fa916e916 Colourise and automatically page help output
Using the autopage library we can automatically send the help output to
a pager (less, by default), git-style. The pager is configured to not
reset the terminal on exit, avoiding the problem when piping to less
manually that the help text you want to refer to disappears off the
screen when you go to use it. The pager is only invoked when the output
is to the terminal.

Since we invoke the pager, we can ensure that it is correctly set up to
interpret ANSI escape codes, so it is safe to use colour to make the
output easier to read. The autopage library provides light styling of
the default argparse help output, and some additional colour
highlighting is added here for the command list (which is generated by
cliff, not using argparse's formatting code).

Change-Id: If9e1aa5166da32c58cc0fa617f4f81eaa9b2c470
Depends-On: https://review.opendev.org/c/openstack/requirements/+/799343
2021-07-12 21:03:32 -04:00
Joel Capitao 9b66f4066c Update unit test to satisfy python3.10+
Fedora is already testing Python 3.10 [1] and an issue
has been raised [2].
All the details are in the BZ ticket but TLDR is that
"optional arguments" was replaced with "options [3].
So, I used assertRegexp to accept both of them (i.e
"optional arguments" and "options").

[1] https://fedoraproject.org/wiki/Changes/Python3.10
[2] https://bugzilla.redhat.com/show_bug.cgi?id=1914138
[3] fb35fa49d1

Change-Id: I18d9f1bea7bb5a7afb273550314c36da7b466a69
2021-06-15 14:53:54 +02:00
Zane Bitter 392f3b2e7c Handle SIGPIPE exit gracefully
If we are piping output to a command that exits before the entire
output is written (e.g. "head") then we will receive a BrokenPipeError.
This is expected and we should react by exiting gracefully, setting an
appropriate return code (128 + SIGPIPE).

Change-Id: I0d60e44450da1f48dbd8f459549da80fda69aad5
2021-06-07 09:13:02 -04:00
matbu 452fff3aad Add conflict_handler parameter as attribut in Command class
Adding conflict_handler as attribut in the Command class in order to be
able to take control of this parameter and change to different behavior
that argparse is handling: error / resolve / ignore.

Callers will be able to override it and get a proper Parser object.

Change-Id: I327ece99a04bc8b2ebfa554dea643b1f2a456336
2021-06-04 18:33:58 +02:00
likui 075345196d Replace getargspec with getfullargspec
inspect.getargspec() is deprecated since py3

[1] https://docs.python.org/3/library/inspect.html#inspect.getargspec

Change-Id: I7a1692d9979e9ffaf781de1f39f5bfa59a01cf3c
2021-05-13 09:12:39 +08:00
Stephen Finucane 117a1005dc requirements: Uncap PrettyTable
PrettyTable was capped at a < 0.8, which meant we were getting the
veritably ancient 0.7.2 release first release in April 2013 (!) [1].
The project is now being maintained as a Jazzband project [2], meaning
we should switch to this new version.

The only significant change required here is that we no longer set the
'min_width' attribute since that actually does something - the wrong
thing - now. We want this attribute to set a lower bound on the wrap
width as opposed to an absolute minimum we can use, which is what
setting the 'min_width' attribute would do.

While we're here, we also remove a now useless bit of Python 2 code and
bump cmd2 to a slightly newer version.

[1] https://pypi.org/project/prettytable/#history
[2] https://github.com/jazzband/prettytable

Change-Id: Iceac729e7a9429e8ab25c60524a48d0aaeebeb37
Signed-off-by: Stephen Finucane <sfinucan@redhat.com>
Depends-On: https://review.opendev.org/c/openstack/requirements/+/774917
2021-02-11 11:01:48 +00:00
Zuul 421f20c9c8 Merge "Add '--sort-ascending', '--sort-descending' parameters" 2021-02-10 12:26:18 +00:00
Zuul 4d16d2bf69 Merge "Make 'FormattableColumn' comparable" 2021-02-10 12:12:30 +00:00
Zuul a5bdcc6e78 Merge "Handle null values when sorting" 2021-02-09 18:35:31 +00:00
Stephen Finucane 7798cb2e37 Add '--sort-ascending', '--sort-descending' parameters
Allow users to reverse sorting direction.

Change-Id: Iecd539139c5a7ce4abaaee2ff5632a2459437d51
Signed-off-by: Stephen Finucane <sfinucan@redhat.com>
2021-01-29 15:40:42 +00:00
Stephen Finucane c1c991045c Make 'FormattableColumn' comparable
Implement the '__lt__' magic method, thus providing the minimal set of
rich comparison methods necessary to support sorting. This will allows
users using these formatters for the more basic types (i.e. not dicts)
to sort their output using the standard '--sort-column' option.

Change-Id: I08e1f1bc75fa6452f19dfb9d221c1daec194d58d
Signed-off-by: Stephen Finucane <sfinucan@redhat.com>
2021-01-29 15:40:42 +00:00
Stephen Finucane 4f45f9a30e Handle null values when sorting
One unfortunate change (or fortunate, depending on how you look at
types) in Python 3 is the inability to sort iterables of different
types. For example:

  >>> x = ['foo', 'bar', None, 'qux']
  >>> sorted(x)
  Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
  TypeError: '<' not supported between instances of 'NoneType' and 'str'

Fortunately, we can take advantage of the fact that by providing a
function for the 'key' that returns a tuple, we can sort on multiple
conditions. In this case, "when the first key returns that two elements
are equal, the second key is used to compare." [1] We can use this to
first separate the values by whether they are None or not, punting those
that are not to the end, before sorting the non-None values normally.
For example:

  >>> x = ['foo', 'bar', None, 'qux']
  >>> sorted(x, key=lambda k: (k is None, k))
  ['bar', 'foo', 'qux', None]

We were already using this feature implicitly through our use of
'operator.itemgetter(*indexes)', which will return a tuple if there is
more than one item in 'indexes', and now we simply make that explicit,
fixing the case where we're attempting to compare a comparable type
with None. For all other cases, such as comparing a value that isn't
comparable, we surround things with a try-catch and a debug logging
statement to allow things to continue.

Note that we could optimize what we're done further by building a key
value that covers all indexes, rather than using a for loop to do so.
For example:

  >>> x = [('baz', 2), (None, 0), ('bar', 3), ('baz', 4), ('qux', 0)]
  >>> sorted(x, key=lambda k: list(
  ...     itertools.chain((k[i] is None, k[i]) for i in (0, 1)))
  ... )
  [('bar', 3), ('baz', 2), ('baz', 4), ('qux', 0), (None, 0)]

However, this would be harder to grok and would also mean we're unable
to handle exceptions on a single column where e.g. there are mixed types
or types that are not comparable while still sorting on the other
columns. Perhaps this would be desirable for some users, but sorting on
a best-effort basis does seem wiser and generally more user friendly.
Anyone that wants to sort on such columns should ensure their types are
comparable or implement their own sorting implementation.

[1] https://www.kite.com/python/answers/how-to-sort-by-two-keys-in-python

Change-Id: I4803051a6dd05c143a15923254af97e32cd39693
Signed-off-by: Stephen Finucane <sfinucan@redhat.com>
Story: 2008456
Task: 41466
2021-01-29 15:40:31 +00:00
xuanyandong 0d18e8812c Remove unicode from code
Change-Id: I040fccd1714dccd7a87aaf10d397ad3a3ef476d3
2021-01-28 17:00:45 +00:00
Zuul 644041f87f Merge "Remove six" 2020-11-18 19:56:56 +00:00
Stephen Finucane 997e05fce6 columns: Make 'FormattableColumn' comparable
Currently, comparing instances of this fails:

  >>> from cliff.columns import FormattableColumn
  >>> class Test(FormattableColumn):
  ...     def human_readable(self):
  ...         return str(self._data)
  ...
  >>> data = {'x': 'y'}
  >>> x = Test(data)
  >>> y = Test(data)
  >>> x == y
  False

Clearly it should not. Resolve this by implementing a custom comparison.

Change-Id: I4b96475ca6a689f4055dc5ea34b82b3867a65555
Signed-off-by: Stephen Finucane <sfinucan@redhat.com>
Story: #2008320
Task: #41218
2020-11-04 15:17:41 +00:00
xuanyandong bc76d324f5 Remove six
Replace the following items with Python 3 style code.

- six.moves
- six.PY2
- six.PY3
- six.string_types
- six.text_type

Change-Id: I1656b976864c8f2343e658a4abf432d30c151d0b
2020-10-29 11:27:41 +00:00
Stephen Finucane f3587efee8 Remove references to setuptools
With the advent of importlib, entry points are no long a setuptools-only
thing. Update the docs to reflect that.

Change-Id: I099f397ddb4d71879597cfe67ef2a1eff4a8d1af
Signed-off-by: Stephen Finucane <sfinucan@redhat.com>
2020-10-22 10:30:15 +01:00
Zane Bitter bc92b0fd92 Document KeyboardInterrupt exit code
Change-Id: Ib97cbf2c9b108932c437a6d69a6ab629244702b3
2020-09-09 21:59:31 -04:00
Zane Bitter fe7475d6c5 Exit gracefully on Ctrl-C
If we receive SIGINT, exit gracefully: run the clean_up method; don't
print a stacktrace; exit with error code 130 (128 + SIGINT).

Change-Id: I77687133d5482912523814a28e42f4f3a1a146d5
Story: 2008124
Task: 40846
2020-09-09 13:53:41 -04:00
Doug Hellmann 7fdd7cb4c5
change help action to use its own exception for exit
Provide a new exception class for the help action to use to indicate
that the app should exit, instead of calling sys.exit(). This allows
argument parsing errors in interactive mode to print help without
exiting the entire application, while still being treated as a
short-cut to avoid every command plugin having to process argument
errors itself.

Change-Id: If882b305ff9186f97ece6c77ef8c1b888c24a72d
Story: 2008071
Signed-off-by: Doug Hellmann <doug@doughellmann.com>
2020-09-09 09:01:56 -04:00
Thiago Paiva Brito 28c172f701 Capturing argparse errors due to problem with cmd2
The Bifrost team got an errors on their CLI that also affects OSC. When
in interactive mode, if argparse fails to parse the input due to, say,
a missing parameter, argparse by default thows a SystemExit(2), but
cmd2 doesn't like it because that could've been a signal to stop the
CLI, so it breaks the interactive session. This fix aims to bypass that
and keep the CLI running so we don't have to start it at every parameter
we forget to type in.

Change-Id: I0e2006a9625e2f8dbdbc0e5921acfb3853a06ee9
Story: 2008071
Task: 40782
2020-08-28 17:52:17 -03:00
Doug Hellmann 6ac510d0cd switch to stevedore for loading entry points
Switch to using stevedore now so that when the cache implementation is
released all cliff applications can take advantage of the performance
benefits.

Change-Id: Ib7bf53091470b55ab87082d315ca283d3600a636
Signed-off-by: Doug Hellmann <doug@doughellmann.com>
2020-07-05 15:58:46 -04:00
Rodolfo Alonso Hernandez 8099c98249 Remove cap on cmd2
After [1] and [2], there is no need to cap the version of cmd2.

This will also fix the current "rally_openstack" import problems
experienced in the CI: http://paste.openstack.org/show/794701/

[1]https://review.opendev.org/#/c/712591/
[2]https://review.opendev.org/#/c/734629/

Change-Id: Ie15e3f5058c4bd104978d9f31f0590d6c795024b
2020-06-12 16:42:56 -05:00
Zuul 6989b47cc2 Merge "Fix compatibility with new cmd2" 2020-06-10 08:49:01 +00:00
Felix Yan b0fb8daff0 Fix compatibility with new cmd2
Closes-Bug: #1810213
Change-Id: I8c926152aa43359be376ec3dea83c42ecc499e80
2020-06-09 14:20:01 -05:00
Monty Taylor 8477c4dbd0 Import command group support from osc-lib
osc-lib adds support for named groups of commands. There's nothing
particularly openstackclient about this support, so add it here.
This way when we add defered plugin loading, it'll work.

Change-Id: Ia0260d2607f4a240b39e90da4b5b09e7cdfde04f
2020-06-07 11:08:29 -05:00
Monty Taylor d1dc0902a9 Remove unneeded tests
These are for <3.2

Change-Id: I376e3601d5799e11590b2814714655692159de99
2020-06-06 14:24:17 -05:00