Skip to content

Commit

Permalink
Merge branch 'master' into better-feedback
Browse files Browse the repository at this point in the history
# Conflicts:
#	inventree/api.py
  • Loading branch information
SchrodingersGat committed Nov 21, 2023
2 parents 4780721 + 81bf901 commit f4f237b
Show file tree
Hide file tree
Showing 10 changed files with 63 additions and 62 deletions.
55 changes: 19 additions & 36 deletions inventree/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ def __init__(self, host=None, **kwargs):
username - Login username
password - Login password
token - Authentication token (if provided, username/password are ignored)
token_name - Name of the token to request (default = 'inventree-python')
use_token_auth - Use token authentication? (default = True)
verbose - Print extra debug messages (default = False)
timeout - Set timeout to use (in seconds). Default: 10
Expand All @@ -64,7 +63,6 @@ def __init__(self, host=None, **kwargs):
self.username = kwargs.get('username', os.environ.get('INVENTREE_API_USERNAME', None))
self.password = kwargs.get('password', os.environ.get('INVENTREE_API_PASSWORD', None))
self.token = kwargs.get('token', os.environ.get('INVENTREE_API_TOKEN', None))
self.token_name = kwargs.get('token_name', 'inventree-python')
self.timeout = kwargs.get('timeout', os.environ.get('INVENTREE_API_TIMEOUT', 10))
self.proxies = kwargs.get('proxies', dict())

Expand All @@ -74,8 +72,6 @@ def __init__(self, host=None, **kwargs):
self.auth = None
self.connected = False

logger.setLevel(logging.DEBUG if self.verbose else logging.INFO)

if kwargs.get('connect', True):
self.connect()

Expand Down Expand Up @@ -153,7 +149,7 @@ def constructApiUrl(self, endpoint_url):
url = urljoin(self.api_url, endpoint_url)

# Ensure the API URL ends with a trailing slash
if not url.endswith('/') and '?' not in url:
if not url.endswith('/'):
url += '/'

return url
Expand All @@ -171,12 +167,13 @@ def testAuth(self):

try:
response = self.get('/user/me/')
except Exception:
return False

if 'username' not in response:
logger.fatal("Username not returned by server")
except requests.exceptions.HTTPError as e:
logger.fatal(f"Authentication error: {str(type(e))}")
return False
except Exception as e:
logger.fatal(f"Unhandled server error: {str(type(e))}")
# Re-throw the exception
raise e

# set user_name if not initially set
if not self.username:
Expand Down Expand Up @@ -239,7 +236,7 @@ def requestToken(self):

if not self.username or not self.password:
raise AttributeError('Supply username and password to request token')

logger.info("Requesting auth token from server...")

if not self.connected:
Expand All @@ -248,14 +245,11 @@ def requestToken(self):

# Request an auth token from the server
try:
url = '/user/token/'
if self.token_name:
url += f'?name={self.token_name}'
response = self.get(url)
response = self.get('/user/token/')
except Exception as e:
logger.error(f"Error requesting token: {str(type(e))}")
return None

if 'token' not in response:
logger.error(f"Token not returned by server: {response}")
return None
Expand Down Expand Up @@ -336,29 +330,18 @@ def request(self, api_url, **kwargs):
# Send request to server!
try:
response = methods[method](api_url, **payload)
# response.raise_for_status()
except Timeout:
raise requests.exceptions.Timeout(f"Server timed out during api.request - {method} @ {api_url}. Timeout {payload['timeout']} s.")
except Exception as err:
except Timeout as e:
# Re-throw Timeout, and add a message to the log
logger.critical(f"Server timed out during api.request - {method} @ {api_url}. Timeout {payload['timeout']} s.")
raise e
except Exception as e:
# Re-thrown any caught errors, and add a message to the log
logger.exception(f"{str(err.__class__.__name__)} error - {method} @ {api_url} (status {err.response.status_code if err.response else 'None'})")

try:
data = response.json()

if type(data) is dict:
for k, v in err.response.json().items():
logger.error(" - %s: %s", k, v)
else:
logger.error(" - %s", data)
except (UnboundLocalError, AttributeError):
# No response object available
pass

raise err
logger.critical(f"Error at api.request - {method} @ {api_url}")
raise e

if response is None:
raise requests.exceptions.HTTPError(f"Null response - {method} '{api_url}'")
logger.error(f"Null response - {method} '{api_url}'")
return None

logger.info(f"Request: {method} {api_url} - {response.status_code}")

Expand Down
8 changes: 4 additions & 4 deletions inventree/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,7 @@ class MetadataMixin:
"""

@property
def metdata_url(self):
def metadata_url(self):
return os.path.join(self._url, "metadata/")

def getMetadata(self):
Expand All @@ -465,7 +465,7 @@ def getMetadata(self):
logger.error("API version 49 or newer required to access instance metadata")
return {}

response = self._api.get(self.metdata_url)
response = self._api.get(self.metadata_url)

return response['metadata']
else:
Expand All @@ -490,14 +490,14 @@ def setMetadata(self, data, overwrite=False):

if overwrite:
return self._api.put(
self.metdata_url,
self.metadata_url,
data={
"metadata": data,
}
)
else:
return self._api.patch(
self.metdata_url,
self.metadata_url,
data={
"metadata": data
}
Expand Down
2 changes: 1 addition & 1 deletion inventree/currency.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@


class CurrencyManager(object):
"""Class for managing InvenTree currency suppport"""
"""Class for managing InvenTree currency support"""

# Currency API endpoint
CURRENCY_ENDPOINT = 'currency/exchange/'
Expand Down
16 changes: 13 additions & 3 deletions inventree/label.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,16 @@


class LabelPrintingMixin:
"""Mixin class for label printing"""
"""Mixin class for label printing.
Classes which implement this mixin should define the following attributes:
LABELNAME: The name of the label type (e.g. 'part', 'stock', 'location')
LABELITEM: The name of the label item (e.g. 'parts', 'items', 'locations')
"""

LABELNAME = ''
LABELITEM = ''

def printlabel(self, label, plugin=None, destination=None, *args, **kwargs):
"""Print the label belonging to the given item.
Expand Down Expand Up @@ -44,13 +53,14 @@ def printlabel(self, label, plugin=None, destination=None, *args, **kwargs):

# If API version less than 130, file download is provided directly
if self._api.api_version < 130 and plugin is None:
download_url = URL
# Ensure we prefix the URL with '/api'
download_url = f"/api{URL}"
else:
# Perform API request, get response
response = self._api.get(URL, params=params)
download_url = response.get('file', None)

# Label file is availble for download
# Label file is available for download
if download_url and destination is not None:
if os.path.exists(destination) and os.path.isdir(destination):
# No file name given, construct one
Expand Down
2 changes: 1 addition & 1 deletion inventree/purchase_order.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ def receive(self, quantity=None, status=10, location=None, batch_code='', serial
"""

if quantity is None:
# Substract number of already received lines from the order quantity
# Subtract number of already received lines from the order quantity
quantity = self.quantity - self.received

if location is None:
Expand Down
2 changes: 1 addition & 1 deletion inventree/sales_order.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class SalesOrder(
inventree.base.InventreeObject,
inventree.base.StatusMixin
):
""" Class respresenting the SalesOrder database model """
""" Class representing the SalesOrder database model """

URL = 'order/so'

Expand Down
9 changes: 7 additions & 2 deletions inventree/stock.py
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,12 @@ def installStock(self, item, **kwargs):
else:
quantity = kwargs.get('quantity', 1)

kwargs['quantity'] = kwargs.get('quantity', quantity)
if self._api.api_version >= 148:
kwargs['quantity'] = kwargs.get('quantity', quantity)
else:
# Note that the 'quantity' parameter is not supported in API versions < 148
kwargs.pop('quantity')

kwargs['stock_item'] = item

url = f"stock/{self.pk}/install/"
Expand Down Expand Up @@ -382,7 +387,7 @@ def upload_result(cls, api, stock_item, test, result, **kwargs):
'value': value,
}

# Send the data to the serever
# Send the data to the server
if api.post(cls.URL, data, files=files):
logging.info(f"Uploaded test result: '{test}'")
ret = True
Expand Down
2 changes: 1 addition & 1 deletion test/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ services:

inventree-py-test-server:
container_name: inventree-py-test-server
image: inventree/inventree:latest
image: inventree/inventree:0.12.8
ports:
# Expose internal port 8000 on external port 12345
- 12345:8000
Expand Down
16 changes: 8 additions & 8 deletions test/test_label.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,13 @@
import os
import sys

from test_api import InvenTreeTestCase # noqa: E402
from inventree.label import LabelPart, LabelStock, LabelLocation
from inventree.part import Part
from inventree.stock import StockItem, StockLocation


sys.path.append(os.path.abspath(os.path.dirname(__file__)))

from test_api import InvenTreeTestCase # noqa: E402
from inventree.label import LabelPart, LabelStock, LabelLocation # noqa: E402
from inventree.part import Part # noqa: E402
from inventree.stock import StockItem, StockLocation # noqa: E402


class LabelTest(InvenTreeTestCase):
"""Tests for Label functions models"""
Expand Down Expand Up @@ -71,9 +70,10 @@ def test_label_printing(self):
lbl_part = LabelPart.list(self.api)[0]

# Attempt to print to file - use label object
prt.printlabel(label=lbl_part, plugin=None, destination="partlabel_1.pdf")
self.assertTrue(prt.printlabel(label=lbl_part, plugin=None, destination="partlabel_1.pdf"))

# Attempt to print to file - use label ID directly
prt.printlabel(label=lbl_part.pk, plugin=None, destination="partlabel_2.pdf")
self.assertTrue(prt.printlabel(label=lbl_part.pk, plugin=None, destination="partlabel_2.pdf"))

# Make sure the files exist
self.assertTrue(os.path.isfile("partlabel_1.pdf"))
Expand Down
13 changes: 8 additions & 5 deletions test/test_stock.py
Original file line number Diff line number Diff line change
Expand Up @@ -448,12 +448,15 @@ def test_install_stock(self):

self.assertIsNone(child_stock.belongs_to)

# Attempt to install with incorrect quantity
with self.assertRaises(requests.exceptions.HTTPError):
parent_stock.installStock(child_stock, quantity=child_stock.quantity * 2)
# The following checks only apply to API version 148 or higher
# Refer to the InvenTree API version notes for more information
if self.api.api_version >= 148:
# Attempt to install with incorrect quantity
with self.assertRaises(requests.exceptions.HTTPError):
parent_stock.installStock(child_stock, quantity=child_stock.quantity * 2)

with self.assertRaises(requests.exceptions.HTTPError):
parent_stock.installStock(child_stock, quantity=-100)
with self.assertRaises(requests.exceptions.HTTPError):
parent_stock.installStock(child_stock, quantity=-100)

# install the *entire* child item into the parent
parent_stock.installStock(child_stock, quantity=child_stock.quantity)
Expand Down

0 comments on commit f4f237b

Please sign in to comment.