Skip to content

Commit 71eb034

Browse files
Merge pull request #281 from inventree/url-join
URL join
2 parents 5779762 + 9eef993 commit 71eb034

File tree

19 files changed

+78
-76
lines changed

19 files changed

+78
-76
lines changed

.github/workflows/build.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ jobs:
99
strategy:
1010
max-parallel: 4
1111
matrix:
12-
python-version: [3.8]
12+
python-version: [3.11]
1313

1414
steps:
1515
- name: Checkout Code

.github/workflows/pep.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ jobs:
99
strategy:
1010
max-parallel: 4
1111
matrix:
12-
python-version: [3.8]
12+
python-version: [3.11]
1313

1414
steps:
1515
- name: Checkout Code

.github/workflows/pypi.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ jobs:
1818
- name: Setup Python
1919
uses: actions/setup-python@v2
2020
with:
21-
python-version: 3.8
21+
python-version: 3.11
2222
- name: Check Release Tag
2323
run: |
2424
python3 ci/check_version_number.py ${{ github.event.release.tag_name }}

inventree/api.py

Lines changed: 13 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ def __init__(self, host=None, **kwargs):
7878
if kwargs.get('connect', True):
7979
self.connect()
8080

81-
def setHostName(self, host):
81+
def setHostName(self, host: str):
8282
"""Validate that the provided base URL is valid"""
8383

8484
if host is None:
@@ -136,7 +136,7 @@ def connect(self):
136136
if not self.token:
137137
self.requestToken()
138138

139-
def constructApiUrl(self, endpoint_url):
139+
def constructApiUrl(self, endpoint_url: str) -> str:
140140
"""Construct an API endpoint URL based on the provided API URL.
141141
142142
Arguments:
@@ -145,17 +145,7 @@ def constructApiUrl(self, endpoint_url):
145145
Returns: A fully qualified URL for the subsequent request
146146
"""
147147

148-
# Strip leading / character if provided
149-
if endpoint_url.startswith("/"):
150-
endpoint_url = endpoint_url[1:]
151-
152-
url = urljoin(self.api_url, endpoint_url)
153-
154-
# Ensure the API URL ends with a trailing slash
155-
if not url.endswith('/'):
156-
url += '/'
157-
158-
return url
148+
return urljoin(self.api_url, endpoint_url)
159149

160150
def testAuth(self):
161151
"""
@@ -169,7 +159,7 @@ def testAuth(self):
169159
return False
170160

171161
try:
172-
response = self.get('/user/me/')
162+
response = self.get('user/me/')
173163
except requests.exceptions.HTTPError as e:
174164
logger.fatal(f"Authentication error: {str(type(e))}")
175165
return False
@@ -254,7 +244,7 @@ def requestToken(self):
254244
# Request an auth token from the server
255245
try:
256246
response = self.get(
257-
'/user/token/',
247+
'user/token/',
258248
params={
259249
'name': self.token_name,
260250
}
@@ -273,14 +263,14 @@ def requestToken(self):
273263

274264
return self.token
275265

276-
def request(self, api_url, **kwargs):
266+
def request(self, url: str, **kwargs):
277267
""" Perform a URL request to the Inventree API """
278268

279269
if not self.connected:
280270
# If we have not established a connection to the server yet, attempt now
281271
self.connect()
282272

283-
api_url = self.constructApiUrl(api_url)
273+
api_url = self.constructApiUrl(url)
284274

285275
data = kwargs.get('data', kwargs.get('json', {}))
286276
files = kwargs.get('files', {})
@@ -401,7 +391,7 @@ def request(self, api_url, **kwargs):
401391

402392
return response
403393

404-
def delete(self, url, **kwargs):
394+
def delete(self, url: str, **kwargs):
405395
""" Perform a DELETE request. Used to remove a record in the database.
406396
407397
"""
@@ -420,7 +410,7 @@ def delete(self, url, **kwargs):
420410

421411
return response
422412

423-
def post(self, url, data, **kwargs):
413+
def post(self, url: str, data: dict, **kwargs):
424414
""" Perform a POST request. Used to create a new record in the database.
425415
426416
Args:
@@ -457,7 +447,7 @@ def post(self, url, data, **kwargs):
457447

458448
return data
459449

460-
def patch(self, url, data, **kwargs):
450+
def patch(self, url: str, data: dict, **kwargs):
461451
"""
462452
Perform a PATCH request.
463453
@@ -495,7 +485,7 @@ def patch(self, url, data, **kwargs):
495485

496486
return data
497487

498-
def put(self, url, data, **kwargs):
488+
def put(self, url: str, data: dict, **kwargs):
499489
"""
500490
Perform a PUT request. Used to update existing records in the database.
501491
@@ -531,7 +521,7 @@ def put(self, url, data, **kwargs):
531521

532522
return data
533523

534-
def get(self, url, **kwargs):
524+
def get(self, url: str, **kwargs):
535525
""" Perform a GET request.
536526
537527
For argument information, refer to the 'request' method
@@ -633,7 +623,7 @@ def scanBarcode(self, barcode_data):
633623
barcode_data = json.dumps(barcode_data)
634624

635625
response = self.post(
636-
'/barcode/',
626+
'barcode/',
637627
{
638628
'barcode': str(barcode_data),
639629
}

inventree/base.py

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,15 @@ class InventreeObject(object):
2020
URL = ""
2121

2222
@classmethod
23-
def get_url(cls, api):
23+
def get_url(cls):
2424
"""Helper method to get the URL associated with this model."""
25-
return cls.URL
25+
26+
url = cls.URL
27+
28+
if not url.endswith('/'):
29+
url += '/'
30+
31+
return url
2632

2733
# Minimum server version for the particular model type
2834
MIN_API_VERSION = None
@@ -90,7 +96,7 @@ def __init__(self, api, pk=None, data=None):
9096
if pk <= 0:
9197
raise ValueError(f"Supplier <pk> value ({pk}) for {self.__class__} must be positive.")
9298

93-
url = self.get_url(api)
99+
url = self.get_url()
94100

95101
self._url = f"{url}/{pk}/"
96102
self._api = api
@@ -134,7 +140,7 @@ def options(cls, api):
134140
cls.checkApiVersion(api)
135141

136142
response = api.request(
137-
cls.URL,
143+
cls.get_url(),
138144
method='OPTIONS',
139145
)
140146

@@ -543,7 +549,7 @@ class MetadataMixin:
543549
- The 'metadata' is not used for any InvenTree business logic
544550
- Instead it can be used by plugins for storing arbitrary information
545551
- Internally it is stored as a JSON database field
546-
- Metadata is accessed via the API by appending '/metadata/' to the API URL
552+
- Metadata is accessed via the API by appending './metadata/' to the API URL
547553
548554
Note: Requires server API version 49 or newer
549555
@@ -668,7 +674,7 @@ def _statusupdate(self, status: str, reload=True, data=None, **kwargs):
668674
raise ValueError(f"Order stats {status} not supported.")
669675

670676
# Set the url
671-
URL = self.URL + f"/{self.pk}/{status}"
677+
URL = self.URL + f"/{self.pk}/{status}/"
672678

673679
if data is None:
674680
data = {}
@@ -718,7 +724,7 @@ def assignBarcode(self, barcode_data: str, reload=True):
718724
model_type = self.barcodeModelType()
719725

720726
response = self._api.post(
721-
'/barcode/link/',
727+
'barcode/link/',
722728
{
723729
'barcode': barcode_data,
724730
model_type: self.pk,
@@ -730,13 +736,13 @@ def assignBarcode(self, barcode_data: str, reload=True):
730736

731737
return response
732738

733-
def unassignBarcode(self, reload=True):
739+
def unassignBarcode(self, reload: bool = True):
734740
"""Unassign a barcode from this object"""
735741

736742
model_type = self.barcodeModelType()
737743

738744
response = self._api.post(
739-
'/barcode/unlink/',
745+
'barcode/unlink/',
740746
{
741747
model_type: self.pk,
742748
}

inventree/build.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ class Build(
1313
):
1414
""" Class representing the Build database model """
1515

16-
URL = 'build'
16+
URL = 'build/'
1717
MODEL_TYPE = 'build'
1818

1919
def issue(self):

inventree/company.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class Address(inventree.base.InventreeObject):
2525
class Company(inventree.base.ImageMixin, inventree.base.MetadataMixin, inventree.base.InventreeObject):
2626
""" Class representing the Company database model """
2727

28-
URL = 'company'
28+
URL = 'company/'
2929
MODEL_TYPE = "company"
3030

3131
def getContacts(self, **kwargs):
@@ -103,7 +103,7 @@ class SupplierPart(inventree.base.BarcodeMixin, inventree.base.BulkDeleteMixin,
103103
- Implements the BulkDeleteMixin
104104
"""
105105

106-
URL = 'company/part'
106+
URL = 'company/part/'
107107

108108
def getPriceBreaks(self):
109109
""" Get a list of price break objects for this SupplierPart """
@@ -122,7 +122,7 @@ class ManufacturerPart(
122122
- Implements the BulkDeleteMixin
123123
"""
124124

125-
URL = 'company/part/manufacturer'
125+
URL = 'company/part/manufacturer/'
126126
MODEL_TYPE = "manufacturerpart"
127127

128128
def getParameters(self, **kwargs):
@@ -139,10 +139,10 @@ class ManufacturerPartParameter(inventree.base.BulkDeleteMixin, inventree.base.I
139139
- Implements the BulkDeleteMixin
140140
"""
141141

142-
URL = 'company/part/manufacturer/parameter'
142+
URL = 'company/part/manufacturer/parameter/'
143143

144144

145145
class SupplierPriceBreak(inventree.base.InventreeObject):
146146
""" Class representing the SupplierPriceBreak database model """
147147

148-
URL = 'company/price-break'
148+
URL = 'company/price-break/'

inventree/label.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ def saveOutput(self, output, filename):
3939
def printLabel(self, template, plugin=None, destination=None, *args, **kwargs):
4040
"""Print a label against the provided label template."""
4141

42-
print_url = '/label/print/'
42+
print_url = 'label/print/'
4343

4444
template_id = self.getTemplateId(template)
4545

@@ -161,7 +161,7 @@ def downloadTemplate(self, destination, overwrite=False):
161161
class LabelTemplate(LabelFunctions):
162162
"""Class representing the LabelTemplate database model."""
163163

164-
URL = 'label/template'
164+
URL = 'label/template/'
165165

166166
def __str__(self):
167167
"""String representation of the LabelTemplate instance."""

inventree/part.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
class PartCategoryParameterTemplate(inventree.base.InventreeObject):
1717
"""A model which link a ParameterTemplate to a PartCategory"""
1818

19-
URL = 'part/category/parameters'
19+
URL = 'part/category/parameters/'
2020

2121
def getCategory(self):
2222
"""Return the referenced PartCategory instance"""
@@ -30,7 +30,7 @@ def getTemplate(self):
3030
class PartCategory(inventree.base.MetadataMixin, inventree.base.InventreeObject):
3131
""" Class representing the PartCategory database model """
3232

33-
URL = 'part/category'
33+
URL = 'part/category/'
3434

3535
def getParts(self, **kwargs):
3636
return Part.list(self._api, category=self.pk, **kwargs)
@@ -68,7 +68,7 @@ class Part(
6868
):
6969
""" Class representing the Part database model """
7070

71-
URL = 'part'
71+
URL = 'part/'
7272
MODEL_TYPE = 'part'
7373

7474
def getCategory(self):
@@ -149,7 +149,7 @@ def getRequirements(self):
149149
class PartTestTemplate(inventree.base.MetadataMixin, inventree.base.InventreeObject):
150150
""" Class representing a test template for a Part """
151151

152-
URL = 'part/test-template'
152+
URL = 'part/test-template/'
153153

154154
@classmethod
155155
def generateTestKey(cls, test_name):
@@ -183,7 +183,7 @@ class BomItem(
183183
):
184184
""" Class representing the BomItem database model """
185185

186-
URL = 'bom'
186+
URL = 'bom/'
187187

188188

189189
class BomItemSubstitute(
@@ -192,13 +192,13 @@ class BomItemSubstitute(
192192
):
193193
"""Class representing the BomItemSubstitute database model"""
194194

195-
URL = "bom/substitute"
195+
URL = "bom/substitute/"
196196

197197

198198
class InternalPrice(inventree.base.InventreeObject):
199199
""" Class representing the InternalPrice model """
200200

201-
URL = 'part/internal-price'
201+
URL = 'part/internal-price/'
202202

203203
@classmethod
204204
def setInternalPrice(cls, api, part, quantity: int, price: float):
@@ -219,7 +219,7 @@ def setInternalPrice(cls, api, part, quantity: int, price: float):
219219
class SalePrice(inventree.base.InventreeObject):
220220
""" Class representing the SalePrice model """
221221

222-
URL = 'part/sale-price'
222+
URL = 'part/sale-price/'
223223

224224
@classmethod
225225
def setSalePrice(cls, api, part, quantity: int, price: float, price_currency: str):
@@ -241,7 +241,7 @@ def setSalePrice(cls, api, part, quantity: int, price: float, price_currency: st
241241
class PartRelated(inventree.base.InventreeObject):
242242
""" Class representing a relationship between parts"""
243243

244-
URL = 'part/related'
244+
URL = 'part/related/'
245245

246246
@classmethod
247247
def add_related(cls, api, part1, part2):
@@ -266,7 +266,7 @@ def add_related(cls, api, part1, part2):
266266

267267
class Parameter(inventree.base.InventreeObject):
268268
"""class representing the Parameter database model """
269-
URL = 'part/parameter'
269+
URL = 'part/parameter/'
270270

271271
def getunits(self):
272272
""" Get the units for this parameter """
@@ -277,4 +277,4 @@ def getunits(self):
277277
class ParameterTemplate(inventree.base.InventreeObject):
278278
""" class representing the Parameter Template database model"""
279279

280-
URL = 'part/parameter/template'
280+
URL = 'part/parameter/template/'

0 commit comments

Comments
 (0)