Skip to content

Commit

Permalink
write initial version of S7156
Browse files Browse the repository at this point in the history
  • Loading branch information
Seppli11 committed Nov 12, 2024
1 parent cbd6564 commit 5b7dc5e
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 24 deletions.
10 changes: 4 additions & 6 deletions rules/S7156/python/metadata.json
Original file line number Diff line number Diff line change
@@ -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",
Expand All @@ -17,8 +16,7 @@
"code": {
"impacts": {
"MAINTAINABILITY": "HIGH",
"RELIABILITY": "MEDIUM",
"SECURITY": "LOW"
"RELIABILITY": "MEDIUM"
},
"attribute": "CONVENTIONAL"
}
Expand Down
72 changes: 54 additions & 18 deletions rules/S7156/python/rule.adoc
Original file line number Diff line number Diff line change
@@ -1,44 +1,80 @@
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

==== Noncompliant code example

[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
//=== How does this work?
//=== Pitfalls
@dataclass
class ADataClass:
...
c = ADataClass()
d = copy.replace(c) # Compliant
----

=== 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

0 comments on commit 5b7dc5e

Please sign in to comment.