write initial version of S7156
This commit is contained in:
parent
cbd6564edd
commit
1a20440092
@ -1,13 +1,12 @@
|
||||
{
|
||||
"title": "FIXME",
|
||||
"title": "\"copy.replace\" should not be invoked with an unsupported argument",
|
||||
"type": "CODE_SMELL",
|
||||
"status": "ready",
|
||||
"remediation": {
|
||||
"func": "Constant\/Issue",
|
||||
"func": "Constant/Issue",
|
||||
"constantCost": "5min"
|
||||
},
|
||||
"tags": [
|
||||
],
|
||||
"tags": [],
|
||||
"defaultSeverity": "Major",
|
||||
"ruleSpecification": "RSPEC-7156",
|
||||
"sqKey": "S7156",
|
||||
@ -17,8 +16,7 @@
|
||||
"code": {
|
||||
"impacts": {
|
||||
"MAINTAINABILITY": "HIGH",
|
||||
"RELIABILITY": "MEDIUM",
|
||||
"SECURITY": "LOW"
|
||||
"RELIABILITY": "MEDIUM"
|
||||
},
|
||||
"attribute": "CONVENTIONAL"
|
||||
}
|
||||
|
@ -1,16 +1,32 @@
|
||||
FIXME: add a description
|
||||
|
||||
// If you want to factorize the description uncomment the following line and create the file.
|
||||
//include::../description.adoc[]
|
||||
:object_replacement_protocol: https://docs.python.org/3/library/copy.html#object.__replace__
|
||||
|
||||
== 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 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
|
||||
|
||||
@ -18,27 +34,45 @@ FIXME: remove the unused optional headers (that are commented out)
|
||||
|
||||
[source,python,diff-id=1,diff-type=noncompliant]
|
||||
----
|
||||
FIXME
|
||||
import copy
|
||||
|
||||
class AClass:
|
||||
...
|
||||
|
||||
a = AClass()
|
||||
b = copy.replace(a) # Noncompliant
|
||||
----
|
||||
|
||||
==== Compliant solution
|
||||
|
||||
[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
|
||||
|
||||
//=== Going the extra mile
|
||||
Ensure that if the ``++__replace__++`` is implemented that the implementation creates a new object instead of updating the old one.
|
||||
|
||||
|
||||
//== Resources
|
||||
//=== Documentation
|
||||
//=== Articles & blog posts
|
||||
//=== Conference presentations
|
||||
//=== Standards
|
||||
//=== External coding guidelines
|
||||
//=== Benchmarks
|
||||
== Resources
|
||||
=== Documentation
|
||||
* https://docs.python.org/3/library/copy.html#copy.replace
|
||||
* https://docs.python.org/3/library/copy.html#object.\\__replace__
|
||||
* https://docs.python.org/3/whatsnew/3.13.html#copy
|
||||
|
Loading…
x
Reference in New Issue
Block a user