Conversation
…type-fix-class
WalkthroughThis PR updates type annotations for Python compatibility, replaces bare Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Areas requiring extra attention:
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 inconclusive)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 7
🧹 Nitpick comments (3)
src/backend/InvenTree/common/models.py (1)
2747-2747: Consider adding validation for integer priority values.The type widening to
Union[Priority, int]allows arbitrary integers to be passed as the priority. While thestr(prio)conversion at line 2774 handles both types safely, there's no validation to ensure integer values correspond to validPriorityenum values (0-5). This could result in invalid or unexpected priority headers in email messages.Consider adding validation:
def issue_mail( subject: str, body: str, from_email: str, recipients: Union[str, list], fail_silently: bool = False, html_message=None, prio: Union[Priority, int] = Priority.NORMAL, headers: Optional[dict] = None, ): """Send an email with the specified subject and body, to the specified recipients list. Mostly used by tasks. """ + # Validate integer priority values + if isinstance(prio, int): + if prio not in Priority.values: + raise ValueError(f"Invalid priority value: {prio}. Must be one of {list(Priority.values)}") + connection = get_connection(fail_silently=fail_silently)Alternatively, document the expected integer range in the docstring if arbitrary values are intentionally permitted.
src/backend/InvenTree/common/notifications.py (1)
130-134: Consider using explicit None check for consistency.Line 132 uses
and obj_ref_value(truthy check) while line 220 usesobj_ref_value is not None(explicit None check). This creates a subtle inconsistency—ifobj_ref_valuewere0, the recent notification check would be skipped but the notification would still be logged.While Django primary keys rarely start at 0, using an explicit None check would be more consistent and type-correct.
Apply this diff for consistency:
if ( check_recent - and obj_ref_value + and obj_ref_value is not None and common.models.NotificationEntry.check_recent(category, obj_ref_value, delta) ):src/backend/InvenTree/InvenTree/helpers.py (1)
465-465: Use a specific type ignore code.The non-specific
# type: ignorecomment suppresses all type-checking errors on this line. Use a specific error code (e.g.,# type: ignore[arg-type]) to make it clear what's being suppressed and prevent hiding other legitimate issues.- wrapper = FileWrapper(io.StringIO(data)) # type: ignore + wrapper = FileWrapper(io.StringIO(data)) # type: ignore[arg-type]
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (37)
pyproject.toml(0 hunks)src/backend/InvenTree/InvenTree/config.py(1 hunks)src/backend/InvenTree/InvenTree/helpers.py(5 hunks)src/backend/InvenTree/InvenTree/helpers_email.py(1 hunks)src/backend/InvenTree/InvenTree/models.py(2 hunks)src/backend/InvenTree/InvenTree/permissions.py(2 hunks)src/backend/InvenTree/common/models.py(1 hunks)src/backend/InvenTree/common/notifications.py(5 hunks)src/backend/InvenTree/common/serializers.py(1 hunks)src/backend/InvenTree/common/settings.py(2 hunks)src/backend/InvenTree/common/tests.py(1 hunks)src/backend/InvenTree/order/models.py(1 hunks)src/backend/InvenTree/plugin/base/action/mixins.py(1 hunks)src/backend/InvenTree/plugin/base/barcodes/mixins.py(2 hunks)src/backend/InvenTree/plugin/base/event/mixins.py(1 hunks)src/backend/InvenTree/plugin/base/icons/mixins.py(2 hunks)src/backend/InvenTree/plugin/base/integration/APICallMixin.py(1 hunks)src/backend/InvenTree/plugin/base/integration/AppMixin.py(1 hunks)src/backend/InvenTree/plugin/base/integration/CurrencyExchangeMixin.py(1 hunks)src/backend/InvenTree/plugin/base/integration/DataExport.py(1 hunks)src/backend/InvenTree/plugin/base/integration/MachineMixin.py(1 hunks)src/backend/InvenTree/plugin/base/integration/NavigationMixin.py(1 hunks)src/backend/InvenTree/plugin/base/integration/NotificationMixin.py(1 hunks)src/backend/InvenTree/plugin/base/integration/ReportMixin.py(1 hunks)src/backend/InvenTree/plugin/base/integration/ScheduleMixin.py(1 hunks)src/backend/InvenTree/plugin/base/integration/SettingsMixin.py(1 hunks)src/backend/InvenTree/plugin/base/integration/TransitionMixin.py(1 hunks)src/backend/InvenTree/plugin/base/integration/UrlsMixin.py(1 hunks)src/backend/InvenTree/plugin/base/integration/ValidationMixin.py(1 hunks)src/backend/InvenTree/plugin/base/label/mixins.py(1 hunks)src/backend/InvenTree/plugin/base/locate/mixins.py(1 hunks)src/backend/InvenTree/plugin/base/mail/mixins.py(1 hunks)src/backend/InvenTree/plugin/broken/bad_actor.py(1 hunks)src/backend/InvenTree/plugin/builtin/labels/inventree_label.py(1 hunks)src/backend/InvenTree/plugin/builtin/labels/inventree_machine.py(1 hunks)src/backend/InvenTree/plugin/samples/mail/test_mail_sample.py(2 hunks)src/backend/InvenTree/report/models.py(2 hunks)
💤 Files with no reviewable changes (1)
- pyproject.toml
🧰 Additional context used
🧬 Code graph analysis (28)
src/backend/InvenTree/plugin/base/integration/MachineMixin.py (1)
src/backend/InvenTree/plugin/plugin.py (2)
add_mixin(229-234)PluginMixinEnum(55-82)
src/backend/InvenTree/plugin/base/integration/UrlsMixin.py (1)
src/backend/InvenTree/plugin/plugin.py (2)
add_mixin(229-234)PluginMixinEnum(55-82)
src/backend/InvenTree/plugin/base/locate/mixins.py (1)
src/backend/InvenTree/plugin/plugin.py (2)
add_mixin(229-234)PluginMixinEnum(55-82)
src/backend/InvenTree/plugin/base/integration/ScheduleMixin.py (1)
src/backend/InvenTree/plugin/plugin.py (2)
add_mixin(229-234)PluginMixinEnum(55-82)
src/backend/InvenTree/plugin/broken/bad_actor.py (1)
src/backend/InvenTree/plugin/plugin.py (1)
add_mixin(229-234)
src/backend/InvenTree/plugin/base/integration/NotificationMixin.py (1)
src/backend/InvenTree/plugin/plugin.py (2)
add_mixin(229-234)PluginMixinEnum(55-82)
src/backend/InvenTree/plugin/base/integration/DataExport.py (1)
src/backend/InvenTree/plugin/plugin.py (2)
add_mixin(229-234)PluginMixinEnum(55-82)
src/backend/InvenTree/common/tests.py (1)
src/backend/InvenTree/common/settings.py (1)
set_global_warning(61-108)
src/backend/InvenTree/InvenTree/helpers_email.py (1)
src/backend/InvenTree/common/models.py (1)
Priority(2512-2520)
src/backend/InvenTree/plugin/base/integration/CurrencyExchangeMixin.py (1)
src/backend/InvenTree/plugin/plugin.py (2)
add_mixin(229-234)PluginMixinEnum(55-82)
src/backend/InvenTree/common/notifications.py (1)
src/backend/InvenTree/common/models.py (2)
check_recent(1623-1629)NotificationEntry(1602-1636)
src/backend/InvenTree/plugin/base/icons/mixins.py (1)
src/backend/InvenTree/plugin/plugin.py (2)
add_mixin(229-234)PluginMixinEnum(55-82)
src/backend/InvenTree/plugin/base/integration/NavigationMixin.py (1)
src/backend/InvenTree/plugin/plugin.py (2)
add_mixin(229-234)PluginMixinEnum(55-82)
src/backend/InvenTree/plugin/base/label/mixins.py (1)
src/backend/InvenTree/plugin/plugin.py (2)
add_mixin(229-234)PluginMixinEnum(55-82)
src/backend/InvenTree/plugin/base/action/mixins.py (1)
src/backend/InvenTree/plugin/plugin.py (2)
add_mixin(229-234)PluginMixinEnum(55-82)
src/backend/InvenTree/plugin/base/barcodes/mixins.py (1)
src/backend/InvenTree/plugin/plugin.py (2)
add_mixin(229-234)PluginMixinEnum(55-82)
src/backend/InvenTree/plugin/base/event/mixins.py (1)
src/backend/InvenTree/plugin/plugin.py (2)
add_mixin(229-234)PluginMixinEnum(55-82)
src/backend/InvenTree/plugin/base/integration/APICallMixin.py (1)
src/backend/InvenTree/plugin/plugin.py (2)
add_mixin(229-234)PluginMixinEnum(55-82)
src/backend/InvenTree/plugin/builtin/labels/inventree_machine.py (3)
src/backend/InvenTree/InvenTree/models.py (1)
get_items(793-801)src/backend/InvenTree/part/models.py (1)
get_items(217-219)src/backend/InvenTree/stock/models.py (1)
get_items(346-348)
src/backend/InvenTree/plugin/base/integration/ValidationMixin.py (1)
src/backend/InvenTree/plugin/plugin.py (2)
add_mixin(229-234)PluginMixinEnum(55-82)
src/backend/InvenTree/plugin/base/mail/mixins.py (1)
src/backend/InvenTree/plugin/plugin.py (2)
add_mixin(229-234)PluginMixinEnum(55-82)
src/backend/InvenTree/plugin/samples/mail/test_mail_sample.py (3)
src/backend/InvenTree/plugin/base/mail/mail.py (2)
process_mail_out(14-41)process_mail_in(44-77)src/backend/InvenTree/plugin/samples/mail/mail_sample.py (2)
process_mail_out(20-28)process_mail_in(30-38)src/backend/InvenTree/common/models.py (1)
set_setting(681-774)
src/backend/InvenTree/plugin/base/integration/ReportMixin.py (1)
src/backend/InvenTree/plugin/plugin.py (2)
add_mixin(229-234)PluginMixinEnum(55-82)
src/backend/InvenTree/InvenTree/helpers.py (1)
src/backend/InvenTree/InvenTree/models.py (1)
path(992-1000)
src/backend/InvenTree/report/models.py (2)
src/backend/InvenTree/common/settings.py (1)
get_global_setting(29-41)src/backend/InvenTree/InvenTree/exceptions.py (1)
log_error(21-95)
src/backend/InvenTree/plugin/base/integration/AppMixin.py (1)
src/backend/InvenTree/plugin/plugin.py (2)
add_mixin(229-234)PluginMixinEnum(55-82)
src/backend/InvenTree/plugin/base/integration/TransitionMixin.py (1)
src/backend/InvenTree/plugin/plugin.py (1)
PluginMixinEnum(55-82)
src/backend/InvenTree/plugin/base/integration/SettingsMixin.py (1)
src/backend/InvenTree/plugin/plugin.py (2)
add_mixin(229-234)PluginMixinEnum(55-82)
🪛 Ruff (0.14.2)
src/backend/InvenTree/InvenTree/helpers.py
12-12: Unused noqa directive (non-enabled: UP035)
Remove unused noqa directive
(RUF100)
161-161: Unused noqa directive (non-enabled: UP006)
Remove unused noqa directive
(RUF100)
src/backend/InvenTree/report/models.py
53-53: Do not catch blind exception: Exception
(BLE001)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (15)
- GitHub Check: Tests - DB [PostgreSQL]
- GitHub Check: Tests - DB [MySQL]
- GitHub Check: Tests - DB [SQLite] + Coverage 3.9
- GitHub Check: Style [Typecheck]
- GitHub Check: Tests - inventree-python
- GitHub Check: Style [Typecheck]
- GitHub Check: Tests - DB [PostgreSQL]
- GitHub Check: Tests - DB [MySQL]
- GitHub Check: Tests - DB [SQLite] + Coverage 3.9
- GitHub Check: Tests - inventree-python
- GitHub Check: Tests - API Schema Documentation
- GitHub Check: matmair.InvenTree (Job Python39)
- GitHub Check: Tests - API Schema Documentation
- GitHub Check: Build - Web UI
- GitHub Check: Build - Web UI
🔇 Additional comments (41)
src/backend/InvenTree/common/tests.py (1)
546-546: LGTM! Appropriate type ignore for negative test case.The type ignore comment correctly silences the type checker for this intentional test of error handling when
Noneis passed as thekeyparameter.src/backend/InvenTree/common/settings.py (2)
5-5: LGTM! Import updated to support widened type annotation.The import change from
OptionaltoUnioncorrectly supports the widened function signature forset_global_warning.
61-61: LGTM! Type annotation correctly widened to match actual usage.The signature change from
Optional[dict]toUnion[dict, bool, None]accurately reflects the function's implementation and usage patterns, whereboolvalues are explicitly supported (line 96 defaultsNonetoTrue).src/backend/InvenTree/InvenTree/helpers_email.py (1)
70-70: Type widening matches the downstream function signature.The change to
Union[Priority, int]is consistent with the corresponding update toissue_mailincommon/models.py(line 2747). Sincesend_emailpassespriodirectly toissue_mail(line 110), this alignment is appropriate.However, the same validation concern mentioned in
common/models.pyapplies here: consider validating integer values to ensure they correspond to validPriorityenum values, or clearly document the acceptable range if arbitrary integers are permitted.src/backend/InvenTree/common/notifications.py (4)
5-5: LGTM! Type imports correctly added.The
UnionandStrOrPromiseimports are appropriate for the enhanced type annotations used in theNotificationBodydataclass fields.Also applies to: 13-13
45-48: LGTM! Type annotations correctly reflect Django translation usage.The
Union[str, StrOrPromise]annotations accurately represent that these fields can accept both plain strings and Django's lazy translation strings (fromgettext_lazy/_()function), as evidenced by the usage in lines 58-84.
113-113: LGTM! Type annotation improves clarity.The
Optional[int]annotation correctly reflects thatobj_ref_valuecan beNone(when no object is provided) or an integer (Django model primary key).
220-221: LGTM! Explicit None check prevents type errors.The
obj_ref_value is not Nonecheck correctly prevents passingNonetoNotificationEntry.notify()which expects an integeruidparameter. The explicit None check also properly handles the edge case whereobj_ref_valuecould be0.src/backend/InvenTree/InvenTree/helpers.py (2)
29-29: LGTM!The
StrOrPromiseimport is appropriate for Django projects, enabling proper type annotations for functions that accept both regular strings and lazy translation objects.
578-578: LGTM!The type annotation correctly handles both regular strings and Django lazy translation objects, which is essential since error messages use
_()for translation (e.g., line 592).src/backend/InvenTree/InvenTree/permissions.py (1)
4-4: LGTM: Import addition supports new type annotations.The addition of
Unionto the typing imports is necessary for the broadened type annotations used in themap_scopefunction signature below.src/backend/InvenTree/InvenTree/config.py (1)
484-485: Line numbers incorrect; type: ignore is appropriate for known cryptography typing limitation.The line numbers in the original comment are wrong (actual lines are 478-479, not 484-485). More importantly, the
# type: ignorecomments here address a documented and known limitation in cryptography's type stubs forserialization.Encodingandserialization.PrivateFormatenums—not a hidden problem in the code itself.Your cryptography version (44.0.3) is current, and this typing gap persists even in recent releases. The workaround is well-documented across cryptography issues and type-checking communities. The code pattern matches cryptography's official documentation exactly, and the
private_bytes()call is correct.While using a more specific code like
# type: ignore[arg-type]would be a minor best-practice improvement, the current approach is acceptable and requires no changes.src/backend/InvenTree/plugin/base/integration/TransitionMixin.py (1)
26-31: LGTM! Correct use ofself.__class__for runtime class resolution.The change from bare
__class__toself.__class__ensures the actual subclass is registered at runtime, which is essential for proper mixin inheritance.src/backend/InvenTree/plugin/base/integration/APICallMixin.py (1)
73-77: LGTM! Proper mixin registration with runtime class.Using
self.__class__correctly registers the actual plugin subclass rather than the mixin base class.src/backend/InvenTree/plugin/base/integration/ReportMixin.py (1)
22-25: LGTM! Consistent with mixin registration pattern.The change ensures correct subclass resolution when the mixin is inherited.
src/backend/InvenTree/plugin/broken/bad_actor.py (1)
11-14: LGTM! Correct mixin registration.The use of
self.__class__ensures the BadActorPlugin class is properly registered.src/backend/InvenTree/plugin/base/locate/mixins.py (1)
32-35: LGTM! Proper runtime class registration.Using
self.__class__correctly identifies the concrete plugin class implementing the LocateMixin.src/backend/InvenTree/plugin/base/integration/MachineMixin.py (1)
30-33: LGTM! Consistent mixin registration pattern.The change to
self.__class__aligns with the pattern used across all plugin mixins for proper subclass resolution.src/backend/InvenTree/plugin/base/integration/CurrencyExchangeMixin.py (1)
25-25: LGTM! Correct runtime class registration.Using
self.__class__ensures the actual plugin subclass (not the base mixin class) is registered, enabling proper runtime type resolution.src/backend/InvenTree/plugin/base/event/mixins.py (1)
37-37: LGTM! Proper subclass resolution.This change ensures the mixin registry receives the concrete plugin class rather than the base EventMixin class.
src/backend/InvenTree/plugin/samples/mail/test_mail_sample.py (2)
16-17: Good refactoring for maintainability.Extracting the repeated string literal to a class attribute improves maintainability and follows the DRY principle.
28-29: No issues found. Type mismatch is intentional design for the sample plugin.The verification confirms that while a type mismatch exists (strings passed instead of email objects), this is intentional design:
- The
process_mail_out()function includes logic to wrap non-list inputs in a list, demonstrating flexibility- The sample plugin implementation intentionally has no type hints and accepts any input type
- The tests verify the plugin infrastructure and event logging mechanism, not actual mail processing
- This is appropriate for a sample/test plugin demonstrating how to implement the mail mixin
The type hints on the standalone functions correctly document the expected interface for production usage. No changes are required.
src/backend/InvenTree/plugin/base/icons/mixins.py (2)
23-23: LGTM! Ensures correct mixin registration.Using
self.__class__registers the actual plugin subclass for proper runtime type tracking.
31-35: Improved error reporting with runtime class name.The error message now references
self.__class__instead of__class__, ensuring the actual plugin class name is reported at runtime rather than the base mixin class name.src/backend/InvenTree/plugin/base/action/mixins.py (1)
19-19: LGTM! Consistent with mixin registration pattern.This change aligns with the broader refactor to register actual plugin subclasses rather than base mixin classes.
src/backend/InvenTree/plugin/base/integration/ScheduleMixin.py (1)
58-58: LGTM! Proper runtime class registration.The change ensures the plugin registry tracks the concrete plugin class for scheduled task management.
src/backend/InvenTree/plugin/base/mail/mixins.py (1)
39-39: LGTM! Correct subclass resolution for mail mixin.Using
self.__class__ensures the actual mail plugin subclass is registered for processing.src/backend/InvenTree/plugin/base/barcodes/mixins.py (2)
40-40: LGTM! Correct barcode mixin registration.Using
self.__class__ensures the concrete barcode plugin class is properly registered with the plugin system.
110-110: LGTM! Proper supplier barcode mixin registration.This change mirrors the pattern in the parent BarcodeMixin, ensuring the actual supplier barcode plugin class is registered.
src/backend/InvenTree/plugin/base/integration/ValidationMixin.py (1)
50-50: LGTM! Proper subclass resolution for mixin registration.Using
self.__class__correctly resolves the runtime subclass rather than the mixin class itself, ensuring proper mixin registration in the plugin system.src/backend/InvenTree/report/models.py (2)
49-57: LGTM! Function signature now correctly aligns with callee requirements.The
log_report_errorfunction signature and implementation now properly match the expected signature ofInvenTree.exceptions.log_error, which requirespathas the first positional argument.
649-649: Remove thetype: ignorecomment—it's unnecessary given identical usage on line 448 in the same file.Django's
ContentFilesignature isContentFile(content, name=None), accepting both bytes and text for content. The call at line 643 (ContentFile(data, report_name)) follows an identical pattern to line 448 (ContentFile(report, report_name)) in the same file, which requires no type suppression. Thetype: ignoreis inconsistent with the codebase convention and does not address a legitimate type-checker issue.Likely an incorrect or invalid review comment.
src/backend/InvenTree/InvenTree/models.py (1)
911-914: Same verification needed for ValidationError format.This location uses the same named-parameter format change as Line 577-580. The same verification applies here.
src/backend/InvenTree/plugin/builtin/labels/inventree_label.py (1)
85-85: Verify the need for type: ignore suppression.Similar to other files in this PR, the
type: ignorecomment suppresses type-checking forContentFile. Ensure this addresses a type-checker limitation rather than an actual type incompatibility.src/backend/InvenTree/plugin/base/integration/UrlsMixin.py (1)
25-25: LGTM! Proper subclass resolution for mixin registration.Consistent with the broader pattern in this PR, using
self.__class__ensures the concrete subclass is registered rather than the mixin base class.src/backend/InvenTree/plugin/base/label/mixins.py (1)
39-39: LGTM! Proper subclass resolution for mixin registration.This change aligns with the consistent pattern across all mixin files in this PR, ensuring proper runtime subclass registration.
src/backend/InvenTree/plugin/base/integration/NavigationMixin.py (1)
25-25: LGTM! Proper subclass resolution for mixin registration.Consistent with the broader refactoring pattern, using
self.__class__ensures the actual runtime subclass is registered.src/backend/InvenTree/plugin/base/integration/DataExport.py (1)
33-33: LGTM! Proper subclass resolution for mixin registration.This completes the consistent pattern of using
self.__class__across all mixin registration calls in this PR, ensuring proper runtime subclass identification.src/backend/InvenTree/plugin/base/integration/SettingsMixin.py (1)
41-41: LGTM: Proper subclass resolution.The change from
__class__toself.__class__ensures that the mixin is registered for the actual concrete plugin class at runtime, rather than the baseSettingsMixinclass. This is the correct approach for mixin registration in a plugin inheritance hierarchy.src/backend/InvenTree/plugin/base/integration/AppMixin.py (1)
30-30: LGTM: Consistent with the refactor pattern.The change to
self.__class__correctly registers the concrete plugin subclass rather than the baseAppMixin. This aligns with the broader refactor across all plugin mixins.src/backend/InvenTree/plugin/base/integration/NotificationMixin.py (1)
33-33: LGTM: Correct subclass resolution.The change to
self.__class__ensures the notification mixin is properly registered for the concrete plugin subclass. This is consistent with the changes across all other plugin mixins in this PR.
| import re | ||
| from decimal import Decimal, InvalidOperation | ||
| from typing import Optional, TypeVar, Union | ||
| from typing import List, Optional, TypeVar, Union # noqa: UP035 |
There was a problem hiding this comment.
Remove unused noqa directive and consider using built-in list type.
The # noqa: UP035 directive is unused according to static analysis, and the codebase appears to use lowercase list type hints elsewhere (e.g., models.py line 991 uses def path(self) -> list:). If the project supports Python 3.9+, prefer list[str] over List[str] for consistency.
Apply this diff if Python 3.9+ is supported:
-from typing import List, Optional, TypeVar, Union # noqa: UP035
+from typing import Optional, TypeVar, UnionThen update line 161 accordingly (see separate comment).
Committable suggestion skipped: line range outside the PR's diff.
🧰 Tools
🪛 Ruff (0.14.2)
12-12: Unused noqa directive (non-enabled: UP035)
Remove unused noqa directive
(RUF100)
🤖 Prompt for AI Agents
In src/backend/InvenTree/InvenTree/helpers.py around line 12, remove the unused
"# noqa: UP035" and stop importing List from typing; instead rely on Python 3.9+
built-in generic types—change the import to only include Optional, TypeVar,
Union (keep others if actually used) and update the type annotation at line 161
from List[str] (or typing.List) to the built-in list[str]. Ensure no other
references to typing.List remain in this file.
|
|
||
|
|
||
| def constructPathString(path: list[str], max_chars: int = 250) -> str: | ||
| def constructPathString(path: List[str], max_chars: int = 250) -> str: # noqa: UP006 |
There was a problem hiding this comment.
Remove unused noqa directive and use built-in list type.
The # noqa: UP006 directive is unused according to static analysis. For consistency with the codebase (see models.py line 991), use the built-in list[str] annotation if Python 3.9+ is supported.
Apply this diff if Python 3.9+ is supported:
-def constructPathString(path: List[str], max_chars: int = 250) -> str: # noqa: UP006
+def constructPathString(path: list[str], max_chars: int = 250) -> str:📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| def constructPathString(path: List[str], max_chars: int = 250) -> str: # noqa: UP006 | |
| def constructPathString(path: list[str], max_chars: int = 250) -> str: |
🧰 Tools
🪛 Ruff (0.14.2)
161-161: Unused noqa directive (non-enabled: UP006)
Remove unused noqa directive
(RUF100)
🤖 Prompt for AI Agents
In src/backend/InvenTree/InvenTree/helpers.py around line 161, remove the unused
"# noqa: UP006" and change the type annotation from typing.List[str] to the
built-in list[str] (i.e., def constructPathString(path: list[str], max_chars:
int = 250) -> str:); also remove the now-unused List import from typing if it is
no longer referenced elsewhere in the file.
| raise ValidationError( | ||
| 'Object %s of type %s no longer exists', str(self), str(self.__class__) | ||
| 'Object {o} of type {t} no longer exists', | ||
| params={'o': str(self), 't': str(self.__class__)}, | ||
| ) |
There was a problem hiding this comment.
🧩 Analysis chain
Verify Django ValidationError supports named-parameter format.
The error message format has been changed from printf-style ('%s') to named-parameter format ('{o}') with a params dictionary. Please confirm that django.core.exceptions.ValidationError supports this format with the params keyword argument in the version of Django being used.
🌐 Web query:
Does Django ValidationError support named-parameter format with params keyword argument?
💡 Result:
Yes. ValidationError accepts a params keyword (a mapping) and message strings should use named placeholders like %(name)s (not positional %s). See the Django “Raising ValidationError” guidance and examples and the code that passes params into ValidationError. [1][2]
Update placeholder syntax from curly braces to percent-style for Django ValidationError.
Django ValidationError expects named placeholders like %(name)s, not curly braces {name}. The code must be updated to:
raise ValidationError(
'Object %(o)s of type %(t)s no longer exists',
params={'o': str(self), 't': str(self.__class__)},
)The current format with {o} and {t} will not be properly interpolated by Django's ValidationError.
🧰 Tools
🪛 Ruff (0.14.2)
577-580: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling
(B904)
577-580: Avoid specifying long messages outside the exception class
(TRY003)
🤖 Prompt for AI Agents
In src/backend/InvenTree/InvenTree/models.py around lines 577 to 580, the
ValidationError message uses Python f-string style curly placeholders {o} and
{t} which Django's ValidationError won't interpolate; change the message to use
percent-style named placeholders like %(o)s and %(t)s and keep the params dict
as-is so Django can substitute the values correctly.
| def map_scope( | ||
| roles: Optional[list[str]] = None, | ||
| roles: Union[list[str], dict[str, str], None] = None, | ||
| only_read=False, | ||
| read_name=DEFAULT_READ, | ||
| map_read: Optional[list[str]] = None, | ||
| map_read: Union[list[str], tuple, None] = None, | ||
| map_read_name=DEFAULT_READ, | ||
| override_all_actions: Optional[str] = None, | ||
| ) -> dict: |
There was a problem hiding this comment.
🧩 Analysis chain
Verify dict iteration behavior and update docstring.
The roles parameter type has been broadened to accept Union[list[str], dict[str, str], None]. When a dict is passed, line 71 will iterate over the dict, yielding only the keys (not values). If the intent is to use dict keys as table identifiers, this works, but the dict values would be ignored.
Additionally, the docstring on line 55 still references Optional[list[str]] and should be updated to reflect the new accepted types.
Please verify:
- Is ignoring dict values (using only keys) the intended behavior when a dict is passed?
- Update the docstring to document the new type signature accurately.
🏁 Script executed:
#!/bin/bash
# Search for call sites of map_scope to understand how it's invoked with different argument types
rg -n -C3 'map_scope\(' --type=pyLength of output: 8010
I need to examine the complete function body and trace the variables being passed. Let me gather more information:
🏁 Script executed:
#!/bin/bash
# Get the complete map_scope function body (lines 44-100 to be safe)
sed -n '44,100p' src/backend/InvenTree/InvenTree/permissions.pyLength of output: 2257
🏁 Script executed:
#!/bin/bash
# Find context around line 140 to see what 'calc' is
sed -n '125,145p' src/backend/InvenTree/InvenTree/permissions.pyLength of output: 929
🏁 Script executed:
#!/bin/bash
# Find context around line 425 to see what '_roles' is
sed -n '410,435p' src/backend/InvenTree/InvenTree/permissions.pyLength of output: 1037
🏁 Script executed:
#!/bin/bash
# Find where _roles is defined
rg -n '_roles' --type=py -B2 -A2 src/backend/InvenTree/InvenTree/permissions.pyLength of output: 987
🏁 Script executed:
#!/bin/bash
# Search for all assignments to variables that could be dict[str, str]
rg -n 'map_scope\(roles=' --type=py -B5 src/backend/InvenTree/InvenTree/permissions.py | head -40Length of output: 242
🏁 Script executed:
#!/bin/bash
# Get the imports section to see where _roles comes from
sed -n '1,30p' src/backend/InvenTree/InvenTree/permissions.pyLength of output: 669
🏁 Script executed:
#!/bin/bash
# Search for _roles definition in the users.ruleset module
find . -path ./node_modules -prune -o -type f -name '*.py' -exec grep -l '_roles' {} \; 2>/dev/null | head -10Length of output: 346
🏁 Script executed:
#!/bin/bash
# Check the users/oauth2_scopes.py file for _roles definition
grep -n '_roles' src/backend/InvenTree/users/oauth2_scopes.py -B2 -A5Length of output: 471
🏁 Script executed:
#!/bin/bash
# Get the full context of _roles definition
cat src/backend/InvenTree/users/oauth2_scopes.py | head -100Length of output: 1303
Update the docstring to reflect the new roles parameter type.
The roles parameter now accepts Union[list[str], dict[str, str], None], but the docstring on line 55 still documents it as Optional[list[str]].
When a dict is passed (as with _roles at line 425), the iteration at line 71 correctly uses only the dict keys—the role/table identifiers needed by get_granular_scope(). The dict values serve only as descriptions and are not needed for scope generation, making this intentional behavior.
Update the docstring to document both accepted types:
list[str]- list of role/table identifiersdict[str, str]- mapping of role/table identifiers to descriptions (only keys are used)
🤖 Prompt for AI Agents
In src/backend/InvenTree/InvenTree/permissions.py around lines 44 to 51, the
docstring for the map_scope function still documents roles as
Optional[list[str]] even though the function accepts Union[list[str], dict[str,
str], None]; update the docstring to list both accepted types and their
meanings: list[str] for a list of role/table identifiers and dict[str, str] for
a mapping of role/table identifiers to descriptions (only the dict keys are used
by the function), and ensure the docstring notes None is allowed and that only
keys are used when a dict is provided.
| only_read=False, | ||
| read_name=DEFAULT_READ, | ||
| map_read: Optional[list[str]] = None, | ||
| map_read: Union[list[str], tuple, None] = None, |
There was a problem hiding this comment.
Update docstring to reflect tuple support.
The map_read parameter now accepts tuples in addition to lists, which is compatible with the usage on line 75 (method in map_read). However, the docstring on line 58 still references Optional[list[str]] and should be updated to document that tuples are now also accepted.
🤖 Prompt for AI Agents
In src/backend/InvenTree/InvenTree/permissions.py around lines 48 to 58 (and
referenced at line 75), the docstring currently documents map_read as
Optional[list[str]] but the parameter signature and usage accept tuples as well;
update the docstring to state that map_read may be a list or tuple of strings
(e.g., Optional[Union[list[str], tuple[str, ...]]]) and adjust any wording to
reflect tuple support so the documented type matches the function signature and
the "method in map_read" usage.
| raise NotImplementedError( | ||
| f'get_status_class() not implemented for {cls.__class__}' | ||
| ) |
There was a problem hiding this comment.
Critical: Incorrect class reference in error message.
In a classmethod, cls.__class__ returns the metaclass type, not the class itself. This will produce an error message like "get_status_class() not implemented for <class 'type'>" instead of showing the actual class name.
Apply this fix:
raise NotImplementedError(
- f'get_status_class() not implemented for {cls.__class__}'
+ f'get_status_class() not implemented for {cls.__name__}'
)🤖 Prompt for AI Agents
In src/backend/InvenTree/order/models.py around lines 531 to 533, the
NotImplementedError message uses cls.__class__ which resolves to the metaclass
(type) in a classmethod; replace that with the actual class reference (e.g. use
cls or cls.__name__) so the error reports the real class name — update the
f-string to include either f'{cls}' or f'{cls.__name__}' instead of
f'{cls.__class__}'.
| view = kwargs['context']['view'] | ||
| template = view.get_object() | ||
| items_to_print = view.get_items() |
There was a problem hiding this comment.
🧩 Analysis chain
Verify error handling and None handling for view methods.
The code directly accesses kwargs['context']['view'] and calls methods on it without error handling. Additionally, view.get_items() can return None according to the base implementation in InvenTree/models.py, which is then passed to driver.get_printers() on line 136.
Consider the following concerns:
- Missing error handling: If the view context key doesn't exist or the view doesn't have these methods, this will raise KeyError or AttributeError.
- None handling: The base
get_items()implementation returnsNone, which may cause issues ifdriver.get_printers()doesn't handle it properly.
Run the following script to verify how drivers handle None items in get_printers():
Additionally, consider adding type annotations for the new variables (view, template, items_to_print) since this is a "type fix" PR.
🏁 Script executed:
#!/bin/bash
# Verify if label printer drivers handle None items_to_print parameter
# Find all label printer driver implementations
ast-grep --pattern $'class $_ ($$$LabelPrinterBaseDriver$$$) {
$$$
def get_printers($$$) {
$$$
}
$$$
}'
# Search for get_printers method implementations and check None handling
rg -nP -A 10 'def get_printers\s*\(' --type=py -g '**/machine/**'Length of output: 1149
---
🏁 Script executed:
```shell
#!/bin/bash
# Verify the full implementation of get_printers and check for None handling
rg -nP -A 25 'def get_printers\s*\(' src/backend/InvenTree/machine/machine_types/label_printer.py
# Check if get_items() actually returns None or if there's a guard
rg -nP -B 3 -A 5 'def get_items\s*\(' --type=py -g '**/models.py' | head -50
Length of output: 2440
---
🏁 Script executed:
```shell
#!/bin/bash
# Search for get_printers in label printer module with correct path
rg -nP -A 30 'def get_printers\s*\(' git/src/backend/InvenTree/machine/machine_types/label_printer.py
# Check the PrintingOptionsSerializer context to see if view is guaranteed
rg -nP -B 5 -A 15 'class PrintingOptionsSerializer' git/src/backend/InvenTree/plugin/builtin/labels/inventree_machine.py
Length of output: 213
---
🏁 Script executed:
```shell
#!/bin/bash
# Find the actual file paths
fd -t f 'label_printer\.py'
fd -t f 'inventree_machine\.py'
# Also try to find them with broader search
fd -t f 'machine_types' -type d
Length of output: 296
---
🏁 Script executed:
```shell
#!/bin/bash
# Get full get_printers implementation
cat src/backend/InvenTree/machine/machine_types/label_printer.py | head -150
# Get PrintingOptionsSerializer and surrounding context
rg -nP -B 10 -A 40 'class PrintingOptionsSerializer' src/backend/InvenTree/plugin/builtin/labels/inventree_machine.py
# Also check for error handling around lines 125-127
rg -nP -B 5 -A 10 "kwargs\['context'\]\['view'\]" src/backend/InvenTree/plugin/builtin/labels/inventree_machine.py
Length of output: 8899
Add error handling for view context access and method calls.
The code directly accesses kwargs['context']['view'] and calls methods without validation. This will raise KeyError if the context keys are missing or AttributeError if the view lacks get_object() or get_items() methods.
Lines 125-127 need defensive checks:
- Verify
kwargs['context']andkwargs['context']['view']exist - Verify the view has
get_object()andget_items()methods before calling them - Handle gracefully if view structure is unexpected
Consider wrapping this block in a try/except or adding explicit checks before accessing these attributes.
🤖 Prompt for AI Agents
In src/backend/InvenTree/plugin/builtin/labels/inventree_machine.py around lines
125 to 127, the code directly accesses kwargs['context']['view'] and calls
view.get_object() and view.get_items() without validation which can raise
KeyError or AttributeError; update the block to first check that 'context'
exists in kwargs and that 'view' exists in kwargs['context'], then verify the
view object has callable get_object and get_items attributes before invoking
them, and if any check fails handle it gracefully (e.g., log a warning and set
template/items_to_print to safe defaults or return early); optionally wrap the
access in a try/except catching KeyError/AttributeError to provide a clear error
log and fallback behavior.
Summary by CodeRabbit
Release Notes
Bug Fixes
Improvements