Метод dataclasses.asdict каким-либо образом изменяет фиктивный объект
У меня странная проблема с классами данных Python, когда они связаны с фиктивными объектами. Ниже приведена моя база кода, и она организована в этой структуре каталогов:
.
├── setup.py
├── src
│ └── sample
│ ├── app.py
│ ├── configuration.py
│ ├── __init__.py
│ └── resource.py
└── tests
└── test_sample.py
Ниже приведен код для resource.py
:
import flask_restful
import flask
import datetime
class Person:
def __init__(self, name, year):
self.name = name
self.birthyear = year
def age_of_person(self):
today = datetime.datetime.now()
return today.year - self.birthyear
class SampleResource(flask_restful.Resource):
def __init__(self, person):
self.person = person
def get(self):
age = self.person.age_of_person()
return flask.jsonify({"name": self.person.name, "age": age})
Итак, у нас есть одна пустышка Person
класс и один SampleResource
(ресурс flask_restful) . Ресурс принимает экземпляр человека, а затем использует свои методы внутри своегоget
метод.
Ниже приведен код моего configuration.py
:
import dataclasses
import sample.resource
from typing import NamedTuple
@dataclasses.dataclass()
class ResourceClsKwargs():
person: sample.resource.Person
# def asdict(self):
# output = dict()
# for field in dataclasses.fields(self):
# output[field.name] = getattr(self, field.name)
# return output
# class ResourceClsKwargs(NamedTuple):
# person: sample.resource.Person
Итак, это простой класс данных, в котором resource_class_kwargs
который требуется передать ресурсу flask_restful
В app.py
составляет:
import sample.resource
import sample.configuration
import dataclasses
import flask
import flask_restful
def main(person):
resource_cls_kwargs = dataclasses.asdict(
sample.configuration.ResourceClsKwargs(person=person)
)
# resource_cls_kwargs = sample.configuration.ResourceClsKwargs(person=person)._asdict()
# resource_cls_kwargs = sample.configuration.ResourceClsKwargs(person=person).asdict()
app = flask.Flask(__name__)
api = flask_restful.Api(app)
api.add_resource(
sample.resource.SampleResource,
"/sample",
resource_class_kwargs=resource_cls_kwargs,
)
return app
if __name__ == "__main__":
subhayan = sample.resource.Person(name="Subhayan", year=1984)
app = main(subhayan)
app.run(debug=True)
Таким образом, создаются соответствующие объекты и просто запускается приложение.
Наконец, это код тестового файла:
"""Test file for project."""
import flask
import sample.app
import sample.resource
def test_flask_app_is_returned_from_main():
shaayan = sample.resource.Person(name="Shaayan", year=1988)
app = sample.app.main(shaayan)
assert isinstance(app, flask.Flask)
def test_that_age_of_person_method_is_run(mocker):
mock = mocker.Mock()
mock.age_of_person.return_value = 36
mock.name = "Subhayan"
expected_ouput = {
"name":"Subhayan",
"age": 36
}
app = sample.app.main(mock)
assert isinstance(app, flask.Flask)
app.config['TESTING'] = True
with app.test_client() as client:
response = client.get('/sample')
assert response.status_code == 200
assert response.json == expected_ouput
mock.age_of_person.assert_called()
Итак, когда я запускаю это, все утверждения проходят, кроме последнего. Таким образом, даже несмотря на то, что методы фиктивных объектов были вызваны, они все равно не работают.assert_called
.
mocker = <pytest_mock.plugin.MockFixture object at 0x7f2761248f10>
def test_that_age_of_person_method_is_run(mocker):
mock = mocker.Mock()
mock.age_of_person.return_value = 36
mock.name = "Subhayan"
expected_ouput = {
"name":"Subhayan",
"age": 36
}
app = sample.app.main(mock)
assert isinstance(app, flask.Flask)
app.config['TESTING'] = True
with app.test_client() as client:
response = client.get('/sample')
assert response.status_code == 200
assert response.json == expected_ouput
> mock.age_of_person.assert_called()
E AssertionError: Expected 'age_of_person' to have been called.
tests/test_sample.py:33: AssertionError
================================================================== short test summary info ===================================================================
FAILED tests/test_sample.py::test_that_age_of_person_method_is_run - AssertionError: Expected 'age_of_person' to have been called.
Как ни странно, если я изменил класс данных на именованный набор, все тесты проходят так:
Код для configuration.py
:
import dataclasses
import sample.resource
from typing import NamedTuple
# @dataclasses.dataclass()
# class ResourceClsKwargs():
# person: sample.resource.Person
# def asdict(self):
# output = dict()
# for field in dataclasses.fields(self):
# output[field.name] = getattr(self, field.name)
# return output
class ResourceClsKwargs(NamedTuple):
person: sample.resource.Person
Код для app.py
:
import sample.resource
import sample.configuration
import dataclasses
import flask
import flask_restful
def main(person):
# resource_cls_kwargs = dataclasses.asdict(
# sample.configuration.ResourceClsKwargs(person=person)
# )
resource_cls_kwargs = sample.configuration.ResourceClsKwargs(person=person)._asdict()
# resource_cls_kwargs = sample.configuration.ResourceClsKwargs(person=person).asdict()
app = flask.Flask(__name__)
api = flask_restful.Api(app)
api.add_resource(
sample.resource.SampleResource,
"/sample",
resource_class_kwargs=resource_cls_kwargs,
)
return app
if __name__ == "__main__":
subhayan = sample.resource.Person(name="Subhayan", year=1984)
app = main(subhayan)
app.run(debug=True)
Я не уверен, есть ли какое-то поведение в отношении классов данных, о котором я должен знать.
Большое спасибо за вашу помощь заранее.