write initial version of S7156

This commit is contained in:
Sebastian Zumbrunn 2024-11-12 15:04:17 +01:00
parent cbd6564edd
commit 1a20440092
2 changed files with 58 additions and 26 deletions

View File

@ -1,13 +1,12 @@
{ {
"title": "FIXME", "title": "\"copy.replace\" should not be invoked with an unsupported argument",
"type": "CODE_SMELL", "type": "CODE_SMELL",
"status": "ready", "status": "ready",
"remediation": { "remediation": {
"func": "Constant\/Issue", "func": "Constant/Issue",
"constantCost": "5min" "constantCost": "5min"
}, },
"tags": [ "tags": [],
],
"defaultSeverity": "Major", "defaultSeverity": "Major",
"ruleSpecification": "RSPEC-7156", "ruleSpecification": "RSPEC-7156",
"sqKey": "S7156", "sqKey": "S7156",
@ -17,8 +16,7 @@
"code": { "code": {
"impacts": { "impacts": {
"MAINTAINABILITY": "HIGH", "MAINTAINABILITY": "HIGH",
"RELIABILITY": "MEDIUM", "RELIABILITY": "MEDIUM"
"SECURITY": "LOW"
}, },
"attribute": "CONVENTIONAL" "attribute": "CONVENTIONAL"
} }

View File

@ -1,16 +1,32 @@
FIXME: add a description :object_replacement_protocol: https://docs.python.org/3/library/copy.html#object.__replace__
// If you want to factorize the description uncomment the following line and create the file.
//include::../description.adoc[]
== Why is this an issue? == Why is this an issue?
FIXME: remove the unused optional headers (that are commented out) Calling ``++copy.replace(...)++`` with an argument of an unsupported type will raise an ``++TypeError++``.
Types supported by ``++copy.replace(...)++`` must implement the {object_replacement_protocol}[replace protocol].
//=== What is the potential impact? The following built-in types are supported by ``++copy.replace(...)++``
* ``++collections.namedtuple()++``
* ``++dataclasses.dataclass++``
* ``++datetime.datetime++``, ``++datetime.date++``, ``++datetime.time++``
* ``++inspect.Signature++``, ``++inspect.Parameter++``
* ``++types.SimpleNamespace++``
* https://docs.python.org/3/reference/datamodel.html#code-objects[code objects]
== How to fix it == How to fix it
//== How to fix it in FRAMEWORK NAME
If the argument passed in is a class defined in this project then implementing the {object_replacement_protocol}[replace protocol] by defining the ``++__replace__++`` method.
[source,python,diff-id=1,diff-type=compliant]
----
class SomeClass:
def __init__(self, name)
self.name = name
def __replace__(self, /, **changes)
return SomeClass(changes.get("name", self.name))
----
=== Code examples === Code examples
@ -18,27 +34,45 @@ FIXME: remove the unused optional headers (that are commented out)
[source,python,diff-id=1,diff-type=noncompliant] [source,python,diff-id=1,diff-type=noncompliant]
---- ----
FIXME import copy
class AClass:
...
a = AClass()
b = copy.replace(a) # Noncompliant
---- ----
==== Compliant solution ==== Compliant solution
[source,python,diff-id=1,diff-type=compliant] [source,python,diff-id=1,diff-type=compliant]
---- ----
FIXME import copy
class AClass:
...
def __replace__(self, /, **changes):
...
a = AClass()
b = copy.replace(a) # Compliant
@dataclass
class ADataClass:
...
c = ADataClass()
d = copy.replace(c) # Compliant
---- ----
//=== How does this work? === Pitfalls
//=== Pitfalls Ensure that if the ``++__replace__++`` is implemented that the implementation creates a new object instead of updating the old one.
//=== Going the extra mile
//== Resources == Resources
//=== Documentation === Documentation
//=== Articles & blog posts * https://docs.python.org/3/library/copy.html#copy.replace
//=== Conference presentations * https://docs.python.org/3/library/copy.html#object.\\__replace__
//=== Standards * https://docs.python.org/3/whatsnew/3.13.html#copy
//=== External coding guidelines
//=== Benchmarks