Repository: nautobot/nornir-nautobot (language: python)

Issue:
Fix nornir inventory defaults
Fixes #39 
Nornir inventory defaults don't seem to be applied
Nornir allows you to set defaults for defaults for Host attributes, like username and password.
This currently doesn't seem to work when using nornir_nautobot.

Consider the following code snippet
```python
from nornir import InitNornir

nr = InitNornir(
    inventory={
        "plugin": "NautobotInventory",
        "options": {
            "nautobot_url": "https://myinstance.of.nautobot.tld",
            "nautobot_token": "api_token",
        },
    },
)

nr.inventory.defaults.username = "username"
```

The expectation would be that every host in the inventory has it's username attribute set with the value "username", if no explicit value was set for that particular host.
```
>>> nr.inventory.hosts["a_host"].username
"username"
```
However the actual result is
```
>>> nr.inventory.hosts["a_host"].username
>>> nr.inventory.hosts["a_host"].username is None
True
```
For this to work properly, the inventory plugin would have to instantiate a Hosts object with a defaults attribute, which doesn't seem to happen right now.

https://github.com/nautobot/nornir-nautobot/blob/0ef2d9fa28689a7221978b962c3ed3759dda8453/nornir_nautobot/plugins/inventory/nautobot.py#L39


Discussion / hints:

Fix patch:
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..5daf9e1
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,202 @@
+---
+name: "CI"
+on:  # yamllint disable
+  - "push"
+  - "pull_request"
+jobs:
+  black:
+    env:
+      INVOKE_LOCAL: "True"
+    runs-on: "ubuntu-20.04"
+    steps:
+      - name: "Check out repository code"
+        uses: "actions/checkout@v2"
+      - name: "Set up Python"
+        uses: "actions/setup-python@v2"
+        with:
+          python-version: "3.9"
+      - name: "Install Python Packages for Linting"
+        run: "pip install --upgrade pip wheel invoke toml black"
+      - name: "Linting: Black"
+        run: "invoke black"
+  bandit:
+    runs-on: "ubuntu-20.04"
+    env:
+      INVOKE_LOCAL: "True"
+    steps:
+      - name: "Check out repository code"
+        uses: "actions/checkout@v2"
+      - name: "Set up Python"
+        uses: "actions/setup-python@v2"
+        with:
+          python-version: "3.9"
+      - name: "Install Python Packages for Linting"
+        run: "pip install --upgrade pip wheel invoke toml bandit"
+      - name: "Linting: Bandit"
+        run: "invoke bandit"
+    needs:
+      - "black"
+  pydocstyle:
+    runs-on: "ubuntu-20.04"
+    env:
+      INVOKE_LOCAL: "True"
+    steps:
+      - name: "Check out repository code"
+        uses: "actions/checkout@v2"
+      - name: "Set up Python"
+        uses: "actions/setup-python@v2"
+        with:
+          python-version: "3.9"
+      - name: "Install Python Packages for Linting"
+        run: "pip install --upgrade pip wheel invoke toml pydocstyle"
+      - name: "Linting: pydocstyle"
+        run: "invoke pydocstyle"
+    needs:
+      - "black"
+  flake8:
+    runs-on: "ubuntu-20.04"
+    env:
+      INVOKE_LOCAL: "True"
+    steps:
+      - name: "Check out repository code"
+        uses: "actions/checkout@v2"
+      - name: "Set up Python"
+        uses: "actions/setup-python@v2"
+        with:
+          python-version: "3.9"
+      - name: "Install Python Packages for Linting"
+        run: "pip install --upgrade pip wheel invoke toml flake8"
+      - name: "Linting: flake8"
+        run: "invoke flake8"
+    needs:
+      - "black"
+  yamllint:
+    runs-on: "ubuntu-20.04"
+    env:
+      INVOKE_LOCAL: "True"
+    steps:
+      - name: "Check out repository code"
+        uses: "actions/checkout@v2"
+      - name: "Set up Python"
+        uses: "actions/setup-python@v2"
+        with:
+          python-version: "3.9"
+      - name: "Install Python Packages for Linting"
+        run: "pip install --upgrade pip wheel invoke toml yamllint"
+      - name: "Linting: yamllint"
+        run: "invoke yamllint"
+    needs:
+      - "black"
+  build:
+    runs-on: "ubuntu-20.04"
+    steps:
+      - name: "Check out repository code"
+        uses: "actions/checkout@v2"
+      - name: "Set up Python"
+        uses: "actions/setup-python@v2"
+        with:
+          python-version: "3.9"
+      - name: "Install Python Packages for Setup"
+        run: "pip install invoke poetry toml"
+      - name: "Build Container"
+        run: "invoke build"
+    needs:
+      - "bandit"
+      - "pydocstyle"
+      - "flake8"
+      - "yamllint"
+  pylint:
+    runs-on: "ubuntu-20.04"
+    steps:
+      - name: "Check out repository code"
+        uses: "actions/checkout@v2"
+      - name: "Set up Python"
+        uses: "actions/setup-python@v2"
+        with:
+          python-version: "3.9"
+      - name: "Install Python Packages for Linting"
+        run: "pip install invoke poetry toml"
+      - name: "Build Container"
+        run: "invoke build"
+      - name: "Linting: Pylint"
+        run: "invoke pylint"
+    needs:
+      - "build"
+  pytest:
+    strategy:
+      fail-fast: true
+      matrix:
+        python-version: ["3.6", "3.7", "3.8", "3.9"]
+    runs-on: "ubuntu-20.04"
+    env:
+      PYTHON_VER: "${{ matrix.python-version }}"
+    steps:
+      - name: "Check out repository code"
+        uses: "actions/checkout@v2"
+      - name: "Set up Python"
+        uses: "actions/setup-python@v2"
+        with:
+          python-version: "3.9"
+      - name: "Install Python Packages for Linting"
+        run: "pip install invoke poetry toml"
+      - name: "Build Container"
+        run: "invoke build"
+      - name: "Run Tests"
+        run: "invoke pytest"
+    needs:
+      - "pylint"
+  publish_gh:
+    name: "Publish to GitHub"
+    runs-on: "ubuntu-20.04"
+    if: "startsWith(github.ref, 'refs/tags/v')"
+    steps:
+      - name: "Check out repository code"
+        uses: "actions/checkout@v2"
+      - name: "Set up Python"
+        uses: "actions/setup-python@v2"
+        with:
+          python-version: "3.9"
+      - name: "Install Python Packages for Linting"
+        run: "pip install invoke poetry toml"
+      - name: "Set env"
+        run: "echo RELEASE_VERSION=${GITHUB_REF:10} >> $GITHUB_ENV"
+      - name: "Run Poetry Version"
+        run: "poetry version $RELEASE_VERSION"
+      - name: "Run Poetry Build"
+        run: "poetry build"
+      - name: "Upload binaries to release"
+        uses: "svenstaro/upload-release-action@v2"
+        with:
+          repo_token: "${{ secrets.NTC_GITHUB_TOKEN }}"
+          file: "dist/*"
+          tag: "${{ github.ref }}"
+          overwrite: true
+          file_glob: true
+    needs:
+      - "pytest"
+  publish_pypi:
+    name: "Push Package to PyPI"
+    runs-on: "ubuntu-20.04"
+    if: "startsWith(github.ref, 'refs/tags/v')"
+    steps:
+      - name: "Check out repository code"
+        uses: "actions/checkout@v2"
+      - name: "Set up Python"
+        uses: "actions/setup-python@v2"
+        with:
+          python-version: "3.9"
+      - name: "Install Python Packages"
+        run: "pip install poetry"
+      - name: "Set env"
+        run: "echo RELEASE_VERSION=${GITHUB_REF:10} >> $GITHUB_ENV"
+      - name: "Run Poetry Version"
+        run: "poetry version $RELEASE_VERSION"
+      - name: "Run Poetry Build"
+        run: "poetry build"
+      - name: "Push to PyPI"
+        uses: "pypa/gh-action-pypi-publish@release/v1"
+        with:
+          user: "__token__"
+          password: "${{ secrets.PYPI_API_TOKEN }}"
+    needs:
+      - "pytest"
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 436e925..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,43 +0,0 @@
----
-# Add additional stages in the order of execution here, and then under the job:include: key
-stages:
-  - "lint"
-  - "pylint"
-  - "test"
-
-if: "type IN (pull_request)" # Add in "branch" as an option if desired for branch testing as well
-language: "python"
-services:
-  - "docker"
-
-env:
-  matrix:
-    - "PYTHON_VER=3.6"
-    - "PYTHON_VER=3.7"
-    - "PYTHON_VER=3.8"
-    - "PYTHON_VER=3.9"
-before_script:
-  - "pip install invoke poetry toml"
-  - "invoke build --nocache"
-script:
-  - "invoke pytest"
-
-jobs:
-  include:
-    - stage: "lint"
-      env:
-        - "INVOKE_LOCAL=True"
-      before_script:
-        - "pip install invoke toml black bandit pydocstyle flake8 yamllint pylint"
-      script:
-        - "invoke black"
-        - "invoke bandit" # Bandit fails to function on > Py3.8 https://github.com/PyCQA/bandit/issues/639
-        - "invoke pydocstyle"
-        - "invoke flake8"
-        - "invoke yamllint"
-    - stage: "pylint"
-      before_script:
-        - "pip install invoke poetry toml"
-        - "invoke build --nocache"
-      script:
-        - "invoke pylint"
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 72a8356..fa68cc6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,30 @@
 # Changelog
 
+## v2.1.1
+
+- (#31) Migrate from Travis-CI to GitHub Actions for CI
+- (#32) Fix data population when generating configurations from the dispatcher
+
+## v2.1.0
+
+- (#26) Updates in poetry packaging for pre 1.0.0 dependencies in Nornir to allow all new up to 1.0.0 releases
+
+## v2.0.3
+
+- (#24) Change import mechanism / changes deprecated function
+
+## v2.0.1
+
+- (#20) Fixes inventory failure when platform is not defined for a device
+## v2.0.0
+
+- (#18) Migrates functions to new NTC netutils library, which is removing methods previously available:
+  - compliance
+  - make_folder
+  - hostname_resolves
+  - test_tcp_port
+  - is_ip
+
 ## v0.1.0 - 2020-12-27
 
 Initial release
diff --git a/README.md b/README.md
index 3a71d9b..995d4f5 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,12 @@
 # nornir_nautobot
 
+[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/ambv/black)
+
+## Build Status
+
+| Branch  | Status                                                                                                                               |
+| ------- | ------------------------------------------------------------------------------------------------------------------------------------ |
+| develop | [![CI](https://github.com/nautobot/nornir-nautobot/actions/workflows/ci.yml/badge.svg)](https://github.com/nautobot/nornir-nautobot/actions/workflows/ci.yml) |
 ## Overview
 
 The nornir_nautobot project intends to solve two primary use cases.
@@ -7,9 +14,7 @@ The nornir_nautobot project intends to solve two primary use cases.
 * Providing a Nornir inventory that leverages Nautobot's API.
 * A set of opinionated Nornir plugins.
 
-The set of plugins intended to provide mechanisms to include common networking workflows that will help enable network automation. As
-as example, there are method to get configurations or test network connectivity. Over time this will include functions to perform
-actions such as get vlans, neighbors, protocols, etc.
+The set of plugins intend to provide mechanisms to include common networking workflows that will help enable network automation. As an example, there are method to get configurations or test network connectivity. Over time this will include functions to perform actions such as get vlans, neighbors, protocols, etc.
 
 ## Getting Started
 
@@ -17,91 +22,10 @@ actions such as get vlans, neighbors, protocols, etc.
 pip install nornir-nautobot
 ```
 
-### 
-
-To get started without a configuration file:
-
-```python
-    nornir_obj = InitNornir(
-        inventory={
-            "plugin": "NautobotInventory",
-            "options": {
-                "nautobot_url": os.getenv("NAUTOBOT_URL"),
-                "nautobot_token": os.getenv("NAUTBOT_TOKEN"),
-                "ssl_verify": False,
-            },
-        },
-    )
-```
-
-1. As part of the initialization of the Nornir object, include the inventory key
-2. Set the plugin to the name of `NautobotInventory`
-3. Set the required options (if not already set via environment variables)
-
-Accepted options include:
-
-| Option            | Parameter         | Value                                                                                 | Default             |
-| ----------------- | ----------------- | ------------------------------------------------------------------------------------- | ------------------- |
-| Nautobot URL      | nautobot_url      | String - The base url of Nautobot (`http://localhost:8000` or `https://nautobot_url`) | env(NAUTOBOT_URL)   |
-| Nautobot Token    | nautobot_token    | String - The token to authenticate to Nautobot API                                    | env(NAUTOBOT_TOKEN) |
-| SSL Verify        | ssl_verify        | Boolean - True or False to verify SSL                                                 | True                |
-| Filter Parameters | filter_parameters | Dictionary - Key/value pairs corresponding to Nautobot API searches                   | {}                  |
-
-
-## Testing
-
-In the early stages of testing since pynautobot is not available in a public state yet, it will be included via the `tests/packages` directory. This is **not** intended to be part of the actual packaging when things go live.
-
-## Construct
-
-Pynautobot will provide for the basic information that is required for Nornir to be able to leverage the inventory. The pynautobot object will also be made available at `host.data.pynautobot_object` to be able to access information provided from the _dcim devices_ endpoint.
-
-
-## Task Plugins
-
-The only task plugin currently is the "dispatcher" plugin. This plugin dispatches to the more specific OS specific functions. To demonstrate the primary components of the code:
-
-#### Dispatcher Sender
-
-```python
-    try:
-        driver_task = getattr(driver_class, method)
-    except AttributeError:
-        logger.log_failure(obj, f"Unable to locate the method {method} for {driver}")
-        raise NornirNautobotException()
-
-    result = task.run(task=driver_task, *args, **kwargs)
-```
-
-#### Dispatcher Receiver
-
-```python
-class NautobotNornirDriver:
-    """Default collection of Nornir Tasks based on Napalm."""
-
-    @staticmethod
-    def get_config(task: Task, backup_file: str, *args, **kwargs) -> Result:
-```
-
-#### Calling Dispatcher
-
-```python
-task.run(
-    task=dispatcher,
-    name="SAVE BACKUP CONFIGURATION TO FILE",
-    method="get_config",
-    obj=obj,
-    logger=logger,
-    backup_file=backup_file,
-    remove_lines=global_settings,
-    substitute_lines=substitute_lines,
-)
-```
-
-The dispatcher expects the two primary objects, the `obj` and `logger` objects. The `obj` object should be a Device model instance. The logger should be `NornirLogger` instance which is imported from `nornir_nautobot.utils.logger`. This logging object optionally takes in a Nautobot job_result object. This is for use within the Nautobot platform Jobs. 
+## Documentation Link
 
-Each task will raise a `NornirNautobotException` for known issues. Using a custom processor, the user can predict when it was an well known error.
+The documentation can be found on [Read the Docs](https://nornir-nautobot.readthedocs.io/en/latest/)
 
-## Processor Plugins
+## Nautobot
 
-Provided for convenience within the `nornir_nautobot.plugins.processors` is the `BaseProcessor` and `BaseLoggingProcessor` as boilerplate code for creating a custom processor.
+Nautobot documentation is available at [Nautobot Read the Docs](https://nautobot.readthedocs.io/en/latest/)
diff --git a/docs/extra.css b/docs/extra.css
new file mode 100644
index 0000000..85d51a1
--- /dev/null
+++ b/docs/extra.css
@@ -0,0 +1,19 @@
+/* Images */
+img {
+    display: block;
+    margin-left: auto;
+    margin-right: auto;
+}
+
+/* Tables */
+table {
+    margin-bottom: 24px;
+    width: 100%;
+}
+th {
+    background-color: #f0f0f0;
+    padding: 6px;
+}
+td {
+    padding: 6px;
+}
\ No newline at end of file
diff --git a/docs/index.md b/docs/index.md
index 4d4bf70..60fc7f1 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -14,4 +14,16 @@ pip install nornir-nautobot
 
 The inventory plugin is used to gather inventory from a Nautobot instance. This queries the DCIM endpoint to gather information about the devices.  
 
-[Using Inventory](inventory/inventory.md)
+[Inventory](inventory/inventory.md)
+
+## Processor Plugin
+
+This is an opinionated plugin to help with network automation workflows with Nautobot.
+
+[Processor Plugin](processor/processor.md)
+
+## Task Plugin
+
+The task plugin helps with dispatching specific functions with multiple underlying OS.
+
+[Task Plugin](task/task.md)
diff --git a/docs/common_issues.md b/docs/inventory/common_issues.md
similarity index 100%
rename from docs/common_issues.md
rename to docs/inventory/common_issues.md
diff --git a/docs/inventory/inventory.md b/docs/inventory/inventory.md
index 6033a8a..d24bf2f 100644
--- a/docs/inventory/inventory.md
+++ b/docs/inventory/inventory.md
@@ -6,12 +6,12 @@ Nornir Inventory takes several configuration options, but can be executed withou
 
 There are two required parameters that may be loaded either through configuration or through the environment. 
 
-| Parameter         | Required | Default | Environment Variable |
-| ----------------- | -------- | ------- | -------------------- |
-| nautobot_url      | True     |         | NAUTOBOT_URL         |
-| nautobot_token    | True     |         | NAUTOBOT_TOKEN       |
-| filter_parameters | False    |         |                      |
-| ssl_verify        | False    | True    |                      |
+| Option            | Parameter         | Value                                                                                           | Default             | Environment Variable |
+| ----------------- | ----------------- | ----------------------------------------------------------------------------------------------- | ------------------- | -------------------- |
+| Nautobot URL      | nautobot_url      | Required: String - The base url of Nautobot (`http://localhost:8000` or `https://nautobot_url`) | env(NAUTOBOT_URL)   | NAUTOBOT_URL         |
+| Nautobot Token    | nautobot_token    | Required: String - The token to authenticate to Nautobot API                                    | env(NAUTOBOT_TOKEN) | NAUTOBOT_TOKEN       |
+| SSL Verify        | ssl_verify        | Boolean - True or False to verify SSL                                                           | True                |                      |
+| Filter Parameters | filter_parameters | Dictionary - Key/value pairs corresponding to Nautobot API searches                             | {}                  |                      |
 
 ## Using Inventory
 
@@ -27,22 +27,9 @@ nornir_obj = InitNornir(
 )
 ```
 
-### Initialization via Configuration
+## Construct
 
-This example shows providing configuration options to set the URL statically, load the configuration of the TOKEN via the environment. This also has SSL verification disabled if required.
-
-```python
-my_nornir = InitNornir(
-    inventory={
-        "plugin": "NautobotInventory",
-        "options": {
-            "nautobot_url": "http://nautobot.example.com",
-            "nautobot_token": os.getenv("NAUTBOT_TOKEN"),
-            "ssl_verify": False,
-        },
-    },
-)
-```
+Pynautobot will provide for the basic information that is required for Nornir to be able to leverage the inventory. The pynautobot object will also be made available at `host.data.pynautobot_object` to be able to access information provided from the _dcim devices_ endpoint.
 
 ## Filtering
 
diff --git a/docs/processor/processor.md b/docs/processor/processor.md
new file mode 100644
index 0000000..9db5d52
--- /dev/null
+++ b/docs/processor/processor.md
@@ -0,0 +1,3 @@
+# Processor Plugins
+
+Provided for convenience within the `nornir_nautobot.plugins.processors` is the `BaseProcessor` and `BaseLoggingProcessor` as boilerplate code for creating a custom processor.
\ No newline at end of file
diff --git a/docs/task/task.md b/docs/task/task.md
new file mode 100644
index 0000000..fb1146c
--- /dev/null
+++ b/docs/task/task.md
@@ -0,0 +1,44 @@
+# Task Plugins
+
+The only task plugin currently is the "dispatcher" plugin. This plugin dispatches to the more specific OS specific functions. To demonstrate the primary components of the code:
+
+## Dispatcher Sender
+
+```python
+    try:
+        driver_task = getattr(driver_class, method)
+    except AttributeError:
+        logger.log_failure(obj, f"Unable to locate the method {method} for {driver}")
+        raise NornirNautobotException()
+
+    result = task.run(task=driver_task, *args, **kwargs)
+```
+
+## Dispatcher Receiver
+
+```python
+class NautobotNornirDriver:
+    """Default collection of Nornir Tasks based on Napalm."""
+
+    @staticmethod
+    def get_config(task: Task, backup_file: str, *args, **kwargs) -> Result:
+```
+
+## Calling Dispatcher
+
+```python
+task.run(
+    task=dispatcher,
+    name="SAVE BACKUP CONFIGURATION TO FILE",
+    method="get_config",
+    obj=obj,
+    logger=logger,
+    backup_file=backup_file,
+    remove_lines=global_settings,
+    substitute_lines=substitute_lines,
+)
+```
+
+The dispatcher expects the two primary objects, the `obj` and `logger` objects. The `obj` object should be a Device model instance. The logger should be `NornirLogger` instance which is imported from `nornir_nautobot.utils.logger`. This logging object optionally takes in a Nautobot job_result object. This is for use within the Nautobot platform Jobs. 
+
+Each task will raise a `NornirNautobotException` for known issues. Using a custom processor, the user can predict when it was an well known error.
diff --git a/mkdocs.yml b/mkdocs.yml
new file mode 100644
index 0000000..11534d9
--- /dev/null
+++ b/mkdocs.yml
@@ -0,0 +1,12 @@
+---
+site_name: "Nornir Nautobot Documentation"
+site_url: "https://nornir-nautobot.readthedocs.io"
+repo_url: "https://github.com/nautobot/nornir-nautobot"
+theme:
+  name: "readthedocs"
+  navigation_depth: 3
+nav:
+  - Introduction: "index.md"
+  - Inventory Plugin: "inventory/inventory.md"
+  - Processor Plugin: "processor/processor.md"
+  - Task Plugin: "task/task.md"
diff --git a/nornir_nautobot/plugins/inventory/nautobot.py b/nornir_nautobot/plugins/inventory/nautobot.py
index 046ba0a..f681c48 100644
--- a/nornir_nautobot/plugins/inventory/nautobot.py
+++ b/nornir_nautobot/plugins/inventory/nautobot.py
@@ -24,7 +24,8 @@
 logger = logging.getLogger(__name__)
 
 
-def _set_host(data: Dict[str, Any], name: str, groups, host) -> Host:
+def _set_host(data: Dict[str, Any], name: str, groups, host, defaults: Defaults) -> Host:
+    host_platform = getattr(data["pynautobot_object"].platform, "slug", None)
     connection_option = {}
     for key, value in data.get("connection_options", {}).items():
         connection_option[key] = ConnectionOptions(
@@ -32,37 +33,41 @@ def _set_host(data: Dict[str, Any], name: str, groups, host) -> Host:
             port=value.get("port"),
             username=value.get("username"),
             password=value.get("password"),
-            platform=host.get("platform", {}).get("slug"),
+            platform=host_platform,
             extras=value.get("extras"),
         )
+
     return Host(
         name=name,
         hostname=host["hostname"],
         username=host.get("username"),
         password=host.get("password"),
-        platform=host.get("platform", {}).get("slug"),
+        platform=host_platform,
         data=data,
         groups=groups,
+        defaults=defaults,
         connection_options=connection_option,
     )
 
 
 # Setup connection to Nautobot
-class NautobotInventory:
+class NautobotInventory:  # pylint: disable=R0902
     """Nautobot Nornir Inventory."""
 
-    def __init__(
+    def __init__(  # pylint: disable=R0913
         self,
         nautobot_url: Union[str, None],
         nautobot_token: Union[str, None],
         ssl_verify: Union[bool, None] = True,
         filter_parameters: Union[Dict[str, Any], None] = None,
+        pynautobot_dict: Union[bool, None] = True,
     ) -> None:
         """Nautobot nornir class initialization."""
         self.nautobot_url = nautobot_url or os.getenv("NAUTOBOT_URL")
         self.nautobot_token = nautobot_token or os.getenv("NAUTOBOT_TOKEN")
         self.filter_parameters = filter_parameters
         self.ssl_verify = ssl_verify
+        self.pynautobot_dict = pynautobot_dict
         self._verify_required()
         self._api_session = None
         self._devices = None
@@ -140,7 +145,8 @@ def load(self) -> Inventory:
             host["data"]["pynautobot_object"] = device
 
             # Create dictionary object available for filtering
-            host["data"]["pynautobot_dictionary"] = dict(device)
+            if self.pynautobot_dict:
+                host["data"]["pynautobot_dictionary"] = dict(device)
             # TODO: #3 Investigate Nornir compatability with dictionary like object
 
             # Add Primary IP address, if found. Otherwise add hostname as the device name
@@ -152,7 +158,11 @@ def load(self) -> Inventory:
 
             # Add host to hosts by name first, ID otherwise - to string
             hosts[device.name or str(device.id)] = _set_host(  # pylint: disable=unsupported-assignment-operation
-                data=host["data"], name=host["name"], groups=host["groups"], host=host
+                data=host["data"],
+                name=host["name"],
+                groups=host["groups"],
+                host=host,
+                defaults=defaults,
             )
 
         return Inventory(hosts=hosts, groups=groups, defaults=defaults)
diff --git a/nornir_nautobot/plugins/tasks/dispatcher/__init__.py b/nornir_nautobot/plugins/tasks/dispatcher/__init__.py
index ceadb7a..d93a39b 100644
--- a/nornir_nautobot/plugins/tasks/dispatcher/__init__.py
+++ b/nornir_nautobot/plugins/tasks/dispatcher/__init__.py
@@ -10,12 +10,13 @@
 LOGGER = logging.getLogger(__name__)
 
 _DEFAULT_DRIVERS_MAPPING = {
-    "default": "nornir_nautobot.plugins.tasks.dispatcher.default",
-    "cisco_nxos": "nornir_nautobot.plugins.tasks.dispatcher.cisco_nxos",
-    "cisco_ios": "nornir_nautobot.plugins.tasks.dispatcher.cisco_ios",
-    "cisco_xr": "nornir_nautobot.plugins.tasks.dispatcher.cisco_xr",
-    "juniper_junos": "nornir_nautobot.plugins.tasks.dispatcher.juniper_junos",
-    "arista_eos": "nornir_nautobot.plugins.tasks.dispatcher.arista_eos",
+    "default": "nornir_nautobot.plugins.tasks.dispatcher.default.NautobotNornirDriver",
+    "default_netmiko": "nornir_nautobot.plugins.tasks.dispatcher.default.NetmikoNautobotNornirDriver",
+    "cisco_nxos": "nornir_nautobot.plugins.tasks.dispatcher.cisco_nxos.NautobotNornirDriver",
+    "cisco_ios": "nornir_nautobot.plugins.tasks.dispatcher.cisco_ios.NautobotNornirDriver",
+    "cisco_xr": "nornir_nautobot.plugins.tasks.dispatcher.cisco_xr.NautobotNornirDriver",
+    "juniper_junos": "nornir_nautobot.plugins.tasks.dispatcher.juniper_junos.NautobotNornirDriver",
+    "arista_eos": "nornir_nautobot.plugins.tasks.dispatcher.arista_eos.NautobotNornirDriver",
 }
 
 
@@ -31,6 +32,7 @@ def dispatcher(task: Task, method: str, logger, obj, *args, **kwargs) -> Result:
     """
     if kwargs.get("default_drivers_mapping"):
         default_drivers_mapping = kwargs["default_drivers_mapping"]
+        del kwargs["default_drivers_mapping"]
     else:
         default_drivers_mapping = _DEFAULT_DRIVERS_MAPPING
 
@@ -44,7 +46,8 @@ def dispatcher(task: Task, method: str, logger, obj, *args, **kwargs) -> Result:
         logger.log_failure(obj, f"Unable to find the driver for {method} for platform: {task.host.platform}")
         raise NornirNautobotException()
 
-    driver_class = getattr(importlib.import_module(driver), "NautobotNornirDriver")
+    module_name, class_name = driver.rsplit(".", 1)
+    driver_class = getattr(importlib.import_module(module_name), class_name)
 
     if not driver_class:
         logger.log_failure(obj, f"Unable to locate the class {driver}")
diff --git a/nornir_nautobot/plugins/tasks/dispatcher/default.py b/nornir_nautobot/plugins/tasks/dispatcher/default.py
index f465e49..f05809b 100644
--- a/nornir_nautobot/plugins/tasks/dispatcher/default.py
+++ b/nornir_nautobot/plugins/tasks/dispatcher/default.py
@@ -2,7 +2,6 @@
 # pylint: disable=raise-missing-from,too-many-arguments
 
 import os
-import re
 import socket
 import jinja2
 
@@ -12,12 +11,15 @@
 from nornir_jinja2.plugins.tasks import template_file
 from nornir_napalm.plugins.tasks import napalm_get
 from nornir_netmiko.tasks import netmiko_send_command
-
+from netutils.config.compliance import compliance
+from netutils.config.clean import clean_config, sanitize_config
+from netutils.ip import is_ip
+from netutils.dns import is_fqdn_resolvable
+from netutils.ping import tcp_ping
 
 from nornir_nautobot.exceptions import NornirNautobotException
+from nornir_nautobot.utils.helpers import make_folder
 
-from .utils.compliance import compliance
-from .utils.functions import make_folder, hostname_resolves, test_tcp_port, is_ip
 
 RUN_COMMAND_MAPPING = {
     "default": "show run",
@@ -64,11 +66,11 @@ def get_config(task: Task, logger, obj, backup_file: str, remove_lines: list, su
         running_config = result[0].result.get("config", {}).get("running", None)
         if remove_lines:
             logger.log_debug("Removing lines from configuration based on `remove_lines` definition")
-            running_config = _remove_lines(running_config, remove_lines)
+            running_config = clean_config(running_config, remove_lines)
 
         if substitute_lines:
             logger.log_debug("Substitute lines from configuration based on `substitute_lines` definition")
-            running_config = _substitute_lines(running_config, substitute_lines)
+            running_config = sanitize_config(running_config, substitute_lines)
 
         make_folder(os.path.dirname(backup_file))
 
@@ -91,14 +93,14 @@ def check_connectivity(task: Task, logger, obj) -> Result:
         if is_ip(task.host.hostname):
             ip_addr = task.host.hostname
         else:
-            if not hostname_resolves(task.host.hostname):
+            if not is_fqdn_resolvable(task.host.hostname):
                 logger.log_failure(obj, "not an IP or resolvable.")
                 raise NornirNautobotException("not an IP or resolvable.")
             ip_addr = socket.gethostbyname(task.host.hostname)
 
         # TODO: Allow port to be configurable
         port = 22
-        if not test_tcp_port(ip_addr, port):
+        if not tcp_ping(ip_addr, port):
             logger.log_failure(obj, f"Attempting to connect to IP: {ip_addr} and port: {port} failed.")
             raise NornirNautobotException(f"Attempting to connect to IP: {ip_addr} and port: {port} failed.")
         if not task.host.username:
@@ -162,9 +164,8 @@ def generate_config(
         """
         try:
             filled_template = task.run(
-                **task.host.data,
+                **task.host,
                 task=template_file,
-                name="JINJA TEMPLATE CREATION",
                 template=jinja_template,
                 path=jinja_root_path,
             )[0].result
@@ -245,60 +246,13 @@ def get_config(task: Task, logger, obj, backup_file: str, remove_lines: list, su
 
         if remove_lines:
             logger.log_debug("Removing lines from configuration based on `remove_lines` definition")
-            running_config = _remove_lines(running_config, remove_lines)
+            running_config = clean_config(running_config, remove_lines)
         if substitute_lines:
             logger.log_debug("Substitute lines from configuration based on `substitute_lines` definition")
-            running_config = _substitute_lines(running_config, substitute_lines)
+            running_config = sanitize_config(running_config, substitute_lines)
 
         make_folder(os.path.dirname(backup_file))
 
         with open(backup_file, "w") as filehandler:
             filehandler.write(running_config)
         return Result(host=task.host, result={"config": running_config})
-
-
-def _remove_lines(config, remove_lines):
-    """Method to remove any lines that are required to be removed.
-
-    Args:
-        config (str): A string that represent the configuration of a device.
-        remove_lines (list): A list of regex strings, that get converted to raw regex.
-
-    Returns:
-        config: The parse configuration, which is absent of any matches from remove_lines.
-    """
-    for removal in remove_lines:
-        config = re.sub(fr"{removal}", "", config, flags=re.MULTILINE)
-    return config
-
-
-def _substitute_lines(config, substitute_lines):
-    r"""Method to substitute any lines, the primary use case is removing secrets.
-
-    Args:
-        config (str): A string that represent the configuration of a device.
-        substitute_lines (list): List of dictionaries representing the replacement. Each list item is a dictionary in the
-        {
-            "regex_replacement": "<redacted_config>",
-            "regex_search": "username\\s+\\S+\\spassword\\s+5\\s+(\\S+)\\s+role\\s+\\S+"
-        }
-
-    Returns:
-        config: The parse configuration, which has the lines swapped based on regex replacements.
-    """
-    if substitute_lines:
-        new_config = ""
-
-        # Loop through the config lines
-        for line in config.split("\n"):
-            # Loop through the replacement list on each line in the config
-            for item in substitute_lines:
-                if re.match(pattern=fr"{item['regex_search']}", string=line):
-                    line = line.replace(
-                        re.match(pattern=fr"{item['regex_search']}", string=line).groups()[0], item["regex_replacement"]
-                    )
-
-                new_config += line.rstrip() + "\n"
-
-        config = new_config
-    return config
diff --git a/nornir_nautobot/plugins/tasks/dispatcher/utils/compliance.py b/nornir_nautobot/plugins/tasks/dispatcher/utils/compliance.py
deleted file mode 100644
index 87870cc..0000000
--- a/nornir_nautobot/plugins/tasks/dispatcher/utils/compliance.py
+++ /dev/null
@@ -1,376 +0,0 @@
-"""Filter Plugins for compliance checks."""
-
-from . import parser  # pylint: disable=relative-beyond-top-level
-
-parser_map = {
-    "arista_eos": parser.EOSConfigParser,
-    "cisco_ios": parser.IOSConfigParser,
-    "cisco_nxos": parser.NXOSConfigParser,
-    "cisco_aireos": parser.AIREOSConfigParser,
-    "linux": parser.LINUXConfigParser,
-    "bigip_f5": parser.F5ConfigParser,
-    "juniper_junos": parser.JunosConfigParser,
-}
-
-default_feature = {
-    "compliant": None,
-    "missing": None,
-    "extra": None,
-    "cannot_parse": True,
-    "unordered_compliant": None,
-    "ordered_compliant": None,
-    "actual": None,
-    "intended": None,
-}
-
-# TODO: Update doc string examples to reflect the how the functions currently work
-def section_config(feature, device_cfg, network_os):
-    """Parse feature section config from device cfg.
-
-        In case section attribute of the the feature is not provided
-        entire content of the device_cfg is returned.
-
-    Args:
-        feature (dict): Feature name and cfg lines that should be parsed.
-        device_cfg (str): Device configuration.
-        network_os (str): Device network operating system.
-
-    Returns:
-        list: The hash report data mapping file hashes to report data.
-
-    Example:
-        >>> feature
-        ... {
-        ...    "name": "BGP",
-        ...    "section": [
-        ...        "router bgp "
-        ...    ]
-        ... }
-        >>> print(device_cfg)
-        ... router bgp 100
-        ...  bgp router-id 10.6.6.5
-        ... !
-        ... snmp-server ifindex persist
-        ... snmp-server packetsize 4096
-        ... snmp-server location BOMI/ITAJAI
-        ... access-list 1 permit 10.22.142.132
-        ... access-list 1 permit 10.22.143.189
-        >>>
-        >>> section_config(feature, device_cfg, "ios")
-        ... router bgp 100
-        ...  bgp router-id 10.6.6.5
-        >>>
-    """
-    section_starts_with = feature.get("section")
-    if not section_starts_with:
-        return device_cfg
-
-    match = False
-    section_config_list = []
-    os_parser = parser_map[network_os]
-    config_parsed = os_parser(device_cfg)
-    for line in config_parsed.config_lines:
-        if match:
-            if line.parents:  # pylint: disable=no-else-continue
-                section_config_list.append(line.config_line)
-                continue
-            else:
-                match = False
-        for line_start in section_starts_with:
-            if not match and line.config_line.startswith(line_start):
-                section_config_list.append(line.config_line)
-                match = True
-    return "\n".join(section_config_list).strip()
-
-
-def compliance(features, backup, intended, network_os):
-    r"""Report compliance for all features provided as input.
-
-    Args:
-        features (list): List of features for particular network os.
-        backup (path): running config or config backup file  to compare against intended.
-        intended (path): intended config to compare against backup.
-        network_os (str): Device network operating system.
-
-    Returns:
-        dict: Compliance information per feature.
-
-    Example:
-        >>> features
-        ... [
-        ...     {
-        ...         "name": "hostname",
-        ...         "section": [
-        ...             "hostname"
-        ...         ]
-        ...     },
-        ...     {
-        ...         "name": "ntp",
-        ...         "section": [
-        ...             "ntp"
-        ...         ]
-        ...     },
-        ...     {
-        ...         "name": "local_users",
-        ...         "section": [
-        ...             "username",
-        ...             "role network-limited"
-        ...         ]
-        ...     }
-        ... ]
-        >>> backup = "my/path/to/backup/file.cfg"
-        >>> intended = "my/path/to/intended/config.cfg"
-        >>> network_os = "aruba"
-        >>> compliance(features, backup, intended, network_os)
-        ... {
-        ...     "hostname": {
-        ...         "cannot_parse": false,
-        ...         "compliant": true,
-        ...         "existing": "hostname R1",
-        ...         "golden": "hostname R1",
-        ...         "not_required": null,
-        ...         "required": null,
-        ...         "unordered_compliant": null
-        ...     },
-        ...     "ntp": {
-        ...         "cannot_parse": false,
-        ...         "compliant": false,
-        ...         "existing": "ntp server 192.168.1.1\nntp server 192.168.1.2 prefer",
-        ...         "golden": "ntp server 192.168.1.1\nntp server 192.168.1.5 prefer",
-        ...         "not_required": "ntp server 192.168.1.2 prefer",
-        ...         "required": "ntp server 192.168.1.5 prefer",
-        ...         "unordered_compliant": false
-        ...     }
-        ... }
-    """
-    backup_cfg = open_file_config(backup)
-    intended_cfg = open_file_config(intended)
-
-    compliance_results = dict()
-
-    for feature in features:
-
-        feature_compliance = default_feature.copy()
-        backup_feature = section_config(feature, backup_cfg, network_os)
-        intended_feature = section_config(feature, intended_cfg, network_os)
-
-        feature_compliance["actual"] = backup_feature
-        feature_compliance["intended"] = intended_feature
-
-        feature_compliance["ordered_compliant"] = _is_feature_ordered_compliant(intended_feature, backup_feature)
-
-        if feature_compliance["ordered_compliant"]:
-            feature_compliance.update(
-                {
-                    "missing": "",
-                    "extra": "",
-                    "unordered_compliant": True,
-                }
-            )
-        else:
-            if backup_feature and intended_feature:
-                feature_compliance.update(_check_configs_differences(intended_feature, backup_feature, network_os))
-        if feature["ordered"] is True:
-            feature_compliance["compliant"] = feature_compliance["ordered_compliant"]
-        elif feature["ordered"] is False:
-            feature_compliance["compliant"] = feature_compliance["unordered_compliant"]
-        else:
-            raise  # pylint: disable=misplaced-bare-raise
-        compliance_results.update({feature["name"]: feature_compliance})
-    return compliance_results
-
-
-def _is_feature_ordered_compliant(feature_intended_cfg, feature_actual_cfg):
-    """Check if feature intended cfg is compliant with feature actual cfg.
-
-    Args:
-        feature_intended_cfg (str): Feature intended configuration.
-        feature_actual_cfg: (str): Feature actual configuration.
-
-    Returns:
-        bool
-
-    Example:
-        >>> print(feature_intended_cfg)
-        ... router bgp 100
-        ...  bgp router-id 10.6.6.5
-        >>>
-        >>> print(feature_actual_cfg)
-        ... router bgp 100
-        ...  bgp router-id 10.6.6.5
-        >>>
-        >>> print(_is_feature_compliant(feature_intended_cfg, feature_actual_cfg))
-        ... True
-        >>>
-    """
-    if not feature_intended_cfg and not feature_actual_cfg:
-        return True
-    if feature_intended_cfg == feature_actual_cfg:
-        return True
-    return False
-
-
-def _check_configs_differences(intended_cfg, actual_cfg, network_os):
-    r"""Find differences between intended and actual config lines.
-
-    Args:
-        intended_cfg (str): Feature intended configuration.
-        actual_cfg: (str): Feature actual configuration.
-        network_os (str): Device network operating system.
-
-    Returns:
-        dict: Config fragments that are missing, extra or unordered_compliant.
-
-    Example:
-        >>> print(intended_cfg)
-        ... ntp server 10.10.10.10
-        ... ntp server 10.10.10.11
-        >>>
-        >>> print(actual_cfg)
-        ... ntp server 10.10.10.10
-        ... ntp server 192.168.0.1
-        >>>
-        >>> _check_configs_differences(intended_cfg, actual_cfg, network_os)
-        ... {
-        ...     "missing": "ntp server 10.10.10.11",
-        ...     "extra": "ntp server 192.168.0.1",
-        ...     "unordered_compliant": False,
-        ... }
-        >>>
-    """
-    missing = ntc_diff_network_config(intended_cfg, actual_cfg, network_os)
-    extra = ntc_diff_network_config(actual_cfg, intended_cfg, network_os)
-    if not missing and not extra:
-        unordered_compliant, _ = find_unordered_cfg_lines(intended_cfg, actual_cfg)
-    else:
-        unordered_compliant = False
-    return {
-        "missing": missing,
-        "extra": extra,
-        "unordered_compliant": unordered_compliant,
-    }
-
-
-def find_unordered_cfg_lines(intended_cfg, actual_cfg):
-    """Check if config lines are miss-ordered, i.e in ACL-s.
-
-    Args:
-        intended_cfg (str): Feature intended configuration.
-        actual_cfg: (str): Feature actual configuration.
-
-    Returns:
-        list: List of tuples with unordered_compliant cfg lines.
-
-    Example:
-        >>> print(intended_cfg)
-        ... ntp server 10.10.10.10
-        ... ntp server 10.10.10.11
-        ... ntp server 10.10.10.12
-        >>>
-        >>> print(actual_cfg)
-        ... ntp server 10.10.10.12
-        ... ntp server 10.10.10.11
-        ... ntp server 10.10.10.10
-        >>>
-        >>> find_unordered_compliant_cfg_lines(intended_cfg, actual_cfg)
-        ... [
-        ...     ("ntp server 10.10.10.10", "ntp server 10.10.10.12"),
-        ...     ("ntp server 10.10.10.12", "ntp server 10.10.10.10")
-        ... ]
-        >>>
-    """
-    intended_lines = intended_cfg.splitlines()
-    actual_lines = actual_cfg.splitlines()
-    unordered_lines = list()
-    if len(intended_lines) == len(actual_lines):
-        # Process to find actual lines that are misordered
-        unordered_lines = [(e1, e2) for e1, e2 in zip(intended_lines, actual_lines) if e1 != e2]
-    # Process to find determine if there are any different lines, regardless of order
-    if not set(intended_lines).difference(actual_lines):
-        return (True, unordered_lines)
-    return (False, unordered_lines)
-
-
-def config_section_not_parsed(features, device_cfg, network_os):
-    """Return device config section that is not checked by compliance.
-
-    Args:
-        features (list): List of features for particular network os.
-        device_cfg (str): Device configuration.
-        network_os (str): Device network operating system.
-
-    Returns:
-        dict: Config that was not parsed or section not found.
-
-    Example:
-        >>> features
-        ... [{
-        ...    "name": "BGP",
-        ...    "section": [
-        ...        "router bgp "
-        ...    ]
-        ... }]
-        >>> print(device_cfg)
-        ... router bgp 100
-        ...  bgp router-id 10.6.6.5
-        ... !
-        ... access-list 1 permit 10.10.10.10
-        ... access-list 1 permit 10.10.10.11
-        >>>
-        >>> config_section_not_parsed(features, device_cfg, network_os)
-        ... {
-        ...     "remaining_cfg":
-        ...         "access-list 1 permit 10.10.10.10
-        ...          access-list 1 permit 10.10.10.11",
-        ...     "section_not_found": []
-        ... }
-        >>>
-    """
-    remaining_cfg = device_cfg
-    section_not_found = list()
-    for feature in features:
-        feature_cfg = section_config(feature, device_cfg, network_os)
-        if not feature_cfg:
-            section_not_found.append(feature["name"])
-        remaining_cfg = remaining_cfg.replace(feature_cfg, "")
-    return {
-        "remaining_cfg": remaining_cfg.strip(),
-        "section_not_found": section_not_found,
-    }
-
-
-def open_file_config(cfg_path):
-    """Open config file from local disk."""
-    try:
-        with open(cfg_path) as filehandler:
-            device_cfg = filehandler.read()
-    except IOError:
-        return False
-    return device_cfg.strip()
-
-
-def ntc_diff_network_config(compare_config, base_config, network_os):
-    """Identify which lines in compare_config are not in base_config.
-
-    Args:
-        compare_config (str): The config to evaluate against base_config.
-        base_config (str): The config to compare compare_config against.
-        network_os (str): The OS per ansible_network_os.
-
-    Returns:
-        base_config (str): The string of additional commands in compare_config separated by a newline.
-    """
-    os_parser = parser_map[network_os]
-    compare_parser = os_parser(compare_config)
-    base_parser = os_parser(base_config)
-    base = set(base_parser.config_lines)
-
-    needed_lines = []
-    for line in compare_parser.config_lines:
-        if line not in base:
-            for parent in line.parents:
-                if parent not in needed_lines:
-                    needed_lines.append(parent)
-            needed_lines.append(line.config_line)
-
-    return "\n".join(needed_lines)
diff --git a/nornir_nautobot/plugins/tasks/dispatcher/utils/functions.py b/nornir_nautobot/plugins/tasks/dispatcher/utils/functions.py
deleted file mode 100644
index ca819c4..0000000
--- a/nornir_nautobot/plugins/tasks/dispatcher/utils/functions.py
+++ /dev/null
@@ -1,48 +0,0 @@
-"""A set of helper utilities."""
-
-import errno
-import os
-import logging
-import socket
-
-LOGGER = logging.getLogger(__name__)
-
-
-def make_folder(folder):
-    """Helper method to sanely create folders."""
-    if not os.path.exists(folder):
-        # Still try and except, since their may be race conditions.
-        try:
-            os.makedirs(folder)
-        except OSError as error:
-            if error.errno != errno.EEXIST:
-                raise
-
-
-def hostname_resolves(hostname):
-    """Helper method to check if IP resolves."""
-    try:
-        socket.gethostbyname(hostname)
-        return True
-    except socket.error:
-        return False
-
-
-def test_tcp_port(ip_addr, port):
-    """Helper method to 'ping' tcp port."""
-    sckt = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-    try:
-        sckt.connect((ip_addr, int(port)))
-        sckt.shutdown(1)
-        return True
-    except socket.error:
-        return False
-
-
-def is_ip(addr):
-    """Helper method to check is string is an IP or not."""
-    try:
-        socket.inet_aton(addr)
-        return True
-    except socket.error:
-        return False
diff --git a/nornir_nautobot/plugins/tasks/dispatcher/utils/parser.py b/nornir_nautobot/plugins/tasks/dispatcher/utils/parser.py
deleted file mode 100644
index 9b6601a..0000000
--- a/nornir_nautobot/plugins/tasks/dispatcher/utils/parser.py
+++ /dev/null
@@ -1,606 +0,0 @@
-"""Parsers for different network operating systems."""
-# pylint: disable=no-member,super-with-arguments,invalid-overridden-method,raise-missing-from,invalid-overridden-method,inconsistent-return-statements,super-with-arguments,redefined-argument-from-local,no-else-break,useless-super-delegation
-
-import re
-from collections import namedtuple
-
-ConfigLine = namedtuple("ConfigLine", "config_line,parents")
-
-
-class BaseConfigParser:  # pylint: disable=too-few-public-methods
-    """Base class for parsers."""
-
-    comment_chars = ["!"]
-    banner_start = ["banner", "vacant-message"]
-
-    def __init__(self, config):
-        """Create ConfigParser Object.
-
-        Args:
-            config (str): The config text to parse.
-        """
-        self.config = config
-        self._config = None
-        self._current_parents = ()
-        self.generator_config = (line for line in self.config_lines_only.splitlines())
-        self.config_lines = []
-        self.build_config_relationship()
-
-    def config_lines_only(self):
-        """Remove lines not related to config."""
-        raise NotImplementedError
-
-
-class BaseSpaceConfigParser(BaseConfigParser):
-    """Base parser class for config syntax that demarcates using spaces/indentation."""
-
-    comment_chars = ["!"]
-    banner_start = ["banner", "vacant-message"]
-
-    def __init__(self, config):
-        """Create ConfigParser Object.
-
-        Args:
-            config (str): The config text to parse.
-        """
-        self._indent_level = 0
-        super(BaseSpaceConfigParser, self).__init__(config)
-
-    @property
-    def indent_level(self):
-        """Count the number of spaces a config line is indented."""
-        return self._indent_level
-
-    @indent_level.setter
-    def indent_level(self, value):
-        self._indent_level = value
-
-    def is_banner_end(self, line):
-        """Determine if line ends the banner config.
-
-        Args:
-            line (str): The current config line in iteration.
-
-        Returns:
-            bool: True if line ends banner, else False.
-        """
-        if self.banner_end in line:
-            return True
-        return False
-
-    def is_banner_start(self, line):
-        """Determine if the line starts a banner config.
-
-        Args:
-            line (str): The current config line in iteration.
-
-        Returns:
-            bool: True if line starts banner, else False.
-        """
-        for banner_start in self.banner_start:
-            if line.lstrip().startswith(banner_start):
-                return True
-        return False
-
-    def is_comment(self, line):
-        """Determine if line is a comment.
-
-        Args:
-            line (str): A config line from the device.
-
-        Returns:
-            bool: True if line is a comment, else False.
-
-        Example:
-            >>> BaseConfigParser.is_comment("interface Ethernet1/1")
-            False
-            >>> BaseConfigParser.is_comment("!")
-            True
-            >>>
-        """
-        for comment_char in self.comment_chars:
-            if line.lstrip().startswith(comment_char):
-                return True
-        return False
-
-    @property
-    def config_lines_only(self):
-        """Remove spaces and comments from config lines.
-
-        Returns:
-            str: The non-space and non-comment lines from ``config``.
-
-        Example:
-            >>> config = '''
-            !
-            aaa group server tacacs+ auth
-             server 10.1.1.1
-             server 10.2.2.2
-
-            !
-            '''
-            >>> config_parser = BaseConfigParser(config)
-            >>> print(config_pareser.config_lines_only)
-            aaa group server tacacs+ auth
-             server 10.1.1.1
-             server 10.2.2.2
-            >>>
-        """
-        if self._config is None:
-            config_lines = (
-                line.rstrip()
-                for line in self.config.splitlines()
-                if line and not self.is_comment(line) and not line.isspace()
-            )
-            self._config = "\n".join(config_lines)
-        return self._config
-
-    @staticmethod
-    def get_leading_space_count(config_line):
-        """Determine how many spaces the ``config_line`` is indented.
-
-        Args:
-           config_line (str): A line of text in the config.
-
-        Returns:
-            int: The number of leading spaces.
-
-        Example:
-            >>> config_line = " description link to ISP"
-            >>> indent_level = BaseConfigParser.get_leading_space_count(config_line)
-            >>> indent_level
-            1
-            >>>
-        """
-        return len(config_line) - len(config_line.lstrip())
-
-    def _remove_parents(self, line, current_spaces):
-        """Remove parents from ``self._curent_parents`` based on indent levels.
-
-        Args:
-            config_line (str): A line of text in the config.
-
-        Returns:
-            tuple: The config lines parent config lines.
-        """
-        deindent_level = 1
-        try:
-            previous_parent = self._current_parents[-1]
-            previous_indent = self.get_leading_space_count(previous_parent)
-            while previous_indent > current_spaces:
-                deindent_level += 1
-                previous_parent = self._current_parents[-deindent_level]
-                previous_indent = self.get_leading_space_count(previous_parent)
-        except IndexError:
-            raise IndexError("\nValidate the first line does not begin with a space" "\n{}\n".format(line))
-        parents = self._current_parents[:-deindent_level] or (self._current_parents[0],)
-        return parents
-
-    def _build_banner(self, config_line):
-        """Handle banner config lines.
-
-        Args:
-            config_line (str): The start of the banner config.
-
-        Returns:
-            str: The next configuration line in the configuration text.
-            None: When banner end is the end of the config text.
-
-        Raises:
-            ValueError: When the parser is unable to identify the End of the Banner.
-        """
-        self._update_config_lines(config_line)
-        self._current_parents += (config_line,)
-        banner_config = []
-        for line in self.generator_config:
-            if not self.is_banner_end(line):
-                banner_config.append(line)
-            else:
-                line = line.replace("\x03", "^C")
-                banner_config.append(line)
-                line = "\n".join(banner_config)
-                if line.endswith("^C"):
-                    banner, end, _ = line.rpartition("^C")
-                    line = banner.rstrip() + end
-                self._update_config_lines(line)
-                self._current_parents = self._current_parents[:-1]
-                try:
-                    return next(self.generator_config)
-                except StopIteration:
-                    return None
-
-        raise ValueError("Unable to parse banner end.")
-
-    def _build_nested_config(self, line):
-        """Handle building child config sections.
-
-        Args:
-            line (str): A configuration line from the configuration text.
-
-        Returns:
-            str: The next top-level configuration line in the configuration text.
-            None: When the last line of configuration text is a nexted configuration line.
-
-        Raises:
-            IndexError: When the number of parents does not match the expected deindent level.
-        """
-        self._update_config_lines(line)
-        for line in self.generator_config:
-            if not line[0].isspace():
-                self._current_parents = ()
-                self.indent_level = 0
-                return line
-
-            spaces = self.get_leading_space_count(line)
-            if spaces == self.indent_level:
-                pass
-            elif spaces > self.indent_level:
-                previous_config = self.config_lines[-1]
-                self._current_parents += (previous_config.config_line,)
-            else:
-                self._current_parents = self._remove_parents(line, spaces)
-
-            if spaces != self.indent_level:
-                self.indent_level = spaces
-
-            if self.is_banner_start(line):
-                line = self._build_banner(line)
-                if line is None or not line[0].isspace():
-                    self._current_parents = ()
-                    self.indent_level = 0
-                    return line
-
-            self._update_config_lines(line)
-
-    def _update_config_lines(self, config_line):
-        """Add a ``ConfigLine`` object to ``self.config_lines``.
-
-        Args:
-            config_line (str): The current config line being evaluated.
-
-        Returns:
-            None
-        """
-        entry = ConfigLine(config_line, self._current_parents)
-        self.config_lines.append(entry)
-
-    def build_config_relationship(self):
-        r"""Parse text tree of config lines and their parents.
-
-        Example:
-            >>> config = (
-            ...     "interface Ethernet1/1\n"
-            ...     "  vlan 10\n"
-            ...     "  no shutdown"
-            ...     "interface Ethernet1/2\n"
-            ...     "  shutdown\n"
-            ... )
-            >>> config_tree = BaseStringConfigParser(config)
-            >>> config_tree.build_config_relationship()
-            ... [
-            ...     ConfigLine("interface Ethernet1/1\n", ()),
-            ...     ConfigLine("vlan 10\n", ("interface Ethernet1/1\n",)),
-            ...     ConfigLine("no shutdown\n", ("interface Ethernet1/1\n",)),
-            ...     ConfigLine("interface Ethernet1/2\n", ()),
-            ...     ConfigLine("shutdown\n", ("interface Ethernet1/2\n",)),
-            ... ]
-            >>>
-        """
-        for line in self.generator_config:
-            if not line[0].isspace():
-                self._current_parents = ()
-                if self.is_banner_start(line):
-                    line = self._build_banner(line)
-            else:
-                previous_config = self.config_lines[-1]
-                self._current_parents = (previous_config.config_line,)
-                self.indent_level = self.get_leading_space_count(line)
-                if not self.is_banner_start(line):
-                    line = self._build_nested_config(line)
-                else:
-                    line = self._build_banner(line)
-                    if line is not None and line[0].isspace():
-                        line = self._build_nested_config(line)
-                    else:
-                        self._current_parents = ()
-
-            if line is None:
-                break
-            elif self.is_banner_start(line):
-                line = self._build_banner(line)
-
-            self._update_config_lines(line)
-        return self.config_lines
-
-
-class BaseBraceConfigParser(BaseConfigParser):
-    """Base parser class for config syntax that demarcates using braces."""
-
-    multiline_delimiters = []
-
-    def __init__(self, config):
-        """Create ConfigParser Object.
-
-        Args:
-            config (str): The config text to parse.
-        """
-        super(BaseBraceConfigParser, self).__init__(config)
-
-    @property
-    def config_lines_only(self):
-        """Remove trailing spaces and empty lines from config lines.
-
-        Returns:
-            str: The non-space lines from ``config``.
-        """
-        config_lines = [line.rstrip() for line in self.config.splitlines() if line and not line.isspace()]
-        return "\n".join(config_lines)
-
-    def build_config_relationship(self):
-        r"""Parse text tree of config lines and their parents.
-
-        Example:
-            >>> config = (
-            ...     "auth ldap system-auth {"
-            ...     "    port ldaps"
-            ...     "    servers { ds6-rwc.gene.com }"
-            ...     "}"
-            ...     "auth partition Common {"
-            ...     "    description "Repository for system objects and shared objects.""
-            ...     "}"
-            ...     "auth password-policy { }"
-            ... )
-            >>> config_tree = BaseBraceConfigParser(config)
-            >>> config_tree.build_config_relationship()
-            ... [
-            ...     ConfigLine("auth ldap system-auth {", parents=()),
-            ...     ConfigLine("    port ldaps", parents=("auth ldap system-auth {",),
-            ...     ConfigLine("    servers { ds6-rwc.gene.com }", parents=("auth ldap system-auth {",),
-            ...     ConfigLine("}", parents=("auth ldap system-auth {",),
-            ...     ConfigLine("auth partition Common {", parents=()),
-            ...     ConfigLine("description \"Repository for system objects and shared objects.\"", parents=("auth partition Common {",)),
-            ...     ConfigLine("}", parents=("auth partition Common {",)),
-            ...     ConfigLine("auth password-policy { }", parents=()),
-            ... ]
-            >>>
-        """
-        for line in self.generator_config:
-            self.config_lines.append(ConfigLine(line, self._current_parents))
-            line_end = line[-1]
-            if line.endswith("{"):
-                self._current_parents += (line,)
-            elif line.lstrip() == "}":
-                self._current_parents = self._current_parents[:-1]
-            elif line_end in self.multiline_delimiters and line.count(line_end) == 1:
-                self._current_parents += (line,)
-                self._build_multiline_config(line_end)
-
-        return self.config_lines
-
-    def _build_multiline_config(self, delimiter):
-        r"""Build config sections between characters demarcating multiline strings.
-
-        Args:
-            delimiter (str): The text to look for to end multiline config.
-
-        Returns:
-            ConfigLine: The multiline string text that was added to ``self.config_lines``.
-
-        Example:
-            >>> config = (
-            ...     'sys syslog {\n'
-            ...     '    include "\n'
-            ...     '        filter f_local0 {\n'
-            ...     '        facility(local0) and not match(\"DEBUG");\n'
-            ...     '    "\n'
-            ...     '}'
-            ... )
-            >>> parser = BaseBraceConfigParser(config)
-            >>> # '    include "' started a multiline config
-            >>> print(parser.config_lines)
-            ... [
-            ...     ConfigLine('sys syslog {', ()),
-            ...     ConfigLine('    include "', ('sys syslog {',)),
-            ...     ConfigLine('        filter flocal0 {\n        facility(local0 and not match(\"Debug");\n    "', ('sys syslog {', '    include "')),
-            ...     ConfigLine('}', ('sys syslog {',))
-            ... ]
-            >>>
-        """
-        multiline_config = []
-        for line in self.generator_config:
-            multiline_config.append(line)
-            if line.lstrip() == delimiter:
-                multiline_entry = ConfigLine("\n".join(multiline_config), self._current_parents)
-                self.config_lines.append(multiline_entry)
-                self._current_parents = self._current_parents[:-1]
-                return multiline_entry
-
-
-class CiscoConfigParser(BaseSpaceConfigParser):
-    """Cisco Implementation of ConfigParser Class."""
-
-    regex_banner = re.compile(r"^(banner\s+\S+|\s*vacant-message)\s+(?P<banner_delimiter>\^C|\x03)")
-
-    def __init__(self, config):
-        """Create ConfigParser Object.
-
-        Args:
-            config (str): The config text to parse.
-        """
-        self._banner_end = None
-        super(CiscoConfigParser, self).__init__(config)
-
-    def _build_banner(self, config_line):
-        """Handle banner config lines.
-
-        Args:
-            config_line (str): The start of the banner config.
-
-        Returns:
-            str: The next configuration line in the configuration text.
-            None: When banner end is the end of the config text.
-
-        Raises:
-            ValueError: When the parser is unable to identify the End of the Banner.
-        """
-        if self.is_banner_one_line(config_line):
-            self._update_config_lines(config_line)
-            try:
-                return next(self.generator_config)
-            except StopIteration:
-                return None
-        return super(CiscoConfigParser, self)._build_banner(config_line)
-
-    def is_banner_one_line(self, config_line):
-        """Determine if all banner config is on one line."""
-        _, delimeter, banner = config_line.partition(self.banner_end)
-        # Based on NXOS configs, the banner delimeter is ignored until another char is used
-        banner_config_start = banner.lstrip(delimeter)
-        if delimeter not in banner_config_start:
-            return False
-        return True
-
-    def is_banner_start(self, line):
-        """Determine if the line starts a banner config."""
-        state = super(CiscoConfigParser, self).is_banner_start(line)
-        if state:
-            self.banner_end = line
-        return state
-
-    @property
-    def banner_end(self):
-        """Demarcate End of Banner char(s)."""
-        return self._banner_end
-
-    @banner_end.setter
-    def banner_end(self, banner_start_line):
-        banner_parsed = self.regex_banner.match(banner_start_line)
-        self._banner_end = banner_parsed.groupdict()["banner_delimiter"]
-
-
-class IOSConfigParser(CiscoConfigParser, BaseSpaceConfigParser):
-    """Cisco IOS implementation of ConfigParser Class."""
-
-    def __init__(self, config):
-        """Create ConfigParser Object.
-
-        Args:
-            config (str): The config text to parse.
-        """
-        self.unique_config_lines = set()
-        self.same_line_children = set()
-        super(IOSConfigParser, self).__init__(config)
-
-    def _build_banner(self, config_line):
-        """Handle banner config lines.
-
-        Args:
-            config_line (str): The start of the banner config.
-
-        Returns:
-            str: The next configuration line in the configuration text.
-            None: When banner end is the end of the config text.
-
-        Raises:
-            ValueError: When the parser is unable to identify the End of the Banner.
-        """
-        config_line = config_line.replace("\x03", "^C")
-        config_line = re.sub(r"\^C+", "^C", config_line)
-        return super(IOSConfigParser, self)._build_banner(config_line)
-
-    def _update_same_line_children_configs(self):
-        """Update parents in ``self.config_lines`` per ``self.same_line_children``."""
-        new_config_lines = []
-        for line in self.config_lines:
-            if line in self.same_line_children:
-                previous_line = new_config_lines[-1]
-                previous_config_line = previous_line.config_line
-                current_parents = previous_line.parents + (previous_config_line,)
-                line = ConfigLine(line.config_line, current_parents)
-            new_config_lines.append(line)
-        self.config_lines = new_config_lines
-
-    def _update_config_lines(self, config_line):
-        """Add a ``ConfigLine`` object to ``self.config_lines``.
-
-        In addition to adding entries to config_lines, this also updates:
-          * self.same_line_children
-          * self.unique_config_lines
-
-        Args:
-            config_line (str): The current config line being evaluated.
-
-        Returns:
-            None
-        """
-        super(IOSConfigParser, self)._update_config_lines(config_line)
-        entry = self.config_lines[-1]
-        if entry in self.unique_config_lines:
-            self.same_line_children.add(entry)
-        self.unique_config_lines.add(entry)
-
-    def build_config_relationship(self):
-        r"""Parse text tree of config lines and their parents.
-
-        Example:
-            >>> config = (
-            ...     "interface Ethernet1/1\n"
-            ...     "  vlan 10\n"
-            ...     "  no shutdown"
-            ...     "interface Ethernet1/2\n"
-            ...     "  shutdown\n"
-            ... )
-            >>> config_tree = BaseConfigParser(config)
-            >>> config_tree.build_config_relationship()
-            ... [
-            ...     ConfigLine("interface Ethernet1/1\n", ()),
-            ...     ConfigLine("vlan 10\n", ("interface Ethernet1/1\n",)),
-            ...     ConfigLine("no shutdown\n", ("interface Ethernet1/1\n",)),
-            ...     ConfigLine("interface Ethernet1/2\n", ()),
-            ...     ConfigLine("shutdown\n", ("interface Ethernet1/2\n",)),
-            ... ]
-            >>>
-        """
-        super(IOSConfigParser, self).build_config_relationship()
-        self._update_same_line_children_configs()
-        return self.config_lines
-
-
-class NXOSConfigParser(CiscoConfigParser, BaseSpaceConfigParser):
-    """NXOS implementation of ConfigParser Class."""
-
-    regex_banner = re.compile(r"^banner\s+\S+\s+(?P<banner_delimiter>\S)")
-
-
-class EOSConfigParser(BaseSpaceConfigParser):
-    """EOSConfigParser implementation fo ConfigParser Class."""
-
-    banner_end = "EOF"
-
-
-class AIREOSConfigParser(CiscoConfigParser, BaseSpaceConfigParser):
-    """AireOSConfigParser implementation fo ConfigParser Class."""
-
-    banner_start = []
-
-    def _build_banner(self, config_line):
-        raise NotImplementedError()
-
-
-class LINUXConfigParser(BaseSpaceConfigParser):
-    """Linux config parser."""
-
-    comment_chars = ["#"]
-
-
-class F5ConfigParser(BaseBraceConfigParser):
-    """F5ConfigParser implementation fo ConfigParser Class."""
-
-    multiline_delimiters = ['"']
-
-
-class JunosConfigParser(BaseSpaceConfigParser):
-    """Junos config parser."""
-
-    comment_chars = []
-    banner_start = []
diff --git a/nornir_nautobot/utils/helpers.py b/nornir_nautobot/utils/helpers.py
new file mode 100644
index 0000000..7536ccf
--- /dev/null
+++ b/nornir_nautobot/utils/helpers.py
@@ -0,0 +1,18 @@
+"""A set of helper utilities."""
+
+import errno
+import os
+import logging
+
+LOGGER = logging.getLogger(__name__)
+
+
+def make_folder(folder):
+    """Helper method to sanely create folders."""
+    if not os.path.exists(folder):
+        # Still try and except, since their may be race conditions.
+        try:
+            os.makedirs(folder)
+        except OSError as error:
+            if error.errno != errno.EEXIST:
+                raise
diff --git a/poetry.lock b/poetry.lock
index 320e92a..56e02b4 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -8,15 +8,16 @@ python-versions = "*"
 
 [[package]]
 name = "astroid"
-version = "2.5"
+version = "2.6.2"
 description = "An abstract syntax tree for Python with inference support."
 category = "dev"
 optional = false
-python-versions = ">=3.6"
+python-versions = "~=3.6"
 
 [package.dependencies]
 lazy-object-proxy = ">=1.4.0"
 typed-ast = {version = ">=1.4.0,<1.5", markers = "implementation_name == \"cpython\" and python_version < \"3.8\""}
+typing-extensions = {version = ">=3.7.4", markers = "python_version < \"3.8\""}
 wrapt = ">=1.11,<1.13"
 
 [[package]]
@@ -29,17 +30,17 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
 
 [[package]]
 name = "attrs"
-version = "20.3.0"
+version = "21.2.0"
 description = "Classes Without Boilerplate"
 category = "dev"
 optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
 
 [package.extras]
-dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "furo", "sphinx", "pre-commit"]
-docs = ["furo", "sphinx", "zope.interface"]
-tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"]
-tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six"]
+dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit"]
+docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"]
+tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface"]
+tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins"]
 
 [[package]]
 name = "bandit"
@@ -97,7 +98,7 @@ d = ["aiohttp (>=3.3.2)", "aiohttp-cors"]
 
 [[package]]
 name = "certifi"
-version = "2020.12.5"
+version = "2021.5.30"
 description = "Python package for providing Mozilla's CA Bundle."
 category = "main"
 optional = false
@@ -124,7 +125,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
 
 [[package]]
 name = "ciscoconfparse"
-version = "1.5.29"
+version = "1.5.30"
 description = "Parse, Audit, Query, Build, and Modify Cisco IOS-style configurations"
 category = "main"
 optional = false
@@ -137,11 +138,15 @@ passlib = "*"
 
 [[package]]
 name = "click"
-version = "7.1.2"
+version = "8.0.1"
 description = "Composable command line interface toolkit"
 category = "dev"
 optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+python-versions = ">=3.6"
+
+[package.dependencies]
+colorama = {version = "*", markers = "platform_system == \"Windows\""}
+importlib-metadata = {version = "*", markers = "python_version < \"3.8\""}
 
 [[package]]
 name = "colorama"
@@ -153,7 +158,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
 
 [[package]]
 name = "cryptography"
-version = "3.4.6"
+version = "3.4.7"
 description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
 category = "main"
 optional = false
@@ -195,17 +200,17 @@ trio = ["trio (>=0.14.0)", "sniffio (>=1.1)"]
 
 [[package]]
 name = "flake8"
-version = "3.8.4"
+version = "3.9.2"
 description = "the modular source code checker: pep8 pyflakes and co"
 category = "dev"
 optional = false
-python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7"
+python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
 
 [package.dependencies]
 importlib-metadata = {version = "*", markers = "python_version < \"3.8\""}
 mccabe = ">=0.6.0,<0.7.0"
-pycodestyle = ">=2.6.0a1,<2.7.0"
-pyflakes = ">=2.2.0,<2.3.0"
+pycodestyle = ">=2.7.0,<2.8.0"
+pyflakes = ">=2.3.0,<2.4.0"
 
 [[package]]
 name = "future"
@@ -217,25 +222,26 @@ python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
 
 [[package]]
 name = "gitdb"
-version = "4.0.5"
+version = "4.0.7"
 description = "Git Object Database"
 category = "dev"
 optional = false
 python-versions = ">=3.4"
 
 [package.dependencies]
-smmap = ">=3.0.1,<4"
+smmap = ">=3.0.1,<5"
 
 [[package]]
 name = "gitpython"
-version = "3.1.13"
+version = "3.1.18"
 description = "Python Git Library"
 category = "dev"
 optional = false
-python-versions = ">=3.4"
+python-versions = ">=3.6"
 
 [package.dependencies]
 gitdb = ">=4.0.1,<5"
+typing-extensions = {version = ">=3.7.4.0", markers = "python_version < \"3.8\""}
 
 [[package]]
 name = "idna"
@@ -247,7 +253,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
 
 [[package]]
 name = "importlib-metadata"
-version = "3.4.0"
+version = "4.6.0"
 description = "Read metadata from Python packages"
 category = "dev"
 optional = false
@@ -259,22 +265,23 @@ zipp = ">=0.5"
 
 [package.extras]
 docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"]
-testing = ["pytest (>=3.5,!=3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "pytest-enabler", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"]
+perf = ["ipython"]
+testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"]
 
 [[package]]
 name = "importlib-resources"
-version = "5.1.0"
+version = "5.2.0"
 description = "Read resources from Python packages"
 category = "main"
 optional = false
 python-versions = ">=3.6"
 
 [package.dependencies]
-zipp = {version = ">=0.4", markers = "python_version < \"3.8\""}
+zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""}
 
 [package.extras]
 docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"]
-testing = ["pytest (>=3.5,!=3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "pytest-enabler", "pytest-black (>=0.3.7)", "pytest-mypy"]
+testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "pytest-black (>=0.3.7)", "pytest-mypy"]
 
 [[package]]
 name = "iniconfig"
@@ -294,7 +301,7 @@ python-versions = "*"
 
 [[package]]
 name = "isort"
-version = "5.7.0"
+version = "5.8.0"
 description = "A Python utility / library to sort Python imports."
 category = "dev"
 optional = false
@@ -307,17 +314,17 @@ colors = ["colorama (>=0.4.3,<0.5.0)"]
 
 [[package]]
 name = "jinja2"
-version = "2.11.3"
+version = "3.0.1"
 description = "A very fast and expressive template engine."
 category = "main"
 optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+python-versions = ">=3.6"
 
 [package.dependencies]
-MarkupSafe = ">=0.23"
+MarkupSafe = ">=2.0"
 
 [package.extras]
-i18n = ["Babel (>=0.8)"]
+i18n = ["Babel (>=2.7)"]
 
 [[package]]
 name = "junos-eznc"
@@ -343,15 +350,15 @@ yamlordereddictloader = "*"
 
 [[package]]
 name = "lazy-object-proxy"
-version = "1.5.2"
+version = "1.6.0"
 description = "A fast and thorough lazy object proxy."
 category = "dev"
 optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
 
 [[package]]
 name = "lxml"
-version = "4.6.2"
+version = "4.6.3"
 description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API."
 category = "main"
 optional = false
@@ -365,11 +372,11 @@ source = ["Cython (>=0.29.7)"]
 
 [[package]]
 name = "markupsafe"
-version = "1.1.1"
+version = "2.0.1"
 description = "Safely add untrusted strings to HTML/XML markup."
 category = "main"
 optional = false
-python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*"
+python-versions = ">=3.6"
 
 [[package]]
 name = "mccabe"
@@ -389,7 +396,7 @@ python-versions = "*"
 
 [[package]]
 name = "napalm"
-version = "3.2.0"
+version = "3.3.1"
 description = "Network Automation and Programmability Abstraction Layer with Multivendor support"
 category = "main"
 optional = false
@@ -402,6 +409,7 @@ future = "*"
 jinja2 = "*"
 junos-eznc = ">=2.2.1"
 lxml = ">=4.3.0"
+ncclient = "*"
 netaddr = "*"
 netmiko = ">=3.1.0"
 paramiko = ">=2.6.0"
@@ -413,7 +421,7 @@ textfsm = "*"
 
 [[package]]
 name = "ncclient"
-version = "0.6.9"
+version = "0.6.12"
 description = "Python library for NETCONF clients"
 category = "main"
 optional = false
@@ -437,7 +445,7 @@ importlib-resources = {version = "*", markers = "python_version < \"3.7\""}
 
 [[package]]
 name = "netmiko"
-version = "3.3.3"
+version = "3.4.0"
 description = "Multi-vendor library to simplify Paramiko SSH connections to network devices"
 category = "main"
 optional = false
@@ -454,9 +462,17 @@ tenacity = "*"
 [package.extras]
 test = ["pyyaml (>=5.1.2)", "pytest (>=5.1.2)"]
 
+[[package]]
+name = "netutils"
+version = "0.2.1"
+description = "Common helper functions useful in network automation."
+category = "main"
+optional = false
+python-versions = ">=3.6,<4.0"
+
 [[package]]
 name = "nornir"
-version = "3.0.0"
+version = "3.1.1"
 description = "Pluggable multi-threaded framework with inventory management to help operate collections of devices"
 category = "main"
 optional = false
@@ -473,19 +489,19 @@ docs = ["jupyter (>=1,<2)", "nbsphinx (>=0.5,<0.6)", "pygments (>=2,<3)", "sphin
 
 [[package]]
 name = "nornir-jinja2"
-version = "0.1.1"
+version = "0.2.0"
 description = "Jinja2 plugins for nornir"
 category = "main"
 optional = false
 python-versions = ">=3.6,<4.0"
 
 [package.dependencies]
-jinja2 = ">=2.11.2,<3.0.0"
-nornir = ">=3.0.0b1,<3.1.0"
+jinja2 = ">=2.11.2,<4"
+nornir = ">=3,<4"
 
 [[package]]
 name = "nornir-napalm"
-version = "0.1.1"
+version = "0.1.2"
 description = "NAPALM's plugins for nornir"
 category = "main"
 optional = false
@@ -493,7 +509,7 @@ python-versions = ">=3.6,<4.0"
 
 [package.dependencies]
 napalm = ">=3,<4"
-nornir = ">=3.0.0b1,<3.1.0"
+nornir = ">=3,<4"
 
 [[package]]
 name = "nornir-netmiko"
@@ -508,7 +524,7 @@ netmiko = ">=3.1.0,<4.0.0"
 
 [[package]]
 name = "nornir-utils"
-version = "0.1.1"
+version = "0.1.2"
 description = "Collection of plugins and functions for nornir that don't require external dependencies"
 category = "main"
 optional = false
@@ -516,21 +532,18 @@ python-versions = ">=3.6,<4.0"
 
 [package.dependencies]
 colorama = ">=0.4.3,<0.5.0"
-nornir = ">=3.0.0b1,<3.1.0"
+nornir = ">=3,<4"
 
 [[package]]
 name = "ntc-templates"
-version = "1.6.0"
-description = "Package to return structured data from the output of network devices."
+version = "2.1.0"
+description = "TextFSM Templates for Network Devices, and Python wrapper for TextFSM's CliTable."
 category = "main"
 optional = false
-python-versions = "*"
+python-versions = ">=3.6,<4.0"
 
 [package.dependencies]
-textfsm = ">=1.1.0"
-
-[package.extras]
-dev = ["pytest", "pyyaml", "black", "yamllint", "ruamel.yaml"]
+textfsm = ">=1.1.0,<2.0.0"
 
 [[package]]
 name = "packaging"
@@ -586,7 +599,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
 
 [[package]]
 name = "pbr"
-version = "5.5.1"
+version = "5.6.0"
 description = "Python Build Reasonableness"
 category = "dev"
 optional = false
@@ -616,7 +629,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
 
 [[package]]
 name = "pycodestyle"
-version = "2.6.0"
+version = "2.7.0"
 description = "Python style guide checker"
 category = "dev"
 optional = false
@@ -632,7 +645,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
 
 [[package]]
 name = "pydantic"
-version = "1.7.3"
+version = "1.7.4"
 description = "Data validation and settings management using python 3.6 type hinting"
 category = "dev"
 optional = false
@@ -649,15 +662,18 @@ typing_extensions = ["typing-extensions (>=3.7.2)"]
 
 [[package]]
 name = "pydocstyle"
-version = "5.1.1"
+version = "6.1.1"
 description = "Python docstring style checker"
 category = "dev"
 optional = false
-python-versions = ">=3.5"
+python-versions = ">=3.6"
 
 [package.dependencies]
 snowballstemmer = "*"
 
+[package.extras]
+toml = ["toml"]
+
 [[package]]
 name = "pyeapi"
 version = "0.8.4"
@@ -675,7 +691,7 @@ test = ["coverage", "mock"]
 
 [[package]]
 name = "pyflakes"
-version = "2.2.0"
+version = "2.3.1"
 description = "passive checker of Python programs"
 category = "dev"
 optional = false
@@ -683,22 +699,19 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
 
 [[package]]
 name = "pylint"
-version = "2.7.0"
+version = "2.9.3"
 description = "python code static checker"
 category = "dev"
 optional = false
 python-versions = "~=3.6"
 
 [package.dependencies]
-astroid = "2.5.0"
+astroid = ">=2.6.2,<2.7"
 colorama = {version = "*", markers = "sys_platform == \"win32\""}
 isort = ">=4.2.5,<6"
 mccabe = ">=0.6,<0.7"
 toml = ">=0.7.1"
 
-[package.extras]
-docs = ["sphinx (>=3.2,<4.0)", "python-docs-theme"]
-
 [[package]]
 name = "pynacl"
 version = "1.4.0"
@@ -717,7 +730,7 @@ tests = ["pytest (>=3.2.1,!=3.3.0)", "hypothesis (>=3.27.0)"]
 
 [[package]]
 name = "pynautobot"
-version = "1.0.1"
+version = "1.0.2"
 description = "Nautobot API client library"
 category = "main"
 optional = false
@@ -726,6 +739,9 @@ python-versions = ">=3.6,<4.0"
 [package.dependencies]
 requests = ">=2.20.0,<3.0.0"
 
+[package.extras]
+docs = ["Sphinx (>=3.5.1,<4.0.0)"]
+
 [[package]]
 name = "pyparsing"
 version = "2.4.7"
@@ -747,7 +763,7 @@ cp2110 = ["hidapi"]
 
 [[package]]
 name = "pytest"
-version = "6.2.2"
+version = "6.2.4"
 description = "pytest: simple powerful testing with Python"
 category = "dev"
 optional = false
@@ -769,8 +785,8 @@ testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xm
 
 [[package]]
 name = "python-dotenv"
-version = "0.15.0"
-description = "Add .env support to your django/flask apps in development and deployments"
+version = "0.18.0"
+description = "Read key-value pairs from a .env file and set them as environment variables"
 category = "dev"
 optional = false
 python-versions = "*"
@@ -788,7 +804,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
 
 [[package]]
 name = "regex"
-version = "2020.11.13"
+version = "2021.4.4"
 description = "Alternative regular expression module, to replace re."
 category = "dev"
 optional = false
@@ -814,7 +830,7 @@ socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"]
 
 [[package]]
 name = "requests-mock"
-version = "1.8.0"
+version = "1.9.3"
 description = "Mock out responses from the requests package"
 category = "dev"
 optional = false
@@ -830,14 +846,14 @@ test = ["fixtures", "mock", "purl", "pytest", "sphinx", "testrepository (>=0.0.1
 
 [[package]]
 name = "ruamel.yaml"
-version = "0.16.12"
+version = "0.16.13"
 description = "ruamel.yaml is a YAML parser/emitter that supports roundtrip preservation of comments, seq/map flow style, and map key order"
 category = "main"
 optional = false
 python-versions = "*"
 
 [package.dependencies]
-"ruamel.yaml.clib" = {version = ">=0.1.2", markers = "platform_python_implementation == \"CPython\" and python_version < \"3.9\""}
+"ruamel.yaml.clib" = {version = ">=0.1.2", markers = "platform_python_implementation == \"CPython\" and python_version < \"3.10\""}
 
 [package.extras]
 docs = ["ryd"]
@@ -845,7 +861,7 @@ jinja2 = ["ruamel.yaml.jinja2 (>=0.2)"]
 
 [[package]]
 name = "ruamel.yaml.clib"
-version = "0.2.2"
+version = "0.2.4"
 description = "C version of reader, parser and emitter for ruamel.yaml derived from libyaml"
 category = "main"
 optional = false
@@ -853,7 +869,7 @@ python-versions = "*"
 
 [[package]]
 name = "scp"
-version = "0.13.3"
+version = "0.13.5"
 description = "scp module for paramiko"
 category = "main"
 optional = false
@@ -864,7 +880,7 @@ paramiko = "*"
 
 [[package]]
 name = "six"
-version = "1.15.0"
+version = "1.16.0"
 description = "Python 2 and 3 compatibility utilities"
 category = "main"
 optional = false
@@ -872,11 +888,11 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
 
 [[package]]
 name = "smmap"
-version = "3.0.5"
+version = "4.0.0"
 description = "A pure Python implementation of a sliding window memory map manager"
 category = "dev"
 optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+python-versions = ">=3.5"
 
 [[package]]
 name = "snowballstemmer"
@@ -900,7 +916,7 @@ pbr = ">=2.0.0,<2.1.0 || >2.1.0"
 
 [[package]]
 name = "tenacity"
-version = "6.3.1"
+version = "7.0.0"
 description = "Retry code until it succeeds"
 category = "main"
 optional = false
@@ -914,7 +930,7 @@ doc = ["reno", "sphinx", "tornado (>=4.5)"]
 
 [[package]]
 name = "textfsm"
-version = "1.1.0"
+version = "1.1.2"
 description = "Python module for parsing semi-structured text into python tables."
 category = "main"
 optional = false
@@ -934,7 +950,7 @@ python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
 
 [[package]]
 name = "transitions"
-version = "0.8.7"
+version = "0.8.8"
 description = "A lightweight, object-oriented Python state machine implementation with many extensions."
 category = "main"
 optional = false
@@ -949,7 +965,7 @@ test = ["pytest"]
 
 [[package]]
 name = "typed-ast"
-version = "1.4.2"
+version = "1.4.3"
 description = "a fork of Python 2 and 3 ast modules with type comment support"
 category = "dev"
 optional = false
@@ -957,7 +973,7 @@ python-versions = "*"
 
 [[package]]
 name = "typing-extensions"
-version = "3.7.4.3"
+version = "3.10.0.0"
 description = "Backported and Experimental Type Hints for Python 3.5+"
 category = "main"
 optional = false
@@ -965,7 +981,7 @@ python-versions = "*"
 
 [[package]]
 name = "urllib3"
-version = "1.26.3"
+version = "1.26.6"
 description = "HTTP library with thread-safe connection pooling, file post, and more."
 category = "main"
 optional = false
@@ -986,7 +1002,7 @@ python-versions = "*"
 
 [[package]]
 name = "yamllint"
-version = "1.26.0"
+version = "1.26.1"
 description = "A linter for YAML files."
 category = "dev"
 optional = false
@@ -1009,20 +1025,20 @@ pyyaml = "*"
 
 [[package]]
 name = "zipp"
-version = "3.4.0"
+version = "3.4.1"
 description = "Backport of pathlib-compatible object wrapper for zip files"
 category = "main"
 optional = false
 python-versions = ">=3.6"
 
 [package.extras]
-docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"]
-testing = ["pytest (>=3.5,!=3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "jaraco.test (>=3.2.0)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"]
+docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"]
+testing = ["pytest (>=4.6)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "pytest-enabler", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"]
 
 [metadata]
 lock-version = "1.1"
 python-versions = "^3.6"
-content-hash = "bacb2b88e86ab6ae5e6dafe7d0cb8c66f38010449ef5be7887dc14e79d4ab7fd"
+content-hash = "a0746d29f2ce6e63fbe4474534fcdf9afa4ca42ca74a2b9f6e168c3d3e9fb7c7"
 
 [metadata.files]
 appdirs = [
@@ -1030,16 +1046,16 @@ appdirs = [
     {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"},
 ]
 astroid = [
-    {file = "astroid-2.5-py3-none-any.whl", hash = "sha256:87ae7f2398b8a0ae5638ddecf9987f081b756e0e9fc071aeebdca525671fc4dc"},
-    {file = "astroid-2.5.tar.gz", hash = "sha256:b31c92f545517dcc452f284bc9c044050862fbe6d93d2b3de4a215a6b384bf0d"},
+    {file = "astroid-2.6.2-py3-none-any.whl", hash = "sha256:606b2911d10c3dcf35e58d2ee5c97360e8477d7b9f3efc3f24811c93e6fc2cd9"},
+    {file = "astroid-2.6.2.tar.gz", hash = "sha256:38b95085e9d92e2ca06cf8b35c12a74fa81da395a6f9e65803742e6509c05892"},
 ]
 atomicwrites = [
     {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"},
     {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"},
 ]
 attrs = [
-    {file = "attrs-20.3.0-py2.py3-none-any.whl", hash = "sha256:31b2eced602aa8423c2aea9c76a724617ed67cf9513173fd3a4f03e3a929c7e6"},
-    {file = "attrs-20.3.0.tar.gz", hash = "sha256:832aa3cde19744e49938b91fea06d69ecb9e649c93ba974535d08ad92164f700"},
+    {file = "attrs-21.2.0-py2.py3-none-any.whl", hash = "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1"},
+    {file = "attrs-21.2.0.tar.gz", hash = "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"},
 ]
 bandit = [
     {file = "bandit-1.7.0-py3-none-any.whl", hash = "sha256:216be4d044209fa06cf2a3e51b319769a51be8318140659719aa7a115c35ed07"},
@@ -1058,8 +1074,8 @@ black = [
     {file = "black-20.8b1.tar.gz", hash = "sha256:1c02557aa099101b9d21496f8a914e9ed2222ef70336404eeeac8edba836fbea"},
 ]
 certifi = [
-    {file = "certifi-2020.12.5-py2.py3-none-any.whl", hash = "sha256:719a74fb9e33b9bd44cc7f3a8d94bc35e4049deebe19ba7d8e108280cfd59830"},
-    {file = "certifi-2020.12.5.tar.gz", hash = "sha256:1a4995114262bffbc2413b159f2a1a480c969de6e6eb13ee966d470af86af59c"},
+    {file = "certifi-2021.5.30-py2.py3-none-any.whl", hash = "sha256:50b1e4f8446b06f41be7dd6338db18e0990601dce795c2b1686458aa7e8fa7d8"},
+    {file = "certifi-2021.5.30.tar.gz", hash = "sha256:2bbf76fd432960138b3ef6dda3dde0544f27cbf8546c458e60baf371917ba9ee"},
 ]
 cffi = [
     {file = "cffi-1.14.5-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:bb89f306e5da99f4d922728ddcd6f7fcebb3241fc40edebcb7284d7514741991"},
@@ -1105,26 +1121,30 @@ chardet = [
     {file = "chardet-4.0.0.tar.gz", hash = "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa"},
 ]
 ciscoconfparse = [
-    {file = "ciscoconfparse-1.5.29-py3-none-any.whl", hash = "sha256:a31a5583539bb3f260c4602f98dae1383f4010e5e74b930332c59e1ec31df63b"},
-    {file = "ciscoconfparse-1.5.29.tar.gz", hash = "sha256:8fb27bfcc7b97c974f68d3b73b01e349f1377171ec0d33b1e996d0a392224a7e"},
+    {file = "ciscoconfparse-1.5.30-py3-none-any.whl", hash = "sha256:1b7b98c0b1b1cb05fadc9c27711d79d4faee9cf4770a72b5798d7167bb97ccc2"},
+    {file = "ciscoconfparse-1.5.30.tar.gz", hash = "sha256:e3c9ad5ff7563c6d3b4542d2826f4b07feb0e46ea5c698886ab8c4d55cc28815"},
 ]
 click = [
-    {file = "click-7.1.2-py2.py3-none-any.whl", hash = "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"},
-    {file = "click-7.1.2.tar.gz", hash = "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a"},
+    {file = "click-8.0.1-py3-none-any.whl", hash = "sha256:fba402a4a47334742d782209a7c79bc448911afe1149d07bdabdf480b3e2f4b6"},
+    {file = "click-8.0.1.tar.gz", hash = "sha256:8c04c11192119b1ef78ea049e0a6f0463e4c48ef00a30160c704337586f3ad7a"},
 ]
 colorama = [
     {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"},
     {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"},
 ]
 cryptography = [
-    {file = "cryptography-3.4.6-cp36-abi3-macosx_10_10_x86_64.whl", hash = "sha256:57ad77d32917bc55299b16d3b996ffa42a1c73c6cfa829b14043c561288d2799"},
-    {file = "cryptography-3.4.6-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:4169a27b818de4a1860720108b55a2801f32b6ae79e7f99c00d79f2a2822eeb7"},
-    {file = "cryptography-3.4.6-cp36-abi3-manylinux2010_x86_64.whl", hash = "sha256:93cfe5b7ff006de13e1e89830810ecbd014791b042cbe5eec253be11ac2b28f3"},
-    {file = "cryptography-3.4.6-cp36-abi3-manylinux2014_aarch64.whl", hash = "sha256:5ecf2bcb34d17415e89b546dbb44e73080f747e504273e4d4987630493cded1b"},
-    {file = "cryptography-3.4.6-cp36-abi3-manylinux2014_x86_64.whl", hash = "sha256:fec7fb46b10da10d9e1d078d1ff8ed9e05ae14f431fdbd11145edd0550b9a964"},
-    {file = "cryptography-3.4.6-cp36-abi3-win32.whl", hash = "sha256:df186fcbf86dc1ce56305becb8434e4b6b7504bc724b71ad7a3239e0c9d14ef2"},
-    {file = "cryptography-3.4.6-cp36-abi3-win_amd64.whl", hash = "sha256:66b57a9ca4b3221d51b237094b0303843b914b7d5afd4349970bb26518e350b0"},
-    {file = "cryptography-3.4.6.tar.gz", hash = "sha256:2d32223e5b0ee02943f32b19245b61a62db83a882f0e76cc564e1cec60d48f87"},
+    {file = "cryptography-3.4.7-cp36-abi3-macosx_10_10_x86_64.whl", hash = "sha256:3d8427734c781ea5f1b41d6589c293089704d4759e34597dce91014ac125aad1"},
+    {file = "cryptography-3.4.7-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:8e56e16617872b0957d1c9742a3f94b43533447fd78321514abbe7db216aa250"},
+    {file = "cryptography-3.4.7-cp36-abi3-manylinux2010_x86_64.whl", hash = "sha256:37340614f8a5d2fb9aeea67fd159bfe4f5f4ed535b1090ce8ec428b2f15a11f2"},
+    {file = "cryptography-3.4.7-cp36-abi3-manylinux2014_aarch64.whl", hash = "sha256:240f5c21aef0b73f40bb9f78d2caff73186700bf1bc6b94285699aff98cc16c6"},
+    {file = "cryptography-3.4.7-cp36-abi3-manylinux2014_x86_64.whl", hash = "sha256:1e056c28420c072c5e3cb36e2b23ee55e260cb04eee08f702e0edfec3fb51959"},
+    {file = "cryptography-3.4.7-cp36-abi3-win32.whl", hash = "sha256:0f1212a66329c80d68aeeb39b8a16d54ef57071bf22ff4e521657b27372e327d"},
+    {file = "cryptography-3.4.7-cp36-abi3-win_amd64.whl", hash = "sha256:de4e5f7f68220d92b7637fc99847475b59154b7a1b3868fb7385337af54ac9ca"},
+    {file = "cryptography-3.4.7-pp36-pypy36_pp73-manylinux2010_x86_64.whl", hash = "sha256:26965837447f9c82f1855e0bc8bc4fb910240b6e0d16a664bb722df3b5b06873"},
+    {file = "cryptography-3.4.7-pp36-pypy36_pp73-manylinux2014_x86_64.whl", hash = "sha256:eb8cc2afe8b05acbd84a43905832ec78e7b3873fb124ca190f574dca7389a87d"},
+    {file = "cryptography-3.4.7-pp37-pypy37_pp73-manylinux2010_x86_64.whl", hash = "sha256:7ec5d3b029f5fa2b179325908b9cd93db28ab7b85bb6c1db56b10e0b54235177"},
+    {file = "cryptography-3.4.7-pp37-pypy37_pp73-manylinux2014_x86_64.whl", hash = "sha256:ee77aa129f481be46f8d92a1a7db57269a2f23052d5f2433b4621bb457081cc9"},
+    {file = "cryptography-3.4.7.tar.gz", hash = "sha256:3d10de8116d25649631977cb37da6cbdd2d6fa0e0281d014a5b7d337255ca713"},
 ]
 dataclasses = [
     {file = "dataclasses-0.7-py3-none-any.whl", hash = "sha256:3459118f7ede7c8bea0fe795bff7c6c2ce287d01dd226202f7c9ebc0610a7836"},
@@ -1135,31 +1155,31 @@ dnspython = [
     {file = "dnspython-2.1.0.zip", hash = "sha256:e4a87f0b573201a0f3727fa18a516b055fd1107e0e5477cded4a2de497df1dd4"},
 ]
 flake8 = [
-    {file = "flake8-3.8.4-py2.py3-none-any.whl", hash = "sha256:749dbbd6bfd0cf1318af27bf97a14e28e5ff548ef8e5b1566ccfb25a11e7c839"},
-    {file = "flake8-3.8.4.tar.gz", hash = "sha256:aadae8761ec651813c24be05c6f7b4680857ef6afaae4651a4eccaef97ce6c3b"},
+    {file = "flake8-3.9.2-py2.py3-none-any.whl", hash = "sha256:bf8fd333346d844f616e8d47905ef3a3384edae6b4e9beb0c5101e25e3110907"},
+    {file = "flake8-3.9.2.tar.gz", hash = "sha256:07528381786f2a6237b061f6e96610a4167b226cb926e2aa2b6b1d78057c576b"},
 ]
 future = [
     {file = "future-0.18.2.tar.gz", hash = "sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d"},
 ]
 gitdb = [
-    {file = "gitdb-4.0.5-py3-none-any.whl", hash = "sha256:91f36bfb1ab7949b3b40e23736db18231bf7593edada2ba5c3a174a7b23657ac"},
-    {file = "gitdb-4.0.5.tar.gz", hash = "sha256:c9e1f2d0db7ddb9a704c2a0217be31214e91a4fe1dea1efad19ae42ba0c285c9"},
+    {file = "gitdb-4.0.7-py3-none-any.whl", hash = "sha256:6c4cc71933456991da20917998acbe6cf4fb41eeaab7d6d67fbc05ecd4c865b0"},
+    {file = "gitdb-4.0.7.tar.gz", hash = "sha256:96bf5c08b157a666fec41129e6d327235284cca4c81e92109260f353ba138005"},
 ]
 gitpython = [
-    {file = "GitPython-3.1.13-py3-none-any.whl", hash = "sha256:c5347c81d232d9b8e7f47b68a83e5dc92e7952127133c5f2df9133f2c75a1b29"},
-    {file = "GitPython-3.1.13.tar.gz", hash = "sha256:8621a7e777e276a5ec838b59280ba5272dd144a18169c36c903d8b38b99f750a"},
+    {file = "GitPython-3.1.18-py3-none-any.whl", hash = "sha256:fce760879cd2aebd2991b3542876dc5c4a909b30c9d69dfc488e504a8db37ee8"},
+    {file = "GitPython-3.1.18.tar.gz", hash = "sha256:b838a895977b45ab6f0cc926a9045c8d1c44e2b653c1fcc39fe91f42c6e8f05b"},
 ]
 idna = [
     {file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"},
     {file = "idna-2.10.tar.gz", hash = "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"},
 ]
 importlib-metadata = [
-    {file = "importlib_metadata-3.4.0-py3-none-any.whl", hash = "sha256:ace61d5fc652dc280e7b6b4ff732a9c2d40db2c0f92bc6cb74e07b73d53a1771"},
-    {file = "importlib_metadata-3.4.0.tar.gz", hash = "sha256:fa5daa4477a7414ae34e95942e4dd07f62adf589143c875c133c1e53c4eff38d"},
+    {file = "importlib_metadata-4.6.0-py3-none-any.whl", hash = "sha256:c6513572926a96458f8c8f725bf0e00108fba0c9583ade9bd15b869c9d726e33"},
+    {file = "importlib_metadata-4.6.0.tar.gz", hash = "sha256:4a5611fea3768d3d967c447ab4e93f567d95db92225b43b7b238dbfb855d70bb"},
 ]
 importlib-resources = [
-    {file = "importlib_resources-5.1.0-py3-none-any.whl", hash = "sha256:885b8eae589179f661c909d699a546cf10d83692553e34dca1bf5eb06f7f6217"},
-    {file = "importlib_resources-5.1.0.tar.gz", hash = "sha256:bfdad047bce441405a49cf8eb48ddce5e56c696e185f59147a8b79e75e9e6380"},
+    {file = "importlib_resources-5.2.0-py3-none-any.whl", hash = "sha256:a0143290bef3cbc99de9e40176e4987780939a955b8632f02ce6c935f42e9bfc"},
+    {file = "importlib_resources-5.2.0.tar.gz", hash = "sha256:22a2c42d8c6a1d30aa8a0e1f57293725bfd5c013d562585e46aff469e0ff78b3"},
 ]
 iniconfig = [
     {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"},
@@ -1171,116 +1191,114 @@ invoke = [
     {file = "invoke-1.5.0.tar.gz", hash = "sha256:f0c560075b5fb29ba14dad44a7185514e94970d1b9d57dcd3723bec5fed92650"},
 ]
 isort = [
-    {file = "isort-5.7.0-py3-none-any.whl", hash = "sha256:fff4f0c04e1825522ce6949973e83110a6e907750cd92d128b0d14aaaadbffdc"},
-    {file = "isort-5.7.0.tar.gz", hash = "sha256:c729845434366216d320e936b8ad6f9d681aab72dc7cbc2d51bedc3582f3ad1e"},
+    {file = "isort-5.8.0-py3-none-any.whl", hash = "sha256:2bb1680aad211e3c9944dbce1d4ba09a989f04e238296c87fe2139faa26d655d"},
+    {file = "isort-5.8.0.tar.gz", hash = "sha256:0a943902919f65c5684ac4e0154b1ad4fac6dcaa5d9f3426b732f1c8b5419be6"},
 ]
 jinja2 = [
-    {file = "Jinja2-2.11.3-py2.py3-none-any.whl", hash = "sha256:03e47ad063331dd6a3f04a43eddca8a966a26ba0c5b7207a9a9e4e08f1b29419"},
-    {file = "Jinja2-2.11.3.tar.gz", hash = "sha256:a6d58433de0ae800347cab1fa3043cebbabe8baa9d29e668f1c768cb87a333c6"},
+    {file = "Jinja2-3.0.1-py3-none-any.whl", hash = "sha256:1f06f2da51e7b56b8f238affdd6b4e2c61e39598a378cc49345bc1bd42a978a4"},
+    {file = "Jinja2-3.0.1.tar.gz", hash = "sha256:703f484b47a6af502e743c9122595cc812b0271f661722403114f71a79d0f5a4"},
 ]
 junos-eznc = [
     {file = "junos-eznc-2.5.4.tar.gz", hash = "sha256:bf036d0af9ee5c5e4f517cb5fc902fe891fa120e18f459805862c53d4a97193a"},
     {file = "junos_eznc-2.5.4-py2.py3-none-any.whl", hash = "sha256:e05c36d56d8b8d13b1fb3bb763828bb3ee80fa1dcadc3a6762e8e2568504676d"},
 ]
 lazy-object-proxy = [
-    {file = "lazy-object-proxy-1.5.2.tar.gz", hash = "sha256:5944a9b95e97de1980c65f03b79b356f30a43de48682b8bdd90aa5089f0ec1f4"},
-    {file = "lazy_object_proxy-1.5.2-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:e960e8be509e8d6d618300a6c189555c24efde63e85acaf0b14b2cd1ac743315"},
-    {file = "lazy_object_proxy-1.5.2-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:522b7c94b524389f4a4094c4bf04c2b02228454ddd17c1a9b2801fac1d754871"},
-    {file = "lazy_object_proxy-1.5.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:3782931963dc89e0e9a0ae4348b44762e868ea280e4f8c233b537852a8996ab9"},
-    {file = "lazy_object_proxy-1.5.2-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:429c4d1862f3fc37cd56304d880f2eae5bd0da83bdef889f3bd66458aac49128"},
-    {file = "lazy_object_proxy-1.5.2-cp35-cp35m-win32.whl", hash = "sha256:cd1bdace1a8762534e9a36c073cd54e97d517a17d69a17985961265be6d22847"},
-    {file = "lazy_object_proxy-1.5.2-cp35-cp35m-win_amd64.whl", hash = "sha256:ddbdcd10eb999d7ab292677f588b658372aadb9a52790f82484a37127a390108"},
-    {file = "lazy_object_proxy-1.5.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:ecb5dd5990cec6e7f5c9c1124a37cb2c710c6d69b0c1a5c4aa4b35eba0ada068"},
-    {file = "lazy_object_proxy-1.5.2-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:b6577f15d5516d7d209c1a8cde23062c0f10625f19e8dc9fb59268859778d7d7"},
-    {file = "lazy_object_proxy-1.5.2-cp36-cp36m-win32.whl", hash = "sha256:c8fe2d6ff0ff583784039d0255ea7da076efd08507f2be6f68583b0da32e3afb"},
-    {file = "lazy_object_proxy-1.5.2-cp36-cp36m-win_amd64.whl", hash = "sha256:fa5b2dee0e231fa4ad117be114251bdfe6afe39213bd629d43deb117b6a6c40a"},
-    {file = "lazy_object_proxy-1.5.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:1d33d6f789697f401b75ce08e73b1de567b947740f768376631079290118ad39"},
-    {file = "lazy_object_proxy-1.5.2-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:57fb5c5504ddd45ed420b5b6461a78f58cbb0c1b0cbd9cd5a43ad30a4a3ee4d0"},
-    {file = "lazy_object_proxy-1.5.2-cp37-cp37m-win32.whl", hash = "sha256:e7273c64bccfd9310e9601b8f4511d84730239516bada26a0c9846c9697617ef"},
-    {file = "lazy_object_proxy-1.5.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6f4e5e68b7af950ed7fdb594b3f19a0014a3ace0fedb86acb896e140ffb24302"},
-    {file = "lazy_object_proxy-1.5.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:cadfa2c2cf54d35d13dc8d231253b7985b97d629ab9ca6e7d672c35539d38163"},
-    {file = "lazy_object_proxy-1.5.2-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:e7428977763150b4cf83255625a80a23dfdc94d43be7791ce90799d446b4e26f"},
-    {file = "lazy_object_proxy-1.5.2-cp38-cp38-win32.whl", hash = "sha256:2f2de8f8ac0be3e40d17730e0600619d35c78c13a099ea91ef7fb4ad944ce694"},
-    {file = "lazy_object_proxy-1.5.2-cp38-cp38-win_amd64.whl", hash = "sha256:38c3865bd220bd983fcaa9aa11462619e84a71233bafd9c880f7b1cb753ca7fa"},
-    {file = "lazy_object_proxy-1.5.2-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:8a44e9901c0555f95ac401377032f6e6af66d8fc1fbfad77a7a8b1a826e0b93c"},
-    {file = "lazy_object_proxy-1.5.2-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:fa7fb7973c622b9e725bee1db569d2c2ee64d2f9a089201c5e8185d482c7352d"},
-    {file = "lazy_object_proxy-1.5.2-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:71a1ef23f22fa8437974b2d60fedb947c99a957ad625f83f43fd3de70f77f458"},
-    {file = "lazy_object_proxy-1.5.2-cp39-cp39-win32.whl", hash = "sha256:ef3f5e288aa57b73b034ce9c1f1ac753d968f9069cd0742d1d69c698a0167166"},
-    {file = "lazy_object_proxy-1.5.2-cp39-cp39-win_amd64.whl", hash = "sha256:37d9c34b96cca6787fe014aeb651217944a967a5b165e2cacb6b858d2997ab84"},
+    {file = "lazy-object-proxy-1.6.0.tar.gz", hash = "sha256:489000d368377571c6f982fba6497f2aa13c6d1facc40660963da62f5c379726"},
+    {file = "lazy_object_proxy-1.6.0-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:c6938967f8528b3668622a9ed3b31d145fab161a32f5891ea7b84f6b790be05b"},
+    {file = "lazy_object_proxy-1.6.0-cp27-cp27m-win32.whl", hash = "sha256:ebfd274dcd5133e0afae738e6d9da4323c3eb021b3e13052d8cbd0e457b1256e"},
+    {file = "lazy_object_proxy-1.6.0-cp27-cp27m-win_amd64.whl", hash = "sha256:ed361bb83436f117f9917d282a456f9e5009ea12fd6de8742d1a4752c3017e93"},
+    {file = "lazy_object_proxy-1.6.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:d900d949b707778696fdf01036f58c9876a0d8bfe116e8d220cfd4b15f14e741"},
+    {file = "lazy_object_proxy-1.6.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:5743a5ab42ae40caa8421b320ebf3a998f89c85cdc8376d6b2e00bd12bd1b587"},
+    {file = "lazy_object_proxy-1.6.0-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:bf34e368e8dd976423396555078def5cfc3039ebc6fc06d1ae2c5a65eebbcde4"},
+    {file = "lazy_object_proxy-1.6.0-cp36-cp36m-win32.whl", hash = "sha256:b579f8acbf2bdd9ea200b1d5dea36abd93cabf56cf626ab9c744a432e15c815f"},
+    {file = "lazy_object_proxy-1.6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:4f60460e9f1eb632584c9685bccea152f4ac2130e299784dbaf9fae9f49891b3"},
+    {file = "lazy_object_proxy-1.6.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:d7124f52f3bd259f510651450e18e0fd081ed82f3c08541dffc7b94b883aa981"},
+    {file = "lazy_object_proxy-1.6.0-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:22ddd618cefe54305df49e4c069fa65715be4ad0e78e8d252a33debf00f6ede2"},
+    {file = "lazy_object_proxy-1.6.0-cp37-cp37m-win32.whl", hash = "sha256:9d397bf41caad3f489e10774667310d73cb9c4258e9aed94b9ec734b34b495fd"},
+    {file = "lazy_object_proxy-1.6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:24a5045889cc2729033b3e604d496c2b6f588c754f7a62027ad4437a7ecc4837"},
+    {file = "lazy_object_proxy-1.6.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:17e0967ba374fc24141738c69736da90e94419338fd4c7c7bef01ee26b339653"},
+    {file = "lazy_object_proxy-1.6.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:410283732af311b51b837894fa2f24f2c0039aa7f220135192b38fcc42bd43d3"},
+    {file = "lazy_object_proxy-1.6.0-cp38-cp38-win32.whl", hash = "sha256:85fb7608121fd5621cc4377a8961d0b32ccf84a7285b4f1d21988b2eae2868e8"},
+    {file = "lazy_object_proxy-1.6.0-cp38-cp38-win_amd64.whl", hash = "sha256:d1c2676e3d840852a2de7c7d5d76407c772927addff8d742b9808fe0afccebdf"},
+    {file = "lazy_object_proxy-1.6.0-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:b865b01a2e7f96db0c5d12cfea590f98d8c5ba64ad222300d93ce6ff9138bcad"},
+    {file = "lazy_object_proxy-1.6.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:4732c765372bd78a2d6b2150a6e99d00a78ec963375f236979c0626b97ed8e43"},
+    {file = "lazy_object_proxy-1.6.0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:9698110e36e2df951c7c36b6729e96429c9c32b3331989ef19976592c5f3c77a"},
+    {file = "lazy_object_proxy-1.6.0-cp39-cp39-win32.whl", hash = "sha256:1fee665d2638491f4d6e55bd483e15ef21f6c8c2095f235fef72601021e64f61"},
+    {file = "lazy_object_proxy-1.6.0-cp39-cp39-win_amd64.whl", hash = "sha256:f5144c75445ae3ca2057faac03fda5a902eff196702b0a24daf1d6ce0650514b"},
 ]
 lxml = [
-    {file = "lxml-4.6.2-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a9d6bc8642e2c67db33f1247a77c53476f3a166e09067c0474facb045756087f"},
-    {file = "lxml-4.6.2-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:791394449e98243839fa822a637177dd42a95f4883ad3dec2a0ce6ac99fb0a9d"},
-    {file = "lxml-4.6.2-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:68a5d77e440df94011214b7db907ec8f19e439507a70c958f750c18d88f995d2"},
-    {file = "lxml-4.6.2-cp27-cp27m-win32.whl", hash = "sha256:fc37870d6716b137e80d19241d0e2cff7a7643b925dfa49b4c8ebd1295eb506e"},
-    {file = "lxml-4.6.2-cp27-cp27m-win_amd64.whl", hash = "sha256:69a63f83e88138ab7642d8f61418cf3180a4d8cd13995df87725cb8b893e950e"},
-    {file = "lxml-4.6.2-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:42ebca24ba2a21065fb546f3e6bd0c58c3fe9ac298f3a320147029a4850f51a2"},
-    {file = "lxml-4.6.2-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:f83d281bb2a6217cd806f4cf0ddded436790e66f393e124dfe9731f6b3fb9afe"},
-    {file = "lxml-4.6.2-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:535f067002b0fd1a4e5296a8f1bf88193080ff992a195e66964ef2a6cfec5388"},
-    {file = "lxml-4.6.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:366cb750140f221523fa062d641393092813b81e15d0e25d9f7c6025f910ee80"},
-    {file = "lxml-4.6.2-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:97db258793d193c7b62d4e2586c6ed98d51086e93f9a3af2b2034af01450a74b"},
-    {file = "lxml-4.6.2-cp35-cp35m-win32.whl", hash = "sha256:648914abafe67f11be7d93c1a546068f8eff3c5fa938e1f94509e4a5d682b2d8"},
-    {file = "lxml-4.6.2-cp35-cp35m-win_amd64.whl", hash = "sha256:4e751e77006da34643ab782e4a5cc21ea7b755551db202bc4d3a423b307db780"},
-    {file = "lxml-4.6.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:681d75e1a38a69f1e64ab82fe4b1ed3fd758717bed735fb9aeaa124143f051af"},
-    {file = "lxml-4.6.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:127f76864468d6630e1b453d3ffbbd04b024c674f55cf0a30dc2595137892d37"},
-    {file = "lxml-4.6.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:4fb85c447e288df535b17ebdebf0ec1cf3a3f1a8eba7e79169f4f37af43c6b98"},
-    {file = "lxml-4.6.2-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:5be4a2e212bb6aa045e37f7d48e3e1e4b6fd259882ed5a00786f82e8c37ce77d"},
-    {file = "lxml-4.6.2-cp36-cp36m-win32.whl", hash = "sha256:8c88b599e226994ad4db29d93bc149aa1aff3dc3a4355dd5757569ba78632bdf"},
-    {file = "lxml-4.6.2-cp36-cp36m-win_amd64.whl", hash = "sha256:6e4183800f16f3679076dfa8abf2db3083919d7e30764a069fb66b2b9eff9939"},
-    {file = "lxml-4.6.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d8d3d4713f0c28bdc6c806a278d998546e8efc3498949e3ace6e117462ac0a5e"},
-    {file = "lxml-4.6.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:8246f30ca34dc712ab07e51dc34fea883c00b7ccb0e614651e49da2c49a30711"},
-    {file = "lxml-4.6.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:923963e989ffbceaa210ac37afc9b906acebe945d2723e9679b643513837b089"},
-    {file = "lxml-4.6.2-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:1471cee35eba321827d7d53d104e7b8c593ea3ad376aa2df89533ce8e1b24a01"},
-    {file = "lxml-4.6.2-cp37-cp37m-win32.whl", hash = "sha256:2363c35637d2d9d6f26f60a208819e7eafc4305ce39dc1d5005eccc4593331c2"},
-    {file = "lxml-4.6.2-cp37-cp37m-win_amd64.whl", hash = "sha256:f4822c0660c3754f1a41a655e37cb4dbbc9be3d35b125a37fab6f82d47674ebc"},
-    {file = "lxml-4.6.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0448576c148c129594d890265b1a83b9cd76fd1f0a6a04620753d9a6bcfd0a4d"},
-    {file = "lxml-4.6.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:60a20bfc3bd234d54d49c388950195d23a5583d4108e1a1d47c9eef8d8c042b3"},
-    {file = "lxml-4.6.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:2e5cc908fe43fe1aa299e58046ad66981131a66aea3129aac7770c37f590a644"},
-    {file = "lxml-4.6.2-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:50c348995b47b5a4e330362cf39fc503b4a43b14a91c34c83b955e1805c8e308"},
-    {file = "lxml-4.6.2-cp38-cp38-win32.whl", hash = "sha256:94d55bd03d8671686e3f012577d9caa5421a07286dd351dfef64791cf7c6c505"},
-    {file = "lxml-4.6.2-cp38-cp38-win_amd64.whl", hash = "sha256:7a7669ff50f41225ca5d6ee0a1ec8413f3a0d8aa2b109f86d540887b7ec0d72a"},
-    {file = "lxml-4.6.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e0bfe9bb028974a481410432dbe1b182e8191d5d40382e5b8ff39cdd2e5c5931"},
-    {file = "lxml-4.6.2-cp39-cp39-manylinux1_i686.whl", hash = "sha256:6fd8d5903c2e53f49e99359b063df27fdf7acb89a52b6a12494208bf61345a03"},
-    {file = "lxml-4.6.2-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:7e9eac1e526386df7c70ef253b792a0a12dd86d833b1d329e038c7a235dfceb5"},
-    {file = "lxml-4.6.2-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:7ee8af0b9f7de635c61cdd5b8534b76c52cd03536f29f51151b377f76e214a1a"},
-    {file = "lxml-4.6.2-cp39-cp39-win32.whl", hash = "sha256:2e6fd1b8acd005bd71e6c94f30c055594bbd0aa02ef51a22bbfa961ab63b2d75"},
-    {file = "lxml-4.6.2-cp39-cp39-win_amd64.whl", hash = "sha256:535332fe9d00c3cd455bd3dd7d4bacab86e2d564bdf7606079160fa6251caacf"},
-    {file = "lxml-4.6.2.tar.gz", hash = "sha256:cd11c7e8d21af997ee8079037fff88f16fda188a9776eb4b81c7e4c9c0a7d7fc"},
+    {file = "lxml-4.6.3-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:df7c53783a46febb0e70f6b05df2ba104610f2fb0d27023409734a3ecbb78fb2"},
+    {file = "lxml-4.6.3-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:1b7584d421d254ab86d4f0b13ec662a9014397678a7c4265a02a6d7c2b18a75f"},
+    {file = "lxml-4.6.3-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:079f3ae844f38982d156efce585bc540c16a926d4436712cf4baee0cce487a3d"},
+    {file = "lxml-4.6.3-cp27-cp27m-win32.whl", hash = "sha256:bc4313cbeb0e7a416a488d72f9680fffffc645f8a838bd2193809881c67dd106"},
+    {file = "lxml-4.6.3-cp27-cp27m-win_amd64.whl", hash = "sha256:8157dadbb09a34a6bd95a50690595e1fa0af1a99445e2744110e3dca7831c4ee"},
+    {file = "lxml-4.6.3-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:7728e05c35412ba36d3e9795ae8995e3c86958179c9770e65558ec3fdfd3724f"},
+    {file = "lxml-4.6.3-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:4bff24dfeea62f2e56f5bab929b4428ae6caba2d1eea0c2d6eb618e30a71e6d4"},
+    {file = "lxml-4.6.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:74f7d8d439b18fa4c385f3f5dfd11144bb87c1da034a466c5b5577d23a1d9b51"},
+    {file = "lxml-4.6.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:f90ba11136bfdd25cae3951af8da2e95121c9b9b93727b1b896e3fa105b2f586"},
+    {file = "lxml-4.6.3-cp35-cp35m-win32.whl", hash = "sha256:f2380a6376dfa090227b663f9678150ef27543483055cc327555fb592c5967e2"},
+    {file = "lxml-4.6.3-cp35-cp35m-win_amd64.whl", hash = "sha256:c4f05c5a7c49d2fb70223d0d5bcfbe474cf928310ac9fa6a7c6dddc831d0b1d4"},
+    {file = "lxml-4.6.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d2e35d7bf1c1ac8c538f88d26b396e73dd81440d59c1ef8522e1ea77b345ede4"},
+    {file = "lxml-4.6.3-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:289e9ca1a9287f08daaf796d96e06cb2bc2958891d7911ac7cae1c5f9e1e0ee3"},
+    {file = "lxml-4.6.3-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:bccbfc27563652de7dc9bdc595cb25e90b59c5f8e23e806ed0fd623755b6565d"},
+    {file = "lxml-4.6.3-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:820628b7b3135403540202e60551e741f9b6d3304371712521be939470b454ec"},
+    {file = "lxml-4.6.3-cp36-cp36m-win32.whl", hash = "sha256:5a0a14e264069c03e46f926be0d8919f4105c1623d620e7ec0e612a2e9bf1c04"},
+    {file = "lxml-4.6.3-cp36-cp36m-win_amd64.whl", hash = "sha256:92e821e43ad382332eade6812e298dc9701c75fe289f2a2d39c7960b43d1e92a"},
+    {file = "lxml-4.6.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:efd7a09678fd8b53117f6bae4fa3825e0a22b03ef0a932e070c0bdbb3a35e654"},
+    {file = "lxml-4.6.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:efac139c3f0bf4f0939f9375af4b02c5ad83a622de52d6dfa8e438e8e01d0eb0"},
+    {file = "lxml-4.6.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:0fbcf5565ac01dff87cbfc0ff323515c823081c5777a9fc7703ff58388c258c3"},
+    {file = "lxml-4.6.3-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:122fba10466c7bd4178b07dba427aa516286b846b2cbd6f6169141917283aae2"},
+    {file = "lxml-4.6.3-cp37-cp37m-win32.whl", hash = "sha256:3439c71103ef0e904ea0a1901611863e51f50b5cd5e8654a151740fde5e1cade"},
+    {file = "lxml-4.6.3-cp37-cp37m-win_amd64.whl", hash = "sha256:4289728b5e2000a4ad4ab8da6e1db2e093c63c08bdc0414799ee776a3f78da4b"},
+    {file = "lxml-4.6.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b007cbb845b28db4fb8b6a5cdcbf65bacb16a8bd328b53cbc0698688a68e1caa"},
+    {file = "lxml-4.6.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:76fa7b1362d19f8fbd3e75fe2fb7c79359b0af8747e6f7141c338f0bee2f871a"},
+    {file = "lxml-4.6.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:26e761ab5b07adf5f555ee82fb4bfc35bf93750499c6c7614bd64d12aaa67927"},
+    {file = "lxml-4.6.3-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:66e575c62792c3f9ca47cb8b6fab9e35bab91360c783d1606f758761810c9791"},
+    {file = "lxml-4.6.3-cp38-cp38-win32.whl", hash = "sha256:89b8b22a5ff72d89d48d0e62abb14340d9e99fd637d046c27b8b257a01ffbe28"},
+    {file = "lxml-4.6.3-cp38-cp38-win_amd64.whl", hash = "sha256:2a9d50e69aac3ebee695424f7dbd7b8c6d6eb7de2a2eb6b0f6c7db6aa41e02b7"},
+    {file = "lxml-4.6.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ce256aaa50f6cc9a649c51be3cd4ff142d67295bfc4f490c9134d0f9f6d58ef0"},
+    {file = "lxml-4.6.3-cp39-cp39-manylinux1_i686.whl", hash = "sha256:7610b8c31688f0b1be0ef882889817939490a36d0ee880ea562a4e1399c447a1"},
+    {file = "lxml-4.6.3-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:f8380c03e45cf09f8557bdaa41e1fa7c81f3ae22828e1db470ab2a6c96d8bc23"},
+    {file = "lxml-4.6.3-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:884ab9b29feaca361f7f88d811b1eea9bfca36cf3da27768d28ad45c3ee6f969"},
+    {file = "lxml-4.6.3-cp39-cp39-win32.whl", hash = "sha256:33bb934a044cf32157c12bfcfbb6649807da20aa92c062ef51903415c704704f"},
+    {file = "lxml-4.6.3-cp39-cp39-win_amd64.whl", hash = "sha256:542d454665a3e277f76954418124d67516c5f88e51a900365ed54a9806122b83"},
+    {file = "lxml-4.6.3.tar.gz", hash = "sha256:39b78571b3b30645ac77b95f7c69d1bffc4cf8c3b157c435a34da72e78c82468"},
 ]
 markupsafe = [
-    {file = "MarkupSafe-1.1.1-cp27-cp27m-macosx_10_6_intel.whl", hash = "sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161"},
-    {file = "MarkupSafe-1.1.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7"},
-    {file = "MarkupSafe-1.1.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183"},
-    {file = "MarkupSafe-1.1.1-cp27-cp27m-win32.whl", hash = "sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b"},
-    {file = "MarkupSafe-1.1.1-cp27-cp27m-win_amd64.whl", hash = "sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e"},
-    {file = "MarkupSafe-1.1.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f"},
-    {file = "MarkupSafe-1.1.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1"},
-    {file = "MarkupSafe-1.1.1-cp34-cp34m-macosx_10_6_intel.whl", hash = "sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5"},
-    {file = "MarkupSafe-1.1.1-cp34-cp34m-manylinux1_i686.whl", hash = "sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1"},
-    {file = "MarkupSafe-1.1.1-cp34-cp34m-manylinux1_x86_64.whl", hash = "sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735"},
-    {file = "MarkupSafe-1.1.1-cp34-cp34m-win32.whl", hash = "sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21"},
-    {file = "MarkupSafe-1.1.1-cp34-cp34m-win_amd64.whl", hash = "sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235"},
-    {file = "MarkupSafe-1.1.1-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b"},
-    {file = "MarkupSafe-1.1.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f"},
-    {file = "MarkupSafe-1.1.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905"},
-    {file = "MarkupSafe-1.1.1-cp35-cp35m-win32.whl", hash = "sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1"},
-    {file = "MarkupSafe-1.1.1-cp35-cp35m-win_amd64.whl", hash = "sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d"},
-    {file = "MarkupSafe-1.1.1-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff"},
-    {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473"},
-    {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e"},
-    {file = "MarkupSafe-1.1.1-cp36-cp36m-win32.whl", hash = "sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66"},
-    {file = "MarkupSafe-1.1.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5"},
-    {file = "MarkupSafe-1.1.1-cp37-cp37m-macosx_10_6_intel.whl", hash = "sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d"},
-    {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e"},
-    {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6"},
-    {file = "MarkupSafe-1.1.1-cp37-cp37m-win32.whl", hash = "sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2"},
-    {file = "MarkupSafe-1.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c"},
-    {file = "MarkupSafe-1.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6788b695d50a51edb699cb55e35487e430fa21f1ed838122d722e0ff0ac5ba15"},
-    {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:cdb132fc825c38e1aeec2c8aa9338310d29d337bebbd7baa06889d09a60a1fa2"},
-    {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:13d3144e1e340870b25e7b10b98d779608c02016d5184cfb9927a9f10c689f42"},
-    {file = "MarkupSafe-1.1.1-cp38-cp38-win32.whl", hash = "sha256:596510de112c685489095da617b5bcbbac7dd6384aeebeda4df6025d0256a81b"},
-    {file = "MarkupSafe-1.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be"},
-    {file = "MarkupSafe-1.1.1.tar.gz", hash = "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b"},
+    {file = "MarkupSafe-2.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51"},
+    {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:0955295dd5eec6cb6cc2fe1698f4c6d84af2e92de33fbcac4111913cd100a6ff"},
+    {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:0446679737af14f45767963a1a9ef7620189912317d095f2d9ffa183a4d25d2b"},
+    {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:f826e31d18b516f653fe296d967d700fddad5901ae07c622bb3705955e1faa94"},
+    {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872"},
+    {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:905fec760bd2fa1388bb5b489ee8ee5f7291d692638ea5f67982d968366bef9f"},
+    {file = "MarkupSafe-2.0.1-cp36-cp36m-win32.whl", hash = "sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d"},
+    {file = "MarkupSafe-2.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9"},
+    {file = "MarkupSafe-2.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567"},
+    {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:6557b31b5e2c9ddf0de32a691f2312a32f77cd7681d8af66c2692efdbef84c18"},
+    {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:49e3ceeabbfb9d66c3aef5af3a60cc43b85c33df25ce03d0031a608b0a8b2e3f"},
+    {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:d7f9850398e85aba693bb640262d3611788b1f29a79f0c93c565694658f4071f"},
+    {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:6a7fae0dd14cf60ad5ff42baa2e95727c3d81ded453457771d02b7d2b3f9c0c2"},
+    {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:b7f2d075102dc8c794cbde1947378051c4e5180d52d276987b8d28a3bd58c17d"},
+    {file = "MarkupSafe-2.0.1-cp37-cp37m-win32.whl", hash = "sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415"},
+    {file = "MarkupSafe-2.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914"},
+    {file = "MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:be98f628055368795d818ebf93da628541e10b75b41c559fdf36d104c5787066"},
+    {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:1d609f577dc6e1aa17d746f8bd3c31aa4d258f4070d61b2aa5c4166c1539de35"},
+    {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7d91275b0245b1da4d4cfa07e0faedd5b0812efc15b702576d103293e252af1b"},
+    {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:01a9b8ea66f1658938f65b93a85ebe8bc016e6769611be228d797c9d998dd298"},
+    {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:47ab1e7b91c098ab893b828deafa1203de86d0bc6ab587b160f78fe6c4011f75"},
+    {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:97383d78eb34da7e1fa37dd273c20ad4320929af65d156e35a5e2d89566d9dfb"},
+    {file = "MarkupSafe-2.0.1-cp38-cp38-win32.whl", hash = "sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64"},
+    {file = "MarkupSafe-2.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833"},
+    {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26"},
+    {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3c112550557578c26af18a1ccc9e090bfe03832ae994343cfdacd287db6a6ae7"},
+    {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:53edb4da6925ad13c07b6d26c2a852bd81e364f95301c66e930ab2aef5b5ddd8"},
+    {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:f5653a225f31e113b152e56f154ccbe59eeb1c7487b39b9d9f9cdb58e6c79dc5"},
+    {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:4efca8f86c54b22348a5467704e3fec767b2db12fc39c6d963168ab1d3fc9135"},
+    {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:ab3ef638ace319fa26553db0624c4699e31a28bb2a835c5faca8f8acf6a5a902"},
+    {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:f8ba0e8349a38d3001fae7eadded3f6606f0da5d748ee53cc1dab1d6527b9509"},
+    {file = "MarkupSafe-2.0.1-cp39-cp39-win32.whl", hash = "sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74"},
+    {file = "MarkupSafe-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8"},
+    {file = "MarkupSafe-2.0.1.tar.gz", hash = "sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a"},
 ]
 mccabe = [
     {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"},
@@ -1291,43 +1309,47 @@ mypy-extensions = [
     {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"},
 ]
 napalm = [
-    {file = "napalm-3.2.0-py2.py3-none-any.whl", hash = "sha256:6ab07a8a360150198b3c33c2fa4e92a9658cda9821736d24f2399343425d2af3"},
-    {file = "napalm-3.2.0.tar.gz", hash = "sha256:6e69a505f5d4a678c42f048d13153afabf10b7fec72868e3bfb53ff4089206fc"},
+    {file = "napalm-3.3.1-py2.py3-none-any.whl", hash = "sha256:ffa7e0c459df2c048ee75fef3f88beaf5f5dc5aecdae67cb2e479a22e3a717e6"},
+    {file = "napalm-3.3.1.tar.gz", hash = "sha256:6fe46d5b4ca761a2bde8ea2bea3e0b808a907afc808c6c67178060eb323320e8"},
 ]
 ncclient = [
-    {file = "ncclient-0.6.9.tar.gz", hash = "sha256:0112f2ad41fb658f52446d870853a63691d69299c73c7351c520d38dbd8dc0c4"},
+    {file = "ncclient-0.6.12.tar.gz", hash = "sha256:37c8a9f9a44f0346144119ab17ae6559e44b5a991f4c34ea3765c678079e4beb"},
 ]
 netaddr = [
     {file = "netaddr-0.8.0-py2.py3-none-any.whl", hash = "sha256:9666d0232c32d2656e5e5f8d735f58fd6c7457ce52fc21c98d45f2af78f990ac"},
     {file = "netaddr-0.8.0.tar.gz", hash = "sha256:d6cc57c7a07b1d9d2e917aa8b36ae8ce61c35ba3fcd1b83ca31c5a0ee2b5a243"},
 ]
 netmiko = [
-    {file = "netmiko-3.3.3-py3-none-any.whl", hash = "sha256:be165b81930aa779a2a34f4437af9f9807553030d2e3ef8da002314fb6b1366d"},
-    {file = "netmiko-3.3.3.tar.gz", hash = "sha256:ead6ea70b46307cce03d121d4da96fd862f76619474d6e962d1019560bb4c5a1"},
+    {file = "netmiko-3.4.0-py3-none-any.whl", hash = "sha256:b66f25717db3609878f83c85604349dd40a0ab494d8eafd817dcde8388131136"},
+    {file = "netmiko-3.4.0.tar.gz", hash = "sha256:acadb9dd97864ee848e2032f1f0e301c7b31e7a4153757d98f5c8ba1b9614993"},
+]
+netutils = [
+    {file = "netutils-0.2.1-py3-none-any.whl", hash = "sha256:8dae11f46e3d00cc6c38e97113e3ea9ef9e18f0f71cdb7c12e2c00b9f95fabcb"},
+    {file = "netutils-0.2.1.tar.gz", hash = "sha256:7ed1f46d5cd7383b86a50c7a05d8f6536230c8af46fd6eceab05fdac4a621a24"},
 ]
 nornir = [
-    {file = "nornir-3.0.0-py3-none-any.whl", hash = "sha256:a8f77a7677850e7632ea9ae35a86f9b09aae353d836bd3e42faae53f17f8b328"},
-    {file = "nornir-3.0.0.tar.gz", hash = "sha256:f87dec4d18d46102969272986bf4d7fab8cef212e2ad54a039f8e249f3e4c975"},
+    {file = "nornir-3.1.1-py3-none-any.whl", hash = "sha256:217199f923c810f4a54dec8d440eb08682c8a4ea4746325bd3067dca2e32cf9f"},
+    {file = "nornir-3.1.1.tar.gz", hash = "sha256:6abf8ca245aab8e36b5770ec94fdb456b6bf53696c6d68f2ee0882898630a392"},
 ]
 nornir-jinja2 = [
-    {file = "nornir_jinja2-0.1.1-py3-none-any.whl", hash = "sha256:6ae0e47eca1e084dc16ed4ffa788d19853637f0b629722e4eed29ca64f91c9b3"},
-    {file = "nornir_jinja2-0.1.1.tar.gz", hash = "sha256:ee4a90b38b1a7d25a272f52bb383e12c20568a0228406dae0e5262edfd4b3998"},
+    {file = "nornir_jinja2-0.2.0-py3-none-any.whl", hash = "sha256:0c446bec7a8492923d4eb9ca00fb327603b41bc35d5f0112843c048737b506b1"},
+    {file = "nornir_jinja2-0.2.0.tar.gz", hash = "sha256:9ee5e725fe5543dcba4ec8b976804e9e88ecd356ea3b62bad97578cea0de1f75"},
 ]
 nornir-napalm = [
-    {file = "nornir_napalm-0.1.1-py3-none-any.whl", hash = "sha256:f0def9ebedd99563cb95a7d390498b934106e1d8e2121dab4f132da02a75fd5d"},
-    {file = "nornir_napalm-0.1.1.tar.gz", hash = "sha256:92b861c5aaf429b40bb9c0a4b24ed471e4f9f3251fa49919200e0d502aad3563"},
+    {file = "nornir_napalm-0.1.2-py3-none-any.whl", hash = "sha256:313986bbb16eeaf3a80daf61f6a97e93ecebc47d0c586a2eb856ea91edc2cc1d"},
+    {file = "nornir_napalm-0.1.2.tar.gz", hash = "sha256:be7808a990242987500a65701edb626197c5d0b87f35d9eb5da7ce7e4d60fdd5"},
 ]
 nornir-netmiko = [
     {file = "nornir_netmiko-0.1.1-py3-none-any.whl", hash = "sha256:c6eadb81f6f3b2f0c27bae151cc62673303f9d085ec3c773ecdc98f20ef30f91"},
     {file = "nornir_netmiko-0.1.1.tar.gz", hash = "sha256:fc41ded40923d23c6155b92c6749170629b4cc2649c340d24bff9f49315836c6"},
 ]
 nornir-utils = [
-    {file = "nornir_utils-0.1.1-py3-none-any.whl", hash = "sha256:21e05774e27ae4d81cf48fd915951260e19b5da3494fc1c74e9ec0fa9742644e"},
-    {file = "nornir_utils-0.1.1.tar.gz", hash = "sha256:636a76a3bdad1a3a618189a01c5425e22cb65d8f361227d7d5a4ca92ed47b0d1"},
+    {file = "nornir_utils-0.1.2-py3-none-any.whl", hash = "sha256:98915e781d4135e424fe1d4617dc231ada9a7c732c8e51e408f53fd3d37a13b0"},
+    {file = "nornir_utils-0.1.2.tar.gz", hash = "sha256:23ae95c4805b0ce8a5ed32935f3f86027e5701175e7740ab8b3a79946c5d90b2"},
 ]
 ntc-templates = [
-    {file = "ntc_templates-1.6.0-py3-none-any.whl", hash = "sha256:a45ca5bf20d8b4585d63f732f3f605761e20279734dab76d1960c082fd6f2417"},
-    {file = "ntc_templates-1.6.0.tar.gz", hash = "sha256:a4420beee9cc14797d945b51bffd6e0126913b2dbc672d2e0a1530d3fec5b28d"},
+    {file = "ntc_templates-2.1.0-py3-none-any.whl", hash = "sha256:b42c0d32cf33ccc2ba89b2ec4268ad43d3d872ff569ecefe727b6649adacd175"},
+    {file = "ntc_templates-2.1.0.tar.gz", hash = "sha256:6ce17e48d951d531afa83ad3b68fda822a3d8937e8c955387053c501edfec41f"},
 ]
 packaging = [
     {file = "packaging-20.9-py2.py3-none-any.whl", hash = "sha256:67714da7f7bc052e064859c05c595155bd1ee9f69f76557e21f051443c20947a"},
@@ -1346,8 +1368,8 @@ pathspec = [
     {file = "pathspec-0.8.1.tar.gz", hash = "sha256:86379d6b86d75816baba717e64b1a3a3469deb93bb76d613c9ce79edc5cb68fd"},
 ]
 pbr = [
-    {file = "pbr-5.5.1-py2.py3-none-any.whl", hash = "sha256:b236cde0ac9a6aedd5e3c34517b423cd4fd97ef723849da6b0d2231142d89c00"},
-    {file = "pbr-5.5.1.tar.gz", hash = "sha256:5fad80b613c402d5b7df7bd84812548b2a61e9977387a80a5fc5c396492b13c9"},
+    {file = "pbr-5.6.0-py2.py3-none-any.whl", hash = "sha256:c68c661ac5cc81058ac94247278eeda6d2e6aecb3e227b0387c30d277e7ef8d4"},
+    {file = "pbr-5.6.0.tar.gz", hash = "sha256:42df03e7797b796625b1029c0400279c7c34fd7df24a7d7818a1abb5b38710dd"},
 ]
 pluggy = [
     {file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"},
@@ -1358,51 +1380,51 @@ py = [
     {file = "py-1.10.0.tar.gz", hash = "sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3"},
 ]
 pycodestyle = [
-    {file = "pycodestyle-2.6.0-py2.py3-none-any.whl", hash = "sha256:2295e7b2f6b5bd100585ebcb1f616591b652db8a741695b3d8f5d28bdc934367"},
-    {file = "pycodestyle-2.6.0.tar.gz", hash = "sha256:c58a7d2815e0e8d7972bf1803331fb0152f867bd89adf8a01dfd55085434192e"},
+    {file = "pycodestyle-2.7.0-py2.py3-none-any.whl", hash = "sha256:514f76d918fcc0b55c6680472f0a37970994e07bbb80725808c17089be302068"},
+    {file = "pycodestyle-2.7.0.tar.gz", hash = "sha256:c389c1d06bf7904078ca03399a4816f974a1d590090fecea0c63ec26ebaf1cef"},
 ]
 pycparser = [
     {file = "pycparser-2.20-py2.py3-none-any.whl", hash = "sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705"},
     {file = "pycparser-2.20.tar.gz", hash = "sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0"},
 ]
 pydantic = [
-    {file = "pydantic-1.7.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:c59ea046aea25be14dc22d69c97bee629e6d48d2b2ecb724d7fe8806bf5f61cd"},
-    {file = "pydantic-1.7.3-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a4143c8d0c456a093387b96e0f5ee941a950992904d88bc816b4f0e72c9a0009"},
-    {file = "pydantic-1.7.3-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:d8df4b9090b595511906fa48deda47af04e7d092318bfb291f4d45dfb6bb2127"},
-    {file = "pydantic-1.7.3-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:514b473d264671a5c672dfb28bdfe1bf1afd390f6b206aa2ec9fed7fc592c48e"},
-    {file = "pydantic-1.7.3-cp36-cp36m-win_amd64.whl", hash = "sha256:dba5c1f0a3aeea5083e75db9660935da90216f8a81b6d68e67f54e135ed5eb23"},
-    {file = "pydantic-1.7.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:59e45f3b694b05a69032a0d603c32d453a23f0de80844fb14d55ab0c6c78ff2f"},
-    {file = "pydantic-1.7.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:5b24e8a572e4b4c18f614004dda8c9f2c07328cb5b6e314d6e1bbd536cb1a6c1"},
-    {file = "pydantic-1.7.3-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:b2b054d095b6431cdda2f852a6d2f0fdec77686b305c57961b4c5dd6d863bf3c"},
-    {file = "pydantic-1.7.3-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:025bf13ce27990acc059d0c5be46f416fc9b293f45363b3d19855165fee1874f"},
-    {file = "pydantic-1.7.3-cp37-cp37m-win_amd64.whl", hash = "sha256:6e3874aa7e8babd37b40c4504e3a94cc2023696ced5a0500949f3347664ff8e2"},
-    {file = "pydantic-1.7.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e682f6442ebe4e50cb5e1cfde7dda6766fb586631c3e5569f6aa1951fd1a76ef"},
-    {file = "pydantic-1.7.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:185e18134bec5ef43351149fe34fda4758e53d05bb8ea4d5928f0720997b79ef"},
-    {file = "pydantic-1.7.3-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:f5b06f5099e163295b8ff5b1b71132ecf5866cc6e7f586d78d7d3fd6e8084608"},
-    {file = "pydantic-1.7.3-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:24ca47365be2a5a3cc3f4a26dcc755bcdc9f0036f55dcedbd55663662ba145ec"},
-    {file = "pydantic-1.7.3-cp38-cp38-win_amd64.whl", hash = "sha256:d1fe3f0df8ac0f3a9792666c69a7cd70530f329036426d06b4f899c025aca74e"},
-    {file = "pydantic-1.7.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f6864844b039805add62ebe8a8c676286340ba0c6d043ae5dea24114b82a319e"},
-    {file = "pydantic-1.7.3-cp39-cp39-manylinux1_i686.whl", hash = "sha256:ecb54491f98544c12c66ff3d15e701612fc388161fd455242447083350904730"},
-    {file = "pydantic-1.7.3-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:ffd180ebd5dd2a9ac0da4e8b995c9c99e7c74c31f985ba090ee01d681b1c4b95"},
-    {file = "pydantic-1.7.3-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:8d72e814c7821125b16f1553124d12faba88e85405b0864328899aceaad7282b"},
-    {file = "pydantic-1.7.3-cp39-cp39-win_amd64.whl", hash = "sha256:475f2fa134cf272d6631072554f845d0630907fce053926ff634cc6bc45bf1af"},
-    {file = "pydantic-1.7.3-py3-none-any.whl", hash = "sha256:38be427ea01a78206bcaf9a56f835784afcba9e5b88fbdce33bbbfbcd7841229"},
-    {file = "pydantic-1.7.3.tar.gz", hash = "sha256:213125b7e9e64713d16d988d10997dabc6a1f73f3991e1ff8e35ebb1409c7dc9"},
+    {file = "pydantic-1.7.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:3c60039e84552442defbcb5d56711ef0e057028ca7bfc559374917408a88d84e"},
+    {file = "pydantic-1.7.4-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:6e7e314acb170e143c6f3912f93f2ec80a96aa2009ee681356b7ce20d57e5c62"},
+    {file = "pydantic-1.7.4-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:8ef77cd17b73b5ba46788d040c0e820e49a2d80cfcd66fda3ba8be31094fd146"},
+    {file = "pydantic-1.7.4-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:115d8aa6f257a1d469c66b6bfc7aaf04cd87c25095f24542065c68ebcb42fe63"},
+    {file = "pydantic-1.7.4-cp36-cp36m-win_amd64.whl", hash = "sha256:66757d4e1eab69a3cfd3114480cc1d72b6dd847c4d30e676ae838c6740fdd146"},
+    {file = "pydantic-1.7.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4c92863263e4bd89e4f9cf1ab70d918170c51bd96305fe7b00853d80660acb26"},
+    {file = "pydantic-1.7.4-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:3b8154babf30a5e0fa3aa91f188356763749d9b30f7f211fafb247d4256d7877"},
+    {file = "pydantic-1.7.4-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:80cc46378505f7ff202879dcffe4bfbf776c15675028f6e08d1d10bdfbb168ac"},
+    {file = "pydantic-1.7.4-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:dda60d7878a5af2d8560c55c7c47a8908344aa78d32ec1c02d742ede09c534df"},
+    {file = "pydantic-1.7.4-cp37-cp37m-win_amd64.whl", hash = "sha256:4c1979d5cc3e14b35f0825caddea5a243dd6085e2a7539c006bc46997ef7a61a"},
+    {file = "pydantic-1.7.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8857576600c32aa488f18d30833aa833b54a48e3bab3adb6de97e463af71f8f8"},
+    {file = "pydantic-1.7.4-cp38-cp38-manylinux1_i686.whl", hash = "sha256:1f86d4da363badb39426a0ff494bf1d8510cd2f7274f460eee37bdbf2fd495ec"},
+    {file = "pydantic-1.7.4-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:3ea1256a9e782149381e8200119f3e2edea7cd6b123f1c79ab4bbefe4d9ba2c9"},
+    {file = "pydantic-1.7.4-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:e28455b42a0465a7bf2cde5eab530389226ce7dc779de28d17b8377245982b1e"},
+    {file = "pydantic-1.7.4-cp38-cp38-win_amd64.whl", hash = "sha256:47c5b1d44934375a3311891cabd450c150a31cf5c22e84aa172967bf186718be"},
+    {file = "pydantic-1.7.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:00250e5123dd0b123ff72be0e1b69140e0b0b9e404d15be3846b77c6f1b1e387"},
+    {file = "pydantic-1.7.4-cp39-cp39-manylinux1_i686.whl", hash = "sha256:d24aa3f7f791a023888976b600f2f389d3713e4f23b7a4c88217d3fce61cdffc"},
+    {file = "pydantic-1.7.4-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:2c44a9afd4c4c850885436a4209376857989aaf0853c7b118bb2e628d4b78c4e"},
+    {file = "pydantic-1.7.4-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:e87edd753da0ca1d44e308a1b1034859ffeab1f4a4492276bff9e1c3230db4fe"},
+    {file = "pydantic-1.7.4-cp39-cp39-win_amd64.whl", hash = "sha256:a3026ee105b5360855e500b4abf1a1d0b034d88e75a2d0d66a4c35e60858e15b"},
+    {file = "pydantic-1.7.4-py3-none-any.whl", hash = "sha256:a82385c6d5a77e3387e94612e3e34b77e13c39ff1295c26e3ba664e7b98073e2"},
+    {file = "pydantic-1.7.4.tar.gz", hash = "sha256:0a1abcbd525fbb52da58c813d54c2ec706c31a91afdb75411a73dd1dec036595"},
 ]
 pydocstyle = [
-    {file = "pydocstyle-5.1.1-py3-none-any.whl", hash = "sha256:aca749e190a01726a4fb472dd4ef23b5c9da7b9205c0a7857c06533de13fd678"},
-    {file = "pydocstyle-5.1.1.tar.gz", hash = "sha256:19b86fa8617ed916776a11cd8bc0197e5b9856d5433b777f51a3defe13075325"},
+    {file = "pydocstyle-6.1.1-py3-none-any.whl", hash = "sha256:6987826d6775056839940041beef5c08cc7e3d71d63149b48e36727f70144dc4"},
+    {file = "pydocstyle-6.1.1.tar.gz", hash = "sha256:1d41b7c459ba0ee6c345f2eb9ae827cab14a7533a88c5c6f7e94923f72df92dc"},
 ]
 pyeapi = [
     {file = "pyeapi-0.8.4.tar.gz", hash = "sha256:c33ad1eadd8ebac75f63488df9412081ce0b024c9e1da12a37196a5c60427c54"},
 ]
 pyflakes = [
-    {file = "pyflakes-2.2.0-py2.py3-none-any.whl", hash = "sha256:0d94e0e05a19e57a99444b6ddcf9a6eb2e5c68d3ca1e98e90707af8152c90a92"},
-    {file = "pyflakes-2.2.0.tar.gz", hash = "sha256:35b2d75ee967ea93b55750aa9edbbf72813e06a66ba54438df2cfac9e3c27fc8"},
+    {file = "pyflakes-2.3.1-py2.py3-none-any.whl", hash = "sha256:7893783d01b8a89811dd72d7dfd4d84ff098e5eed95cfa8905b22bbffe52efc3"},
+    {file = "pyflakes-2.3.1.tar.gz", hash = "sha256:f5bc8ecabc05bb9d291eb5203d6810b49040f6ff446a756326104746cc00c1db"},
 ]
 pylint = [
-    {file = "pylint-2.7.0-py3-none-any.whl", hash = "sha256:3ea3926700db399765db1faf53860f11e4e981a090646e9eacd01ca78e020579"},
-    {file = "pylint-2.7.0.tar.gz", hash = "sha256:2e0c6749d809985e4f181c336a8f89b2b797340d8049160bf95f35a3f0ecf6fc"},
+    {file = "pylint-2.9.3-py3-none-any.whl", hash = "sha256:5d46330e6b8886c31b5e3aba5ff48c10f4aa5e76cbf9002c6544306221e63fbc"},
+    {file = "pylint-2.9.3.tar.gz", hash = "sha256:23a1dc8b30459d78e9ff25942c61bb936108ccbe29dd9e71c01dc8274961709a"},
 ]
 pynacl = [
     {file = "PyNaCl-1.4.0-cp27-cp27m-macosx_10_10_x86_64.whl", hash = "sha256:ea6841bc3a76fa4942ce00f3bda7d436fda21e2d91602b9e21b7ca9ecab8f3ff"},
@@ -1425,8 +1447,8 @@ pynacl = [
     {file = "PyNaCl-1.4.0.tar.gz", hash = "sha256:54e9a2c849c742006516ad56a88f5c74bf2ce92c9f67435187c3c5953b346505"},
 ]
 pynautobot = [
-    {file = "pynautobot-1.0.1-py3-none-any.whl", hash = "sha256:449441fa9e3b744cc4e380baa0d51e8aa76c7ce950162d75f2816689615baae4"},
-    {file = "pynautobot-1.0.1.tar.gz", hash = "sha256:a77b1a99d9e004853d21ed08c7712f26d2a26b764684e3201f91352c2b976f45"},
+    {file = "pynautobot-1.0.2-py3-none-any.whl", hash = "sha256:19dd6fbb4663440f0d890137ff58dd5206cb4452f885f3eba7874888ca22727d"},
+    {file = "pynautobot-1.0.2.tar.gz", hash = "sha256:8cb0afe97a48f16301a7a4bd58e409b4517fb5c9c9fc808f2cce6ea4e99e1408"},
 ]
 pyparsing = [
     {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"},
@@ -1437,12 +1459,12 @@ pyserial = [
     {file = "pyserial-3.5.tar.gz", hash = "sha256:3c77e014170dfffbd816e6ffc205e9842efb10be9f58ec16d3e8675b4925cddb"},
 ]
 pytest = [
-    {file = "pytest-6.2.2-py3-none-any.whl", hash = "sha256:b574b57423e818210672e07ca1fa90aaf194a4f63f3ab909a2c67ebb22913839"},
-    {file = "pytest-6.2.2.tar.gz", hash = "sha256:9d1edf9e7d0b84d72ea3dbcdfd22b35fb543a5e8f2a60092dd578936bf63d7f9"},
+    {file = "pytest-6.2.4-py3-none-any.whl", hash = "sha256:91ef2131a9bd6be8f76f1f08eac5c5317221d6ad1e143ae03894b862e8976890"},
+    {file = "pytest-6.2.4.tar.gz", hash = "sha256:50bcad0a0b9c5a72c8e4e7c9855a3ad496ca6a881a3641b4260605450772c54b"},
 ]
 python-dotenv = [
-    {file = "python-dotenv-0.15.0.tar.gz", hash = "sha256:587825ed60b1711daea4832cf37524dfd404325b7db5e25ebe88c495c9f807a0"},
-    {file = "python_dotenv-0.15.0-py2.py3-none-any.whl", hash = "sha256:0c8d1b80d1a1e91717ea7d526178e3882732420b03f08afea0406db6402e220e"},
+    {file = "python-dotenv-0.18.0.tar.gz", hash = "sha256:effaac3c1e58d89b3ccb4d04a40dc7ad6e0275fda25fd75ae9d323e2465e202d"},
+    {file = "python_dotenv-0.18.0-py2.py3-none-any.whl", hash = "sha256:dd8fe852847f4fbfadabf6183ddd4c824a9651f02d51714fa075c95561959c7d"},
 ]
 pyyaml = [
     {file = "PyYAML-5.4.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:3b2b1824fe7112845700f815ff6a489360226a5609b96ec2190a45e62a9fc922"},
@@ -1468,104 +1490,94 @@ pyyaml = [
     {file = "PyYAML-5.4.1.tar.gz", hash = "sha256:607774cbba28732bfa802b54baa7484215f530991055bb562efbed5b2f20a45e"},
 ]
 regex = [
-    {file = "regex-2020.11.13-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:8b882a78c320478b12ff024e81dc7d43c1462aa4a3341c754ee65d857a521f85"},
-    {file = "regex-2020.11.13-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a63f1a07932c9686d2d416fb295ec2c01ab246e89b4d58e5fa468089cab44b70"},
-    {file = "regex-2020.11.13-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:6e4b08c6f8daca7d8f07c8d24e4331ae7953333dbd09c648ed6ebd24db5a10ee"},
-    {file = "regex-2020.11.13-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:bba349276b126947b014e50ab3316c027cac1495992f10e5682dc677b3dfa0c5"},
-    {file = "regex-2020.11.13-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:56e01daca75eae420bce184edd8bb341c8eebb19dd3bce7266332258f9fb9dd7"},
-    {file = "regex-2020.11.13-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:6a8ce43923c518c24a2579fda49f093f1397dad5d18346211e46f134fc624e31"},
-    {file = "regex-2020.11.13-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:1ab79fcb02b930de09c76d024d279686ec5d532eb814fd0ed1e0051eb8bd2daa"},
-    {file = "regex-2020.11.13-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:9801c4c1d9ae6a70aeb2128e5b4b68c45d4f0af0d1535500884d644fa9b768c6"},
-    {file = "regex-2020.11.13-cp36-cp36m-win32.whl", hash = "sha256:49cae022fa13f09be91b2c880e58e14b6da5d10639ed45ca69b85faf039f7a4e"},
-    {file = "regex-2020.11.13-cp36-cp36m-win_amd64.whl", hash = "sha256:749078d1eb89484db5f34b4012092ad14b327944ee7f1c4f74d6279a6e4d1884"},
-    {file = "regex-2020.11.13-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b2f4007bff007c96a173e24dcda236e5e83bde4358a557f9ccf5e014439eae4b"},
-    {file = "regex-2020.11.13-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:38c8fd190db64f513fe4e1baa59fed086ae71fa45083b6936b52d34df8f86a88"},
-    {file = "regex-2020.11.13-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5862975b45d451b6db51c2e654990c1820523a5b07100fc6903e9c86575202a0"},
-    {file = "regex-2020.11.13-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:262c6825b309e6485ec2493ffc7e62a13cf13fb2a8b6d212f72bd53ad34118f1"},
-    {file = "regex-2020.11.13-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:bafb01b4688833e099d79e7efd23f99172f501a15c44f21ea2118681473fdba0"},
-    {file = "regex-2020.11.13-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:e32f5f3d1b1c663af7f9c4c1e72e6ffe9a78c03a31e149259f531e0fed826512"},
-    {file = "regex-2020.11.13-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:3bddc701bdd1efa0d5264d2649588cbfda549b2899dc8d50417e47a82e1387ba"},
-    {file = "regex-2020.11.13-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:02951b7dacb123d8ea6da44fe45ddd084aa6777d4b2454fa0da61d569c6fa538"},
-    {file = "regex-2020.11.13-cp37-cp37m-win32.whl", hash = "sha256:0d08e71e70c0237883d0bef12cad5145b84c3705e9c6a588b2a9c7080e5af2a4"},
-    {file = "regex-2020.11.13-cp37-cp37m-win_amd64.whl", hash = "sha256:1fa7ee9c2a0e30405e21031d07d7ba8617bc590d391adfc2b7f1e8b99f46f444"},
-    {file = "regex-2020.11.13-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:baf378ba6151f6e272824b86a774326f692bc2ef4cc5ce8d5bc76e38c813a55f"},
-    {file = "regex-2020.11.13-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e3faaf10a0d1e8e23a9b51d1900b72e1635c2d5b0e1bea1c18022486a8e2e52d"},
-    {file = "regex-2020.11.13-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:2a11a3e90bd9901d70a5b31d7dd85114755a581a5da3fc996abfefa48aee78af"},
-    {file = "regex-2020.11.13-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:d1ebb090a426db66dd80df8ca85adc4abfcbad8a7c2e9a5ec7513ede522e0a8f"},
-    {file = "regex-2020.11.13-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:b2b1a5ddae3677d89b686e5c625fc5547c6e492bd755b520de5332773a8af06b"},
-    {file = "regex-2020.11.13-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:2c99e97d388cd0a8d30f7c514d67887d8021541b875baf09791a3baad48bb4f8"},
-    {file = "regex-2020.11.13-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:c084582d4215593f2f1d28b65d2a2f3aceff8342aa85afd7be23a9cad74a0de5"},
-    {file = "regex-2020.11.13-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:a3d748383762e56337c39ab35c6ed4deb88df5326f97a38946ddd19028ecce6b"},
-    {file = "regex-2020.11.13-cp38-cp38-win32.whl", hash = "sha256:7913bd25f4ab274ba37bc97ad0e21c31004224ccb02765ad984eef43e04acc6c"},
-    {file = "regex-2020.11.13-cp38-cp38-win_amd64.whl", hash = "sha256:6c54ce4b5d61a7129bad5c5dc279e222afd00e721bf92f9ef09e4fae28755683"},
-    {file = "regex-2020.11.13-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1862a9d9194fae76a7aaf0150d5f2a8ec1da89e8b55890b1786b8f88a0f619dc"},
-    {file = "regex-2020.11.13-cp39-cp39-manylinux1_i686.whl", hash = "sha256:4902e6aa086cbb224241adbc2f06235927d5cdacffb2425c73e6570e8d862364"},
-    {file = "regex-2020.11.13-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:7a25fcbeae08f96a754b45bdc050e1fb94b95cab046bf56b016c25e9ab127b3e"},
-    {file = "regex-2020.11.13-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:d2d8ce12b7c12c87e41123997ebaf1a5767a5be3ec545f64675388970f415e2e"},
-    {file = "regex-2020.11.13-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:f7d29a6fc4760300f86ae329e3b6ca28ea9c20823df123a2ea8693e967b29917"},
-    {file = "regex-2020.11.13-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:717881211f46de3ab130b58ec0908267961fadc06e44f974466d1887f865bd5b"},
-    {file = "regex-2020.11.13-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:3128e30d83f2e70b0bed9b2a34e92707d0877e460b402faca908c6667092ada9"},
-    {file = "regex-2020.11.13-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:8f6a2229e8ad946e36815f2a03386bb8353d4bde368fdf8ca5f0cb97264d3b5c"},
-    {file = "regex-2020.11.13-cp39-cp39-win32.whl", hash = "sha256:f8f295db00ef5f8bae530fc39af0b40486ca6068733fb860b42115052206466f"},
-    {file = "regex-2020.11.13-cp39-cp39-win_amd64.whl", hash = "sha256:a15f64ae3a027b64496a71ab1f722355e570c3fac5ba2801cafce846bf5af01d"},
-    {file = "regex-2020.11.13.tar.gz", hash = "sha256:83d6b356e116ca119db8e7c6fc2983289d87b27b3fac238cfe5dca529d884562"},
+    {file = "regex-2021.4.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:619d71c59a78b84d7f18891fe914446d07edd48dc8328c8e149cbe0929b4e000"},
+    {file = "regex-2021.4.4-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:47bf5bf60cf04d72bf6055ae5927a0bd9016096bf3d742fa50d9bf9f45aa0711"},
+    {file = "regex-2021.4.4-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:281d2fd05555079448537fe108d79eb031b403dac622621c78944c235f3fcf11"},
+    {file = "regex-2021.4.4-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:bd28bc2e3a772acbb07787c6308e00d9626ff89e3bfcdebe87fa5afbfdedf968"},
+    {file = "regex-2021.4.4-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:7c2a1af393fcc09e898beba5dd59196edaa3116191cc7257f9224beaed3e1aa0"},
+    {file = "regex-2021.4.4-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:c38c71df845e2aabb7fb0b920d11a1b5ac8526005e533a8920aea97efb8ec6a4"},
+    {file = "regex-2021.4.4-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:96fcd1888ab4d03adfc9303a7b3c0bd78c5412b2bfbe76db5b56d9eae004907a"},
+    {file = "regex-2021.4.4-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:ade17eb5d643b7fead300a1641e9f45401c98eee23763e9ed66a43f92f20b4a7"},
+    {file = "regex-2021.4.4-cp36-cp36m-win32.whl", hash = "sha256:e8e5b509d5c2ff12f8418006d5a90e9436766133b564db0abaec92fd27fcee29"},
+    {file = "regex-2021.4.4-cp36-cp36m-win_amd64.whl", hash = "sha256:11d773d75fa650cd36f68d7ca936e3c7afaae41b863b8c387a22aaa78d3c5c79"},
+    {file = "regex-2021.4.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d3029c340cfbb3ac0a71798100ccc13b97dddf373a4ae56b6a72cf70dfd53bc8"},
+    {file = "regex-2021.4.4-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:18c071c3eb09c30a264879f0d310d37fe5d3a3111662438889ae2eb6fc570c31"},
+    {file = "regex-2021.4.4-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:4c557a7b470908b1712fe27fb1ef20772b78079808c87d20a90d051660b1d69a"},
+    {file = "regex-2021.4.4-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:01afaf2ec48e196ba91b37451aa353cb7eda77efe518e481707e0515025f0cd5"},
+    {file = "regex-2021.4.4-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:3a9cd17e6e5c7eb328517969e0cb0c3d31fd329298dd0c04af99ebf42e904f82"},
+    {file = "regex-2021.4.4-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:90f11ff637fe8798933fb29f5ae1148c978cccb0452005bf4c69e13db951e765"},
+    {file = "regex-2021.4.4-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:919859aa909429fb5aa9cf8807f6045592c85ef56fdd30a9a3747e513db2536e"},
+    {file = "regex-2021.4.4-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:339456e7d8c06dd36a22e451d58ef72cef293112b559010db3d054d5560ef439"},
+    {file = "regex-2021.4.4-cp37-cp37m-win32.whl", hash = "sha256:67bdb9702427ceddc6ef3dc382455e90f785af4c13d495f9626861763ee13f9d"},
+    {file = "regex-2021.4.4-cp37-cp37m-win_amd64.whl", hash = "sha256:32e65442138b7b76dd8173ffa2cf67356b7bc1768851dded39a7a13bf9223da3"},
+    {file = "regex-2021.4.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1e1c20e29358165242928c2de1482fb2cf4ea54a6a6dea2bd7a0e0d8ee321500"},
+    {file = "regex-2021.4.4-cp38-cp38-manylinux1_i686.whl", hash = "sha256:314d66636c494ed9c148a42731b3834496cc9a2c4251b1661e40936814542b14"},
+    {file = "regex-2021.4.4-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:6d1b01031dedf2503631d0903cb563743f397ccaf6607a5e3b19a3d76fc10480"},
+    {file = "regex-2021.4.4-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:741a9647fcf2e45f3a1cf0e24f5e17febf3efe8d4ba1281dcc3aa0459ef424dc"},
+    {file = "regex-2021.4.4-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:4c46e22a0933dd783467cf32b3516299fb98cfebd895817d685130cc50cd1093"},
+    {file = "regex-2021.4.4-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:e512d8ef5ad7b898cdb2d8ee1cb09a8339e4f8be706d27eaa180c2f177248a10"},
+    {file = "regex-2021.4.4-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:980d7be47c84979d9136328d882f67ec5e50008681d94ecc8afa8a65ed1f4a6f"},
+    {file = "regex-2021.4.4-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:ce15b6d103daff8e9fee13cf7f0add05245a05d866e73926c358e871221eae87"},
+    {file = "regex-2021.4.4-cp38-cp38-win32.whl", hash = "sha256:a91aa8619b23b79bcbeb37abe286f2f408d2f2d6f29a17237afda55bb54e7aac"},
+    {file = "regex-2021.4.4-cp38-cp38-win_amd64.whl", hash = "sha256:c0502c0fadef0d23b128605d69b58edb2c681c25d44574fc673b0e52dce71ee2"},
+    {file = "regex-2021.4.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:598585c9f0af8374c28edd609eb291b5726d7cbce16be6a8b95aa074d252ee17"},
+    {file = "regex-2021.4.4-cp39-cp39-manylinux1_i686.whl", hash = "sha256:ee54ff27bf0afaf4c3b3a62bcd016c12c3fdb4ec4f413391a90bd38bc3624605"},
+    {file = "regex-2021.4.4-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:7d9884d86dd4dd489e981d94a65cd30d6f07203d90e98f6f657f05170f6324c9"},
+    {file = "regex-2021.4.4-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:bf5824bfac591ddb2c1f0a5f4ab72da28994548c708d2191e3b87dd207eb3ad7"},
+    {file = "regex-2021.4.4-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:563085e55b0d4fb8f746f6a335893bda5c2cef43b2f0258fe1020ab1dd874df8"},
+    {file = "regex-2021.4.4-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:b9c3db21af35e3b3c05764461b262d6f05bbca08a71a7849fd79d47ba7bc33ed"},
+    {file = "regex-2021.4.4-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:3916d08be28a1149fb97f7728fca1f7c15d309a9f9682d89d79db75d5e52091c"},
+    {file = "regex-2021.4.4-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:fd45ff9293d9274c5008a2054ecef86a9bfe819a67c7be1afb65e69b405b3042"},
+    {file = "regex-2021.4.4-cp39-cp39-win32.whl", hash = "sha256:fa4537fb4a98fe8fde99626e4681cc644bdcf2a795038533f9f711513a862ae6"},
+    {file = "regex-2021.4.4-cp39-cp39-win_amd64.whl", hash = "sha256:97f29f57d5b84e73fbaf99ab3e26134e6687348e95ef6b48cfd2c06807005a07"},
+    {file = "regex-2021.4.4.tar.gz", hash = "sha256:52ba3d3f9b942c49d7e4bc105bb28551c44065f139a65062ab7912bef10c9afb"},
 ]
 requests = [
     {file = "requests-2.25.1-py2.py3-none-any.whl", hash = "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"},
     {file = "requests-2.25.1.tar.gz", hash = "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804"},
 ]
 requests-mock = [
-    {file = "requests-mock-1.8.0.tar.gz", hash = "sha256:e68f46844e4cee9d447150343c9ae875f99fa8037c6dcf5f15bf1fe9ab43d226"},
-    {file = "requests_mock-1.8.0-py2.py3-none-any.whl", hash = "sha256:11215c6f4df72702aa357f205cf1e537cffd7392b3e787b58239bde5fb3db53b"},
+    {file = "requests-mock-1.9.3.tar.gz", hash = "sha256:8d72abe54546c1fc9696fa1516672f1031d72a55a1d66c85184f972a24ba0eba"},
+    {file = "requests_mock-1.9.3-py2.py3-none-any.whl", hash = "sha256:0a2d38a117c08bb78939ec163522976ad59a6b7fdd82b709e23bb98004a44970"},
 ]
 "ruamel.yaml" = [
-    {file = "ruamel.yaml-0.16.12-py2.py3-none-any.whl", hash = "sha256:012b9470a0ea06e4e44e99e7920277edf6b46eee0232a04487ea73a7386340a5"},
-    {file = "ruamel.yaml-0.16.12.tar.gz", hash = "sha256:076cc0bc34f1966d920a49f18b52b6ad559fbe656a0748e3535cf7b3f29ebf9e"},
+    {file = "ruamel.yaml-0.16.13-py2.py3-none-any.whl", hash = "sha256:64b06e7873eb8e1125525ecef7345447d786368cadca92a7cd9b59eae62e95a3"},
+    {file = "ruamel.yaml-0.16.13.tar.gz", hash = "sha256:bb48c514222702878759a05af96f4b7ecdba9b33cd4efcf25c86b882cef3a942"},
 ]
 "ruamel.yaml.clib" = [
-    {file = "ruamel.yaml.clib-0.2.2-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:28116f204103cb3a108dfd37668f20abe6e3cafd0d3fd40dba126c732457b3cc"},
-    {file = "ruamel.yaml.clib-0.2.2-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:daf21aa33ee9b351f66deed30a3d450ab55c14242cfdfcd377798e2c0d25c9f1"},
-    {file = "ruamel.yaml.clib-0.2.2-cp27-cp27m-win32.whl", hash = "sha256:30dca9bbcbb1cc858717438218d11eafb78666759e5094dd767468c0d577a7e7"},
-    {file = "ruamel.yaml.clib-0.2.2-cp27-cp27m-win_amd64.whl", hash = "sha256:f6061a31880c1ed6b6ce341215336e2f3d0c1deccd84957b6fa8ca474b41e89f"},
-    {file = "ruamel.yaml.clib-0.2.2-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:73b3d43e04cc4b228fa6fa5d796409ece6fcb53a6c270eb2048109cbcbc3b9c2"},
-    {file = "ruamel.yaml.clib-0.2.2-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:53b9dd1abd70e257a6e32f934ebc482dac5edb8c93e23deb663eac724c30b026"},
-    {file = "ruamel.yaml.clib-0.2.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:839dd72545ef7ba78fd2aa1a5dd07b33696adf3e68fae7f31327161c1093001b"},
-    {file = "ruamel.yaml.clib-0.2.2-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:1236df55e0f73cd138c0eca074ee086136c3f16a97c2ac719032c050f7e0622f"},
-    {file = "ruamel.yaml.clib-0.2.2-cp35-cp35m-win32.whl", hash = "sha256:b1e981fe1aff1fd11627f531524826a4dcc1f26c726235a52fcb62ded27d150f"},
-    {file = "ruamel.yaml.clib-0.2.2-cp35-cp35m-win_amd64.whl", hash = "sha256:4e52c96ca66de04be42ea2278012a2342d89f5e82b4512fb6fb7134e377e2e62"},
-    {file = "ruamel.yaml.clib-0.2.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:a873e4d4954f865dcb60bdc4914af7eaae48fb56b60ed6daa1d6251c72f5337c"},
-    {file = "ruamel.yaml.clib-0.2.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:ab845f1f51f7eb750a78937be9f79baea4a42c7960f5a94dde34e69f3cce1988"},
-    {file = "ruamel.yaml.clib-0.2.2-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:2fd336a5c6415c82e2deb40d08c222087febe0aebe520f4d21910629018ab0f3"},
-    {file = "ruamel.yaml.clib-0.2.2-cp36-cp36m-win32.whl", hash = "sha256:e9f7d1d8c26a6a12c23421061f9022bb62704e38211fe375c645485f38df34a2"},
-    {file = "ruamel.yaml.clib-0.2.2-cp36-cp36m-win_amd64.whl", hash = "sha256:2602e91bd5c1b874d6f93d3086f9830f3e907c543c7672cf293a97c3fabdcd91"},
-    {file = "ruamel.yaml.clib-0.2.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:44c7b0498c39f27795224438f1a6be6c5352f82cb887bc33d962c3a3acc00df6"},
-    {file = "ruamel.yaml.clib-0.2.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:8e8fd0a22c9d92af3a34f91e8a2594eeb35cba90ab643c5e0e643567dc8be43e"},
-    {file = "ruamel.yaml.clib-0.2.2-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:75f0ee6839532e52a3a53f80ce64925ed4aed697dd3fa890c4c918f3304bd4f4"},
-    {file = "ruamel.yaml.clib-0.2.2-cp37-cp37m-win32.whl", hash = "sha256:464e66a04e740d754170be5e740657a3b3b6d2bcc567f0c3437879a6e6087ff6"},
-    {file = "ruamel.yaml.clib-0.2.2-cp37-cp37m-win_amd64.whl", hash = "sha256:52ae5739e4b5d6317b52f5b040b1b6639e8af68a5b8fd606a8b08658fbd0cab5"},
-    {file = "ruamel.yaml.clib-0.2.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4df5019e7783d14b79217ad9c56edf1ba7485d614ad5a385d1b3c768635c81c0"},
-    {file = "ruamel.yaml.clib-0.2.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:5254af7d8bdf4d5484c089f929cb7f5bafa59b4f01d4f48adda4be41e6d29f99"},
-    {file = "ruamel.yaml.clib-0.2.2-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:8be05be57dc5c7b4a0b24edcaa2f7275866d9c907725226cdde46da09367d923"},
-    {file = "ruamel.yaml.clib-0.2.2-cp38-cp38-win32.whl", hash = "sha256:74161d827407f4db9072011adcfb825b5258a5ccb3d2cd518dd6c9edea9e30f1"},
-    {file = "ruamel.yaml.clib-0.2.2-cp38-cp38-win_amd64.whl", hash = "sha256:058a1cc3df2a8aecc12f983a48bda99315cebf55a3b3a5463e37bb599b05727b"},
-    {file = "ruamel.yaml.clib-0.2.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c6ac7e45367b1317e56f1461719c853fd6825226f45b835df7436bb04031fd8a"},
-    {file = "ruamel.yaml.clib-0.2.2-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:b4b0d31f2052b3f9f9b5327024dc629a253a83d8649d4734ca7f35b60ec3e9e5"},
-    {file = "ruamel.yaml.clib-0.2.2-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:1f8c0a4577c0e6c99d208de5c4d3fd8aceed9574bb154d7a2b21c16bb924154c"},
-    {file = "ruamel.yaml.clib-0.2.2-cp39-cp39-win32.whl", hash = "sha256:46d6d20815064e8bb023ea8628cfb7402c0f0e83de2c2227a88097e239a7dffd"},
-    {file = "ruamel.yaml.clib-0.2.2-cp39-cp39-win_amd64.whl", hash = "sha256:6c0a5dc52fc74eb87c67374a4e554d4761fd42a4d01390b7e868b30d21f4b8bb"},
-    {file = "ruamel.yaml.clib-0.2.2.tar.gz", hash = "sha256:2d24bd98af676f4990c4d715bcdc2a60b19c56a3fb3a763164d2d8ca0e806ba7"},
+    {file = "ruamel.yaml.clib-0.2.4-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:329ac9064c1cfff9fc77fbecd90d07d698176fcd0720bfef9c2d27faa09dcc0e"},
+    {file = "ruamel.yaml.clib-0.2.4-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:091a38f04f8a332ba7b3dba26197cd522bc29936943b3d1732ce3c463bb6b275"},
+    {file = "ruamel.yaml.clib-0.2.4-cp35-cp35m-win32.whl", hash = "sha256:650cc8e65e2568fac84dc14970a09fe21b013a90621fff1626ea6d656cc03dc4"},
+    {file = "ruamel.yaml.clib-0.2.4-cp35-cp35m-win_amd64.whl", hash = "sha256:729869106d5b7eb5e0260f7da4fcfef2cd9b324729fadc08edc27b1e86ad3013"},
+    {file = "ruamel.yaml.clib-0.2.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:2ae2f58c18991c8565d41018177548a91c2f1511d8a185254632388f142fbae9"},
+    {file = "ruamel.yaml.clib-0.2.4-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:c8a04c3f62a0b6a2696d003dd30e96e0b9d4a5ff450fe359c39a4a7466b9b935"},
+    {file = "ruamel.yaml.clib-0.2.4-cp36-cp36m-win32.whl", hash = "sha256:fd400bd19ea3e86bad9fb5176ab7efb6efb5e440cc2fd435c86de021620d8fa7"},
+    {file = "ruamel.yaml.clib-0.2.4-cp36-cp36m-win_amd64.whl", hash = "sha256:b1772bff158f785085ebc8e635a0b9450f0072413bc89d8fc7f0ee803d1ab7f8"},
+    {file = "ruamel.yaml.clib-0.2.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3271fb4a379050735f90177d1e61b5cc9acb5130baf995f3c775fa2aa2b113fb"},
+    {file = "ruamel.yaml.clib-0.2.4-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:aa157cee912030d8abfb97b278295abbb7923dedfd892f2e94c22adbf5730398"},
+    {file = "ruamel.yaml.clib-0.2.4-cp37-cp37m-win32.whl", hash = "sha256:202e4751f038383241036e79640e7efd23d7272e3ce0cc8a11b9804ad604c5da"},
+    {file = "ruamel.yaml.clib-0.2.4-cp37-cp37m-win_amd64.whl", hash = "sha256:3e506603394f5a678e9b924324bc1352c0493d7010ab4df687eb6d868631f9fb"},
+    {file = "ruamel.yaml.clib-0.2.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b9f95ae85986b53d6d0d253d570a9bb3a229e5319f1f76b2ba7809fa86cad890"},
+    {file = "ruamel.yaml.clib-0.2.4-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:2b9a62080d18c7fa17443e37f0d941d1be0a66ddcf5be5253f91cc59a15a9c1e"},
+    {file = "ruamel.yaml.clib-0.2.4-cp38-cp38-win32.whl", hash = "sha256:769468005ce63bad78575b9d9f095f388ac1f45a331969e04135ac9626c3529d"},
+    {file = "ruamel.yaml.clib-0.2.4-cp38-cp38-win_amd64.whl", hash = "sha256:83d72c5434151071cb67690be0034f9162ea282e58e47f9e8d23e8d14ca96584"},
+    {file = "ruamel.yaml.clib-0.2.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:243941fe8f98053662f0394057b29d7146fe56e1b0011971302ea75e4b111529"},
+    {file = "ruamel.yaml.clib-0.2.4-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:2d75c965c407fdef9d1b33cd39faf47aa106d3fa2cf83960ec9ed95c4c9a55bc"},
+    {file = "ruamel.yaml.clib-0.2.4-cp39-cp39-win32.whl", hash = "sha256:f012b89c56f936e31f12a1484f08964c4681ae75488bc79c8909f37c517500f6"},
+    {file = "ruamel.yaml.clib-0.2.4-cp39-cp39-win_amd64.whl", hash = "sha256:a6d8749819403338093c61ee897b97d0f4aa73297e97feb1705d143c002b5bed"},
+    {file = "ruamel.yaml.clib-0.2.4.tar.gz", hash = "sha256:f997f13fd94e37e8b7d7dbe759088bb428adc6570da06b64a913d932d891ac8d"},
 ]
 scp = [
-    {file = "scp-0.13.3-py2.py3-none-any.whl", hash = "sha256:f2fa9fb269ead0f09b4e2ceb47621beb7000c135f272f6b70d3d9d29928d7bf0"},
-    {file = "scp-0.13.3.tar.gz", hash = "sha256:8bd748293d7362073169b96ce4b8c4f93bcc62cfc5f7e1d949e01e406a025bd4"},
+    {file = "scp-0.13.5-py2.py3-none-any.whl", hash = "sha256:be62d3ca534790dbaa509634fe28af6729f0d798388eaa5fdd3a1b191556dbde"},
+    {file = "scp-0.13.5.tar.gz", hash = "sha256:0ab2ee9178b8be53dc5c9fe2f33761e01a2435087f5c9fb5b54519873c650d60"},
 ]
 six = [
-    {file = "six-1.15.0-py2.py3-none-any.whl", hash = "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"},
-    {file = "six-1.15.0.tar.gz", hash = "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259"},
+    {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
+    {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
 ]
 smmap = [
-    {file = "smmap-3.0.5-py2.py3-none-any.whl", hash = "sha256:7bfcf367828031dc893530a29cb35eb8c8f2d7c8f2d0989354d75d24c8573714"},
-    {file = "smmap-3.0.5.tar.gz", hash = "sha256:84c2751ef3072d4f6b2785ec7ee40244c6f45eb934d9e543e2c51f1bd3d54c50"},
+    {file = "smmap-4.0.0-py2.py3-none-any.whl", hash = "sha256:a9a7479e4c572e2e775c404dcd3080c8dc49f39918c2cf74913d30c4c478e3c2"},
+    {file = "smmap-4.0.0.tar.gz", hash = "sha256:7e65386bd122d45405ddf795637b7f7d2b532e7e401d46bbe3fb49b9986d5182"},
 ]
 snowballstemmer = [
     {file = "snowballstemmer-2.1.0-py2.py3-none-any.whl", hash = "sha256:b51b447bea85f9968c13b650126a888aabd4cb4463fca868ec596826325dedc2"},
@@ -1576,72 +1588,72 @@ stevedore = [
     {file = "stevedore-3.3.0.tar.gz", hash = "sha256:3a5bbd0652bf552748871eaa73a4a8dc2899786bc497a2aa1fcb4dcdb0debeee"},
 ]
 tenacity = [
-    {file = "tenacity-6.3.1-py2.py3-none-any.whl", hash = "sha256:baed357d9f35ec64264d8a4bbf004c35058fad8795c5b0d8a7dc77ecdcbb8f39"},
-    {file = "tenacity-6.3.1.tar.gz", hash = "sha256:e14d191fb0a309b563904bbc336582efe2037de437e543b38da749769b544d7f"},
+    {file = "tenacity-7.0.0-py2.py3-none-any.whl", hash = "sha256:a0ce48587271515db7d3a5e700df9ae69cce98c4b57c23a4886da15243603dd8"},
+    {file = "tenacity-7.0.0.tar.gz", hash = "sha256:5bd16ef5d3b985647fe28dfa6f695d343aa26479a04e8792b9d3c8f49e361ae1"},
 ]
 textfsm = [
-    {file = "textfsm-1.1.0-py2.py3-none-any.whl", hash = "sha256:0aef3f9cad3d03905915fd62bff358c42b7dc35c863ff2cb0b5324c2b746cc24"},
+    {file = "textfsm-1.1.2-py2.py3-none-any.whl", hash = "sha256:f3d4e9bd4344935a08e6844e53d6220e2e4fb7e465bee51fa909152ed6bab406"},
+    {file = "textfsm-1.1.2.tar.gz", hash = "sha256:85a450b441aff04b1cac726bdb36f35534a5b196cca08c8bc14fddd879c4255c"},
 ]
 toml = [
     {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"},
     {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"},
 ]
 transitions = [
-    {file = "transitions-0.8.7-py2.py3-none-any.whl", hash = "sha256:626229df01ea91dc0b28491bf5af7cc0aba6c2aa7289658e55ea77288258fa49"},
-    {file = "transitions-0.8.7.tar.gz", hash = "sha256:8c60ec0828cd037820726283cad5d4d77a5e31514e058b51250420e9873e9bc7"},
+    {file = "transitions-0.8.8-py2.py3-none-any.whl", hash = "sha256:f35efa070fbdf9a0f3f093b19f1258068786af75786a8cbcc884444f3d1a66d4"},
+    {file = "transitions-0.8.8.tar.gz", hash = "sha256:e7a86b31a161a76133f189b3ae9dad2755a80ea4c1e0eee1805648d021fb677d"},
 ]
 typed-ast = [
-    {file = "typed_ast-1.4.2-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:7703620125e4fb79b64aa52427ec192822e9f45d37d4b6625ab37ef403e1df70"},
-    {file = "typed_ast-1.4.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:c9aadc4924d4b5799112837b226160428524a9a45f830e0d0f184b19e4090487"},
-    {file = "typed_ast-1.4.2-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:9ec45db0c766f196ae629e509f059ff05fc3148f9ffd28f3cfe75d4afb485412"},
-    {file = "typed_ast-1.4.2-cp35-cp35m-win32.whl", hash = "sha256:85f95aa97a35bdb2f2f7d10ec5bbdac0aeb9dafdaf88e17492da0504de2e6400"},
-    {file = "typed_ast-1.4.2-cp35-cp35m-win_amd64.whl", hash = "sha256:9044ef2df88d7f33692ae3f18d3be63dec69c4fb1b5a4a9ac950f9b4ba571606"},
-    {file = "typed_ast-1.4.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:c1c876fd795b36126f773db9cbb393f19808edd2637e00fd6caba0e25f2c7b64"},
-    {file = "typed_ast-1.4.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:5dcfc2e264bd8a1db8b11a892bd1647154ce03eeba94b461effe68790d8b8e07"},
-    {file = "typed_ast-1.4.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:8db0e856712f79c45956da0c9a40ca4246abc3485ae0d7ecc86a20f5e4c09abc"},
-    {file = "typed_ast-1.4.2-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:d003156bb6a59cda9050e983441b7fa2487f7800d76bdc065566b7d728b4581a"},
-    {file = "typed_ast-1.4.2-cp36-cp36m-win32.whl", hash = "sha256:4c790331247081ea7c632a76d5b2a265e6d325ecd3179d06e9cf8d46d90dd151"},
-    {file = "typed_ast-1.4.2-cp36-cp36m-win_amd64.whl", hash = "sha256:d175297e9533d8d37437abc14e8a83cbc68af93cc9c1c59c2c292ec59a0697a3"},
-    {file = "typed_ast-1.4.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cf54cfa843f297991b7388c281cb3855d911137223c6b6d2dd82a47ae5125a41"},
-    {file = "typed_ast-1.4.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:b4fcdcfa302538f70929eb7b392f536a237cbe2ed9cba88e3bf5027b39f5f77f"},
-    {file = "typed_ast-1.4.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:987f15737aba2ab5f3928c617ccf1ce412e2e321c77ab16ca5a293e7bbffd581"},
-    {file = "typed_ast-1.4.2-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:37f48d46d733d57cc70fd5f30572d11ab8ed92da6e6b28e024e4a3edfb456e37"},
-    {file = "typed_ast-1.4.2-cp37-cp37m-win32.whl", hash = "sha256:36d829b31ab67d6fcb30e185ec996e1f72b892255a745d3a82138c97d21ed1cd"},
-    {file = "typed_ast-1.4.2-cp37-cp37m-win_amd64.whl", hash = "sha256:8368f83e93c7156ccd40e49a783a6a6850ca25b556c0fa0240ed0f659d2fe496"},
-    {file = "typed_ast-1.4.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:963c80b583b0661918718b095e02303d8078950b26cc00b5e5ea9ababe0de1fc"},
-    {file = "typed_ast-1.4.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e683e409e5c45d5c9082dc1daf13f6374300806240719f95dc783d1fc942af10"},
-    {file = "typed_ast-1.4.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:84aa6223d71012c68d577c83f4e7db50d11d6b1399a9c779046d75e24bed74ea"},
-    {file = "typed_ast-1.4.2-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:a38878a223bdd37c9709d07cd357bb79f4c760b29210e14ad0fb395294583787"},
-    {file = "typed_ast-1.4.2-cp38-cp38-win32.whl", hash = "sha256:a2c927c49f2029291fbabd673d51a2180038f8cd5a5b2f290f78c4516be48be2"},
-    {file = "typed_ast-1.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:c0c74e5579af4b977c8b932f40a5464764b2f86681327410aa028a22d2f54937"},
-    {file = "typed_ast-1.4.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:07d49388d5bf7e863f7fa2f124b1b1d89d8aa0e2f7812faff0a5658c01c59aa1"},
-    {file = "typed_ast-1.4.2-cp39-cp39-manylinux1_i686.whl", hash = "sha256:240296b27397e4e37874abb1df2a608a92df85cf3e2a04d0d4d61055c8305ba6"},
-    {file = "typed_ast-1.4.2-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:d746a437cdbca200622385305aedd9aef68e8a645e385cc483bdc5e488f07166"},
-    {file = "typed_ast-1.4.2-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:14bf1522cdee369e8f5581238edac09150c765ec1cb33615855889cf33dcb92d"},
-    {file = "typed_ast-1.4.2-cp39-cp39-win32.whl", hash = "sha256:cc7b98bf58167b7f2db91a4327da24fb93368838eb84a44c472283778fc2446b"},
-    {file = "typed_ast-1.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:7147e2a76c75f0f64c4319886e7639e490fee87c9d25cb1d4faef1d8cf83a440"},
-    {file = "typed_ast-1.4.2.tar.gz", hash = "sha256:9fc0b3cb5d1720e7141d103cf4819aea239f7d136acf9ee4a69b047b7986175a"},
+    {file = "typed_ast-1.4.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:2068531575a125b87a41802130fa7e29f26c09a2833fea68d9a40cf33902eba6"},
+    {file = "typed_ast-1.4.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:c907f561b1e83e93fad565bac5ba9c22d96a54e7ea0267c708bffe863cbe4075"},
+    {file = "typed_ast-1.4.3-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:1b3ead4a96c9101bef08f9f7d1217c096f31667617b58de957f690c92378b528"},
+    {file = "typed_ast-1.4.3-cp35-cp35m-win32.whl", hash = "sha256:dde816ca9dac1d9c01dd504ea5967821606f02e510438120091b84e852367428"},
+    {file = "typed_ast-1.4.3-cp35-cp35m-win_amd64.whl", hash = "sha256:777a26c84bea6cd934422ac2e3b78863a37017618b6e5c08f92ef69853e765d3"},
+    {file = "typed_ast-1.4.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f8afcf15cc511ada719a88e013cec87c11aff7b91f019295eb4530f96fe5ef2f"},
+    {file = "typed_ast-1.4.3-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:52b1eb8c83f178ab787f3a4283f68258525f8d70f778a2f6dd54d3b5e5fb4341"},
+    {file = "typed_ast-1.4.3-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:01ae5f73431d21eead5015997ab41afa53aa1fbe252f9da060be5dad2c730ace"},
+    {file = "typed_ast-1.4.3-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:c190f0899e9f9f8b6b7863debfb739abcb21a5c054f911ca3596d12b8a4c4c7f"},
+    {file = "typed_ast-1.4.3-cp36-cp36m-win32.whl", hash = "sha256:398e44cd480f4d2b7ee8d98385ca104e35c81525dd98c519acff1b79bdaac363"},
+    {file = "typed_ast-1.4.3-cp36-cp36m-win_amd64.whl", hash = "sha256:bff6ad71c81b3bba8fa35f0f1921fb24ff4476235a6e94a26ada2e54370e6da7"},
+    {file = "typed_ast-1.4.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0fb71b8c643187d7492c1f8352f2c15b4c4af3f6338f21681d3681b3dc31a266"},
+    {file = "typed_ast-1.4.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:760ad187b1041a154f0e4d0f6aae3e40fdb51d6de16e5c99aedadd9246450e9e"},
+    {file = "typed_ast-1.4.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5feca99c17af94057417d744607b82dd0a664fd5e4ca98061480fd8b14b18d04"},
+    {file = "typed_ast-1.4.3-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:95431a26309a21874005845c21118c83991c63ea800dd44843e42a916aec5899"},
+    {file = "typed_ast-1.4.3-cp37-cp37m-win32.whl", hash = "sha256:aee0c1256be6c07bd3e1263ff920c325b59849dc95392a05f258bb9b259cf39c"},
+    {file = "typed_ast-1.4.3-cp37-cp37m-win_amd64.whl", hash = "sha256:9ad2c92ec681e02baf81fdfa056fe0d818645efa9af1f1cd5fd6f1bd2bdfd805"},
+    {file = "typed_ast-1.4.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b36b4f3920103a25e1d5d024d155c504080959582b928e91cb608a65c3a49e1a"},
+    {file = "typed_ast-1.4.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:067a74454df670dcaa4e59349a2e5c81e567d8d65458d480a5b3dfecec08c5ff"},
+    {file = "typed_ast-1.4.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7538e495704e2ccda9b234b82423a4038f324f3a10c43bc088a1636180f11a41"},
+    {file = "typed_ast-1.4.3-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:af3d4a73793725138d6b334d9d247ce7e5f084d96284ed23f22ee626a7b88e39"},
+    {file = "typed_ast-1.4.3-cp38-cp38-win32.whl", hash = "sha256:f2362f3cb0f3172c42938946dbc5b7843c2a28aec307c49100c8b38764eb6927"},
+    {file = "typed_ast-1.4.3-cp38-cp38-win_amd64.whl", hash = "sha256:dd4a21253f42b8d2b48410cb31fe501d32f8b9fbeb1f55063ad102fe9c425e40"},
+    {file = "typed_ast-1.4.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f328adcfebed9f11301eaedfa48e15bdece9b519fb27e6a8c01aa52a17ec31b3"},
+    {file = "typed_ast-1.4.3-cp39-cp39-manylinux1_i686.whl", hash = "sha256:2c726c276d09fc5c414693a2de063f521052d9ea7c240ce553316f70656c84d4"},
+    {file = "typed_ast-1.4.3-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:cae53c389825d3b46fb37538441f75d6aecc4174f615d048321b716df2757fb0"},
+    {file = "typed_ast-1.4.3-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:b9574c6f03f685070d859e75c7f9eeca02d6933273b5e69572e5ff9d5e3931c3"},
+    {file = "typed_ast-1.4.3-cp39-cp39-win32.whl", hash = "sha256:209596a4ec71d990d71d5e0d312ac935d86930e6eecff6ccc7007fe54d703808"},
+    {file = "typed_ast-1.4.3-cp39-cp39-win_amd64.whl", hash = "sha256:9c6d1a54552b5330bc657b7ef0eae25d00ba7ffe85d9ea8ae6540d2197a3788c"},
+    {file = "typed_ast-1.4.3.tar.gz", hash = "sha256:fb1bbeac803adea29cedd70781399c99138358c26d05fcbd23c13016b7f5ec65"},
 ]
 typing-extensions = [
-    {file = "typing_extensions-3.7.4.3-py2-none-any.whl", hash = "sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f"},
-    {file = "typing_extensions-3.7.4.3-py3-none-any.whl", hash = "sha256:7cb407020f00f7bfc3cb3e7881628838e69d8f3fcab2f64742a5e76b2f841918"},
-    {file = "typing_extensions-3.7.4.3.tar.gz", hash = "sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c"},
+    {file = "typing_extensions-3.10.0.0-py2-none-any.whl", hash = "sha256:0ac0f89795dd19de6b97debb0c6af1c70987fd80a2d62d1958f7e56fcc31b497"},
+    {file = "typing_extensions-3.10.0.0-py3-none-any.whl", hash = "sha256:779383f6086d90c99ae41cf0ff39aac8a7937a9283ce0a414e5dd782f4c94a84"},
+    {file = "typing_extensions-3.10.0.0.tar.gz", hash = "sha256:50b6f157849174217d0656f99dc82fe932884fb250826c18350e159ec6cdf342"},
 ]
 urllib3 = [
-    {file = "urllib3-1.26.3-py2.py3-none-any.whl", hash = "sha256:1b465e494e3e0d8939b50680403e3aedaa2bc434b7d5af64dfd3c958d7f5ae80"},
-    {file = "urllib3-1.26.3.tar.gz", hash = "sha256:de3eedaad74a2683334e282005cd8d7f22f4d55fa690a2a1020a416cb0a47e73"},
+    {file = "urllib3-1.26.6-py2.py3-none-any.whl", hash = "sha256:39fb8672126159acb139a7718dd10806104dec1e2f0f6c88aab05d17df10c8d4"},
+    {file = "urllib3-1.26.6.tar.gz", hash = "sha256:f57b4c16c62fa2760b7e3d97c35b255512fb6b59a259730f36ba32ce9f8e342f"},
 ]
 wrapt = [
     {file = "wrapt-1.12.1.tar.gz", hash = "sha256:b62ffa81fb85f4332a4f609cab4ac40709470da05643a082ec1eb88e6d9b97d7"},
 ]
 yamllint = [
-    {file = "yamllint-1.26.0-py2.py3-none-any.whl", hash = "sha256:8a5f8e442f49309eaf3e9d7232ce76f2fc8026f5c0c0b164b83f33fed1399637"},
-    {file = "yamllint-1.26.0.tar.gz", hash = "sha256:b0e4c89985c7f5f8451c2eb8c67d804d10ac13a4abe031cbf49bdf3465d01087"},
+    {file = "yamllint-1.26.1.tar.gz", hash = "sha256:87d9462b3ed7e9dfa19caa177f7a77cd9888b3dc4044447d6ae0ab233bcd1324"},
 ]
 yamlordereddictloader = [
     {file = "yamlordereddictloader-0.4.0.tar.gz", hash = "sha256:7f30f0b99ea3f877f7cb340c570921fa9d639b7f69cba18be051e27f8de2080e"},
 ]
 zipp = [
-    {file = "zipp-3.4.0-py3-none-any.whl", hash = "sha256:102c24ef8f171fd729d46599845e95c7ab894a4cf45f5de11a44cc7444fb1108"},
-    {file = "zipp-3.4.0.tar.gz", hash = "sha256:ed5eee1974372595f9e416cc7bbeeb12335201d8081ca8a0743c954d4446e5cb"},
+    {file = "zipp-3.4.1-py3-none-any.whl", hash = "sha256:51cb66cc54621609dd593d1787f286ee42a5c0adbb4b29abea5a63edc3e03098"},
+    {file = "zipp-3.4.1.tar.gz", hash = "sha256:3607921face881ba3e026887d8150cca609d517579abe052ac81fc5aeffdbd76"},
 ]
diff --git a/pyproject.toml b/pyproject.toml
index 5b43680..c8ade7b 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
 [tool.poetry]
 name = "nornir-nautobot"
-version = "1.0.0"
+version = "2.1.2"
 description = "Nornir Nautobot"
 authors = ["Network to Code, LLC <opensource@networktocode.com>"]
 readme = "README.md"
@@ -21,11 +21,12 @@ documentation = "https://nornir-nautobot.readthedocs.io"
 python = "^3.6"
 nornir = "^3.0.0"
 requests = "^2.25.1"
-nornir-utils = "^0.1.1"
-nornir-napalm = "^0.1.1"
-nornir-jinja2 = "^0.1.1"
-nornir-netmiko = "^0.1.1"
+nornir-utils = "^0"
+nornir-napalm = "^0"
+nornir-jinja2 = "^0"
+nornir-netmiko = "^0"
 pynautobot = "^1.0.1"
+netutils = "^0"
 
 [tool.poetry.dev-dependencies]
 pytest = "*"


Test patch:
diff --git a/tests/unit/mocks/01_get_devices.json b/tests/unit/mocks/01_get_devices.json
index 11ef7d3..0afc2c9 100644
--- a/tests/unit/mocks/01_get_devices.json
+++ b/tests/unit/mocks/01_get_devices.json
@@ -1,5 +1,5 @@
 {
-    "count": 12,
+    "count": 3,
     "next": null,
     "previous": null,
     "results": [
@@ -28,12 +28,7 @@
                 "slug": "network"
             },
             "tenant": null,
-            "platform": {
-                "id": 2,
-                "url": "http://nautobot-demo.com/api/dcim/platforms/2/",
-                "name": "Cisco IOS",
-                "slug": "ios"
-            },
+            "platform": null,
             "serial": "9ZYX8XZUMP0AF69YGO5Z5",
             "asset_tag": null,
             "site": {
diff --git a/tests/unit/test_nautobot_inventory.py b/tests/unit/test_nautobot_inventory.py
index 909584a..86b31d5 100644
--- a/tests/unit/test_nautobot_inventory.py
+++ b/tests/unit/test_nautobot_inventory.py
@@ -7,6 +7,8 @@
 from requests.sessions import Session
 import pynautobot
 from requests_mock import Mocker
+from nornir import InitNornir
+from nornir.core.task import Task
 
 # Application Imports
 from nornir_nautobot.plugins.inventory.nautobot import NautobotInventory
@@ -134,3 +136,177 @@ def test_filter_devices():
             expected_devices.append(pynautobot_obj.dcim.devices.get(name=device))
 
         assert test_class.devices == expected_devices
+
+
+def test_device_required_properties():
+    def mock_nornir_task(task: Task):
+        """Example to show work inside of a task.
+
+        Args:
+            task (Task): Nornir Task
+        """
+        return task.host.platform
+
+    with Mocker() as mock:
+        load_api_calls(mock)
+        test_nornir = InitNornir(
+            inventory={
+                "plugin": "NautobotInventory",
+                "options": {
+                    "nautobot_url": "http://mock.example.com",
+                    "nautobot_token": "0123456789abcdef01234567890",
+                    "filter_parameters": {"site": "msp"},
+                },
+            },
+        )
+
+    # Run through Nornir tasks
+    nornir_task_result = test_nornir.run(task=mock_nornir_task)
+
+    # Verify expected result
+    for task_result in nornir_task_result:
+        assert nornir_task_result[task_result].result == "ios"
+
+
+def test_nornir_nautobot_device_count():
+    # Import mock requests
+    with Mocker() as mock:
+        load_api_calls(mock)
+        test_nornir = InitNornir(
+            inventory={
+                "plugin": "NautobotInventory",
+                "options": {
+                    "nautobot_url": "http://mock.example.com",
+                    "nautobot_token": "0123456789abcdef01234567890",
+                },
+            },
+        )
+
+    # Verify that the length of the inventory is 3 devices
+    assert len(test_nornir.inventory.hosts) == 3
+
+
+def test_nornir_nautobot_with_defaults():
+    """
+    Tests that nornir defaults are getting applied to NautobotInventory hosts
+    """
+    with Mocker() as mock:
+        load_api_calls(mock)
+        nr_obj = InitNornir(
+            inventory={
+                "plugin": "NautobotInventory",
+                "options": {
+                    "nautobot_url": "http://mock.example.com",
+                    "nautobot_token": "0123456789abcdef01234567890",
+                    "pynautobot_dict": False,
+                },
+            },
+            logging={"enabled": False},
+        )
+        nr_obj.inventory.defaults.username = "username"
+        nr_obj.inventory.defaults.password = "password"
+
+        assert nr_obj.inventory.hosts["den-dist01"].username == nr_obj.inventory.defaults.username
+        assert nr_obj.inventory.hosts["den-dist02"].password == nr_obj.inventory.defaults.password
+
+
+@pytest.mark.parametrize(
+    "device, expected_platform", [("den-dist01", None), ("den-wan01", "ios"), ("den-dist02", "ios")]
+)
+def test_nornir_nautobot_device_platform(device, expected_platform):
+    # Import mock requests
+    with Mocker() as mock:
+        load_api_calls(mock)
+        test_nornir = InitNornir(
+            inventory={
+                "plugin": "NautobotInventory",
+                "options": {
+                    "nautobot_url": "http://mock.example.com",
+                    "nautobot_token": "0123456789abcdef01234567890",
+                },
+            },
+        )
+
+    assert test_nornir.inventory.hosts[device].platform == expected_platform
+
+
+@pytest.mark.parametrize(
+    "device, expected_hostname", [("den-dist01", "10.17.1.2"), ("den-wan01", "10.16.0.2"), ("den-dist02", "10.17.1.6")]
+)
+def test_nornir_nautobot_device_hostname(device, expected_hostname):
+    # Import mock requests
+    with Mocker() as mock:
+        load_api_calls(mock)
+        test_nornir = InitNornir(
+            inventory={
+                "plugin": "NautobotInventory",
+                "options": {
+                    "nautobot_url": "http://mock.example.com",
+                    "nautobot_token": "0123456789abcdef01234567890",
+                },
+            },
+        )
+
+    assert test_nornir.inventory.hosts[device].hostname == expected_hostname
+
+
+# Setup of groups for a future PR
+@pytest.mark.parametrize("device, expected_groups", [("den-dist01", []), ("den-wan01", []), ("den-dist02", [])])
+def test_nornir_nautobot_device_groups(device, expected_groups):
+    # Import mock requests
+    with Mocker() as mock:
+        load_api_calls(mock)
+        test_nornir = InitNornir(
+            inventory={
+                "plugin": "NautobotInventory",
+                "options": {
+                    "nautobot_url": "http://mock.example.com",
+                    "nautobot_token": "0123456789abcdef01234567890",
+                },
+            },
+        )
+
+    assert test_nornir.inventory.hosts[device].groups == expected_groups
+
+
+@pytest.mark.parametrize("device", ["den-dist01", "den-wan01", "den-dist02"])
+def test_pynautobot_as_dict(device):
+    """
+    Test the pynautobot flag sets the presence of a 'pynautobot_dictionary' data attribute
+    """
+    # Import mock requests
+    with Mocker() as mock:
+        load_api_calls(mock)
+        nornir_with_pynb_dict = InitNornir(
+            inventory={
+                "plugin": "NautobotInventory",
+                "options": {
+                    "nautobot_url": "http://mock.example.com",
+                    "nautobot_token": "0123456789abcdef01234567890",
+                },
+            },
+            logging={"enabled": False},
+        )
+        assert "pynautobot_dictionary" in list(nornir_with_pynb_dict.inventory.hosts[device].keys())
+
+
+@pytest.mark.parametrize("device", ["den-dist01", "den-wan01", "den-dist02"])
+def test_no_pynautobot_as_dict(device):
+    """
+    Test the pynautobot flag unsets the presence of a 'pynautobot_dictionary' data attribute
+    """
+    # Import mock requests
+    with Mocker() as mock:
+        load_api_calls(mock)
+        nornir_no_pynb_dict = InitNornir(
+            inventory={
+                "plugin": "NautobotInventory",
+                "options": {
+                    "nautobot_url": "http://mock.example.com",
+                    "nautobot_token": "0123456789abcdef01234567890",
+                    "pynautobot_dict": False,
+                },
+            },
+            logging={"enabled": False},
+        )
+        assert "pynautobot_dictionary" not in list(nornir_no_pynb_dict.inventory.hosts[device].keys())