Skip to content

Commit 59dfa68

Browse files
authored
Major update - v0.1 (#3)
* Got a recursive algo working * More progress * Working algo? * Working algo :) * Working on ordering creator * Structuring as package, creating the final class * Getting close to being ready for release :) * Unit tests passed * Better README * More README * Moving notebooks into the scratch folder * Removing old tests * Making it clear that this is a Python 3.7 package
1 parent 6b051ab commit 59dfa68

17 files changed

+3025
-174
lines changed

.gitignore

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ __pycache__/
88

99
# Distribution / packaging
1010
.Python
11-
env/
1211
build/
1312
develop-eggs/
1413
dist/
@@ -20,6 +19,7 @@ lib64/
2019
parts/
2120
sdist/
2221
var/
22+
wheels/
2323
*.egg-info/
2424
.installed.cfg
2525
*.egg
@@ -42,7 +42,7 @@ htmlcov/
4242
.cache
4343
nosetests.xml
4444
coverage.xml
45-
*,cover
45+
*.cover
4646
.hypothesis/
4747

4848
# Translations
@@ -66,7 +66,7 @@ docs/_build/
6666
# PyBuilder
6767
target/
6868

69-
# IPython Notebook
69+
# Jupyter Notebook
7070
.ipynb_checkpoints
7171

7272
# pyenv
@@ -75,15 +75,25 @@ target/
7575
# celery beat schedule file
7676
celerybeat-schedule
7777

78-
# dotenv
79-
.env
78+
# SageMath parsed files
79+
*.sage.py
8080

81-
# virtualenv
81+
# Environments
82+
.env
83+
.venv
84+
env/
8285
venv/
8386
ENV/
8487

8588
# Spyder project settings
8689
.spyderproject
90+
.spyproject
8791

8892
# Rope project settings
8993
.ropeproject
94+
95+
# mkdocs documentation
96+
/site
97+
98+
# mypy
99+
.mypy_cache/

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MIT License
22

3-
Copyright (c) 2019 Jake Sherman
3+
Copyright (c) 2019-2021 Jake Sherman
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

MANIFEST.in

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
include README.md
2+
include LICENSE
3+
include MANIFEST.in
4+
include requirements.txt

README.md

Lines changed: 46 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
# Dependency Algorithm
22

3-
Here is my take on an algorithm in Python that resolves dependencies. I walk through the process of creating the algorithm in `dependency_algo.ipynb`, and implement it in a `Dependencies` class in `Dependencies.py`. The `Dependencies` class accepts as an input a dictionary of items as keys and lists of dependencies as values (see below). Alternatively, you may use the `add_item` method to add items to a `Dependencies` object.
4-
5-
I did not look at other dependency algorithms when creating this, but afterwards I found some [great work by Ferry Boender](http://www.electricmonk.nl/log/2008/08/07/dependency-resolving-algorithm/) that used recursion to resolve dependencies. My solutions do not use recursion.
3+
Here is my take on an algorithm in Python 3.7 that resolves dependencies. The best way to illustrate how this works is with an example...
64

75
## Example
86

9-
Dictionary of items we want to resolve dependencies for:
7+
Let's say that we have the following dictionary where the keys are items, and the values are the dependencies of those items. Each dependency must itself be an item, and items with no dependencies have an empty list `[]` as they dependency:
108

119
```python
1210
my_items = {
@@ -20,42 +18,67 @@ my_items = {
2018
}
2119
```
2220

23-
We can use the `Dependencies` class to take these items and order them.
21+
Note that we've only provided a partial dictionary of items to their dependencies...for example, notice how C is dependent on D, which is dependent on B (no dependencies) and E, which is dependent on F...therefore, C is dependent on D, B, E, and F.
22+
23+
We can use the `Dependencies` class to get the complete list of dependencies for an item, like so:
2424

2525
```python
26-
import collections
27-
from Dependencies import Dependencies
26+
from dependency_algorithm import Dependencies
2827

2928
# Creating a Dependencies object
3029
dependencies = Dependencies(my_items)
31-
32-
# The order method returns an OrderedDict
33-
print Dependencies(my_items).order()
30+
dependencies.complete_dependencies("C")
3431
```
3532

3633
```
37-
>>> OrderedDict([('B', []),
38-
>>> ('F', []),
39-
>>> ('E', ['F']),
40-
>>> ('D', ['B', 'E']),
41-
>>> ('C', ['D']),
42-
>>> ('A', ['B', 'C', 'D']),
43-
>>> ('Z', ['A', 'B', 'C', 'D'])])
34+
>>> ['D', 'B', 'E', 'F']
4435
```
4536

46-
We can also output a list of the item names in order
37+
More importantly, we can return the items in an order such that the dependencies resolve:
4738

4839
```python
49-
print Dependencies(my_items).order_list()
40+
dependencies.resolve_dependencies()
5041
```
5142

5243
```
5344
>>> ['B', 'F', 'E', 'D', 'C', 'A', 'Z']
5445
```
5546

47+
In many cases, there are multiple correct ordering of our items such that each item's dependencies resolve. If we're interested in all possible correct orderings, the `Dependencies` class can permutate over all possible orderings, and identify the correct ones (albeit at a high computational cost), like so:
48+
49+
```python
50+
dependencies.all_possible_resolution_orders(verbose=True)
51+
```
52+
53+
```
54+
>>> Number of permutations: 5040
55+
>>> Number of correct orderings: 3
56+
>>> Number of incorrect orderings: 5037
57+
>>> [('B', 'F', 'E', 'D', 'C', 'A', 'Z'),
58+
>>> ('F', 'B', 'E', 'D', 'C', 'A', 'Z'),
59+
>>> ('F', 'E', 'B', 'D', 'C', 'A', 'Z')]
60+
```
61+
62+
That's pretty much it! The `Dependencies` class also performs two checks, one for any dependencies that are "missing" (i.e., they are not keys in the input dictionary of items and dependencies), and another for cirular dependencies (i.e., A is dependent on B which is dependent on A which is...and so on...).
63+
64+
## Installation
65+
66+
Requires Python 3.7 or greater.
67+
68+
```
69+
pip install dependency_algorithm
70+
```
71+
72+
## Running the unit tests with `pytest`
73+
74+
```
75+
git clone https://github.com/jakesherman/dependency_algorithm.git
76+
cd dependency_algorithm
77+
pip install -e .
78+
python -m pytest
79+
```
5680

57-
## Files
81+
## Future work
5882

59-
- `dependency_algo.ipynb` Jupyter Notebook where I walk through the steps I used in creating the algorithm
60-
- `Dependencies.py` contains the `Dependencies` class used to order a dictionary of items and their dependencies
61-
- `tests.py` has a few quick tests to check to make sure that the `Dependencies` class is functioning correctly
83+
* New version of `Dependencies._enhanced_list_dependencies` that uses iteration instead of recursion
84+
* Improved version of `Dependencies.all_possible_resolution_orders` that uses a more efficient algorithm than looping through permutations, ex. a recursive algorithm

dependency_algorithm/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from .dependency_algorithm import (
2+
CircularDependencyException,
3+
Dependencies,
4+
MissingDependencyException
5+
)

0 commit comments

Comments
 (0)