mirror of
https://github.com/ansible/awx.git
synced 2026-05-20 23:37:39 -02:30
simplify awxkit dependencies
- remove flake8 as an install requirements (it's only used for tests) - vendor toposort, which is Apache 2.0 licensed (and very small) - change websocket-client to a setuptools optional dependency, which you can install via: pip install "./awxkit[websockets]" - add `jq` and `tabulate` under an additional optional setuptools dependency: pip install "./awxkit[formatting]" - remove `cryptography`, which is only used for random RSA generation (unused by the CLI)
This commit is contained in:
82
awxkit/awxkit/utils/toposort.py
Normal file
82
awxkit/awxkit/utils/toposort.py
Normal file
@@ -0,0 +1,82 @@
|
||||
#######################################################################
|
||||
# Implements a topological sort algorithm.
|
||||
#
|
||||
# Copyright 2014 True Blade Systems, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# Notes:
|
||||
# Based on http://code.activestate.com/recipes/578272-topological-sort
|
||||
# with these major changes:
|
||||
# Added unittests.
|
||||
# Deleted doctests (maybe not the best idea in the world, but it cleans
|
||||
# up the docstring).
|
||||
# Moved functools import to the top of the file.
|
||||
# Changed assert to a ValueError.
|
||||
# Changed iter[items|keys] to [items|keys], for python 3
|
||||
# compatibility. I don't think it matters for python 2 these are
|
||||
# now lists instead of iterables.
|
||||
# Copy the input so as to leave it unmodified.
|
||||
# Renamed function from toposort2 to toposort.
|
||||
# Handle empty input.
|
||||
# Switch tests to use set literals.
|
||||
#
|
||||
########################################################################
|
||||
|
||||
from functools import reduce as _reduce
|
||||
|
||||
__all__ = ['toposort', 'CircularDependencyError']
|
||||
|
||||
|
||||
class CircularDependencyError(ValueError):
|
||||
def __init__(self, data):
|
||||
# Sort the data just to make the output consistent, for use in
|
||||
# error messages. That's convenient for doctests.
|
||||
s = 'Circular dependencies exist among these items: {{{}}}'.format(', '.join('{!r}:{!r}'.format(key, value) for key, value in sorted(data.items()))) # noqa
|
||||
super(CircularDependencyError, self).__init__(s)
|
||||
self.data = data
|
||||
|
||||
|
||||
def toposort(data):
|
||||
"""Dependencies are expressed as a dictionary whose keys are items
|
||||
and whose values are a set of dependent items. Output is a list of
|
||||
sets in topological order. The first set consists of items with no
|
||||
dependences, each subsequent set consists of items that depend upon
|
||||
items in the preceeding sets.
|
||||
"""
|
||||
|
||||
# Special case empty input.
|
||||
if len(data) == 0:
|
||||
return
|
||||
|
||||
# Copy the input so as to leave it unmodified.
|
||||
data = data.copy()
|
||||
|
||||
# Ignore self dependencies.
|
||||
for k, v in data.items():
|
||||
v.discard(k)
|
||||
# Find all items that don't depend on anything.
|
||||
extra_items_in_deps = _reduce(set.union, data.values()) - set(data.keys())
|
||||
# Add empty dependences where needed.
|
||||
data.update({item: set() for item in extra_items_in_deps})
|
||||
while True:
|
||||
ordered = set(item for item, dep in data.items() if len(dep) == 0)
|
||||
if not ordered:
|
||||
break
|
||||
yield ordered
|
||||
data = {
|
||||
item: (dep - ordered)
|
||||
for item, dep in data.items() if item not in ordered
|
||||
}
|
||||
if len(data) != 0:
|
||||
raise CircularDependencyError(data)
|
||||
Reference in New Issue
Block a user