Skip to content

Commit fed24ba

Browse files
committed
Merge remote-tracking branch 'pycardano/main' into feat/cip67-cip68
2 parents ddf05d2 + d2a9c85 commit fed24ba

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

68 files changed

+5977
-1168
lines changed

.github/workflows/main.yml

+8-5
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ jobs:
1414
strategy:
1515
matrix:
1616
os: [ubuntu-latest, macos-latest]
17-
python-version: ['3.8', '3.9', '3.10', '3.11']
17+
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13']
1818

1919
steps:
2020
- uses: actions/checkout@v4
@@ -28,15 +28,18 @@ jobs:
2828
- name: Install dependencies
2929
run: |
3030
poetry install
31+
- name: Ensure pure cbor2 is installed
32+
run: |
33+
make ensure-pure-cbor2
3134
- name: Run unit tests
3235
run: |
3336
poetry run pytest --doctest-modules --ignore=examples --cov=pycardano --cov-config=.coveragerc --cov-report=xml
3437
- name: "Upload coverage to Codecov"
3538
if: ${{ matrix.python-version == '3.11' }}
3639
uses: codecov/codecov-action@v4
3740
with:
38-
fail_ci_if_error: true
39-
token: ${{ secrets.CODECOV_TOKEN }}
41+
fail_ci_if_error: false
42+
token: ${{ secrets.CODECOV_TOKEN || '' }}
4043
- name: Run static analyses
4144
if: ${{ matrix.python-version == '3.11' }}
4245
run: |
@@ -72,8 +75,8 @@ jobs:
7275
if: ${{ matrix.python-version == '3.11' }}
7376
uses: codecov/codecov-action@v4
7477
with:
75-
fail_ci_if_error: true
76-
token: ${{ secrets.CODECOV_TOKEN }}
78+
fail_ci_if_error: false
79+
token: ${{ secrets.CODECOV_TOKEN || '' }}
7780

7881
- name: Dump docker logs
7982
if: failure()

.github/workflows/publish.yml

+3
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ jobs:
2424
- name: Install dependencies
2525
run: |
2626
poetry install
27+
- name: Ensure pure cbor2 is installed
28+
run: |
29+
make ensure-pure-cbor2
2730
- name: Lint with flake8
2831
run: |
2932
poetry run flake8 pycardano

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@ docs/build
55
dist
66
.mypy_cache
77
coverage.xml
8+
.cbor2_version
89

910
# IDE
1011
.idea
1112
.code
1213
/integration-test/.env
1314
/integration-test/tmp_configs/*
15+
/integration-test/.coverage*

Makefile

+22-4
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,25 @@ export PRINT_HELP_PYSCRIPT
2323

2424
BROWSER := poetry run python -c "$$BROWSER_PYSCRIPT"
2525

26+
ensure-pure-cbor2: ## ensures cbor2 is installed with pure Python implementation
27+
@poetry run python -c "from importlib.metadata import version; \
28+
print(version('cbor2'))" > .cbor2_version
29+
@poetry run python -c "import cbor2, inspect; \
30+
print('Checking cbor2 implementation...'); \
31+
decoder_path = inspect.getfile(cbor2.CBORDecoder); \
32+
using_c_ext = decoder_path.endswith('.so'); \
33+
print(f'Implementation path: {decoder_path}'); \
34+
print(f'Using C extension: {using_c_ext}'); \
35+
exit(1 if using_c_ext else 0)" || \
36+
(echo "Reinstalling cbor2 with pure Python implementation..." && \
37+
poetry run pip uninstall -y cbor2 && \
38+
CBOR2_BUILD_C_EXTENSION=0 poetry run pip install --no-binary cbor2 "cbor2==$$(cat .cbor2_version)" --force-reinstall && \
39+
rm .cbor2_version)
40+
2641
help:
2742
@python -c "$$PRINT_HELP_PYSCRIPT" < $(MAKEFILE_LIST)
2843

29-
cov: ## check code coverage
44+
cov: ensure-pure-cbor2 ## check code coverage
3045
poetry run pytest -n 4 --cov pycardano
3146

3247
cov-html: cov ## check code coverage and generate an html report
@@ -54,13 +69,16 @@ clean-test: ## remove test and coverage artifacts
5469
rm -fr cov_html/
5570
rm -fr .pytest_cache
5671

57-
test: ## runs tests
72+
test: ensure-pure-cbor2 ## runs tests
5873
poetry run pytest -vv -n 4
5974

75+
test-integration: ## runs integration tests
76+
cd integration-test && ./run_tests.sh
77+
6078
test-single: ## runs tests with "single" markers
6179
poetry run pytest -s -vv -m single
6280

63-
qa: ## runs static analyses
81+
qa: ensure-pure-cbor2 ## runs static analyses
6482
poetry run flake8 pycardano
6583
poetry run mypy --install-types --non-interactive pycardano
6684
poetry run black --check .
@@ -75,6 +93,6 @@ docs: ## build the documentation
7593
poetry run sphinx-build docs/source docs/build/html
7694
$(BROWSER) docs/build/html/index.html
7795

78-
release: clean qa test format ## build dist version and release to pypi
96+
release: clean qa test format ensure-pure-cbor2 ## build dist version and release to pypi
7997
poetry build
8098
poetry publish

README.md

-1
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,5 @@ You can support us by 1) sponsoring through Github, or 2) donating ADA to our AD
254254
## Sponsors :heart:
255255

256256
<p align="left">
257-
<a href="https://github.com/KtorZ"><img src="https://avatars.githubusercontent.com/u/5680256?s=50&v=4"/></a>
258257
<a href="https://github.com/blockfrost"><img src="https://avatars.githubusercontent.com/u/70073210?s=50&v=4"/></a>
259258
</p>

docs/requirements.txt

+27-26
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,52 @@
11
alabaster==0.7.13 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
22
annotated-types==0.7.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
33
asn1crypto==1.5.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
4-
attrs==24.2.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
5-
babel==2.16.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
4+
attrs==25.1.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
5+
babel==2.17.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
66
black==24.8.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
77
blinker==1.8.2 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
88
blockfrost-python==0.6.0 ; python_full_version >= "3.8.1" and python_version < "4"
9-
cachetools==5.5.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
9+
cachetools==5.5.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
1010
cardano-tools==2.1.0 ; python_full_version >= "3.8.1" and python_version < "4.0"
11-
cbor2==5.6.4 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
12-
certifi==2024.8.30 ; python_full_version >= "3.8.1" and python_version < "4"
11+
cbor2==5.6.5 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
12+
certifi==2025.1.31 ; python_full_version >= "3.8.1" and python_version < "4"
1313
certvalidator==0.11.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
1414
cffi==1.17.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
15-
charset-normalizer==3.3.2 ; python_full_version >= "3.8.1" and python_version < "4"
16-
click==8.1.7 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
15+
charset-normalizer==3.4.1 ; python_full_version >= "3.8.1" and python_version < "4"
16+
click==8.1.8 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
1717
colorama==0.4.6 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" and (sys_platform == "win32" or platform_system == "Windows")
1818
coloredlogs==15.0.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
1919
cose==0.9.dev8 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
2020
coverage[toml]==7.6.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
21-
cryptography==43.0.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
21+
cryptography==43.0.3 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
2222
decorator==5.1.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
2323
docker==7.1.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
2424
docutils==0.19 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
2525
ecdsa==0.19.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
2626
ecpy==1.2.5 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
2727
exceptiongroup==1.2.2 ; python_full_version >= "3.8.1" and python_version < "3.11"
2828
execnet==2.1.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
29-
flake8==7.1.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
29+
flake8==7.1.2 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
3030
flask==2.3.3 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
31-
frozendict==2.4.4 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
32-
frozenlist==1.4.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
31+
frozendict==2.4.6 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
32+
frozenlist==1.5.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
3333
humanfriendly==10.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
3434
idna==3.10 ; python_full_version >= "3.8.1" and python_version < "4"
3535
imagesize==1.4.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
3636
importlib-metadata==8.5.0 ; python_full_version >= "3.8.1" and python_version < "3.10"
3737
iniconfig==2.0.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
3838
isort==5.13.2 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
3939
itsdangerous==2.2.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
40-
jinja2==3.1.4 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
40+
jinja2==3.1.5 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
4141
markupsafe==2.1.5 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
4242
mccabe==0.7.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
4343
mnemonic==0.21 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
4444
mypy-extensions==1.0.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
4545
mypy==1.11.2 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
46-
ogmios==1.2.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
47-
orjson==3.10.7 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
46+
ogmios==1.3.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
47+
orjson==3.10.15 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
4848
oscrypto==1.3.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
49-
packaging==24.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
49+
packaging==24.2 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
5050
pathspec==0.12.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
5151
pexpect==4.9.0 ; python_full_version >= "3.8.1" and python_version < "4.0"
5252
platformdirs==4.3.6 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
@@ -56,21 +56,21 @@ ptyprocess==0.7.0 ; python_full_version >= "3.8.1" and python_version < "4.0"
5656
py==1.11.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
5757
pycodestyle==2.12.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
5858
pycparser==2.22 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
59-
pydantic-core==2.23.4 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
60-
pydantic==2.9.2 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
59+
pydantic-core==2.27.2 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
60+
pydantic==2.10.6 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
6161
pyflakes==3.2.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
62-
pygments==2.18.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
62+
pygments==2.19.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
6363
pynacl==1.5.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
6464
pyreadline3==3.5.4 ; sys_platform == "win32" and python_full_version >= "3.8.1" and python_full_version < "4.0.0"
6565
pytest-cov==5.0.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
6666
pytest-xdist==3.6.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
67-
pytest==8.3.3 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
68-
pytz==2024.2 ; python_full_version >= "3.8.1" and python_version < "3.9"
69-
pywin32==306 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" and sys_platform == "win32"
67+
pytest==8.3.4 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
68+
pytz==2025.1 ; python_full_version >= "3.8.1" and python_version < "3.9"
69+
pywin32==308 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" and sys_platform == "win32"
7070
requests==2.32.3 ; python_full_version >= "3.8.1" and python_version < "4"
7171
retry==0.9.2 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
72-
setuptools==75.1.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
73-
six==1.16.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
72+
setuptools==75.3.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
73+
six==1.17.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
7474
snowballstemmer==2.2.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
7575
sphinx-copybutton==0.5.2 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
7676
sphinx-rtd-theme==2.0.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
@@ -82,11 +82,12 @@ sphinxcontrib-jquery==4.1 ; python_full_version >= "3.8.1" and python_full_versi
8282
sphinxcontrib-jsmath==1.0.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
8383
sphinxcontrib-qthelp==1.0.3 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
8484
sphinxcontrib-serializinghtml==1.1.5 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
85-
tomli==2.0.1 ; python_full_version >= "3.8.1" and python_full_version <= "3.11.0a6"
86-
typeguard==4.3.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
85+
standard-imghdr==3.13.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
86+
tomli==2.2.1 ; python_full_version >= "3.8.1" and python_full_version <= "3.11.0a6"
87+
typeguard==4.4.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
8788
typing-extensions==4.12.2 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
8889
urllib3==2.2.3 ; python_full_version >= "3.8.1" and python_version < "4"
8990
websocket-client==1.8.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
9091
websockets==13.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
91-
werkzeug==3.0.4 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
92+
werkzeug==3.0.6 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
9293
zipp==3.20.2 ; python_full_version >= "3.8.1" and python_version < "3.10"
+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Governance
2+
==============================
3+
4+
.. automodule:: pycardano.governance
5+
:members:
6+
:undoc-members:
7+
:show-inheritance:
+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Pool parameters
2+
========================
3+
4+
.. automodule:: pycardano.pool_params
5+
:members:
6+
:undoc-members:
7+
:show-inheritance:

docs/source/index.rst

+2
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,14 @@ making it a light-weight library that is easy and fast to set up in all kinds of
3838
api/pycardano.crypto
3939
api/pycardano.coinselection
4040
api/pycardano.exception
41+
api/pycardano.governance
4142
api/pycardano.hash
4243
api/pycardano.key
4344
api/pycardano.metadata
4445
api/pycardano.nativescript
4546
api/pycardano.network
4647
api/pycardano.plutus
48+
api/pycardano.poolparams
4749
api/pycardano.serialization
4850
api/pycardano.transaction
4951
api/pycardano.utils

examples/more_examples/.env-example

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
network="testnet"
2+
wallet_mnemonic="select calm scorpion mask furnace nerve fade slam bid suggest avoid remove half depend turn little midnight fossil submit cart sick glance inner slide"
3+
blockfrost_api_key="preprod...."

examples/more_examples/.gitignore

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
.env
2+
/keys/*
3+
!keys/.gitkeep
4+
tempfile.pdf
5+
tempfile_copy.pdf

examples/more_examples/01_address.py

+78
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import os
2+
3+
from blockfrost import ApiError, ApiUrls, BlockFrostApi, BlockFrostIPFS
4+
from dotenv import load_dotenv
5+
6+
from pycardano import *
7+
8+
load_dotenv()
9+
network = os.getenv("network")
10+
wallet_mnemonic = os.getenv("wallet_mnemonic")
11+
12+
13+
if network == "testnet":
14+
base_url = ApiUrls.preprod.value
15+
cardano_network = Network.TESTNET
16+
else:
17+
base_url = ApiUrls.mainnet.value
18+
cardano_network = Network.MAINNET
19+
20+
21+
new_wallet = crypto.bip32.HDWallet.from_mnemonic(wallet_mnemonic)
22+
payment_key = new_wallet.derive_from_path(f"m/1852'/1815'/0'/0/0")
23+
staking_key = new_wallet.derive_from_path(f"m/1852'/1815'/0'/2/0")
24+
payment_skey = ExtendedSigningKey.from_hdwallet(payment_key)
25+
staking_skey = ExtendedSigningKey.from_hdwallet(staking_key)
26+
27+
28+
print("Enterprise address (only payment):")
29+
print("Payment Derivation path: m/1852'/1815'/0'/0/0")
30+
31+
enterprise_address = Address(
32+
payment_part=payment_skey.to_verification_key().hash(), network=cardano_network
33+
)
34+
print(enterprise_address)
35+
36+
print(" ")
37+
print("Staking enabled address:")
38+
print("Payment Derivation path: m/1852'/1815'/0'/0/0")
39+
print("Staking Derivation path: m/1852'/1815'/0'/2/0")
40+
41+
staking_enabled_address = Address(
42+
payment_part=payment_skey.to_verification_key().hash(),
43+
staking_part=staking_skey.to_verification_key().hash(),
44+
network=cardano_network,
45+
)
46+
print(staking_enabled_address)
47+
48+
print(" ")
49+
next_step = input("Press Enter to continue...")
50+
print(" ")
51+
52+
for i in range(5):
53+
derivation_path = f"m/1852'/1815'/0'/0/{i}"
54+
55+
payment_key = new_wallet.derive_from_path(derivation_path)
56+
payment_skey = ExtendedSigningKey.from_hdwallet(payment_key)
57+
58+
enterprise_address = Address(
59+
payment_part=payment_skey.to_verification_key().hash(), network=cardano_network
60+
)
61+
print(f"Address {derivation_path}: {enterprise_address}")
62+
63+
print(" ")
64+
next_step = input("Press Enter to continue...")
65+
print(" ")
66+
67+
for i in range(5):
68+
derivation_path = f"m/1852'/1815'/0'/0/{i}"
69+
70+
payment_key = new_wallet.derive_from_path(derivation_path)
71+
payment_skey = ExtendedSigningKey.from_hdwallet(payment_key)
72+
73+
staking_enabled_address = Address(
74+
payment_part=payment_skey.to_verification_key().hash(),
75+
staking_part=staking_skey.to_verification_key().hash(),
76+
network=cardano_network,
77+
)
78+
print(f"Address {derivation_path}: {staking_enabled_address}")

0 commit comments

Comments
 (0)