From af93e1dbaf070f3d4bd3f8244bb16aaa8f64d587 Mon Sep 17 00:00:00 2001 From: Milan Saxena Date: Tue, 11 Feb 2025 19:31:32 -0800 Subject: [PATCH 1/3] new e2e test + backend updates --- cdp/client/__init__.py | 2 + cdp/client/models/__init__.py | 2 + cdp/client/models/ethereum_transaction.py | 10 +- .../models/ethereum_validator_metadata.py | 10 +- cdp/client/models/transaction_log.py | 91 +++++++++++++ cdp/client/models/transaction_receipt.py | 127 ++++++++++++++++++ cdp/client/models/user_operation.py | 9 +- tests/test_e2e.py | 30 +++++ 8 files changed, 271 insertions(+), 10 deletions(-) create mode 100644 cdp/client/models/transaction_log.py create mode 100644 cdp/client/models/transaction_receipt.py diff --git a/cdp/client/__init__.py b/cdp/client/__init__.py index 1eac2d4..4946da2 100644 --- a/cdp/client/__init__.py +++ b/cdp/client/__init__.py @@ -159,6 +159,8 @@ from cdp.client.models.trade_list import TradeList from cdp.client.models.transaction import Transaction from cdp.client.models.transaction_content import TransactionContent +from cdp.client.models.transaction_log import TransactionLog +from cdp.client.models.transaction_receipt import TransactionReceipt from cdp.client.models.transaction_type import TransactionType from cdp.client.models.transfer import Transfer from cdp.client.models.transfer_list import TransferList diff --git a/cdp/client/models/__init__.py b/cdp/client/models/__init__.py index 80300d3..7070d25 100644 --- a/cdp/client/models/__init__.py +++ b/cdp/client/models/__init__.py @@ -122,6 +122,8 @@ from cdp.client.models.trade_list import TradeList from cdp.client.models.transaction import Transaction from cdp.client.models.transaction_content import TransactionContent +from cdp.client.models.transaction_log import TransactionLog +from cdp.client.models.transaction_receipt import TransactionReceipt from cdp.client.models.transaction_type import TransactionType from cdp.client.models.transfer import Transfer from cdp.client.models.transfer_list import TransferList diff --git a/cdp/client/models/ethereum_transaction.py b/cdp/client/models/ethereum_transaction.py index 9405d8e..4658a3c 100644 --- a/cdp/client/models/ethereum_transaction.py +++ b/cdp/client/models/ethereum_transaction.py @@ -23,6 +23,7 @@ from cdp.client.models.ethereum_token_transfer import EthereumTokenTransfer from cdp.client.models.ethereum_transaction_access_list import EthereumTransactionAccessList from cdp.client.models.ethereum_transaction_flattened_trace import EthereumTransactionFlattenedTrace +from cdp.client.models.transaction_receipt import TransactionReceipt from typing import Optional, Set from typing_extensions import Self @@ -49,7 +50,8 @@ class EthereumTransaction(BaseModel): block_timestamp: Optional[datetime] = Field(default=None, description="The timestamp of the block in which the event was emitted") mint: Optional[StrictStr] = Field(default=None, description="This is for handling optimism rollup specific EIP-2718 transaction type field.") rlp_encoded_tx: Optional[StrictStr] = Field(default=None, description="RLP encoded transaction as a hex string (prefixed with 0x) for native compatibility with popular eth clients such as etherjs, viem etc.") - __properties: ClassVar[List[str]] = ["from", "gas", "gas_price", "hash", "input", "nonce", "to", "index", "value", "type", "max_fee_per_gas", "max_priority_fee_per_gas", "priority_fee_per_gas", "transaction_access_list", "token_transfers", "flattened_traces", "block_timestamp", "mint", "rlp_encoded_tx"] + receipt: Optional[TransactionReceipt] = None + __properties: ClassVar[List[str]] = ["from", "gas", "gas_price", "hash", "input", "nonce", "to", "index", "value", "type", "max_fee_per_gas", "max_priority_fee_per_gas", "priority_fee_per_gas", "transaction_access_list", "token_transfers", "flattened_traces", "block_timestamp", "mint", "rlp_encoded_tx", "receipt"] model_config = ConfigDict( populate_by_name=True, @@ -107,6 +109,9 @@ def to_dict(self) -> Dict[str, Any]: if _item_flattened_traces: _items.append(_item_flattened_traces.to_dict()) _dict['flattened_traces'] = _items + # override the default output from pydantic by calling `to_dict()` of receipt + if self.receipt: + _dict['receipt'] = self.receipt.to_dict() return _dict @classmethod @@ -137,7 +142,8 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: "flattened_traces": [EthereumTransactionFlattenedTrace.from_dict(_item) for _item in obj["flattened_traces"]] if obj.get("flattened_traces") is not None else None, "block_timestamp": obj.get("block_timestamp"), "mint": obj.get("mint"), - "rlp_encoded_tx": obj.get("rlp_encoded_tx") + "rlp_encoded_tx": obj.get("rlp_encoded_tx"), + "receipt": TransactionReceipt.from_dict(obj["receipt"]) if obj.get("receipt") is not None else None }) return _obj diff --git a/cdp/client/models/ethereum_validator_metadata.py b/cdp/client/models/ethereum_validator_metadata.py index 43d72ec..bf73f3f 100644 --- a/cdp/client/models/ethereum_validator_metadata.py +++ b/cdp/client/models/ethereum_validator_metadata.py @@ -18,7 +18,7 @@ import json from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictStr -from typing import Any, ClassVar, Dict, List +from typing import Any, ClassVar, Dict, List, Optional from cdp.client.models.balance import Balance from typing import Optional, Set from typing_extensions import Self @@ -36,7 +36,9 @@ class EthereumValidatorMetadata(BaseModel): withdrawable_epoch: StrictStr = Field(description="The epoch at which the validator can withdraw.", alias="withdrawableEpoch") balance: Balance effective_balance: Balance - __properties: ClassVar[List[str]] = ["index", "public_key", "withdrawal_address", "slashed", "activationEpoch", "exitEpoch", "withdrawableEpoch", "balance", "effective_balance"] + fee_recipient_address: StrictStr = Field(description="The address for execution layer rewards (MEV & tx fees). If using a reward splitter plan, this is a smart contract address that splits rewards based on defined commissions and send a portion to the forwarded_fee_recipient_address. ") + forwarded_fee_recipient_address: Optional[StrictStr] = Field(default=None, description="If using a reward splitter plan, this address receives a defined percentage of the total execution layer rewards. ") + __properties: ClassVar[List[str]] = ["index", "public_key", "withdrawal_address", "slashed", "activationEpoch", "exitEpoch", "withdrawableEpoch", "balance", "effective_balance", "fee_recipient_address", "forwarded_fee_recipient_address"] model_config = ConfigDict( populate_by_name=True, @@ -103,7 +105,9 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: "exitEpoch": obj.get("exitEpoch"), "withdrawableEpoch": obj.get("withdrawableEpoch"), "balance": Balance.from_dict(obj["balance"]) if obj.get("balance") is not None else None, - "effective_balance": Balance.from_dict(obj["effective_balance"]) if obj.get("effective_balance") is not None else None + "effective_balance": Balance.from_dict(obj["effective_balance"]) if obj.get("effective_balance") is not None else None, + "fee_recipient_address": obj.get("fee_recipient_address"), + "forwarded_fee_recipient_address": obj.get("forwarded_fee_recipient_address") }) return _obj diff --git a/cdp/client/models/transaction_log.py b/cdp/client/models/transaction_log.py new file mode 100644 index 0000000..401ccb6 --- /dev/null +++ b/cdp/client/models/transaction_log.py @@ -0,0 +1,91 @@ +# coding: utf-8 + +""" + Coinbase Platform API + + This is the OpenAPI 3.0 specification for the Coinbase Platform APIs, used in conjunction with the Coinbase Platform SDKs. + + The version of the OpenAPI document: 0.0.1-alpha + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 + + +from __future__ import annotations +import pprint +import re # noqa: F401 +import json + +from pydantic import BaseModel, ConfigDict, Field, StrictStr +from typing import Any, ClassVar, Dict, List +from typing import Optional, Set +from typing_extensions import Self + +class TransactionLog(BaseModel): + """ + A log emitted from an onchain transaction. + """ # noqa: E501 + address: StrictStr = Field(description="An onchain address of a contract.") + topics: List[StrictStr] + data: StrictStr = Field(description="The data included in this log.") + __properties: ClassVar[List[str]] = ["address", "topics", "data"] + + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) + + + def to_str(self) -> str: + """Returns the string representation of the model using alias""" + return pprint.pformat(self.model_dump(by_alias=True)) + + def to_json(self) -> str: + """Returns the JSON representation of the model using alias""" + # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead + return json.dumps(self.to_dict()) + + @classmethod + def from_json(cls, json_str: str) -> Optional[Self]: + """Create an instance of TransactionLog from a JSON string""" + return cls.from_dict(json.loads(json_str)) + + def to_dict(self) -> Dict[str, Any]: + """Return the dictionary representation of the model using alias. + + This has the following differences from calling pydantic's + `self.model_dump(by_alias=True)`: + + * `None` is only added to the output dict for nullable fields that + were set at model initialization. Other fields with value `None` + are ignored. + """ + excluded_fields: Set[str] = set([ + ]) + + _dict = self.model_dump( + by_alias=True, + exclude=excluded_fields, + exclude_none=True, + ) + return _dict + + @classmethod + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: + """Create an instance of TransactionLog from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate({ + "address": obj.get("address"), + "topics": obj.get("topics"), + "data": obj.get("data") + }) + return _obj + + diff --git a/cdp/client/models/transaction_receipt.py b/cdp/client/models/transaction_receipt.py new file mode 100644 index 0000000..4d6323b --- /dev/null +++ b/cdp/client/models/transaction_receipt.py @@ -0,0 +1,127 @@ +# coding: utf-8 + +""" + Coinbase Platform API + + This is the OpenAPI 3.0 specification for the Coinbase Platform APIs, used in conjunction with the Coinbase Platform SDKs. + + The version of the OpenAPI document: 0.0.1-alpha + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 + + +from __future__ import annotations +import pprint +import re # noqa: F401 +import json + +from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictInt, StrictStr +from typing import Any, ClassVar, Dict, List, Optional +from cdp.client.models.transaction_log import TransactionLog +from typing import Optional, Set +from typing_extensions import Self + +class TransactionReceipt(BaseModel): + """ + The receipt of an onchain transaction's execution. + """ # noqa: E501 + to: Optional[StrictStr] = Field(default=None, description="The address this transaction is to. This is null if the transaction was an init transaction, used to deploy a contract.") + var_from: Optional[StrictStr] = Field(default=None, description="The address this transaction is from.", alias="from") + contract_address: Optional[StrictStr] = Field(default=None, description="The EVM address of the smart contract. If this transaction has a null to address, it is an init transaction used to deploy a contract, in which case this is the address created by that contract.") + transaction_index: Optional[StrictInt] = Field(default=None, description="The index of this transaction in the list of transactions included in the block this transaction was mined in.") + type: Optional[StrictInt] = Field(default=None, description="The EIP-2718 transaction type. See https://eips.ethereum.org/EIPS/eip-2718 for more details.") + logs_bloom: Optional[StrictStr] = Field(default=None, description="A bloom-filter, which includes all the addresses and topics included in any log in this transaction.") + block_hash: Optional[StrictStr] = Field(default=None, description="The hash of the block at which the transaction was recorded.") + transaction_hash: Optional[StrictStr] = Field(default=None, description="The hash of the onchain sponsored send transaction.") + block_number: Optional[StrictInt] = Field(default=None, description="The block height (number) of the block that this transaction was included in.") + confirmations: Optional[StrictInt] = Field(default=None, description="The number of blocks that have been mined since this transaction, including the actual block it was mined in.") + root: Optional[StrictStr] = Field(default=None, description="The intermediate state root of a receipt.") + cumulative_gas_used: Optional[StrictInt] = Field(default=None, description="For the block this transaction was included in, this is the sum of the gas used by each transaction in the ordered list of transactions up to (and including) this transaction.") + byzantium: Optional[StrictBool] = Field(default=None, description="This is true if the block is in a post-Byzantium Hard Fork block.") + status: StrictInt = Field(description="The status of a transaction is 1 if successful or 0 if it was reverted.") + logs: List[TransactionLog] + gas_used: Optional[StrictStr] = Field(default=None, description="The amount of gas actually used by this transaction.") + effective_gas_price: Optional[StrictStr] = Field(default=None, description="The effective gas price the transaction was charged at.") + __properties: ClassVar[List[str]] = ["to", "from", "contract_address", "transaction_index", "type", "logs_bloom", "block_hash", "transaction_hash", "block_number", "confirmations", "root", "cumulative_gas_used", "byzantium", "status", "logs", "gas_used", "effective_gas_price"] + + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) + + + def to_str(self) -> str: + """Returns the string representation of the model using alias""" + return pprint.pformat(self.model_dump(by_alias=True)) + + def to_json(self) -> str: + """Returns the JSON representation of the model using alias""" + # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead + return json.dumps(self.to_dict()) + + @classmethod + def from_json(cls, json_str: str) -> Optional[Self]: + """Create an instance of TransactionReceipt from a JSON string""" + return cls.from_dict(json.loads(json_str)) + + def to_dict(self) -> Dict[str, Any]: + """Return the dictionary representation of the model using alias. + + This has the following differences from calling pydantic's + `self.model_dump(by_alias=True)`: + + * `None` is only added to the output dict for nullable fields that + were set at model initialization. Other fields with value `None` + are ignored. + """ + excluded_fields: Set[str] = set([ + ]) + + _dict = self.model_dump( + by_alias=True, + exclude=excluded_fields, + exclude_none=True, + ) + # override the default output from pydantic by calling `to_dict()` of each item in logs (list) + _items = [] + if self.logs: + for _item_logs in self.logs: + if _item_logs: + _items.append(_item_logs.to_dict()) + _dict['logs'] = _items + return _dict + + @classmethod + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: + """Create an instance of TransactionReceipt from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate({ + "to": obj.get("to"), + "from": obj.get("from"), + "contract_address": obj.get("contract_address"), + "transaction_index": obj.get("transaction_index"), + "type": obj.get("type"), + "logs_bloom": obj.get("logs_bloom"), + "block_hash": obj.get("block_hash"), + "transaction_hash": obj.get("transaction_hash"), + "block_number": obj.get("block_number"), + "confirmations": obj.get("confirmations"), + "root": obj.get("root"), + "cumulative_gas_used": obj.get("cumulative_gas_used"), + "byzantium": obj.get("byzantium"), + "status": obj.get("status"), + "logs": [TransactionLog.from_dict(_item) for _item in obj["logs"]] if obj.get("logs") is not None else None, + "gas_used": obj.get("gas_used"), + "effective_gas_price": obj.get("effective_gas_price") + }) + return _obj + + diff --git a/cdp/client/models/user_operation.py b/cdp/client/models/user_operation.py index 947319c..f2ca9b2 100644 --- a/cdp/client/models/user_operation.py +++ b/cdp/client/models/user_operation.py @@ -32,15 +32,13 @@ class UserOperation(BaseModel): calls: List[Call] = Field(description="The list of calls to make from the smart wallet.") unsigned_payload: StrictStr = Field(description="The hex-encoded hash that must be signed by the user.") signature: Optional[StrictStr] = Field(default=None, description="The hex-encoded signature of the user operation.") - status: Optional[StrictStr] = Field(default=None, description="The status of the user operation.") - __properties: ClassVar[List[str]] = ["id", "network_id", "calls", "unsigned_payload", "signature", "status"] + transaction_hash: Optional[StrictStr] = Field(default=None, description="The hash of the transaction that was broadcast.") + status: StrictStr = Field(description="The status of the user operation.") + __properties: ClassVar[List[str]] = ["id", "network_id", "calls", "unsigned_payload", "signature", "transaction_hash", "status"] @field_validator('status') def status_validate_enum(cls, value): """Validates the enum""" - if value is None: - return value - if value not in set(['pending', 'signed', 'broadcast', 'complete', 'failed']): raise ValueError("must be one of enum values ('pending', 'signed', 'broadcast', 'complete', 'failed')") return value @@ -108,6 +106,7 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: "calls": [Call.from_dict(_item) for _item in obj["calls"]] if obj.get("calls") is not None else None, "unsigned_payload": obj.get("unsigned_payload"), "signature": obj.get("signature"), + "transaction_hash": obj.get("transaction_hash"), "status": obj.get("status") }) return _obj diff --git a/tests/test_e2e.py b/tests/test_e2e.py index 04ba70a..98032c0 100644 --- a/tests/test_e2e.py +++ b/tests/test_e2e.py @@ -171,6 +171,36 @@ def test_historical_balances(imported_wallet): assert balances assert all(balance.amount > 0 for balance in balances) +@pytest.mark.e2e +def test_invoke_contract_with_transaction_receipt(imported_wallet): + """Test invoke contract with transaction receipt.""" + destination_wallet = Wallet.create() + + faucet_transaction = imported_wallet.faucet("usdc") + faucet_transaction.wait() + + # Transfer 0.000001 USDC to the destination address. + invocation = imported_wallet.invoke_contract( + contract_address="0x036CbD53842c5426634e7929541eC2318f3dCF7e", + method="transfer", + args={"to": destination_wallet.default_address.address_id, "value": "1"} + ) + + invocation.wait() + + transaction_content = invocation.transaction.content.actual_instance + transaction_receipt = transaction_content.receipt + + assert transaction_receipt.status == 1 + + transaction_logs = transaction_receipt.logs + assert len(transaction_logs) == 1 + + transaction_log = transaction_logs[0] + assert transaction_log.address == "0x036CbD53842c5426634e7929541eC2318f3dCF7e" + assert transaction_log.topics[0] == "Transfer" + assert transaction_log.topics[1] == f"from: {imported_wallet.default_address.address_id}" + assert transaction_log.topics[2] == f"to: {destination_wallet.default_address.address_id}" @pytest.mark.skip(reason="Gasless transfers have unpredictable latency") def test_gasless_transfer(imported_wallet): From 2a6d81f4d823ea43257ec2784f09313510c89e65 Mon Sep 17 00:00:00 2001 From: Milan Saxena Date: Wed, 12 Feb 2025 13:18:08 -0800 Subject: [PATCH 2/3] add changes from openapi spec for transaction receipt --- cdp/client/models/transaction_receipt.py | 36 ++++-------------------- 1 file changed, 5 insertions(+), 31 deletions(-) diff --git a/cdp/client/models/transaction_receipt.py b/cdp/client/models/transaction_receipt.py index 4d6323b..ae97b1f 100644 --- a/cdp/client/models/transaction_receipt.py +++ b/cdp/client/models/transaction_receipt.py @@ -17,8 +17,8 @@ import re # noqa: F401 import json -from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictInt, StrictStr -from typing import Any, ClassVar, Dict, List, Optional +from pydantic import BaseModel, ConfigDict, Field, StrictInt, StrictStr +from typing import Any, ClassVar, Dict, List from cdp.client.models.transaction_log import TransactionLog from typing import Optional, Set from typing_extensions import Self @@ -27,24 +27,11 @@ class TransactionReceipt(BaseModel): """ The receipt of an onchain transaction's execution. """ # noqa: E501 - to: Optional[StrictStr] = Field(default=None, description="The address this transaction is to. This is null if the transaction was an init transaction, used to deploy a contract.") - var_from: Optional[StrictStr] = Field(default=None, description="The address this transaction is from.", alias="from") - contract_address: Optional[StrictStr] = Field(default=None, description="The EVM address of the smart contract. If this transaction has a null to address, it is an init transaction used to deploy a contract, in which case this is the address created by that contract.") - transaction_index: Optional[StrictInt] = Field(default=None, description="The index of this transaction in the list of transactions included in the block this transaction was mined in.") - type: Optional[StrictInt] = Field(default=None, description="The EIP-2718 transaction type. See https://eips.ethereum.org/EIPS/eip-2718 for more details.") - logs_bloom: Optional[StrictStr] = Field(default=None, description="A bloom-filter, which includes all the addresses and topics included in any log in this transaction.") - block_hash: Optional[StrictStr] = Field(default=None, description="The hash of the block at which the transaction was recorded.") - transaction_hash: Optional[StrictStr] = Field(default=None, description="The hash of the onchain sponsored send transaction.") - block_number: Optional[StrictInt] = Field(default=None, description="The block height (number) of the block that this transaction was included in.") - confirmations: Optional[StrictInt] = Field(default=None, description="The number of blocks that have been mined since this transaction, including the actual block it was mined in.") - root: Optional[StrictStr] = Field(default=None, description="The intermediate state root of a receipt.") - cumulative_gas_used: Optional[StrictInt] = Field(default=None, description="For the block this transaction was included in, this is the sum of the gas used by each transaction in the ordered list of transactions up to (and including) this transaction.") - byzantium: Optional[StrictBool] = Field(default=None, description="This is true if the block is in a post-Byzantium Hard Fork block.") status: StrictInt = Field(description="The status of a transaction is 1 if successful or 0 if it was reverted.") logs: List[TransactionLog] - gas_used: Optional[StrictStr] = Field(default=None, description="The amount of gas actually used by this transaction.") - effective_gas_price: Optional[StrictStr] = Field(default=None, description="The effective gas price the transaction was charged at.") - __properties: ClassVar[List[str]] = ["to", "from", "contract_address", "transaction_index", "type", "logs_bloom", "block_hash", "transaction_hash", "block_number", "confirmations", "root", "cumulative_gas_used", "byzantium", "status", "logs", "gas_used", "effective_gas_price"] + gas_used: StrictStr = Field(description="The amount of gas actually used by this transaction.") + effective_gas_price: StrictStr = Field(description="The effective gas price the transaction was charged at.") + __properties: ClassVar[List[str]] = ["status", "logs", "gas_used", "effective_gas_price"] model_config = ConfigDict( populate_by_name=True, @@ -104,19 +91,6 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: return cls.model_validate(obj) _obj = cls.model_validate({ - "to": obj.get("to"), - "from": obj.get("from"), - "contract_address": obj.get("contract_address"), - "transaction_index": obj.get("transaction_index"), - "type": obj.get("type"), - "logs_bloom": obj.get("logs_bloom"), - "block_hash": obj.get("block_hash"), - "transaction_hash": obj.get("transaction_hash"), - "block_number": obj.get("block_number"), - "confirmations": obj.get("confirmations"), - "root": obj.get("root"), - "cumulative_gas_used": obj.get("cumulative_gas_used"), - "byzantium": obj.get("byzantium"), "status": obj.get("status"), "logs": [TransactionLog.from_dict(_item) for _item in obj["logs"]] if obj.get("logs") is not None else None, "gas_used": obj.get("gas_used"), From 3d836e39d144db508352919382360c141d1931d5 Mon Sep 17 00:00:00 2001 From: Milan Saxena Date: Wed, 12 Feb 2025 14:04:07 -0800 Subject: [PATCH 3/3] remove cache dependencies install for unit tests --- .github/workflows/unit_tests.yml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml index fd1c375..72d1e17 100644 --- a/.github/workflows/unit_tests.yml +++ b/.github/workflows/unit_tests.yml @@ -24,13 +24,6 @@ jobs: virtualenvs-create: true virtualenvs-in-project: true - - name: Load cached venv - id: cached-poetry-dependencies - uses: actions/cache@v3 - with: - path: ./.venv - key: venv-${{ runner.os }}-${{ matrix.python }}-${{ hashFiles('poetry.lock') }} - - name: Install dependencies if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true' run: poetry install --with dev