From cce73da2a0cc2d754a0420e3c207c490c5619307 Mon Sep 17 00:00:00 2001 From: 07pepa <9963200+07pepa@users.noreply.github.com> Date: Mon, 28 Oct 2024 22:15:58 +0100 Subject: [PATCH] start to use Perflint and flake8-comprehensions to improved performance --- .pre-commit-config.yaml | 4 ++-- beanie/migrations/runner.py | 5 +---- beanie/odm/documents.py | 10 +++++---- beanie/odm/fields.py | 13 +++-------- beanie/odm/interfaces/find.py | 3 +-- beanie/odm/utils/init.py | 2 +- beanie/odm/views.py | 10 +++++---- pyproject.toml | 6 ++++- tests/fastapi/routes.py | 2 +- tests/migrations/test_break.py | 14 ++++++++++-- tests/odm/conftest.py | 30 +++++++++++++------------ tests/odm/documents/test_inheritance.py | 10 ++++----- tests/odm/test_cache.py | 9 ++++---- tests/odm/test_fields.py | 2 +- tests/odm/test_state_management.py | 11 +++++---- tests/typing/find.py | 13 +++++------ 16 files changed, 74 insertions(+), 70 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6aeb202cc..0e707d657 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,12 +1,12 @@ repos: - repo: https://github.com/charliermarsh/ruff-pre-commit - rev: v0.6.9 + rev: v0.7.1 hooks: - id: ruff args: [ --fix ] - id: ruff-format - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.11.2 + rev: v1.13.0 hooks: - id: mypy additional_dependencies: diff --git a/beanie/migrations/runner.py b/beanie/migrations/runner.py index 06b2a747b..94839d2c1 100644 --- a/beanie/migrations/runner.py +++ b/beanie/migrations/runner.py @@ -203,10 +203,7 @@ async def build(cls, path: Path): :return: """ logger.info("Building migration list") - names = [] - for modulepath in path.glob("*.py"): - names.append(modulepath.name) - names.sort() + names = sorted([modulepath.name for modulepath in path.glob("*.py")]) db = DBHandler.get_db() await init_beanie( diff --git a/beanie/odm/documents.py b/beanie/odm/documents.py index c6f5c8518..877e79dcf 100644 --- a/beanie/odm/documents.py +++ b/beanie/odm/documents.py @@ -1182,12 +1182,14 @@ async def fetch_link(self, field: Union[str, Any]): setattr(self, field, values) async def fetch_all_links(self): - coros = [] link_fields = self.get_link_fields() if link_fields is not None: - for ref in link_fields.values(): - coros.append(self.fetch_link(ref.field_name)) # TODO lists - await asyncio.gather(*coros) + await asyncio.gather( + *[ + self.fetch_link(ref.field_name) + for ref in link_fields.values() + ] + ) @classmethod def get_link_fields(cls) -> Optional[Dict[str, LinkInfo]]: diff --git a/beanie/odm/fields.py b/beanie/odm/fields.py index 3cf5d492f..1ad011029 100644 --- a/beanie/odm/fields.py +++ b/beanie/odm/fields.py @@ -326,7 +326,7 @@ async def fetch_list( data = Link.repack_links(links) # type: ignore ids_to_fetch = [] document_class = None - for doc_id, link in data.items(): + for link in data.values(): if isinstance(link, Link): if document_class is None: document_class = link.document_class @@ -363,10 +363,7 @@ def repack_links( @classmethod async def fetch_many(cls, links: List[Link]): - coros = [] - for link in links: - coros.append(link.fetch()) - return await asyncio.gather(*coros) + return await asyncio.gather(*[link.fetch() for link in links]) if IS_PYDANTIC_V2: @@ -538,11 +535,7 @@ def __repr__(self): def list_difference( left: List[IndexModelField], right: List[IndexModelField] ): - result = [] - for index in left: - if index not in right: - result.append(index) - return result + return [index for index in left if index not in right] @staticmethod def list_to_index_model(left: List[IndexModelField]): diff --git a/beanie/odm/interfaces/find.py b/beanie/odm/interfaces/find.py index c96f5bf41..739b0e5ee 100644 --- a/beanie/odm/interfaces/find.py +++ b/beanie/odm/interfaces/find.py @@ -454,8 +454,7 @@ def _add_class_id_filter(cls, args: Tuple, with_children: bool = False): args += ( { cls.get_settings().class_id: { - "$in": [cls._class_id] - + [cname for cname in cls._children.keys()] + "$in": [cls._class_id] + list(cls._children.keys()) } }, ) diff --git a/beanie/odm/utils/init.py b/beanie/odm/utils/init.py index 212d60721..c7a144aab 100644 --- a/beanie/odm/utils/init.py +++ b/beanie/odm/utils/init.py @@ -370,7 +370,7 @@ def set_default_class_vars(cls: Type[Document]): to init settings :return: """ - cls._children = dict() + cls._children = {} cls._parent = None cls._inheritance_inited = False cls._class_id = None diff --git a/beanie/odm/views.py b/beanie/odm/views.py index a38985f6d..677da646e 100644 --- a/beanie/odm/views.py +++ b/beanie/odm/views.py @@ -55,12 +55,14 @@ async def fetch_link(self, field: Union[str, Any]): setattr(self, field, values) async def fetch_all_links(self): - coros = [] link_fields = self.get_link_fields() if link_fields is not None: - for ref in link_fields.values(): - coros.append(self.fetch_link(ref.field_name)) # TODO lists - await asyncio.gather(*coros) + await asyncio.gather( + *[ + self.fetch_link(ref.field_name) + for ref in link_fields.values() + ] + ) @classmethod def get_link_fields(cls) -> Optional[Dict[str, LinkInfo]]: diff --git a/pyproject.toml b/pyproject.toml index 151184fb3..a74555125 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -112,7 +112,11 @@ include = ["**/*.py", ".github/**/*.py"] [tool.ruff.lint] ignore = ["E501"] -extend-select = ["I001"] +extend-select = [ + 'I', # isort + 'PERF', # Perflint + 'C4', # flake8-comprehensions +] per-file-ignores = { "tests/*" = ["E711"] } # Allow unused variables when underscore-prefixed. diff --git a/tests/fastapi/routes.py b/tests/fastapi/routes.py index fd9522040..bbff8dccd 100644 --- a/tests/fastapi/routes.py +++ b/tests/fastapi/routes.py @@ -41,7 +41,7 @@ async def create_houses_with_window_link(window: WindowInput): HouseAPI.model_validate if IS_PYDANTIC_V2 else HouseAPI.parse_obj ) house = validator( - dict(name="test_name", windows=[WindowAPI.link_from_id(window.id)]) + {"name": "test_name", "windows": [WindowAPI.link_from_id(window.id)]} ) await house.insert(link_rule=WriteRules.WRITE) return house diff --git a/tests/migrations/test_break.py b/tests/migrations/test_break.py index c305a3048..386713bdd 100644 --- a/tests/migrations/test_break.py +++ b/tests/migrations/test_break.py @@ -56,7 +56,17 @@ async def test_migration_break(settings, notes, db): inspection = await OldNote.inspect_collection() assert inspection.status == InspectionStatuses.OK notes = await OldNote.get_motor_collection().find().to_list(length=100) - names = set(n["name"] for n in notes) - assert names == {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"} + assert {n["name"] for n in notes} == { + "0", + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + } for note in notes: assert "title" not in note diff --git a/tests/odm/conftest.py b/tests/odm/conftest.py index b6cdd99b5..beca36903 100644 --- a/tests/odm/conftest.py +++ b/tests/odm/conftest.py @@ -309,12 +309,16 @@ async def deprecated_init_beanie(db): database=db, document_models=[DocumentWithDeprecatedHiddenField], ) - assert len(w) == 1 - assert issubclass(w[-1].category, DeprecationWarning) - assert ( - "DocumentWithDeprecatedHiddenField: 'hidden=True' is deprecated, please use 'exclude=True'" - in str(w[-1].message) - ) + found = False + for warning in w: + if ( + "DocumentWithDeprecatedHiddenField: 'hidden=True' is deprecated, please use 'exclude=True" + in str(warning.message) + ): + found = True + break + + assert found @pytest.fixture(autouse=True) @@ -372,15 +376,13 @@ def document_soft_delete_not_inserted(): @pytest.fixture def documents_soft_delete_not_inserted(): - docs = [] - for i in range(3): - docs.append( - DocumentTestModelWithSoftDelete( - test_int=randint(0, 1000000), - test_str="kipasa", - ) + return [ + DocumentTestModelWithSoftDelete( + test_int=randint(0, 1000000), + test_str="kipasa", ) - return docs + for _ in range(3) + ] @pytest.fixture diff --git a/tests/odm/documents/test_inheritance.py b/tests/odm/documents/test_inheritance.py index 8454573b8..ce4342caf 100644 --- a/tests/odm/documents/test_inheritance.py +++ b/tests/odm/documents/test_inheritance.py @@ -63,8 +63,8 @@ async def test_inheritance(self, db): assert len(white_vehicles) == 3 assert len(cars_only) == 2 - assert {Car, Bus} == set(i.__class__ for i in cars_and_buses) - assert {Bicycle, Car, Bus} == set(i.__class__ for i in white_vehicles) + assert {Car, Bus} == {i.__class__ for i in cars_and_buses} + assert {Bicycle, Car, Bus} == {i.__class__ for i in white_vehicles} white_vehicles_2 = await Car.find(Vehicle.color == "white").to_list() assert len(white_vehicles_2) == 1 @@ -92,13 +92,13 @@ async def test_links(self, db): # re-fetch from DB w/o links owner = await Owner.get(owner.id) - assert {Link} == set(i.__class__ for i in owner.vehicles) + assert {Link} == {i.__class__ for i in owner.vehicles} await owner.fetch_all_links() - assert {Car, Bus} == set(i.__class__ for i in owner.vehicles) + assert {Car, Bus} == {i.__class__ for i in owner.vehicles} # re-fetch from DB with resolved links owner = await Owner.get(owner.id, fetch_links=True) - assert {Car, Bus} == set(i.__class__ for i in owner.vehicles) + assert {Car, Bus} == {i.__class__ for i in owner.vehicles} for e in (owner, car_1, car_2, bus_1): await e.delete() diff --git a/tests/odm/test_cache.py b/tests/odm/test_cache.py index 1a9c7e25b..421bf1e0f 100644 --- a/tests/odm/test_cache.py +++ b/tests/odm/test_cache.py @@ -82,11 +82,10 @@ async def test_aggregation(documents): async def test_capacity(documents): await documents(10) - docs = [] - for i in range(10): - docs.append( - await DocumentTestModel.find_one(DocumentTestModel.test_int == i) - ) + docs = [ + await DocumentTestModel.find_one(DocumentTestModel.test_int == i) + for i in range(10) + ] await DocumentTestModel.find_one(DocumentTestModel.test_int == 1).set( {DocumentTestModel.test_str: "NEW_VALUE"} diff --git a/tests/odm/test_fields.py b/tests/odm/test_fields.py index 2e94b2419..20c765e5a 100644 --- a/tests/odm/test_fields.py +++ b/tests/odm/test_fields.py @@ -68,7 +68,7 @@ async def test_custom_filed_types(): ipv6network="2001:db00::0/24", timedelta=4782453, set_type={"one", "two", "three"}, - tuple_type=tuple([3, "string"]), + tuple_type=(3, "string"), path="/etc/hosts", ) custom2 = DocumentWithCustomFiledsTypes( diff --git a/tests/odm/test_state_management.py b/tests/odm/test_state_management.py index 3dbfb2459..49b2c5158 100644 --- a/tests/odm/test_state_management.py +++ b/tests/odm/test_state_management.py @@ -389,13 +389,12 @@ async def test_find_one(self, saved_doc_default, state): assert new_doc.get_previous_saved_state() is None async def test_find_many(self): - docs = [] - for i in range(10): - docs.append( - DocumentWithTurnedOnStateManagement( - num_1=i, num_2=i + 1, internal=InternalDoc() - ) + docs = [ + DocumentWithTurnedOnStateManagement( + num_1=i, num_2=i + 1, internal=InternalDoc() ) + for i in range(10) + ] await DocumentWithTurnedOnStateManagement.insert_many(docs) found_docs = await DocumentWithTurnedOnStateManagement.find( diff --git a/tests/typing/find.py b/tests/typing/find.py index 45691d86b..1a4083086 100644 --- a/tests/typing/find.py +++ b/tests/typing/find.py @@ -12,17 +12,14 @@ async def find_many_with_projection() -> List[ProjectionTest]: async def find_many_generator() -> List[Test]: - docs: List[Test] = [] - async for doc in Test.find(): - docs.append(doc) - return docs + return [doc async for doc in Test.find()] async def find_many_generator_with_projection() -> List[ProjectionTest]: - docs: List[ProjectionTest] = [] - async for doc in Test.find().project(projection_model=ProjectionTest): - docs.append(doc) - return docs + return [ + doc + async for doc in Test.find().project(projection_model=ProjectionTest) + ] async def find_one() -> Optional[Test]: