Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 14 additions & 11 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,19 @@ for line in sys.stdin:
endef
export PRINT_HELP_PYSCRIPT

BROWSER := poetry run python -c "$$BROWSER_PYSCRIPT"
# Use "make RUN=uv" to run with uv instead of poetry
RUN ?= poetry

BROWSER := $(RUN) run python -c "$$BROWSER_PYSCRIPT"

help:
@python -c "$$PRINT_HELP_PYSCRIPT" < $(MAKEFILE_LIST)

cov: ## check code coverage
poetry run pytest -n 4 --cov pycardano
$(RUN) run pytest -n 4 --cov pycardano

cov-html: cov ## check code coverage and generate an html report
poetry run coverage html -d cov_html
$(RUN) run coverage html -d cov_html
$(BROWSER) cov_html/index.html


Expand All @@ -55,26 +58,26 @@ clean-test: ## remove test and coverage artifacts
rm -fr .pytest_cache

test: ## runs tests
poetry run pytest -vv -n 4
$(RUN) run pytest -vv -n 4

test-integration: ## runs integration tests
cd integration-test && ./run_tests.sh

test-single: ## runs tests with "single" markers
poetry run pytest -s -vv -m single
$(RUN) run pytest -s -vv -m single

qa: ## runs static analyses
poetry run flake8 pycardano
poetry run mypy --install-types --non-interactive pycardano
poetry run black --check .
$(RUN) run flake8 pycardano
$(RUN) run mypy --install-types --non-interactive pycardano
$(RUN) run black --check .

format: ## runs code style and formatter
poetry run isort .
poetry run black .
$(RUN) run isort .
$(RUN) run black .

docs: ## build the documentation
rm -r -f docs/build
poetry run sphinx-build docs/source docs/build/html
$(RUN) run sphinx-build docs/source docs/build/html
$(BROWSER) docs/build/html/index.html

release: clean qa test format ## build dist version and release to pypi
Expand Down
30 changes: 20 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -187,29 +187,37 @@ Clone the repository:

`git clone https://github.com/Python-Cardano/pycardano.git`

PyCardano uses [poetry](https://python-poetry.org/) to manage its dependencies.
Install poetry for osx / linux / bashonwindows:
PyCardano supports both [poetry](https://python-poetry.org/) and [uv](https://docs.astral.sh/uv/) for dependency management.

`curl -sSL https://install.python-poetry.org | python3 -`
**Using poetry:**

Go to [poetry installation](https://python-poetry.org/docs/#installation) for more details.
```bash
curl -sSL https://install.python-poetry.org | python3 -
cd pycardano && poetry install
```

Go to [poetry installation](https://python-poetry.org/docs/#installation) for more details.

Change directory into the repo, install all dependencies using poetry, and you are all set!
When testing or running any program, it is recommended to enter
a [poetry shell](https://python-poetry.org/docs/cli/#shell) in which all python dependencies are automatically
configured: `poetry shell`.

`cd pycardano && poetry install`
**Using uv:**

When testing or running any program, it is recommended to enter
a [poetry shell](https://python-poetry.org/docs/cli/#shell) in which all python dependencies are automatically
configured: `poetry shell`.
```bash
curl -LsSf https://astral.sh/uv/install.sh | sh
cd pycardano && uv sync
```

Go to [uv installation](https://docs.astral.sh/uv/getting-started/installation/) for more details.


#### Test

PyCardano uses [pytest](https://docs.pytest.org/en/6.2.x/) for unit testing.

Run all tests:
`make test`
`make test` or `make RUN=uv test`

Run all tests in a specific test file:
`poetry run pytest test/pycardano/test_transaction.py`
Expand All @@ -220,6 +228,8 @@ Run a specific test function:
Run a specific test function in a test file:
`poetry run pytest test/pycardano/test_transaction.py -k "test_transaction_body"`

Replace `poetry run` with `uv run` in any of the above commands if using uv.

#### Test coverage

We use [Coverage](https://coverage.readthedocs.io/en/latest/) to calculate the test coverage.
Expand Down
2 changes: 1 addition & 1 deletion poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

33 changes: 33 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
[project]
name = "pycardano"
version = "0.19.2"
description = "A Cardano library in Python"
requires-python = ">=3.9.1"
dynamic = ["dependencies"]

[tool.poetry]
name = "pycardano"
version = "0.19.2"
Expand Down Expand Up @@ -42,6 +49,7 @@ websockets = ">=13.0"
base58 = ">=2.1.0"
cbor2pure = ">=5.7.2"

# NOTE: Keep [tool.poetry.group.dev.dependencies] and [dependency-groups.dev] in sync.
[tool.poetry.group.dev.dependencies]
pytest = ">=8.2.0"
pytest-cov = ">=5.0.0"
Expand All @@ -54,6 +62,25 @@ Flask = ">=2.0.3"
pytest-xdist = ">=3.5.0"
mypy = "1.14.1"

[dependency-groups]
dev = [
"pytest>=8.2.0",
"pytest-cov>=5.0.0",
"flake8>=7.0.0",
"isort>=5.11.4",
"black>=26.1.0; python_version>='3.10'",
"sphinx-copybutton>=0.5.0",
"retry>=0.9.2",
"Flask>=2.0.3",
"pytest-xdist>=3.5.0",
"mypy==1.14.1",
]
docs = [
"sphinx>=7.2.3",
"sphinx-rtd-theme>=3.0.2",
]

# NOTE: Keep [tool.poetry.group.docs.dependencies] and [dependency-groups.docs] in sync.
[tool.poetry.group.docs.dependencies]
sphinx = ">=7.2.3"
sphinx-rtd-theme = ">=3.0.2"
Expand All @@ -62,6 +89,9 @@ sphinx-rtd-theme = ">=3.0.2"
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"

[tool.uv]
seed = true


[tool.pytest.ini_options]
addopts = "--doctest-modules --ignore=examples --ignore=integration-test --ignore=test/resources/haskell"
Expand All @@ -74,6 +104,9 @@ markers = [
]


[tool.black]
target-version = ["py39", "py310", "py311", "py312", "py313"]

[tool.isort]
profile = "black"

Expand Down
8 changes: 5 additions & 3 deletions test/pycardano/backend/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,11 @@ def genesis_json():

@pytest.fixture(autouse=True)
def mock_check_socket():
with patch("pathlib.Path.exists", return_value=True), patch(
"pathlib.Path.is_socket", return_value=True
), patch("pathlib.Path.is_file", return_value=True):
with (
patch("pathlib.Path.exists", return_value=True),
patch("pathlib.Path.is_socket", return_value=True),
patch("pathlib.Path.is_file", return_value=True),
):
yield


Expand Down
143 changes: 79 additions & 64 deletions test/pycardano/backend/test_blockfrost.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,35 +52,38 @@ def test_epoch_property():


def test_last_block_slot():
with patch(
"blockfrost.api.BlockFrostApi.epoch_latest",
return_value=convert_json_to_object(
{
"epoch": 225,
}
with (
patch(
"blockfrost.api.BlockFrostApi.epoch_latest",
return_value=convert_json_to_object(
{
"epoch": 225,
}
),
),
), patch(
"blockfrost.api.BlockFrostApi.block_latest",
return_value=convert_json_to_object(
{
"time": 1641338934,
"height": 15243593,
"hash": "4ea1ba291e8eef538635a53e59fddba7810d1679631cc3aed7c8e6c4091a516a",
"slot": 412162133,
"epoch": 425,
"epoch_slot": 12,
"slot_leader": "pool1pu5jlj4q9w9jlxeu370a3c9myx47md5j5m2str0naunn2qnikdy",
"size": 3,
"tx_count": 1,
"output": "128314491794",
"fees": "592661",
"block_vrf": "vrf_vk1wf2k6lhujezqcfe00l6zetxpnmh9n6mwhpmhm0dvfh3fxgmdnrfqkms8ty",
"op_cert": "da905277534faf75dae41732650568af545134ee08a3c0392dbefc8096ae177c",
"op_cert_counter": "18",
"previous_block": "43ebccb3ac72c7cebd0d9b755a4b08412c9f5dcb81b8a0ad1e3c197d29d47b05",
"next_block": "8367f026cf4b03e116ff8ee5daf149b55ba5a6ec6dec04803b8dc317721d15fa",
"confirmations": 4698,
}
patch(
"blockfrost.api.BlockFrostApi.block_latest",
return_value=convert_json_to_object(
{
"time": 1641338934,
"height": 15243593,
"hash": "4ea1ba291e8eef538635a53e59fddba7810d1679631cc3aed7c8e6c4091a516a",
"slot": 412162133,
"epoch": 425,
"epoch_slot": 12,
"slot_leader": "pool1pu5jlj4q9w9jlxeu370a3c9myx47md5j5m2str0naunn2qnikdy",
"size": 3,
"tx_count": 1,
"output": "128314491794",
"fees": "592661",
"block_vrf": "vrf_vk1wf2k6lhujezqcfe00l6zetxpnmh9n6mwhpmhm0dvfh3fxgmdnrfqkms8ty",
"op_cert": "da905277534faf75dae41732650568af545134ee08a3c0392dbefc8096ae177c",
"op_cert_counter": "18",
"previous_block": "43ebccb3ac72c7cebd0d9b755a4b08412c9f5dcb81b8a0ad1e3c197d29d47b05",
"next_block": "8367f026cf4b03e116ff8ee5daf149b55ba5a6ec6dec04803b8dc317721d15fa",
"confirmations": 4698,
}
),
),
):
chain_context = BlockFrostChainContext(
Expand All @@ -103,16 +106,19 @@ def test_genesis_param():
"security_param": 2160,
}

with patch(
"blockfrost.api.BlockFrostApi.epoch_latest",
return_value=convert_json_to_object(
{
"epoch": 225,
}
with (
patch(
"blockfrost.api.BlockFrostApi.epoch_latest",
return_value=convert_json_to_object(
{
"epoch": 225,
}
),
),
patch(
"blockfrost.api.BlockFrostApi.genesis",
return_value=convert_json_to_object(genesis_json),
),
), patch(
"blockfrost.api.BlockFrostApi.genesis",
return_value=convert_json_to_object(genesis_json),
):
chain_context = BlockFrostChainContext(
"project_id", base_url=ApiUrls.preprod.value
Expand Down Expand Up @@ -189,16 +195,19 @@ def test_protocol_param():
"min_fee_ref_script_cost_per_byte": 1,
}

with patch(
"blockfrost.api.BlockFrostApi.epoch_latest",
return_value=convert_json_to_object(
{
"epoch": 225,
}
with (
patch(
"blockfrost.api.BlockFrostApi.epoch_latest",
return_value=convert_json_to_object(
{
"epoch": 225,
}
),
),
patch(
"blockfrost.api.BlockFrostApi.epoch_latest_parameters",
return_value=convert_json_to_object(protocol_param_json),
),
), patch(
"blockfrost.api.BlockFrostApi.epoch_latest_parameters",
return_value=convert_json_to_object(protocol_param_json),
):
chain_context = BlockFrostChainContext(
"project_id", base_url=ApiUrls.preprod.value
Expand Down Expand Up @@ -286,16 +295,19 @@ def test_utxos():
},
]

with patch(
"blockfrost.api.BlockFrostApi.epoch_latest",
return_value=convert_json_to_object(
{
"epoch": 225,
}
with (
patch(
"blockfrost.api.BlockFrostApi.epoch_latest",
return_value=convert_json_to_object(
{
"epoch": 225,
}
),
),
patch(
"blockfrost.api.BlockFrostApi.address_utxos",
return_value=convert_json_to_object(utxos_json),
),
), patch(
"blockfrost.api.BlockFrostApi.address_utxos",
return_value=convert_json_to_object(utxos_json),
):
chain_context = BlockFrostChainContext(
"project_id", base_url=ApiUrls.preprod.value
Expand All @@ -310,16 +322,19 @@ def test_utxos():
def test_submit_tx_cbor():
response = Response()
response.status_code = 200
with patch(
"blockfrost.api.BlockFrostApi.epoch_latest",
return_value=convert_json_to_object(
{
"epoch": 225,
}
with (
patch(
"blockfrost.api.BlockFrostApi.epoch_latest",
return_value=convert_json_to_object(
{
"epoch": 225,
}
),
),
patch(
"blockfrost.api.BlockFrostApi.transaction_submit",
return_value=response,
),
), patch(
"blockfrost.api.BlockFrostApi.transaction_submit",
return_value=response,
):
chain_context = BlockFrostChainContext(
"project_id", base_url=ApiUrls.preprod.value
Expand Down
Loading
Loading