Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

File restructure and Linting #103

Merged
merged 17 commits into from
Oct 13, 2023
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions .github/workflows/Pynetbox.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: Pynetbox Data Uploader Tests

on:
push:
branches:
- master
pull_request:
paths:
- "Pynetbox_Data_Uploader/**"
- ".github/workflows/Pynetbox.yaml"

jobs:
test_and_lint:
runs-on: ubuntu-20.04
strategy:
matrix:
python-version: ["3.x"]
steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v3
with:
python-version: ${{ matrix.python-version }}
cache: "pip"

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r Pynetbox_Data_Uploader/requirements.txt

- name: Run tests
run: cd Pynetbox_Data_Uploader && python3 -m pytest .

- name: Analyse with pylint
run: |
cd Pynetbox_Data_Uploader && pylint $(git ls-files '*.py') --rcfile=.pylintrc

1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,3 @@ venv/

.coverage
coverage.xml
Netbox_CSV_Read/DataFiles
14 changes: 14 additions & 0 deletions Pynetbox_Data_Uploader/.pylintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[FORMAT]
# Black will enforce 88 chars on Python code
# this will enforce 120 chars on docs / comments
max-line-length=120

# Disable various warnings:
# C0114: Missing module string - we don't need module strings for the small repo
# C0115: Missing class doc string - a lot of the actions are self explanatory
# W0511: TODOs they're well....to do later
# R0801: Similar lines - Imports and method signatures will flag this, such as forwarding action args
# C0116: Missing method docstring - Adds too much noise
# E0401: Ignore import errors as imports work

disable=C0114,C0115,E0401,W0511,R0801,C0116,E0401
Empty file.
Empty file.
Original file line number Diff line number Diff line change
@@ -1,30 +1,30 @@
import pandas
from typing import List, Dict
import pandas as pd


class CsvUtils:
"""
This class provides methods to read data from CSV files and allow the data to be easily read and used elsewhere.
This class provides methods to read data from csv_things files
and allow the data to be easily read and used elsewhere.
"""
def __init__(self):
self.pd = pandas

def csv_to_python(self, file_path: str) -> Dict:
@staticmethod
def csv_to_python(file_path: str) -> Dict:
"""
This method reads data from csv files and writes them to a dictionary.
:param file_path: The file path of the CSV file to be read from.
:param file_path: The file path of the csv_things file to be read from.
:return: Returns the data from the csv as a dictionary.
"""
dataframe = self.pd.read_csv(file_path)
dataframe = pd.read_csv(file_path)
dataframe = dataframe.to_dict(orient="list")
return dataframe

@staticmethod
def separate_data(data: dict) -> List:
"""
This method reduces Pandas CSV to Dict conversion to individual dictionaries.
:param data: The data from the CSV file
:return: Returns a list of dictionaries which each represent a row of data from CSV.
This method reduces Pandas csv_things to Dict conversion to individual dictionaries.
:param data: The data from the csv_things file
:return: Returns a list of dictionaries which each represent a row of data from csv_things.
"""
data_keys = list(data.keys())
len_rows = len(data[data_keys[0]])
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
from typing import Dict, List
from Enums.dcim_device_id import DeviceInfoID
from Enums.dcim_device_no_id import DeviceInfoNoID
from Netbox_Api.netbox_connect import NetboxConnect
from Netbox_Api.netbox_data import NetboxGetID
from enums.dcim_device_id import DeviceInfoID
from enums.dcim_device_no_id import DeviceInfoNoID
from netbox_api.netbox_connect import NetboxConnect
from netbox_api.netbox_data import NetboxGetID


class FormatDict(NetboxConnect):
"""
This class takes dictionaries with string values and changes those to ID values from Netbox.
"""

def __init__(self, dicts: list):
"""
This method initialises the class with the following parameters.
Expand Down
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ class DeviceInfoID(Enum):
"""
This Enums Class stores enums that are used to retrieve data from Netbox.
"""

DEVICE_ROLE = "dcim.device_roles"
DESCRIPTION = "dcim.devices"
DEVICE_TYPE = "dcim.device_types"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ class DeviceInfoNoID(Enum):
"""
This Enums Class stores enums that are used to retrieve data from Netbox.
"""
position = "position"
name = "name"
serial = "serial"
airflow = "airflow"
status = "status"
face = "face"

POSITION = "position"
NAME = "name"
SERIAL = "serial"
AIRFLOW = "airflow"
STATUS = "status"
FACE = "face"
Empty file.
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import pynetbox as nb

# pylint:disable = too-few-public-methods


class NetboxConnect:
"""
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from typing import Optional
from Netbox_Api.netbox_connect import NetboxConnect
from netbox_api.netbox_connect import NetboxConnect


class NetboxDCIM:
Expand All @@ -23,7 +23,7 @@ def create_device(self, data: dict | list) -> bool:
return bool(devices)

def create_device_type(
self, model: str, slug: str, manufacturer: str, u_height=1
self, model: str, slug: str, manufacturer: str, u_height=1
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you forgot type hint for u_height

) -> bool:
"""
This method creates a new device type in Netbox.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
from Netbox_Api.netbox_connect import NetboxConnect
from Enums.dcim_device_id import DeviceInfoID
from Enums.dcim_device_no_id import DeviceInfoNoID
from operator import attrgetter
from typing import Optional
from typing import Optional, Union
from netbox_api.netbox_connect import NetboxConnect
from enums.dcim_device_id import DeviceInfoID
from enums.dcim_device_no_id import DeviceInfoNoID

# pylint:disable = too-few-public-methods


class NetboxGetID(NetboxConnect):
"""
This class retrieves field value ID's from Netbox.
"""

def __init__(self, url: str, token: str, api: Optional = None):
"""
This method initialises the class with the following parameters.
Expand All @@ -23,21 +26,23 @@ def __init__(self, url: str, token: str, api: Optional = None):
self.enums_id = DeviceInfoID
self.enums_no_id = DeviceInfoNoID

def get_id(self, attr_string: str, netbox_value: str, site_value: str) -> int | str:
def get_id(
self, attr_string: str, netbox_value: str, site_value: str
) -> Union[int, str]:
"""
This method uses the Pynetbox Api .get() method to retrieve the ID of a string value from Netbox.
This method uses Pynetbox Api .get() to retrieve the ID of a string value from Netbox.
:param attr_string: The attribute string to get.
:param netbox_value: The value to search for in Netbox.
:param site_value: The value of the site key in the dictionary
:return: Returns the value/ID
"""
attr_string = attr_string.upper()
attr_to_look_for = getattr(self.enums_id, attr_string).value # Gets Enums value
attr_to_look_for = getattr(self.enums_id, attr_string).value # Gets enums value
value = attrgetter(attr_to_look_for)(self.netbox) # Gets netbox attr
if attr_string == "DEVICE_TYPE":
value = value.get(slug=netbox_value).id
elif attr_string == "LOCATION":
if type(site_value) == int:
if isinstance(site_value, int):
site_name = self.netbox.dcim.sites.get(site_value).name
site_slug = site_name.replace(" ", "-").lower()
value = value.get(name=netbox_value, site=site_slug)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from typing import Optional
from Netbox_Api.netbox_connect import NetboxConnect
from netbox_api.netbox_connect import NetboxConnect


class NetboxExistence:
Expand Down Expand Up @@ -29,4 +29,4 @@ def check_device_type_exists(self, device_type: str) -> bool:
:return: Returns bool.
"""
device_type = self.netbox.dcim.device_types.get(slug=device_type)
return bool(device_type)
return bool(device_type)
5 changes: 5 additions & 0 deletions Pynetbox_Data_Uploader/pytest.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[pytest]
pythonpath = lib
testpaths = Tests
python_files = *.py
python_functions = test_*
Binary file not shown.
Empty file.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from unittest.mock import MagicMock, NonCallableMock
from CSV.csv_utils import CsvUtils
from unittest.mock import NonCallableMock, patch
from csv_things.csv_utils import CsvUtils
import pytest


Expand All @@ -12,10 +12,9 @@ def test_csv_to_python(instance):
"""
This test ensures that the csv_read method is called once with the file_path arg.
"""
mock_dataframe = MagicMock()
file_path = NonCallableMock()
instance.pd = mock_dataframe
instance.csv_to_python(file_path)
with patch("csv_things.csv_utils.pd") as mock_dataframe:
instance.csv_to_python(file_path)
mock_dataframe.read_csv.assert_called_once_with(file_path)


Expand All @@ -24,7 +23,9 @@ def test_separate_data(instance):
This test ensures that the dictionaries from panda formatted into row by row dictionaries.
These are much more understandable and can be used individually or in bulk.
"""
test_data = {"key1": ["Adata1", "Bdata1"],
"key2": ["Adata2", "Bdata2"]}
test_data = {"key1": ["Adata1", "Bdata1"], "key2": ["Adata2", "Bdata2"]}
format_data = instance.separate_data(test_data)
assert format_data == [{"key1": "Adata1", "key2": "Adata2"}, {"key1": "Bdata1", "key2": "Bdata2"}]
assert format_data == [
{"key1": "Adata1", "key2": "Adata2"},
{"key1": "Bdata1", "key2": "Bdata2"},
]
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from unittest.mock import MagicMock, NonCallableMock, patch
from Netbox_Api.netbox_connect import NetboxConnect
from unittest.mock import NonCallableMock, patch
from netbox_api.netbox_connect import NetboxConnect
import pytest


Expand All @@ -14,7 +14,7 @@ def test_api_object(instance):
"""
This test checks that the Api method is called once.
"""
with patch("Netbox_Api.netbox_connect.nb") as mock_netbox:
with patch("netbox_api.netbox_connect.nb") as mock_netbox:
res = instance.api_object()
mock_netbox.api.assert_called_once_with(instance.url, instance.token)
assert res == mock_netbox.api.return_value
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from unittest.mock import MagicMock, NonCallableMock
from Netbox_Api.netbox_create import NetboxDCIM
from netbox_api.netbox_create import NetboxDCIM
import pytest


Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from unittest.mock import MagicMock, NonCallableMock
from Netbox_Api.netbox_existence import NetboxExistence
from netbox_api.netbox_existence import NetboxExistence
import pytest


Expand Down Expand Up @@ -34,4 +34,4 @@ def test_check_device_type_exists(instance):
device_type = NonCallableMock()
instance.netbox.dcim.device_types = mock_device_types
instance.check_device_type_exists(device_type)
mock_device_types.get.assert_called_once_with(slug=device_type)
mock_device_types.get.assert_called_once_with(slug=device_type)