main: initial library code
This commit is contained in:
14
.gitignore
vendored
Normal file
14
.gitignore
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
.cache/
|
||||||
|
.coverage
|
||||||
|
.coverage-report/
|
||||||
|
.pdm.lock/
|
||||||
|
.vscode/
|
||||||
|
**/__pycache__/
|
||||||
|
**/*.pyc
|
||||||
|
.pdm-build/
|
||||||
|
dist/
|
||||||
|
build/
|
||||||
|
pytest_cache/
|
||||||
|
.venv/
|
||||||
|
var/
|
||||||
|
.env
|
||||||
19
.style.yapf
Normal file
19
.style.yapf
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
[style]
|
||||||
|
based_on_style = pep8
|
||||||
|
column_limit = 240
|
||||||
|
blank_line_before_class_docstring = False
|
||||||
|
blank_lines_around_top_level_definition = 2
|
||||||
|
blank_line_before_nested_class_or_def = False
|
||||||
|
continuation_align_style = Fixed
|
||||||
|
continuation_indent_width = 4
|
||||||
|
dedent_closing_brackets = True
|
||||||
|
align_closing_bracket_with_visual_indent = False
|
||||||
|
split_before_closing_bracket = True
|
||||||
|
split_before_first_argument = False
|
||||||
|
coalesce_brackets = True
|
||||||
|
each_dict_entry_on_separate_line = True
|
||||||
|
spaces_around_dict_delimiters = True
|
||||||
|
spaces_before_comment = 1
|
||||||
|
split_all_comma_separated_values = True
|
||||||
|
split_before_dict_set_generator = True
|
||||||
|
allow_split_before_dict_value = False
|
||||||
3
README.md
Normal file
3
README.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# dragiyski-vulkan-registry
|
||||||
|
|
||||||
|
Extracts static type data for vulkan objects from Khronos registry XML.
|
||||||
280
pdm.lock
generated
Normal file
280
pdm.lock
generated
Normal file
@@ -0,0 +1,280 @@
|
|||||||
|
# This file is @generated by PDM.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
groups = ["default", "dev"]
|
||||||
|
strategy = ["inherit_metadata"]
|
||||||
|
lock_version = "4.5.0"
|
||||||
|
content_hash = "sha256:ea778e61d15d5929eb362fb1ff3225f8e279fe85642318bfdcbca607601d2a8a"
|
||||||
|
|
||||||
|
[[metadata.targets]]
|
||||||
|
requires_python = ">=3.12"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "colorama"
|
||||||
|
version = "0.4.6"
|
||||||
|
requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
|
||||||
|
summary = "Cross-platform colored terminal text."
|
||||||
|
groups = ["dev"]
|
||||||
|
marker = "sys_platform == \"win32\""
|
||||||
|
files = [
|
||||||
|
{file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
|
||||||
|
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "coverage"
|
||||||
|
version = "7.13.5"
|
||||||
|
requires_python = ">=3.10"
|
||||||
|
summary = "Code coverage measurement for Python"
|
||||||
|
groups = ["dev"]
|
||||||
|
files = [
|
||||||
|
{file = "coverage-7.13.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:460cf0114c5016fa841214ff5564aa4864f11948da9440bc97e21ad1f4ba1e01"},
|
||||||
|
{file = "coverage-7.13.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0e223ce4b4ed47f065bfb123687686512e37629be25cc63728557ae7db261422"},
|
||||||
|
{file = "coverage-7.13.5-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:6e3370441f4513c6252bf042b9c36d22491142385049243253c7e48398a15a9f"},
|
||||||
|
{file = "coverage-7.13.5-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:03ccc709a17a1de074fb1d11f217342fb0d2b1582ed544f554fc9fc3f07e95f5"},
|
||||||
|
{file = "coverage-7.13.5-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3f4818d065964db3c1c66dc0fbdac5ac692ecbc875555e13374fdbe7eedb4376"},
|
||||||
|
{file = "coverage-7.13.5-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:012d5319e66e9d5a218834642d6c35d265515a62f01157a45bcc036ecf947256"},
|
||||||
|
{file = "coverage-7.13.5-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8dd02af98971bdb956363e4827d34425cb3df19ee550ef92855b0acb9c7ce51c"},
|
||||||
|
{file = "coverage-7.13.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f08fd75c50a760c7eb068ae823777268daaf16a80b918fa58eea888f8e3919f5"},
|
||||||
|
{file = "coverage-7.13.5-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:843ea8643cf967d1ac7e8ecd4bb00c99135adf4816c0c0593fdcc47b597fcf09"},
|
||||||
|
{file = "coverage-7.13.5-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:9d44d7aa963820b1b971dbecd90bfe5fe8f81cff79787eb6cca15750bd2f79b9"},
|
||||||
|
{file = "coverage-7.13.5-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:7132bed4bd7b836200c591410ae7d97bf7ae8be6fc87d160b2bd881df929e7bf"},
|
||||||
|
{file = "coverage-7.13.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a698e363641b98843c517817db75373c83254781426e94ada3197cabbc2c919c"},
|
||||||
|
{file = "coverage-7.13.5-cp312-cp312-win32.whl", hash = "sha256:bdba0a6b8812e8c7df002d908a9a2ea3c36e92611b5708633c50869e6d922fdf"},
|
||||||
|
{file = "coverage-7.13.5-cp312-cp312-win_amd64.whl", hash = "sha256:d2c87e0c473a10bffe991502eac389220533024c8082ec1ce849f4218dded810"},
|
||||||
|
{file = "coverage-7.13.5-cp312-cp312-win_arm64.whl", hash = "sha256:bf69236a9a81bdca3bff53796237aab096cdbf8d78a66ad61e992d9dac7eb2de"},
|
||||||
|
{file = "coverage-7.13.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5ec4af212df513e399cf11610cc27063f1586419e814755ab362e50a85ea69c1"},
|
||||||
|
{file = "coverage-7.13.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:941617e518602e2d64942c88ec8499f7fbd49d3f6c4327d3a71d43a1973032f3"},
|
||||||
|
{file = "coverage-7.13.5-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:da305e9937617ee95c2e39d8ff9f040e0487cbf1ac174f777ed5eddd7a7c1f26"},
|
||||||
|
{file = "coverage-7.13.5-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:78e696e1cc714e57e8b25760b33a8b1026b7048d270140d25dafe1b0a1ee05a3"},
|
||||||
|
{file = "coverage-7.13.5-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:02ca0eed225b2ff301c474aeeeae27d26e2537942aa0f87491d3e147e784a82b"},
|
||||||
|
{file = "coverage-7.13.5-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:04690832cbea4e4663d9149e05dba142546ca05cb1848816760e7f58285c970a"},
|
||||||
|
{file = "coverage-7.13.5-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0590e44dd2745c696a778f7bab6aa95256de2cbc8b8cff4f7db8ff09813d6969"},
|
||||||
|
{file = "coverage-7.13.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d7cfad2d6d81dd298ab6b89fe72c3b7b05ec7544bdda3b707ddaecff8d25c161"},
|
||||||
|
{file = "coverage-7.13.5-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:e092b9499de38ae0fbfbc603a74660eb6ff3e869e507b50d85a13b6db9863e15"},
|
||||||
|
{file = "coverage-7.13.5-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:48c39bc4a04d983a54a705a6389512883d4a3b9862991b3617d547940e9f52b1"},
|
||||||
|
{file = "coverage-7.13.5-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:2d3807015f138ffea1ed9afeeb8624fd781703f2858b62a8dd8da5a0994c57b6"},
|
||||||
|
{file = "coverage-7.13.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ee2aa19e03161671ec964004fb74b2257805d9710bf14a5c704558b9d8dbaf17"},
|
||||||
|
{file = "coverage-7.13.5-cp313-cp313-win32.whl", hash = "sha256:ce1998c0483007608c8382f4ff50164bfc5bd07a2246dd272aa4043b75e61e85"},
|
||||||
|
{file = "coverage-7.13.5-cp313-cp313-win_amd64.whl", hash = "sha256:631efb83f01569670a5e866ceb80fe483e7c159fac6f167e6571522636104a0b"},
|
||||||
|
{file = "coverage-7.13.5-cp313-cp313-win_arm64.whl", hash = "sha256:f4cd16206ad171cbc2470dbea9103cf9a7607d5fe8c242fdf1edf36174020664"},
|
||||||
|
{file = "coverage-7.13.5-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0428cbef5783ad91fe240f673cc1f76b25e74bbfe1a13115e4aa30d3f538162d"},
|
||||||
|
{file = "coverage-7.13.5-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e0b216a19534b2427cc201a26c25da4a48633f29a487c61258643e89d28200c0"},
|
||||||
|
{file = "coverage-7.13.5-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:972a9cd27894afe4bc2b1480107054e062df08e671df7c2f18c205e805ccd806"},
|
||||||
|
{file = "coverage-7.13.5-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:4b59148601efcd2bac8c4dbf1f0ad6391693ccf7a74b8205781751637076aee3"},
|
||||||
|
{file = "coverage-7.13.5-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:505d7083c8b0c87a8fa8c07370c285847c1f77739b22e299ad75a6af6c32c5c9"},
|
||||||
|
{file = "coverage-7.13.5-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:60365289c3741e4db327e7baff2a4aaacf22f788e80fa4683393891b70a89fbd"},
|
||||||
|
{file = "coverage-7.13.5-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1b88c69c8ef5d4b6fe7dea66d6636056a0f6a7527c440e890cf9259011f5e606"},
|
||||||
|
{file = "coverage-7.13.5-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:5b13955d31d1633cf9376908089b7cebe7d15ddad7aeaabcbe969a595a97e95e"},
|
||||||
|
{file = "coverage-7.13.5-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:f70c9ab2595c56f81a89620e22899eea8b212a4041bd728ac6f4a28bf5d3ddd0"},
|
||||||
|
{file = "coverage-7.13.5-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:084b84a8c63e8d6fc7e3931b316a9bcafca1458d753c539db82d31ed20091a87"},
|
||||||
|
{file = "coverage-7.13.5-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:ad14385487393e386e2ea988b09d62dd42c397662ac2dabc3832d71253eee479"},
|
||||||
|
{file = "coverage-7.13.5-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:7f2c47b36fe7709a6e83bfadf4eefb90bd25fbe4014d715224c4316f808e59a2"},
|
||||||
|
{file = "coverage-7.13.5-cp313-cp313t-win32.whl", hash = "sha256:67e9bc5449801fad0e5dff329499fb090ba4c5800b86805c80617b4e29809b2a"},
|
||||||
|
{file = "coverage-7.13.5-cp313-cp313t-win_amd64.whl", hash = "sha256:da86cdcf10d2519e10cabb8ac2de03da1bcb6e4853790b7fbd48523332e3a819"},
|
||||||
|
{file = "coverage-7.13.5-cp313-cp313t-win_arm64.whl", hash = "sha256:0ecf12ecb326fe2c339d93fc131816f3a7367d223db37817208905c89bded911"},
|
||||||
|
{file = "coverage-7.13.5-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:fbabfaceaeb587e16f7008f7795cd80d20ec548dc7f94fbb0d4ec2e038ce563f"},
|
||||||
|
{file = "coverage-7.13.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:9bb2a28101a443669a423b665939381084412b81c3f8c0fcfbac57f4e30b5b8e"},
|
||||||
|
{file = "coverage-7.13.5-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:bd3a2fbc1c6cccb3c5106140d87cc6a8715110373ef42b63cf5aea29df8c217a"},
|
||||||
|
{file = "coverage-7.13.5-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6c36ddb64ed9d7e496028d1d00dfec3e428e0aabf4006583bb1839958d280510"},
|
||||||
|
{file = "coverage-7.13.5-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:380e8e9084d8eb38db3a9176a1a4f3c0082c3806fa0dc882d1d87abc3c789247"},
|
||||||
|
{file = "coverage-7.13.5-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e808af52a0513762df4d945ea164a24b37f2f518cbe97e03deaa0ee66139b4d6"},
|
||||||
|
{file = "coverage-7.13.5-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e301d30dd7e95ae068671d746ba8c34e945a82682e62918e41b2679acd2051a0"},
|
||||||
|
{file = "coverage-7.13.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:800bc829053c80d240a687ceeb927a94fd108bbdc68dfbe505d0d75ab578a882"},
|
||||||
|
{file = "coverage-7.13.5-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:0b67af5492adb31940ee418a5a655c28e48165da5afab8c7fa6fd72a142f8740"},
|
||||||
|
{file = "coverage-7.13.5-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:c9136ff29c3a91e25b1d1552b5308e53a1e0653a23e53b6366d7c2dcbbaf8a16"},
|
||||||
|
{file = "coverage-7.13.5-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:cff784eef7f0b8f6cb28804fbddcfa99f89efe4cc35fb5627e3ac58f91ed3ac0"},
|
||||||
|
{file = "coverage-7.13.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:68a4953be99b17ac3c23b6efbc8a38330d99680c9458927491d18700ef23ded0"},
|
||||||
|
{file = "coverage-7.13.5-cp314-cp314-win32.whl", hash = "sha256:35a31f2b1578185fbe6aa2e74cea1b1d0bbf4c552774247d9160d29b80ed56cc"},
|
||||||
|
{file = "coverage-7.13.5-cp314-cp314-win_amd64.whl", hash = "sha256:2aa055ae1857258f9e0045be26a6d62bdb47a72448b62d7b55f4820f361a2633"},
|
||||||
|
{file = "coverage-7.13.5-cp314-cp314-win_arm64.whl", hash = "sha256:1b11eef33edeae9d142f9b4358edb76273b3bfd30bc3df9a4f95d0e49caf94e8"},
|
||||||
|
{file = "coverage-7.13.5-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:10a0c37f0b646eaff7cce1874c31d1f1ccb297688d4c747291f4f4c70741cc8b"},
|
||||||
|
{file = "coverage-7.13.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b5db73ba3c41c7008037fa731ad5459fc3944cb7452fc0aa9f822ad3533c583c"},
|
||||||
|
{file = "coverage-7.13.5-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:750db93a81e3e5a9831b534be7b1229df848b2e125a604fe6651e48aa070e5f9"},
|
||||||
|
{file = "coverage-7.13.5-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9ddb4f4a5479f2539644be484da179b653273bca1a323947d48ab107b3ed1f29"},
|
||||||
|
{file = "coverage-7.13.5-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d8a7a2049c14f413163e2bdabd37e41179b1d1ccb10ffc6ccc4b7a718429c607"},
|
||||||
|
{file = "coverage-7.13.5-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e1c85e0b6c05c592ea6d8768a66a254bfb3874b53774b12d4c89c481eb78cb90"},
|
||||||
|
{file = "coverage-7.13.5-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:777c4d1eff1b67876139d24288aaf1817f6c03d6bae9c5cc8d27b83bcfe38fe3"},
|
||||||
|
{file = "coverage-7.13.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:6697e29b93707167687543480a40f0db8f356e86d9f67ddf2e37e2dfd91a9dab"},
|
||||||
|
{file = "coverage-7.13.5-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:8fdf453a942c3e4d99bd80088141c4c6960bb232c409d9c3558e2dbaa3998562"},
|
||||||
|
{file = "coverage-7.13.5-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:32ca0c0114c9834a43f045a87dcebd69d108d8ffb666957ea65aa132f50332e2"},
|
||||||
|
{file = "coverage-7.13.5-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:8769751c10f339021e2638cd354e13adeac54004d1941119b2c96fe5276d45ea"},
|
||||||
|
{file = "coverage-7.13.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cec2d83125531bd153175354055cdb7a09987af08a9430bd173c937c6d0fba2a"},
|
||||||
|
{file = "coverage-7.13.5-cp314-cp314t-win32.whl", hash = "sha256:0cd9ed7a8b181775459296e402ca4fb27db1279740a24e93b3b41942ebe4b215"},
|
||||||
|
{file = "coverage-7.13.5-cp314-cp314t-win_amd64.whl", hash = "sha256:301e3b7dfefecaca37c9f1aa6f0049b7d4ab8dd933742b607765d757aca77d43"},
|
||||||
|
{file = "coverage-7.13.5-cp314-cp314t-win_arm64.whl", hash = "sha256:9dacc2ad679b292709e0f5fc1ac74a6d4d5562e424058962c7bb0c658ad25e45"},
|
||||||
|
{file = "coverage-7.13.5-py3-none-any.whl", hash = "sha256:34b02417cf070e173989b3db962f7ed56d2f644307b2cf9d5a0f258e13084a61"},
|
||||||
|
{file = "coverage-7.13.5.tar.gz", hash = "sha256:c81f6515c4c40141f83f502b07bbfa5c240ba25bbe73da7b33f1e5b6120ff179"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "coverage"
|
||||||
|
version = "7.13.5"
|
||||||
|
extras = ["toml"]
|
||||||
|
requires_python = ">=3.10"
|
||||||
|
summary = "Code coverage measurement for Python"
|
||||||
|
groups = ["dev"]
|
||||||
|
dependencies = [
|
||||||
|
"coverage==7.13.5",
|
||||||
|
"tomli; python_full_version <= \"3.11.0a6\"",
|
||||||
|
]
|
||||||
|
files = [
|
||||||
|
{file = "coverage-7.13.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:460cf0114c5016fa841214ff5564aa4864f11948da9440bc97e21ad1f4ba1e01"},
|
||||||
|
{file = "coverage-7.13.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0e223ce4b4ed47f065bfb123687686512e37629be25cc63728557ae7db261422"},
|
||||||
|
{file = "coverage-7.13.5-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:6e3370441f4513c6252bf042b9c36d22491142385049243253c7e48398a15a9f"},
|
||||||
|
{file = "coverage-7.13.5-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:03ccc709a17a1de074fb1d11f217342fb0d2b1582ed544f554fc9fc3f07e95f5"},
|
||||||
|
{file = "coverage-7.13.5-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3f4818d065964db3c1c66dc0fbdac5ac692ecbc875555e13374fdbe7eedb4376"},
|
||||||
|
{file = "coverage-7.13.5-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:012d5319e66e9d5a218834642d6c35d265515a62f01157a45bcc036ecf947256"},
|
||||||
|
{file = "coverage-7.13.5-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8dd02af98971bdb956363e4827d34425cb3df19ee550ef92855b0acb9c7ce51c"},
|
||||||
|
{file = "coverage-7.13.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f08fd75c50a760c7eb068ae823777268daaf16a80b918fa58eea888f8e3919f5"},
|
||||||
|
{file = "coverage-7.13.5-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:843ea8643cf967d1ac7e8ecd4bb00c99135adf4816c0c0593fdcc47b597fcf09"},
|
||||||
|
{file = "coverage-7.13.5-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:9d44d7aa963820b1b971dbecd90bfe5fe8f81cff79787eb6cca15750bd2f79b9"},
|
||||||
|
{file = "coverage-7.13.5-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:7132bed4bd7b836200c591410ae7d97bf7ae8be6fc87d160b2bd881df929e7bf"},
|
||||||
|
{file = "coverage-7.13.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a698e363641b98843c517817db75373c83254781426e94ada3197cabbc2c919c"},
|
||||||
|
{file = "coverage-7.13.5-cp312-cp312-win32.whl", hash = "sha256:bdba0a6b8812e8c7df002d908a9a2ea3c36e92611b5708633c50869e6d922fdf"},
|
||||||
|
{file = "coverage-7.13.5-cp312-cp312-win_amd64.whl", hash = "sha256:d2c87e0c473a10bffe991502eac389220533024c8082ec1ce849f4218dded810"},
|
||||||
|
{file = "coverage-7.13.5-cp312-cp312-win_arm64.whl", hash = "sha256:bf69236a9a81bdca3bff53796237aab096cdbf8d78a66ad61e992d9dac7eb2de"},
|
||||||
|
{file = "coverage-7.13.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5ec4af212df513e399cf11610cc27063f1586419e814755ab362e50a85ea69c1"},
|
||||||
|
{file = "coverage-7.13.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:941617e518602e2d64942c88ec8499f7fbd49d3f6c4327d3a71d43a1973032f3"},
|
||||||
|
{file = "coverage-7.13.5-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:da305e9937617ee95c2e39d8ff9f040e0487cbf1ac174f777ed5eddd7a7c1f26"},
|
||||||
|
{file = "coverage-7.13.5-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:78e696e1cc714e57e8b25760b33a8b1026b7048d270140d25dafe1b0a1ee05a3"},
|
||||||
|
{file = "coverage-7.13.5-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:02ca0eed225b2ff301c474aeeeae27d26e2537942aa0f87491d3e147e784a82b"},
|
||||||
|
{file = "coverage-7.13.5-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:04690832cbea4e4663d9149e05dba142546ca05cb1848816760e7f58285c970a"},
|
||||||
|
{file = "coverage-7.13.5-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0590e44dd2745c696a778f7bab6aa95256de2cbc8b8cff4f7db8ff09813d6969"},
|
||||||
|
{file = "coverage-7.13.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d7cfad2d6d81dd298ab6b89fe72c3b7b05ec7544bdda3b707ddaecff8d25c161"},
|
||||||
|
{file = "coverage-7.13.5-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:e092b9499de38ae0fbfbc603a74660eb6ff3e869e507b50d85a13b6db9863e15"},
|
||||||
|
{file = "coverage-7.13.5-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:48c39bc4a04d983a54a705a6389512883d4a3b9862991b3617d547940e9f52b1"},
|
||||||
|
{file = "coverage-7.13.5-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:2d3807015f138ffea1ed9afeeb8624fd781703f2858b62a8dd8da5a0994c57b6"},
|
||||||
|
{file = "coverage-7.13.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ee2aa19e03161671ec964004fb74b2257805d9710bf14a5c704558b9d8dbaf17"},
|
||||||
|
{file = "coverage-7.13.5-cp313-cp313-win32.whl", hash = "sha256:ce1998c0483007608c8382f4ff50164bfc5bd07a2246dd272aa4043b75e61e85"},
|
||||||
|
{file = "coverage-7.13.5-cp313-cp313-win_amd64.whl", hash = "sha256:631efb83f01569670a5e866ceb80fe483e7c159fac6f167e6571522636104a0b"},
|
||||||
|
{file = "coverage-7.13.5-cp313-cp313-win_arm64.whl", hash = "sha256:f4cd16206ad171cbc2470dbea9103cf9a7607d5fe8c242fdf1edf36174020664"},
|
||||||
|
{file = "coverage-7.13.5-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0428cbef5783ad91fe240f673cc1f76b25e74bbfe1a13115e4aa30d3f538162d"},
|
||||||
|
{file = "coverage-7.13.5-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e0b216a19534b2427cc201a26c25da4a48633f29a487c61258643e89d28200c0"},
|
||||||
|
{file = "coverage-7.13.5-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:972a9cd27894afe4bc2b1480107054e062df08e671df7c2f18c205e805ccd806"},
|
||||||
|
{file = "coverage-7.13.5-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:4b59148601efcd2bac8c4dbf1f0ad6391693ccf7a74b8205781751637076aee3"},
|
||||||
|
{file = "coverage-7.13.5-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:505d7083c8b0c87a8fa8c07370c285847c1f77739b22e299ad75a6af6c32c5c9"},
|
||||||
|
{file = "coverage-7.13.5-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:60365289c3741e4db327e7baff2a4aaacf22f788e80fa4683393891b70a89fbd"},
|
||||||
|
{file = "coverage-7.13.5-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1b88c69c8ef5d4b6fe7dea66d6636056a0f6a7527c440e890cf9259011f5e606"},
|
||||||
|
{file = "coverage-7.13.5-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:5b13955d31d1633cf9376908089b7cebe7d15ddad7aeaabcbe969a595a97e95e"},
|
||||||
|
{file = "coverage-7.13.5-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:f70c9ab2595c56f81a89620e22899eea8b212a4041bd728ac6f4a28bf5d3ddd0"},
|
||||||
|
{file = "coverage-7.13.5-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:084b84a8c63e8d6fc7e3931b316a9bcafca1458d753c539db82d31ed20091a87"},
|
||||||
|
{file = "coverage-7.13.5-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:ad14385487393e386e2ea988b09d62dd42c397662ac2dabc3832d71253eee479"},
|
||||||
|
{file = "coverage-7.13.5-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:7f2c47b36fe7709a6e83bfadf4eefb90bd25fbe4014d715224c4316f808e59a2"},
|
||||||
|
{file = "coverage-7.13.5-cp313-cp313t-win32.whl", hash = "sha256:67e9bc5449801fad0e5dff329499fb090ba4c5800b86805c80617b4e29809b2a"},
|
||||||
|
{file = "coverage-7.13.5-cp313-cp313t-win_amd64.whl", hash = "sha256:da86cdcf10d2519e10cabb8ac2de03da1bcb6e4853790b7fbd48523332e3a819"},
|
||||||
|
{file = "coverage-7.13.5-cp313-cp313t-win_arm64.whl", hash = "sha256:0ecf12ecb326fe2c339d93fc131816f3a7367d223db37817208905c89bded911"},
|
||||||
|
{file = "coverage-7.13.5-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:fbabfaceaeb587e16f7008f7795cd80d20ec548dc7f94fbb0d4ec2e038ce563f"},
|
||||||
|
{file = "coverage-7.13.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:9bb2a28101a443669a423b665939381084412b81c3f8c0fcfbac57f4e30b5b8e"},
|
||||||
|
{file = "coverage-7.13.5-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:bd3a2fbc1c6cccb3c5106140d87cc6a8715110373ef42b63cf5aea29df8c217a"},
|
||||||
|
{file = "coverage-7.13.5-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6c36ddb64ed9d7e496028d1d00dfec3e428e0aabf4006583bb1839958d280510"},
|
||||||
|
{file = "coverage-7.13.5-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:380e8e9084d8eb38db3a9176a1a4f3c0082c3806fa0dc882d1d87abc3c789247"},
|
||||||
|
{file = "coverage-7.13.5-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e808af52a0513762df4d945ea164a24b37f2f518cbe97e03deaa0ee66139b4d6"},
|
||||||
|
{file = "coverage-7.13.5-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e301d30dd7e95ae068671d746ba8c34e945a82682e62918e41b2679acd2051a0"},
|
||||||
|
{file = "coverage-7.13.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:800bc829053c80d240a687ceeb927a94fd108bbdc68dfbe505d0d75ab578a882"},
|
||||||
|
{file = "coverage-7.13.5-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:0b67af5492adb31940ee418a5a655c28e48165da5afab8c7fa6fd72a142f8740"},
|
||||||
|
{file = "coverage-7.13.5-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:c9136ff29c3a91e25b1d1552b5308e53a1e0653a23e53b6366d7c2dcbbaf8a16"},
|
||||||
|
{file = "coverage-7.13.5-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:cff784eef7f0b8f6cb28804fbddcfa99f89efe4cc35fb5627e3ac58f91ed3ac0"},
|
||||||
|
{file = "coverage-7.13.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:68a4953be99b17ac3c23b6efbc8a38330d99680c9458927491d18700ef23ded0"},
|
||||||
|
{file = "coverage-7.13.5-cp314-cp314-win32.whl", hash = "sha256:35a31f2b1578185fbe6aa2e74cea1b1d0bbf4c552774247d9160d29b80ed56cc"},
|
||||||
|
{file = "coverage-7.13.5-cp314-cp314-win_amd64.whl", hash = "sha256:2aa055ae1857258f9e0045be26a6d62bdb47a72448b62d7b55f4820f361a2633"},
|
||||||
|
{file = "coverage-7.13.5-cp314-cp314-win_arm64.whl", hash = "sha256:1b11eef33edeae9d142f9b4358edb76273b3bfd30bc3df9a4f95d0e49caf94e8"},
|
||||||
|
{file = "coverage-7.13.5-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:10a0c37f0b646eaff7cce1874c31d1f1ccb297688d4c747291f4f4c70741cc8b"},
|
||||||
|
{file = "coverage-7.13.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b5db73ba3c41c7008037fa731ad5459fc3944cb7452fc0aa9f822ad3533c583c"},
|
||||||
|
{file = "coverage-7.13.5-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:750db93a81e3e5a9831b534be7b1229df848b2e125a604fe6651e48aa070e5f9"},
|
||||||
|
{file = "coverage-7.13.5-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9ddb4f4a5479f2539644be484da179b653273bca1a323947d48ab107b3ed1f29"},
|
||||||
|
{file = "coverage-7.13.5-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d8a7a2049c14f413163e2bdabd37e41179b1d1ccb10ffc6ccc4b7a718429c607"},
|
||||||
|
{file = "coverage-7.13.5-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e1c85e0b6c05c592ea6d8768a66a254bfb3874b53774b12d4c89c481eb78cb90"},
|
||||||
|
{file = "coverage-7.13.5-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:777c4d1eff1b67876139d24288aaf1817f6c03d6bae9c5cc8d27b83bcfe38fe3"},
|
||||||
|
{file = "coverage-7.13.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:6697e29b93707167687543480a40f0db8f356e86d9f67ddf2e37e2dfd91a9dab"},
|
||||||
|
{file = "coverage-7.13.5-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:8fdf453a942c3e4d99bd80088141c4c6960bb232c409d9c3558e2dbaa3998562"},
|
||||||
|
{file = "coverage-7.13.5-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:32ca0c0114c9834a43f045a87dcebd69d108d8ffb666957ea65aa132f50332e2"},
|
||||||
|
{file = "coverage-7.13.5-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:8769751c10f339021e2638cd354e13adeac54004d1941119b2c96fe5276d45ea"},
|
||||||
|
{file = "coverage-7.13.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cec2d83125531bd153175354055cdb7a09987af08a9430bd173c937c6d0fba2a"},
|
||||||
|
{file = "coverage-7.13.5-cp314-cp314t-win32.whl", hash = "sha256:0cd9ed7a8b181775459296e402ca4fb27db1279740a24e93b3b41942ebe4b215"},
|
||||||
|
{file = "coverage-7.13.5-cp314-cp314t-win_amd64.whl", hash = "sha256:301e3b7dfefecaca37c9f1aa6f0049b7d4ab8dd933742b607765d757aca77d43"},
|
||||||
|
{file = "coverage-7.13.5-cp314-cp314t-win_arm64.whl", hash = "sha256:9dacc2ad679b292709e0f5fc1ac74a6d4d5562e424058962c7bb0c658ad25e45"},
|
||||||
|
{file = "coverage-7.13.5-py3-none-any.whl", hash = "sha256:34b02417cf070e173989b3db962f7ed56d2f644307b2cf9d5a0f258e13084a61"},
|
||||||
|
{file = "coverage-7.13.5.tar.gz", hash = "sha256:c81f6515c4c40141f83f502b07bbfa5c240ba25bbe73da7b33f1e5b6120ff179"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "iniconfig"
|
||||||
|
version = "2.3.0"
|
||||||
|
requires_python = ">=3.10"
|
||||||
|
summary = "brain-dead simple config-ini parsing"
|
||||||
|
groups = ["dev"]
|
||||||
|
files = [
|
||||||
|
{file = "iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12"},
|
||||||
|
{file = "iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "packaging"
|
||||||
|
version = "26.2"
|
||||||
|
requires_python = ">=3.8"
|
||||||
|
summary = "Core utilities for Python packages"
|
||||||
|
groups = ["dev"]
|
||||||
|
files = [
|
||||||
|
{file = "packaging-26.2-py3-none-any.whl", hash = "sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e"},
|
||||||
|
{file = "packaging-26.2.tar.gz", hash = "sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pluggy"
|
||||||
|
version = "1.6.0"
|
||||||
|
requires_python = ">=3.9"
|
||||||
|
summary = "plugin and hook calling mechanisms for python"
|
||||||
|
groups = ["dev"]
|
||||||
|
files = [
|
||||||
|
{file = "pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746"},
|
||||||
|
{file = "pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pygments"
|
||||||
|
version = "2.20.0"
|
||||||
|
requires_python = ">=3.9"
|
||||||
|
summary = "Pygments is a syntax highlighting package written in Python."
|
||||||
|
groups = ["dev"]
|
||||||
|
files = [
|
||||||
|
{file = "pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176"},
|
||||||
|
{file = "pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pytest"
|
||||||
|
version = "9.0.3"
|
||||||
|
requires_python = ">=3.10"
|
||||||
|
summary = "pytest: simple powerful testing with Python"
|
||||||
|
groups = ["dev"]
|
||||||
|
dependencies = [
|
||||||
|
"colorama>=0.4; sys_platform == \"win32\"",
|
||||||
|
"exceptiongroup>=1; python_version < \"3.11\"",
|
||||||
|
"iniconfig>=1.0.1",
|
||||||
|
"packaging>=22",
|
||||||
|
"pluggy<2,>=1.5",
|
||||||
|
"pygments>=2.7.2",
|
||||||
|
"tomli>=1; python_version < \"3.11\"",
|
||||||
|
]
|
||||||
|
files = [
|
||||||
|
{file = "pytest-9.0.3-py3-none-any.whl", hash = "sha256:2c5efc453d45394fdd706ade797c0a81091eccd1d6e4bccfcd476e2b8e0ab5d9"},
|
||||||
|
{file = "pytest-9.0.3.tar.gz", hash = "sha256:b86ada508af81d19edeb213c681b1d48246c1a91d304c6c81a427674c17eb91c"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pytest-cov"
|
||||||
|
version = "7.1.0"
|
||||||
|
requires_python = ">=3.9"
|
||||||
|
summary = "Pytest plugin for measuring coverage."
|
||||||
|
groups = ["dev"]
|
||||||
|
dependencies = [
|
||||||
|
"coverage[toml]>=7.10.6",
|
||||||
|
"pluggy>=1.2",
|
||||||
|
"pytest>=7",
|
||||||
|
]
|
||||||
|
files = [
|
||||||
|
{file = "pytest_cov-7.1.0-py3-none-any.whl", hash = "sha256:a0461110b7865f9a271aa1b51e516c9a95de9d696734a2f71e3e78f46e1d4678"},
|
||||||
|
{file = "pytest_cov-7.1.0.tar.gz", hash = "sha256:30674f2b5f6351aa09702a9c8c364f6a01c27aae0c1366ae8016160d1efc56b2"},
|
||||||
|
]
|
||||||
44
pyproject.toml
Normal file
44
pyproject.toml
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
[build-system]
|
||||||
|
requires = ["pdm-backend", "build"]
|
||||||
|
build-backend = "pdm.backend"
|
||||||
|
|
||||||
|
[project]
|
||||||
|
name = "dragiyski-vulkan-registry"
|
||||||
|
version = "0.0.1"
|
||||||
|
description = "Extracts and parses the Vulkan API registry XML file, providing a Python interface to access the data."
|
||||||
|
readme = "README.md"
|
||||||
|
authors = [ { name = "Plamen Dragiyski", email = "plamen@dragiyski.org" } ]
|
||||||
|
requires-python = ">=3.12"
|
||||||
|
|
||||||
|
[dependency-groups]
|
||||||
|
dev = [
|
||||||
|
"pytest>=9.0.1",
|
||||||
|
"pytest-cov>=7.0.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[tool.pdm]
|
||||||
|
package-dir = "src"
|
||||||
|
|
||||||
|
[tool.pdm.build]
|
||||||
|
includes = ["src"]
|
||||||
|
excludes = ["tests"]
|
||||||
|
|
||||||
|
[tool.pdm.scripts]
|
||||||
|
test = "pytest"
|
||||||
|
coverage = "pytest --cov=dragiyski.vulkan --cov-report=html"
|
||||||
|
|
||||||
|
[tool.pytest]
|
||||||
|
minversion="0.9"
|
||||||
|
testpaths = [
|
||||||
|
"tests"
|
||||||
|
]
|
||||||
|
python_files = [
|
||||||
|
"test_*.py"
|
||||||
|
]
|
||||||
|
pythonpath = ["src"]
|
||||||
|
|
||||||
|
[tool.coverage.run]
|
||||||
|
branch = true
|
||||||
|
|
||||||
|
[tool.coverage.html]
|
||||||
|
directory = ".coverage-report/html"
|
||||||
15
src/dragiyski/vulkan/registry/__init__.py
Normal file
15
src/dragiyski/vulkan/registry/__init__.py
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
from .taxonomy import Taxonomy
|
||||||
|
|
||||||
|
def __init__(globals):
|
||||||
|
import importlib.resources
|
||||||
|
from .xml import Node, parse_xml
|
||||||
|
|
||||||
|
roots: list[Node] = [
|
||||||
|
parse_xml(file, is_file=True)
|
||||||
|
for file in (importlib.resources.files() / 'data').iterdir()
|
||||||
|
]
|
||||||
|
|
||||||
|
globals['taxonomy'] = Taxonomy(*roots)
|
||||||
|
|
||||||
|
__init__(globals())
|
||||||
|
del __init__
|
||||||
2020
src/dragiyski/vulkan/registry/data/video.xml
Normal file
2020
src/dragiyski/vulkan/registry/data/video.xml
Normal file
File diff suppressed because it is too large
Load Diff
33618
src/dragiyski/vulkan/registry/data/vk.xml
Normal file
33618
src/dragiyski/vulkan/registry/data/vk.xml
Normal file
File diff suppressed because it is too large
Load Diff
979
src/dragiyski/vulkan/registry/taxonomy.py
Normal file
979
src/dragiyski/vulkan/registry/taxonomy.py
Normal file
@@ -0,0 +1,979 @@
|
|||||||
|
from collections import OrderedDict
|
||||||
|
import re
|
||||||
|
from .xml import Node
|
||||||
|
|
||||||
|
PREFIX_OBJECT_TYPE = 'VK_OBJECT_TYPE_'
|
||||||
|
PREFIX_DEBUG_REPORT_OBJECT_TYPE = 'VK_DEBUG_REPORT_OBJECT_TYPE_'
|
||||||
|
|
||||||
|
|
||||||
|
class Taxonomy:
|
||||||
|
def __init__(self, *roots: Node, api: str = 'vulkan'):
|
||||||
|
self.api = api
|
||||||
|
self.nodes: dict[str, list] = {}
|
||||||
|
self.ctypes: set = {
|
||||||
|
'int8_t',
|
||||||
|
'int16_t',
|
||||||
|
'int32_t',
|
||||||
|
'int64_t',
|
||||||
|
'uint8_t',
|
||||||
|
'uint16_t',
|
||||||
|
'uint32_t',
|
||||||
|
'uint64_t',
|
||||||
|
'size_t',
|
||||||
|
}
|
||||||
|
self.external_types: set[str] = set(self.ctypes)
|
||||||
|
self.vulkan_names: dict[str, str] = dict()
|
||||||
|
self.vulkan_node_info: dict[str, dict] = {
|
||||||
|
'define': {},
|
||||||
|
'basetype': {},
|
||||||
|
'enum': {},
|
||||||
|
'bitmask': {},
|
||||||
|
'handle': {},
|
||||||
|
'struct': {},
|
||||||
|
'union': {},
|
||||||
|
'callback': {},
|
||||||
|
'value': {},
|
||||||
|
'command': {},
|
||||||
|
}
|
||||||
|
self.tags = set()
|
||||||
|
self.bitmask_bit_map: dict[str, str] = dict()
|
||||||
|
self.bit_bitmask_map: dict[str, str] = dict()
|
||||||
|
self.alias_map: dict[str, str] = dict()
|
||||||
|
self.alias_target_map: dict[str, set[str]] = dict()
|
||||||
|
self.error_nodes: dict[str, list[Node]] = dict()
|
||||||
|
self.value_group_map: dict[str, str | None] = dict()
|
||||||
|
self.group_value_map: dict[str, set] = dict()
|
||||||
|
self.handle_parent = {}
|
||||||
|
self.feature_names = set()
|
||||||
|
self.feature_dependent_map: dict[str, set[str]] = dict()
|
||||||
|
self.feature_dependency_map: dict[str, set[str]] = dict()
|
||||||
|
self.feature_require_map: dict[str, set[str]] = dict()
|
||||||
|
self.feature_deprecate_map: dict[str, set[str]] = dict()
|
||||||
|
self.feature_remove_map: dict[str, set[str]] = dict()
|
||||||
|
self.name_feature_map: dict[str, set[str]] = dict()
|
||||||
|
self.extension_map: dict[str, int] = dict()
|
||||||
|
self.name_extension_map: dict[int, str] = dict()
|
||||||
|
self.extension_require_map: dict[str, set[str]] = dict()
|
||||||
|
self.extension_deprecate_map: dict[str, set[str]] = dict()
|
||||||
|
self.extension_remove_map: dict[str, set[str]] = dict()
|
||||||
|
self.api_unsupported_names = set()
|
||||||
|
|
||||||
|
self._init_type_node_by_category = {
|
||||||
|
None: self._init_ctype_node,
|
||||||
|
'basetype': self._init_basetype_node,
|
||||||
|
'define': self._init_define_type_node,
|
||||||
|
'enum': self._init_enum_type_node,
|
||||||
|
'bitmask': self._init_bitmask_type_node,
|
||||||
|
'handle': self._init_handle_type_node,
|
||||||
|
'struct': self._init_struct_type_node,
|
||||||
|
'union': self._init_union_type_node,
|
||||||
|
'funcpointer': self._init_callback_type_node,
|
||||||
|
}
|
||||||
|
|
||||||
|
for root in roots:
|
||||||
|
self._init_tags(root)
|
||||||
|
self._init_types_nodes(root)
|
||||||
|
self._init_enums_nodes(root)
|
||||||
|
self._init_command_nodes(root)
|
||||||
|
self._init_feature_nodes(root)
|
||||||
|
self._init_extension_nodes(root)
|
||||||
|
self._reverse_feature_dependecies()
|
||||||
|
self._resolve_usage()
|
||||||
|
self._manage_type_dependencies()
|
||||||
|
self._resolve_extends()
|
||||||
|
self._apply_ctype_aliases()
|
||||||
|
self._init_members()
|
||||||
|
self._init_arguments()
|
||||||
|
self._init_handles()
|
||||||
|
self._init_handle_output()
|
||||||
|
self._init_handle_destroy()
|
||||||
|
self._init_io()
|
||||||
|
|
||||||
|
def is_valid_api(self, node: Node) -> bool:
|
||||||
|
if node.has_attribute('api'):
|
||||||
|
api_set = {x.strip().lower() for x in node.get_attribute('api').split(',')}
|
||||||
|
if self.api not in api_set:
|
||||||
|
return False
|
||||||
|
if node.node_name == 'command' and node.has_attribute('export'):
|
||||||
|
export_set = {x.strip().lower() for x in node.get_attribute('export').split(',')}
|
||||||
|
if self.api not in export_set:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _init_tags(self, root: Node):
|
||||||
|
for tags_node in root.get_all('tags'):
|
||||||
|
for tag_node in tags_node.get_all('tag'):
|
||||||
|
if not tag_node.has_attribute('name'):
|
||||||
|
self.error_nodes.setdefault('missing_name', []).append(tag_node)
|
||||||
|
continue
|
||||||
|
name = tag_node.get_attribute('name')
|
||||||
|
self.tags.add(name)
|
||||||
|
|
||||||
|
def _parse_node_name_from_attribute(self, node: Node) -> str | None:
|
||||||
|
if not node.has_attribute('name'):
|
||||||
|
self.error_nodes.setdefault('missing_name', []).append(node)
|
||||||
|
return None
|
||||||
|
return node.get_attribute('name')
|
||||||
|
|
||||||
|
def _parse_node_name_from_child(self, node: Node) -> str | None:
|
||||||
|
if 'name' not in node.children:
|
||||||
|
self.error_nodes.setdefault('missing_name', []).append(node)
|
||||||
|
return None
|
||||||
|
return node.get('name').get_text()
|
||||||
|
|
||||||
|
def _parse_node_name(self, node: Node) -> str | None:
|
||||||
|
if node.has_attribute('name'):
|
||||||
|
return node.get_attribute('name')
|
||||||
|
if 'name' in node.children:
|
||||||
|
return node.get('name').get_text()
|
||||||
|
self.error_nodes.setdefault('missing_name', []).append(node)
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _parse_node_name_for_function(self, node: Node) -> str | None:
|
||||||
|
if node.has_attribute('name'):
|
||||||
|
return node.get_attribute('name')
|
||||||
|
if 'proto' in node.children:
|
||||||
|
proto_node = node.get('proto')
|
||||||
|
if 'name' in proto_node.children:
|
||||||
|
return proto_node.get('name').get_text()
|
||||||
|
self.error_nodes.setdefault('missing_name', []).append(node)
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _init_types_nodes(self, root: Node):
|
||||||
|
for types_node in root.get_all('types'):
|
||||||
|
if not self.is_valid_api(types_node):
|
||||||
|
continue
|
||||||
|
for type_node in types_node.get_all('type'):
|
||||||
|
if not self.is_valid_api(type_node):
|
||||||
|
continue
|
||||||
|
if type_node.has_attribute('alias'):
|
||||||
|
self._init_alias_node(type_node)
|
||||||
|
continue
|
||||||
|
category = None
|
||||||
|
if type_node.has_attribute('category'):
|
||||||
|
category = type_node.get_attribute('category')
|
||||||
|
if category in self._init_type_node_by_category:
|
||||||
|
self._init_type_node_by_category[category](type_node)
|
||||||
|
|
||||||
|
def _init_node(self, node: Node, name: str):
|
||||||
|
self.nodes.setdefault(name, []).append(node)
|
||||||
|
|
||||||
|
def _init_alias_node(self, type_node: Node):
|
||||||
|
if not type_node.has_attribute('name'):
|
||||||
|
self.error_nodes.setdefault('missing_name', []).append(type_node)
|
||||||
|
return
|
||||||
|
name = type_node.get_attribute('name')
|
||||||
|
target_name = type_node.get_attribute('alias')
|
||||||
|
self.alias_map[name] = target_name
|
||||||
|
self.alias_target_map.setdefault(target_name, set()).add(name)
|
||||||
|
self._init_node(type_node, name)
|
||||||
|
|
||||||
|
def _init_ctype_node(self, type_node: Node):
|
||||||
|
name = self._parse_node_name(type_node)
|
||||||
|
if name is None:
|
||||||
|
return
|
||||||
|
self._init_node(type_node, name)
|
||||||
|
self.ctypes.add(name)
|
||||||
|
self.external_types.add(name)
|
||||||
|
|
||||||
|
def _init_basetype_node(self, type_node: Node):
|
||||||
|
name = self._parse_node_name(type_node)
|
||||||
|
if name is None:
|
||||||
|
return
|
||||||
|
self._init_node(type_node, name)
|
||||||
|
self.ctypes.add(name)
|
||||||
|
self.external_types.add(name)
|
||||||
|
self._init_node_info(name, 'basetype')
|
||||||
|
|
||||||
|
def _init_node_info(self, name: str, type: str):
|
||||||
|
node_info = self.vulkan_node_info[type].setdefault(name, {})
|
||||||
|
node_info.setdefault('used_by', set())
|
||||||
|
self.external_types.discard(name)
|
||||||
|
|
||||||
|
def _init_define_type_node(self, type_node: Node):
|
||||||
|
if '#define' not in type_node.get_text():
|
||||||
|
return
|
||||||
|
name = self._parse_node_name(type_node)
|
||||||
|
if name is None:
|
||||||
|
return
|
||||||
|
self._init_node(type_node, name)
|
||||||
|
self.vulkan_names[name] = 'define'
|
||||||
|
self._init_node_info(name, 'define')
|
||||||
|
|
||||||
|
def _init_enum_type_node(self, type_node: Node):
|
||||||
|
name = self._parse_node_name(type_node)
|
||||||
|
if name is None:
|
||||||
|
return
|
||||||
|
if 'FlagBits' in name:
|
||||||
|
bitmask_name = name.replace('FlagBits', 'Flags')
|
||||||
|
self.bitmask_bit_map[bitmask_name] = name
|
||||||
|
self.bit_bitmask_map[name] = bitmask_name
|
||||||
|
self.ctypes.add(bitmask_name)
|
||||||
|
self.vulkan_names[bitmask_name] = 'bitmask'
|
||||||
|
self._init_node_info(bitmask_name, 'bitmask')
|
||||||
|
else:
|
||||||
|
self._init_node(type_node, name)
|
||||||
|
self.ctypes.add(name)
|
||||||
|
self.vulkan_names[name] = 'enum'
|
||||||
|
self._init_node_info(name, 'enum')
|
||||||
|
|
||||||
|
def _init_bitmask_type_node(self, type_node: Node):
|
||||||
|
name = self._parse_node_name(type_node)
|
||||||
|
if name is None:
|
||||||
|
return
|
||||||
|
self._init_node(type_node, name)
|
||||||
|
self.ctypes.add(name)
|
||||||
|
self.vulkan_names[name] = 'bitmask'
|
||||||
|
self.vulkan_node_info['enum'].pop(name, None)
|
||||||
|
self._init_node_info(name, 'bitmask')
|
||||||
|
|
||||||
|
def _init_handle_type_node(self, type_node: Node):
|
||||||
|
name = self._parse_node_name(type_node)
|
||||||
|
if name is None:
|
||||||
|
return
|
||||||
|
self._init_node(type_node, name)
|
||||||
|
self.ctypes.add(name)
|
||||||
|
self.vulkan_names[name] = 'handle'
|
||||||
|
self._init_node_info(name, 'handle')
|
||||||
|
self.vulkan_node_info['handle'][name].setdefault('uses', set())
|
||||||
|
|
||||||
|
def _init_struct_type_node(self, type_node: Node):
|
||||||
|
name = self._parse_node_name(type_node)
|
||||||
|
if name is None:
|
||||||
|
return
|
||||||
|
self.vulkan_names[name] = 'struct'
|
||||||
|
self._init_node_info(name, 'struct')
|
||||||
|
self.vulkan_node_info['struct'][name]['extends'] = set()
|
||||||
|
self.vulkan_node_info['struct'][name]['extended_by'] = set()
|
||||||
|
self._init_complex_type_node(type_node, name, self.vulkan_node_info['struct'][name])
|
||||||
|
|
||||||
|
def _init_union_type_node(self, type_node: Node):
|
||||||
|
name = self._parse_node_name(type_node)
|
||||||
|
if name is None:
|
||||||
|
return
|
||||||
|
self.vulkan_names[name] = 'union'
|
||||||
|
self._init_node_info(name, 'union')
|
||||||
|
self._init_complex_type_node(type_node, name, self.vulkan_node_info['union'][name])
|
||||||
|
|
||||||
|
def _init_complex_type_node(self, type_node: Node, name: str, node_info: dict):
|
||||||
|
self.ctypes.add(name)
|
||||||
|
self._init_node(type_node, name)
|
||||||
|
node_info.setdefault('uses', set())
|
||||||
|
node_info.setdefault('input_of', set())
|
||||||
|
node_info.setdefault('output_of', set())
|
||||||
|
|
||||||
|
def _init_callback_type_node(self, type_node: Node):
|
||||||
|
type_name = self._parse_node_name_for_function(type_node)
|
||||||
|
if type_name is None:
|
||||||
|
return
|
||||||
|
name = type_name
|
||||||
|
if name.startswith('PFN_'):
|
||||||
|
name = name[4:]
|
||||||
|
self._init_node(type_node, name)
|
||||||
|
self.ctypes.add(type_name)
|
||||||
|
self.ctypes.add(name)
|
||||||
|
self.vulkan_names[name] = 'callback'
|
||||||
|
self._init_node_info(name, 'callback')
|
||||||
|
self.vulkan_node_info['callback'][name].setdefault('uses', set())
|
||||||
|
self.vulkan_node_info['callback'][name].setdefault('return_use', None)
|
||||||
|
self.vulkan_node_info['callback'][name].setdefault('argument_use', set())
|
||||||
|
if 'proto' in type_node.children:
|
||||||
|
proto_node = type_node.get('proto')
|
||||||
|
if 'type' in proto_node.children:
|
||||||
|
return_type = proto_node.get('type').get_text()
|
||||||
|
self.vulkan_node_info['callback'][name]['return_use'] = return_type
|
||||||
|
for param_node in type_node.get_all('param'):
|
||||||
|
if 'type' not in param_node.children:
|
||||||
|
continue
|
||||||
|
param_type = param_node.get('type').get_text()
|
||||||
|
self.vulkan_node_info['callback'][name]['argument_use'].add(param_type)
|
||||||
|
|
||||||
|
def _init_value_node(self, value_node: Node, name: str, group_name: str | None):
|
||||||
|
self.value_group_map[name] = group_name
|
||||||
|
self.group_value_map.setdefault(group_name, set()).add(name)
|
||||||
|
self.vulkan_names[name] = 'value'
|
||||||
|
self._init_node_info(name, 'value')
|
||||||
|
self._init_node(value_node, name)
|
||||||
|
|
||||||
|
def _init_enums_nodes(self, root: Node):
|
||||||
|
for enums_node in root.get_all('enums'):
|
||||||
|
if not self.is_valid_api(enums_node):
|
||||||
|
continue
|
||||||
|
if enums_node.has_attribute('alias'):
|
||||||
|
self._init_alias_node(enums_node)
|
||||||
|
continue
|
||||||
|
enums_name = enums_node.get_attribute('name')
|
||||||
|
if enums_name is None:
|
||||||
|
self.error_nodes.setdefault('missing_name', []).append(enums_node)
|
||||||
|
continue
|
||||||
|
enums_type = enums_node.get_attribute('type')
|
||||||
|
if enums_type is not None:
|
||||||
|
if enums_type == 'enum':
|
||||||
|
self._init_enums_node(enums_node, enums_name)
|
||||||
|
elif enums_type == 'bitmask':
|
||||||
|
self._init_bitmask_node(enums_node, enums_name)
|
||||||
|
else:
|
||||||
|
enums_type = None
|
||||||
|
for enum_node in enums_node.get_all('enum'):
|
||||||
|
if not self.is_valid_api(enum_node):
|
||||||
|
continue
|
||||||
|
if enum_node.has_attribute('alias'):
|
||||||
|
self._init_alias_node(enum_node)
|
||||||
|
continue
|
||||||
|
enum_name = enum_node.get_attribute('name')
|
||||||
|
if enum_name is None:
|
||||||
|
self.error_nodes.setdefault('missing_name', []).append(enum_node)
|
||||||
|
continue
|
||||||
|
group_name = None if enums_type is None else enums_name
|
||||||
|
self._init_value_node(enum_node, enum_name, group_name)
|
||||||
|
|
||||||
|
def _init_enums_node(self, enums_node: Node, enums_name: str):
|
||||||
|
self._init_node(enums_node, enums_name)
|
||||||
|
self.ctypes.add(enums_name)
|
||||||
|
self.vulkan_names[enums_name] = 'enum'
|
||||||
|
self._init_node_info(enums_name, 'enum')
|
||||||
|
|
||||||
|
def _init_bitmask_node(self, enums_node: Node, enums_name: str):
|
||||||
|
bitmask_name = enums_name
|
||||||
|
if 'FlagBits' in bitmask_name:
|
||||||
|
bitmask_name = bitmask_name.replace('FlagBits', 'Flags')
|
||||||
|
self.bitmask_bit_map[bitmask_name] = enums_name
|
||||||
|
self.bit_bitmask_map[enums_name] = bitmask_name
|
||||||
|
self.vulkan_names.pop(enums_name, None)
|
||||||
|
self.vulkan_node_info['enum'].pop(enums_name, None)
|
||||||
|
self._init_node(enums_node, bitmask_name)
|
||||||
|
self.ctypes.add(bitmask_name)
|
||||||
|
self.ctypes.add(enums_name)
|
||||||
|
self.vulkan_names[bitmask_name] = 'bitmask'
|
||||||
|
self.vulkan_node_info['enum'].pop(bitmask_name, None)
|
||||||
|
self._init_node_info(bitmask_name, 'bitmask')
|
||||||
|
|
||||||
|
def _init_command_nodes(self, root: Node):
|
||||||
|
for commands_node in root.get_all('commands'):
|
||||||
|
if not self.is_valid_api(commands_node):
|
||||||
|
continue
|
||||||
|
for command_node in commands_node.get_all('command'):
|
||||||
|
if not self.is_valid_api(command_node):
|
||||||
|
continue
|
||||||
|
if command_node.has_attribute('alias'):
|
||||||
|
self._init_alias_node(command_node)
|
||||||
|
continue
|
||||||
|
command_name = self._parse_node_name_for_function(command_node)
|
||||||
|
if command_name is None:
|
||||||
|
continue
|
||||||
|
self._init_node(command_node, command_name)
|
||||||
|
self.ctypes.add(command_name)
|
||||||
|
self.vulkan_names[command_name] = 'command'
|
||||||
|
self._init_node_info(command_name, 'command')
|
||||||
|
self.vulkan_node_info['command'][command_name].setdefault('uses', set())
|
||||||
|
self.vulkan_node_info['command'][command_name].setdefault('return_use', None)
|
||||||
|
self.vulkan_node_info['command'][command_name].setdefault('argument_use', set())
|
||||||
|
if 'proto' in command_node.children:
|
||||||
|
proto_node = command_node.get('proto')
|
||||||
|
if 'type' in proto_node.children:
|
||||||
|
return_type = proto_node.get('type').get_text()
|
||||||
|
self.vulkan_node_info['command'][command_name]['return_use'] = return_type
|
||||||
|
for param_node in command_node.get_all('param'):
|
||||||
|
if 'type' not in param_node.children:
|
||||||
|
continue
|
||||||
|
param_type = param_node.get('type').get_text()
|
||||||
|
self.vulkan_node_info['command'][command_name]['argument_use'].add(param_type)
|
||||||
|
|
||||||
|
def _init_feature_nodes(self, root: Node):
|
||||||
|
for feature_node in root.get_all('feature'):
|
||||||
|
if not self.is_valid_api(feature_node):
|
||||||
|
continue
|
||||||
|
feature_name = feature_node.get_attribute('name')
|
||||||
|
if feature_name is None:
|
||||||
|
self.error_nodes.setdefault('missing_name', []).append(feature_node)
|
||||||
|
continue
|
||||||
|
self.feature_dependency_map.setdefault(feature_name, set())
|
||||||
|
if feature_node.get_attribute('apitype') != 'internal':
|
||||||
|
self.feature_names.add(feature_name)
|
||||||
|
self.feature_require_map.setdefault(feature_name, set())
|
||||||
|
self.feature_deprecate_map.setdefault(feature_name, set())
|
||||||
|
self.feature_remove_map.setdefault(feature_name, set())
|
||||||
|
if feature_node.has_attribute('depends'):
|
||||||
|
depends = {
|
||||||
|
x.strip()
|
||||||
|
for x in feature_node.get_attribute('depends').split(',')
|
||||||
|
}
|
||||||
|
self.feature_dependency_map[feature_name].update(depends)
|
||||||
|
self._init_inclusion_nodes(
|
||||||
|
feature_node,
|
||||||
|
feature_name,
|
||||||
|
self.feature_require_map,
|
||||||
|
self.feature_deprecate_map,
|
||||||
|
self.feature_remove_map,
|
||||||
|
self.name_feature_map
|
||||||
|
)
|
||||||
|
|
||||||
|
def _init_extension_nodes(self, root: Node):
|
||||||
|
for extensions_node in root.get_all('extensions'):
|
||||||
|
if not self.is_valid_api(extensions_node):
|
||||||
|
continue
|
||||||
|
for extension_node in extensions_node.get_all('extension'):
|
||||||
|
if not self.is_valid_api(extension_node):
|
||||||
|
continue
|
||||||
|
extension_name = extension_node.get_attribute('name')
|
||||||
|
if extension_name is None:
|
||||||
|
self.error_nodes.setdefault('missing_name', []).append(extension_node)
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
extension_number = int(extension_node.get_attribute('number'))
|
||||||
|
except ValueError:
|
||||||
|
self.error_nodes.setdefault('invalid_extension_number', []).append(extension_node)
|
||||||
|
continue
|
||||||
|
self.extension_map[extension_name] = extension_number
|
||||||
|
self.extension_require_map.setdefault(extension_name, set())
|
||||||
|
self.extension_deprecate_map.setdefault(extension_name, set())
|
||||||
|
self.extension_remove_map.setdefault(extension_name, set())
|
||||||
|
self._init_inclusion_nodes(
|
||||||
|
extension_node,
|
||||||
|
extension_name,
|
||||||
|
self.extension_require_map,
|
||||||
|
self.extension_deprecate_map,
|
||||||
|
self.extension_remove_map,
|
||||||
|
self.name_extension_map
|
||||||
|
)
|
||||||
|
|
||||||
|
def _init_inclusion_nodes(
|
||||||
|
self,
|
||||||
|
base_node: Node,
|
||||||
|
base_name: str,
|
||||||
|
inclusion_require_map: dict[str, set[str]],
|
||||||
|
inclusion_deprecate_map: dict[str, set[str]],
|
||||||
|
inclusion_remove_map: dict[str, set[str]],
|
||||||
|
name_inclusion_map: dict[str, set[str]]
|
||||||
|
):
|
||||||
|
for require_node in base_node.get_all('require'):
|
||||||
|
for enum_node in require_node.get_all('enum'):
|
||||||
|
if not self.is_valid_api(enum_node):
|
||||||
|
continue
|
||||||
|
if enum_node.has_attribute('alias'):
|
||||||
|
self._init_alias_node(enum_node)
|
||||||
|
continue
|
||||||
|
enum_name = enum_node.get_attribute('name')
|
||||||
|
if enum_name is None:
|
||||||
|
self.error_nodes.setdefault('missing_name', []).append(enum_node)
|
||||||
|
continue
|
||||||
|
group_name = None
|
||||||
|
if enum_node.has_attribute('extends'):
|
||||||
|
group_name = enum_node.get_attribute('extends')
|
||||||
|
self.group_value_map.setdefault(group_name, set()).add(enum_name)
|
||||||
|
self.value_group_map[enum_name] = group_name
|
||||||
|
inclusion_require_map[base_name].add(enum_name)
|
||||||
|
name_inclusion_map.setdefault(enum_name, set()).add(base_name)
|
||||||
|
self.vulkan_names[enum_name] = 'value'
|
||||||
|
self._init_node_info(enum_name, 'value')
|
||||||
|
self._init_node(enum_node, enum_name)
|
||||||
|
for type_node in require_node.get_all('type'):
|
||||||
|
if not self.is_valid_api(type_node):
|
||||||
|
continue
|
||||||
|
if type_node.has_attribute('alias'):
|
||||||
|
self._init_alias_node(type_node)
|
||||||
|
continue
|
||||||
|
type_name = type_node.get_attribute('name')
|
||||||
|
if type_name is None:
|
||||||
|
self.error_nodes.setdefault('missing_name', []).append(type_node)
|
||||||
|
continue
|
||||||
|
inclusion_require_map[base_name].add(type_name)
|
||||||
|
name_inclusion_map.setdefault(type_name, set()).add(base_name)
|
||||||
|
self._init_node(type_node, type_name)
|
||||||
|
for command_node in require_node.get_all('command'):
|
||||||
|
if not self.is_valid_api(command_node):
|
||||||
|
continue
|
||||||
|
if command_node.has_attribute('alias'):
|
||||||
|
self._init_alias_node(command_node)
|
||||||
|
continue
|
||||||
|
command_name = command_node.get_attribute('name')
|
||||||
|
if command_name is None:
|
||||||
|
self.error_nodes.setdefault('missing_name', []).append(command_node)
|
||||||
|
continue
|
||||||
|
inclusion_require_map[base_name].add(command_name)
|
||||||
|
name_inclusion_map.setdefault(command_name, set()).add(base_name)
|
||||||
|
self._init_node(command_node, command_name)
|
||||||
|
for inclusion_method in ['deprecate', 'remove']:
|
||||||
|
for inclusion_category in ['enum', 'type', 'command']:
|
||||||
|
for inclusion_node in base_node.get_all(inclusion_method):
|
||||||
|
if not self.is_valid_api(inclusion_node):
|
||||||
|
continue
|
||||||
|
for reference_node in inclusion_node.get_all(inclusion_category):
|
||||||
|
if not self.is_valid_api(reference_node):
|
||||||
|
continue
|
||||||
|
if reference_node.has_attribute('alias'):
|
||||||
|
self._init_alias_node(reference_node)
|
||||||
|
continue
|
||||||
|
reference_name = reference_node.get_attribute('name')
|
||||||
|
if reference_name is None:
|
||||||
|
self.error_nodes.setdefault('missing_name', []).append(inclusion_node)
|
||||||
|
continue
|
||||||
|
if inclusion_method == 'deprecate':
|
||||||
|
inclusion_deprecate_map[base_name].add(reference_name)
|
||||||
|
name_inclusion_map.setdefault(reference_name, set()).add(base_name)
|
||||||
|
elif inclusion_method == 'remove':
|
||||||
|
inclusion_remove_map[base_name].add(reference_name)
|
||||||
|
self._init_node(reference_node, reference_name)
|
||||||
|
|
||||||
|
def _resolve_alias(self, name: str) -> str:
|
||||||
|
while name in self.alias_map:
|
||||||
|
name = self.alias_map[name]
|
||||||
|
return name
|
||||||
|
|
||||||
|
def _manage_type_dependencies(self):
|
||||||
|
unsupported = {
|
||||||
|
'union': set(),
|
||||||
|
'struct': set(),
|
||||||
|
'callback': set(),
|
||||||
|
'command': set(),
|
||||||
|
}
|
||||||
|
all_unsupported = set()
|
||||||
|
|
||||||
|
# Step 1: Remove struct types that have sType members values not defined in the current API.
|
||||||
|
for name in self.vulkan_node_info['struct']:
|
||||||
|
for node in self.nodes.get(name, []):
|
||||||
|
node: Node
|
||||||
|
if 'member' not in node.children:
|
||||||
|
continue
|
||||||
|
for member_node in node.get_all('member'):
|
||||||
|
if not self.is_valid_api(member_node):
|
||||||
|
continue
|
||||||
|
if 'name' not in member_node.children or 'type' not in member_node.children:
|
||||||
|
continue
|
||||||
|
member_type = self._resolve_alias(member_node.get('type').get_text())
|
||||||
|
member_name = member_node.get('name').get_text()
|
||||||
|
if member_name != 'sType' or member_type != 'VkStructureType' or not member_node.has_attribute('values'):
|
||||||
|
continue
|
||||||
|
stype_values = {x.strip() for x in member_node.get_attribute('values').split(',')}
|
||||||
|
for stype_value in stype_values:
|
||||||
|
stype_value = self._resolve_alias(stype_value)
|
||||||
|
if stype_value not in self.group_value_map['VkStructureType']:
|
||||||
|
unsupported['struct'].add(name)
|
||||||
|
all_unsupported.add(name)
|
||||||
|
|
||||||
|
# Step 1: Remove callbacks with no user data argument.
|
||||||
|
for name in self.vulkan_node_info['callback']:
|
||||||
|
for node in self.nodes.get(name, []):
|
||||||
|
node: Node
|
||||||
|
if 'proto' not in node.children:
|
||||||
|
continue
|
||||||
|
has_user_data = False
|
||||||
|
for decl_node in node.get_all('param'):
|
||||||
|
if not self.is_valid_api(decl_node):
|
||||||
|
continue
|
||||||
|
if 'name' not in decl_node.children:
|
||||||
|
continue
|
||||||
|
param_name = decl_node.get('name').get_text()
|
||||||
|
if param_name == 'pUserData':
|
||||||
|
has_user_data = True
|
||||||
|
break
|
||||||
|
if not has_user_data:
|
||||||
|
has_binding_use = False
|
||||||
|
for depend_name in self.vulkan_node_info['callback'][name]['used_by']:
|
||||||
|
if depend_name in all_unsupported:
|
||||||
|
continue
|
||||||
|
depend_category = self.vulkan_names[depend_name]
|
||||||
|
if depend_category in ['command', 'callback']:
|
||||||
|
depend_info = self.vulkan_node_info[depend_category][depend_name]
|
||||||
|
if name in depend_info['argument_use']:
|
||||||
|
has_binding_use = True
|
||||||
|
break
|
||||||
|
elif depend_category in ['struct', 'union']:
|
||||||
|
has_binding_use = True
|
||||||
|
break
|
||||||
|
if has_binding_use:
|
||||||
|
unsupported['callback'].add(name)
|
||||||
|
all_unsupported.add(name)
|
||||||
|
|
||||||
|
# Step 2: Cascade removal of types using unsupported types.
|
||||||
|
remove_length = len(all_unsupported)
|
||||||
|
while True:
|
||||||
|
for complex_category in ['struct', 'union']:
|
||||||
|
for name in self.vulkan_node_info[complex_category]:
|
||||||
|
if name in unsupported[complex_category]:
|
||||||
|
continue
|
||||||
|
for node in self.nodes.get(name, []):
|
||||||
|
node: Node
|
||||||
|
if 'member' not in node.children:
|
||||||
|
continue
|
||||||
|
for member_node in node.get_all('member'):
|
||||||
|
if not self.is_valid_api(member_node):
|
||||||
|
continue
|
||||||
|
if 'type' not in member_node.children:
|
||||||
|
continue
|
||||||
|
member_type = self._resolve_alias(member_node.get('type').get_text())
|
||||||
|
if member_type.startswith('PFN_'):
|
||||||
|
member_type = member_type[4:]
|
||||||
|
member_type = self._resolve_alias(member_type)
|
||||||
|
if member_type in all_unsupported:
|
||||||
|
unsupported[complex_category].add(name)
|
||||||
|
all_unsupported.add(name)
|
||||||
|
for function_category in ['callback', 'command']:
|
||||||
|
for name in self.vulkan_node_info[function_category]:
|
||||||
|
if name in unsupported[function_category]:
|
||||||
|
continue
|
||||||
|
for node in self.nodes.get(name, []):
|
||||||
|
node: Node
|
||||||
|
if 'proto' not in node.children:
|
||||||
|
continue
|
||||||
|
for decl_node in node.get_all('param') + [node.get('proto')]:
|
||||||
|
if not self.is_valid_api(decl_node):
|
||||||
|
continue
|
||||||
|
type_node = decl_node.get('type')
|
||||||
|
if type_node is None:
|
||||||
|
continue
|
||||||
|
param_type = self._resolve_alias(type_node.get_text())
|
||||||
|
if param_type.startswith('PFN_'):
|
||||||
|
param_type = param_type[4:]
|
||||||
|
param_type = self._resolve_alias(param_type)
|
||||||
|
if param_type in all_unsupported:
|
||||||
|
unsupported[function_category].add(name)
|
||||||
|
all_unsupported.add(name)
|
||||||
|
new_remove_length = len(all_unsupported)
|
||||||
|
if new_remove_length == remove_length:
|
||||||
|
break
|
||||||
|
remove_length = new_remove_length
|
||||||
|
|
||||||
|
# Finally, for all unsupported types by the current API, remove them, but keep a record in self.api_unsupported_names.
|
||||||
|
for unsupported_type in unsupported:
|
||||||
|
for name in unsupported[unsupported_type]:
|
||||||
|
self.ctypes.discard(name)
|
||||||
|
self.nodes.pop(name, None)
|
||||||
|
self.vulkan_node_info[unsupported_type].pop(name, None)
|
||||||
|
self.vulkan_names.pop(name, None)
|
||||||
|
if name in self.alias_map:
|
||||||
|
target_name = self.alias_map.pop(name)
|
||||||
|
self.alias_target_map[target_name].discard(name)
|
||||||
|
if len(self.alias_target_map[target_name]) == 0:
|
||||||
|
self.alias_target_map.pop(target_name)
|
||||||
|
self.alias_map.pop(name, None)
|
||||||
|
if name in self.alias_target_map:
|
||||||
|
for alias_name in self.alias_target_map.pop(name):
|
||||||
|
self.alias_map.pop(alias_name, None)
|
||||||
|
all_unsupported.add(alias_name)
|
||||||
|
self.alias_target_map.pop(name, None)
|
||||||
|
|
||||||
|
self.api_unsupported_names.update(all_unsupported)
|
||||||
|
|
||||||
|
def _resolve_type(self, type_name: str):
|
||||||
|
type_name = self._resolve_alias(type_name)
|
||||||
|
if type_name in self.bit_bitmask_map:
|
||||||
|
return self.bit_bitmask_map[type_name]
|
||||||
|
return type_name
|
||||||
|
|
||||||
|
def _resolve_usage(self):
|
||||||
|
for complex_category in ['struct', 'union']:
|
||||||
|
for name in self.vulkan_node_info[complex_category]:
|
||||||
|
for node in self.nodes.get(name, []):
|
||||||
|
node: Node
|
||||||
|
if 'member' not in node.children:
|
||||||
|
continue
|
||||||
|
for member_node in node.get_all('member'):
|
||||||
|
if not self.is_valid_api(member_node):
|
||||||
|
continue
|
||||||
|
if 'type' not in member_node.children:
|
||||||
|
continue
|
||||||
|
member_type = self._resolve_type(member_node.get('type').get_text())
|
||||||
|
if member_type.startswith('PFN_'):
|
||||||
|
member_type = member_type[4:]
|
||||||
|
member_type = self._resolve_alias(member_type)
|
||||||
|
if member_type in self.vulkan_names:
|
||||||
|
self.vulkan_node_info[complex_category][name]['uses'].add(member_type)
|
||||||
|
self.vulkan_node_info[self.vulkan_names[member_type]][member_type]['used_by'].add(name)
|
||||||
|
elif member_type in self.vulkan_node_info['basetype']:
|
||||||
|
self.vulkan_node_info[complex_category][name]['uses'].add(member_type)
|
||||||
|
self.vulkan_node_info['basetype'][member_type]['used_by'].add(name)
|
||||||
|
for function_category in ['callback', 'command']:
|
||||||
|
for name in self.vulkan_node_info[function_category]:
|
||||||
|
for node in self.nodes.get(name, []):
|
||||||
|
node: Node
|
||||||
|
if 'proto' not in node.children:
|
||||||
|
continue
|
||||||
|
for decl_node in node.get_all('param') + [node.get('proto')]:
|
||||||
|
if not self.is_valid_api(decl_node):
|
||||||
|
continue
|
||||||
|
type_node = decl_node.get('type')
|
||||||
|
if type_node is None:
|
||||||
|
continue
|
||||||
|
param_type = self._resolve_type(type_node.get_text())
|
||||||
|
if param_type.startswith('PFN_'):
|
||||||
|
param_type = param_type[4:]
|
||||||
|
param_type = self._resolve_alias(param_type)
|
||||||
|
if param_type in self.vulkan_names:
|
||||||
|
self.vulkan_node_info[function_category][name]['uses'].add(param_type)
|
||||||
|
self.vulkan_node_info[self.vulkan_names[param_type]][param_type]['used_by'].add(name)
|
||||||
|
elif member_type in self.vulkan_node_info['basetype']:
|
||||||
|
self.vulkan_node_info[complex_category][name]['uses'].add(member_type)
|
||||||
|
self.vulkan_node_info['basetype'][member_type]['used_by'].add(name)
|
||||||
|
for name in self.vulkan_node_info['handle']:
|
||||||
|
for node in self.nodes.get(name, []):
|
||||||
|
node: Node
|
||||||
|
if 'type' not in node.children or 'name' not in node.children:
|
||||||
|
continue
|
||||||
|
if node.has_attribute('parent'):
|
||||||
|
parent_name = node.get_attribute('parent')
|
||||||
|
self.handle_parent[name] = parent_name
|
||||||
|
self.vulkan_node_info['handle'][name]['uses'].add(parent_name)
|
||||||
|
self.vulkan_node_info['handle'][parent_name]['used_by'].add(name)
|
||||||
|
handle_type = node.get('type').get_text()
|
||||||
|
if handle_type in self.vulkan_names:
|
||||||
|
self.vulkan_node_info['handle'][name]['uses'].add(handle_type)
|
||||||
|
self.vulkan_node_info[self.vulkan_names[handle_type]][handle_type]['used_by'].add(name)
|
||||||
|
elif member_type in self.vulkan_node_info['basetype']:
|
||||||
|
self.vulkan_node_info[complex_category][name]['uses'].add(member_type)
|
||||||
|
self.vulkan_node_info['basetype'][member_type]['used_by'].add(name)
|
||||||
|
|
||||||
|
def _reverse_feature_dependecies(self):
|
||||||
|
def add(target_feature: str, current_feature: str, visited: set[str]):
|
||||||
|
self.feature_dependent_map[target_feature].add(current_feature)
|
||||||
|
if current_feature in visited:
|
||||||
|
return
|
||||||
|
loop(target_feature, current_feature, visited)
|
||||||
|
|
||||||
|
def loop(target_feature: str, current_feature: str, visited: set[str]):
|
||||||
|
for dependency in self.feature_dependency_map.get(current_feature, set()):
|
||||||
|
add(target_feature, dependency, visited | {current_feature})
|
||||||
|
|
||||||
|
for feature_name in self.feature_names:
|
||||||
|
self.feature_dependent_map.setdefault(feature_name, set())
|
||||||
|
loop(feature_name, feature_name, set())
|
||||||
|
|
||||||
|
def _resolve_extends(self):
|
||||||
|
for name in self.vulkan_node_info['struct']:
|
||||||
|
for node in self.nodes.get(name, []):
|
||||||
|
node: Node
|
||||||
|
if 'member' not in node.children:
|
||||||
|
continue
|
||||||
|
if not node.has_attribute('structextends'):
|
||||||
|
continue
|
||||||
|
extend_list = {x.strip() for x in node.get_attribute('structextends').split(',')}
|
||||||
|
for extend in extend_list:
|
||||||
|
if extend in self.vulkan_node_info['struct']:
|
||||||
|
self.vulkan_node_info['struct'][name]['extends'].add(extend)
|
||||||
|
self.vulkan_node_info['struct'][extend]['extended_by'].add(name)
|
||||||
|
|
||||||
|
def _apply_ctype_aliases(self):
|
||||||
|
for name in self.alias_target_map:
|
||||||
|
self.ctypes.update(self.alias_target_map[name])
|
||||||
|
|
||||||
|
def _resolve_type_name(self, type_name: str) -> str:
|
||||||
|
type_name = self._resolve_alias(type_name)
|
||||||
|
if type_name.startswith('PFN_'):
|
||||||
|
type_name = type_name[4:]
|
||||||
|
if type_name in self.bit_bitmask_map:
|
||||||
|
type_name = self.bit_bitmask_map[type_name]
|
||||||
|
type_name = self._resolve_alias(type_name)
|
||||||
|
return type_name
|
||||||
|
|
||||||
|
def _init_members(self):
|
||||||
|
for category in ['struct', 'union']:
|
||||||
|
for name, info in self.vulkan_node_info[category].items():
|
||||||
|
members = info['members'] = OrderedDict()
|
||||||
|
for node in self.nodes.get(name, []):
|
||||||
|
node: Node
|
||||||
|
if 'member' not in node.children:
|
||||||
|
continue
|
||||||
|
info['node'] = node
|
||||||
|
for member_node in node.get_all('member'):
|
||||||
|
if not self.is_valid_api(member_node):
|
||||||
|
continue
|
||||||
|
member_info = {}
|
||||||
|
if 'name' not in member_node.children:
|
||||||
|
raise ValueError(f'Member node {member_node} of {category} {name} is missing a name')
|
||||||
|
member_info['node'] = member_node
|
||||||
|
member_name = member_node.get('name').get_text()
|
||||||
|
members[member_name] = member_info
|
||||||
|
if 'type' not in member_node.children:
|
||||||
|
member_info['class'] = 'unknown'
|
||||||
|
continue
|
||||||
|
member_type = self._resolve_type_name(member_node.get('type').get_text())
|
||||||
|
if member_type in self.vulkan_names:
|
||||||
|
member_info['class'] = self.vulkan_names[member_type]
|
||||||
|
member_info['type'] = member_type
|
||||||
|
else:
|
||||||
|
member_info['class'] = 'external'
|
||||||
|
member_info['type'] = member_type
|
||||||
|
|
||||||
|
def _init_arguments(self):
|
||||||
|
for category in ['command', 'callback']:
|
||||||
|
for name, info in self.vulkan_node_info[category].items():
|
||||||
|
arguments = info['arguments'] = OrderedDict()
|
||||||
|
for node in self.nodes.get(name, []):
|
||||||
|
node: Node
|
||||||
|
if 'proto' not in node.children:
|
||||||
|
continue
|
||||||
|
info['node'] = node
|
||||||
|
proto_node = node.get('proto')
|
||||||
|
info['return'] = return_info = {}
|
||||||
|
return_info['node'] = proto_node
|
||||||
|
if 'type' in proto_node.children:
|
||||||
|
return_type = self._resolve_type_name(proto_node.get('type').get_text())
|
||||||
|
if return_type in self.vulkan_names:
|
||||||
|
return_info['class'] = self.vulkan_names[return_type]
|
||||||
|
return_info['type'] = return_type
|
||||||
|
else:
|
||||||
|
return_info['class'] = 'ctype' if return_type in self.ctypes else 'external'
|
||||||
|
return_info['type'] = return_type
|
||||||
|
else:
|
||||||
|
return_info['class'] = 'unknown'
|
||||||
|
for argument_node in node.get_all('param'):
|
||||||
|
if not self.is_valid_api(argument_node):
|
||||||
|
continue
|
||||||
|
argument_info = {}
|
||||||
|
if 'name' not in argument_node.children:
|
||||||
|
raise ValueError(f'Argument node {argument_node} of {category} {name} is missing a name')
|
||||||
|
argument_info['node'] = argument_node
|
||||||
|
argument_name = argument_node.get('name').get_text()
|
||||||
|
arguments[argument_name] = argument_info
|
||||||
|
if 'type' not in argument_node.children:
|
||||||
|
argument_info['class'] = 'unknown'
|
||||||
|
continue
|
||||||
|
argument_type = self._resolve_type_name(argument_node.get('type').get_text())
|
||||||
|
if argument_type in self.vulkan_names:
|
||||||
|
argument_info['class'] = self.vulkan_names[argument_type]
|
||||||
|
argument_info['type'] = argument_type
|
||||||
|
else:
|
||||||
|
argument_info['class'] = 'ctype' if argument_type in self.ctypes else 'external'
|
||||||
|
argument_info['type'] = argument_type
|
||||||
|
|
||||||
|
def _init_handles(self):
|
||||||
|
for name, info in self.vulkan_node_info['handle'].items():
|
||||||
|
for node in self.nodes.get(name, []):
|
||||||
|
node: Node
|
||||||
|
if 'type' not in node.children or 'name' not in node.children or not node.has_attribute('objtypeenum'):
|
||||||
|
continue
|
||||||
|
info['parent'] = node.get_attribute('parent') if node.has_attribute('parent') else None
|
||||||
|
object_type = node.get_attribute('objtypeenum')
|
||||||
|
if not object_type.startswith('VK_OBJECT_TYPE_'):
|
||||||
|
raise ValueError(f'Handle node {node} of handle {name} has invalid object type enum {object_type}')
|
||||||
|
info['VkObjectType'] = object_type
|
||||||
|
info['VkDebugReportObjectTypeEXT'] = PREFIX_DEBUG_REPORT_OBJECT_TYPE + object_type[len(PREFIX_OBJECT_TYPE):]
|
||||||
|
info['path'] = []
|
||||||
|
info['output_of'] = set()
|
||||||
|
info['destroyed_by'] = set()
|
||||||
|
for name, info in self.vulkan_node_info['handle'].items():
|
||||||
|
path_name = name
|
||||||
|
while path_name is not None:
|
||||||
|
info['path'].append(path_name)
|
||||||
|
path_name = self.handle_parent.get(path_name, None)
|
||||||
|
|
||||||
|
def _search_for_handle_output(self, category: str, name: str, /, *path) -> set[str]:
|
||||||
|
output_handles = set()
|
||||||
|
if name in path:
|
||||||
|
return output_handles
|
||||||
|
info = self.vulkan_node_info[category][name]
|
||||||
|
for member_info in info['members'].values():
|
||||||
|
member_node = member_info['node']
|
||||||
|
member_node: Node
|
||||||
|
member_ctype = member_node.get_text_before(member_node.get('name'))
|
||||||
|
ptr_count = member_ctype.count('*')
|
||||||
|
if 'const' in member_ctype:
|
||||||
|
continue
|
||||||
|
if ptr_count > 0:
|
||||||
|
if member_info['class'] == 'handle' and member_info['type'] in self.vulkan_node_info['handle']:
|
||||||
|
output_handles.add(member_info['type'])
|
||||||
|
continue
|
||||||
|
if member_info['class'] in ('struct', 'union') and member_info['type'] in self.vulkan_node_info['struct']:
|
||||||
|
result = self._search_for_handle_output(member_info['class'], member_info['type'], *path, name)
|
||||||
|
output_handles.update(result)
|
||||||
|
return output_handles
|
||||||
|
|
||||||
|
def _init_handle_output(self):
|
||||||
|
for command_name, command_info in self.vulkan_node_info['command'].items():
|
||||||
|
for arg_info in command_info['arguments'].values():
|
||||||
|
arg_node = arg_info['node']
|
||||||
|
arg_node: Node
|
||||||
|
arg_ctype = arg_node.get_text_before(arg_node.get('name'))
|
||||||
|
ptr_count = arg_ctype.count('*')
|
||||||
|
if 'const' in arg_ctype:
|
||||||
|
continue
|
||||||
|
if ptr_count > 0:
|
||||||
|
if arg_info['class'] == 'handle' and arg_info['type'] in self.vulkan_node_info['handle']:
|
||||||
|
self.vulkan_node_info['handle'][arg_info['type']]['output_of'].add(command_name)
|
||||||
|
elif arg_info['class'] in ('struct', 'union') and arg_info['type'] in self.vulkan_node_info['struct']:
|
||||||
|
output_handles = self._search_for_handle_output(arg_info['class'], arg_info['type'])
|
||||||
|
for handle in output_handles:
|
||||||
|
self.vulkan_node_info['handle'][handle]['output_of'].add(command_name)
|
||||||
|
|
||||||
|
def _init_handle_destroy(self):
|
||||||
|
for command_name, command_info in self.vulkan_node_info['command'].items():
|
||||||
|
if not any(word in command_name for word in ['Destroy', 'Free', 'Release']):
|
||||||
|
continue
|
||||||
|
handle_params = {}
|
||||||
|
for arg_name, arg_info in command_info['arguments'].items():
|
||||||
|
if arg_info['class'] == 'handle' and arg_info['type'] in self.vulkan_node_info['handle']:
|
||||||
|
handle_params[arg_name] = arg_info['type']
|
||||||
|
target_handle_name = None
|
||||||
|
target_handle_path_length = -1
|
||||||
|
for arg_name, target_handle_name in handle_params.items():
|
||||||
|
handle_path_length = len(self.vulkan_node_info['handle'][target_handle_name]['path'])
|
||||||
|
if handle_path_length > target_handle_path_length:
|
||||||
|
target_handle_name = target_handle_name
|
||||||
|
target_handle_path_length = handle_path_length
|
||||||
|
expected_parameters = set()
|
||||||
|
additional_parameters = set()
|
||||||
|
for arg_name, arg_info in command_info['arguments'].items():
|
||||||
|
if arg_name in expected_parameters:
|
||||||
|
continue
|
||||||
|
arg_node = arg_info['node']
|
||||||
|
arg_node: Node
|
||||||
|
if arg_node.has_attribute('len') and not arg_node.has_attribute('altlen'):
|
||||||
|
length = [s.strip() for s in arg_node.get_attribute('len').split(',') if s.strip().lower() != 'null-terminated']
|
||||||
|
for length_arg in length:
|
||||||
|
length_words = [word.strip() for word in re.split(r'\b', length_arg) if word.strip()]
|
||||||
|
if len(length_words) > 0 and length_words[0] in command_info['arguments']:
|
||||||
|
expected_parameters.add(length_words[0])
|
||||||
|
continue
|
||||||
|
if arg_info['class'] == 'handle' and arg_info['type'] in self.vulkan_node_info['handle']:
|
||||||
|
expected_parameters.add(arg_name)
|
||||||
|
continue
|
||||||
|
if arg_info['class'] == 'struct' and arg_info['type'] == 'VkAllocationCallbacks':
|
||||||
|
expected_parameters.add(arg_name)
|
||||||
|
continue
|
||||||
|
additional_parameters.add(arg_name)
|
||||||
|
additional_parameters = additional_parameters - expected_parameters
|
||||||
|
if len(additional_parameters) > 0:
|
||||||
|
continue
|
||||||
|
target_handle_qualname = target_handle_name
|
||||||
|
for tag in self.tags:
|
||||||
|
if target_handle_qualname.endswith(tag):
|
||||||
|
target_handle_qualname = target_handle_qualname[:-len(tag)]
|
||||||
|
break
|
||||||
|
handle_words = re.split(r'(?<!^)(?=[A-Z])', target_handle_qualname)[1:]
|
||||||
|
handle_words = [target_handle_qualname] + handle_words
|
||||||
|
if not any(word in command_name for word in handle_words):
|
||||||
|
continue
|
||||||
|
self.vulkan_node_info['handle'][target_handle_name]['destroyed_by'].add(command_name)
|
||||||
|
for handle_name, handle_info in self.vulkan_node_info['handle'].items():
|
||||||
|
if len(handle_info['destroyed_by']) > 1:
|
||||||
|
raise ValueError(f'Handle {handle_name} is destroyed by multiple commands: {handle_info["destroyed_by"]}')
|
||||||
|
if len(handle_info['destroyed_by']) == 1:
|
||||||
|
handle_info['destroyed_by'] = next(iter(handle_info['destroyed_by']))
|
||||||
|
else:
|
||||||
|
handle_info['destroyed_by'] = None
|
||||||
|
|
||||||
|
def _init_relationship_complex(self, command_name: str, complex_name: str, relationship_type: str, /, *visited: str):
|
||||||
|
if complex_name in visited:
|
||||||
|
return
|
||||||
|
category = self.vulkan_names[complex_name]
|
||||||
|
complex_info = self.vulkan_node_info[category][complex_name]
|
||||||
|
complex_info[relationship_type].add(command_name)
|
||||||
|
if category == 'struct':
|
||||||
|
for extending_struct in complex_info['extended_by']:
|
||||||
|
self._init_relationship_complex(command_name, extending_struct, relationship_type, *visited, complex_name)
|
||||||
|
for member_info in complex_info['members'].values():
|
||||||
|
if member_info['class'] in ('struct', 'union'):
|
||||||
|
self._init_relationship_complex(command_name, member_info['type'], relationship_type, *visited, complex_name)
|
||||||
|
|
||||||
|
def _init_io(self):
|
||||||
|
for command_name, command_info in self.vulkan_node_info['command'].items():
|
||||||
|
for arg_info in command_info['arguments'].values():
|
||||||
|
if arg_info['class'] == 'struct':
|
||||||
|
arg_node = arg_info['node']
|
||||||
|
arg_node: Node
|
||||||
|
arg_type_prefix = arg_node.get_text_before(arg_node.get('type')).strip()
|
||||||
|
arg_type_suffix = arg_node.get_text_after(arg_node.get('type')).strip()
|
||||||
|
relationship_type = 'input_of' if 'const' in arg_type_prefix or arg_type_suffix.startswith('const') else 'output_of'
|
||||||
|
if arg_info['class'] in ('struct', 'union'):
|
||||||
|
self._init_relationship_complex(command_name, arg_info['type'], relationship_type)
|
||||||
|
|
||||||
257
src/dragiyski/vulkan/registry/xml.py
Normal file
257
src/dragiyski/vulkan/registry/xml.py
Normal file
@@ -0,0 +1,257 @@
|
|||||||
|
from xml.parsers import expat
|
||||||
|
from functools import cached_property
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Optional, Iterable
|
||||||
|
|
||||||
|
|
||||||
|
class Node:
|
||||||
|
class MultipleChildrenError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def __init__(self, node_name: str, node_value: str, node_type: str, attributes: dict = {}):
|
||||||
|
self.child_nodes = []
|
||||||
|
self.children = {}
|
||||||
|
self.parent_node = None
|
||||||
|
self.parent_index = None
|
||||||
|
self.parent_name_index = None
|
||||||
|
self.node_name = node_name
|
||||||
|
self.attributes = dict(attributes)
|
||||||
|
self.node_type = node_type
|
||||||
|
self.node_value = node_value
|
||||||
|
|
||||||
|
def has_attribute(self, name: str) -> bool:
|
||||||
|
return name in self.attributes
|
||||||
|
|
||||||
|
def get_attribute(self, name: str, default=None) -> str:
|
||||||
|
if self.has_attribute(name):
|
||||||
|
return self.attributes[name]
|
||||||
|
return default
|
||||||
|
|
||||||
|
def set_attribute(self, name: str, value) -> None:
|
||||||
|
if value is None:
|
||||||
|
if name in self.attributes:
|
||||||
|
del self.attributes[name]
|
||||||
|
else:
|
||||||
|
self.attributes[name] = str(value)
|
||||||
|
|
||||||
|
def get(self, name: str, default=None) -> 'Optional[Node]':
|
||||||
|
if name not in self.children:
|
||||||
|
return default
|
||||||
|
node_list = self.children[name]
|
||||||
|
if len(node_list) > 1:
|
||||||
|
raise Node.MultipleChildrenError(f'{self.file_path}: Expected 1 child with name "{name}", got {len(node_list)} children')
|
||||||
|
elif len(node_list) == 0:
|
||||||
|
return default
|
||||||
|
return node_list[0]
|
||||||
|
|
||||||
|
def get_all(self, name: str) -> 'list[Node]':
|
||||||
|
if name not in self.children:
|
||||||
|
return []
|
||||||
|
return self.children[name]
|
||||||
|
|
||||||
|
def tree_get_all(self, name: str) -> 'Iterable[Node]':
|
||||||
|
if self.node_name == name:
|
||||||
|
yield self
|
||||||
|
for child in self.child_nodes:
|
||||||
|
yield from child.tree_get_all(name)
|
||||||
|
|
||||||
|
def append_child(self, node):
|
||||||
|
if node.node_name not in self.children:
|
||||||
|
self.children[node.node_name] = []
|
||||||
|
child_index = len(self.child_nodes)
|
||||||
|
child_name_index = len(self.children[node.node_name])
|
||||||
|
node.parent_node = self
|
||||||
|
node.parent_index = child_index
|
||||||
|
node.parent_name_index = child_name_index
|
||||||
|
self.child_nodes.append(node)
|
||||||
|
self.children[node.node_name].append(node)
|
||||||
|
|
||||||
|
def get_text_nodes(self, *, skip_comments=True) -> 'Iterable[Node]':
|
||||||
|
for child in self.child_nodes:
|
||||||
|
if child.node_type == 'text':
|
||||||
|
yield child
|
||||||
|
elif child.node_type == 'element':
|
||||||
|
if skip_comments and child.node_name == 'comment':
|
||||||
|
continue
|
||||||
|
yield from child.get_text_nodes(skip_comments=skip_comments)
|
||||||
|
|
||||||
|
def get_text(self, *, skip_comments=True) -> str:
|
||||||
|
if self.node_type == 'text':
|
||||||
|
return self.node_value
|
||||||
|
elif self.node_type == 'element':
|
||||||
|
return ''.join([x.node_value for x in self.get_text_nodes(skip_comments=skip_comments)])
|
||||||
|
else:
|
||||||
|
return ''
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def path(self) -> 'list[str]':
|
||||||
|
return (self.parent_node.path if self.parent_node is not None else []) + [self.node_name]
|
||||||
|
|
||||||
|
def get_text_nodes_before(self, node, *, skip_comments=True):
|
||||||
|
items = []
|
||||||
|
self._get_text_nodes_before(node, items, skip_comments=skip_comments)
|
||||||
|
return items
|
||||||
|
|
||||||
|
def get_text_nodes_after(self, node, *, skip_comments=True):
|
||||||
|
items = []
|
||||||
|
self._get_text_nodes_after(node, items, skip_comments=skip_comments)
|
||||||
|
return items
|
||||||
|
|
||||||
|
def get_text_before(self, node, *, skip_comments=True):
|
||||||
|
return ''.join([n.get_text() for n in self.get_text_nodes_before(node, skip_comments=skip_comments)])
|
||||||
|
|
||||||
|
def get_text_after(self, node, *, skip_comments=True):
|
||||||
|
return ''.join([n.get_text() for n in self.get_text_nodes_after(node, skip_comments=skip_comments)])
|
||||||
|
|
||||||
|
def _get_text_nodes_before(self, node, items, *, skip_comments=True):
|
||||||
|
return_value = True
|
||||||
|
for child in self.child_nodes:
|
||||||
|
if not return_value:
|
||||||
|
break
|
||||||
|
if child is node:
|
||||||
|
return False
|
||||||
|
if child.node_type == 'text':
|
||||||
|
items.append(child)
|
||||||
|
elif child.node_type == 'element':
|
||||||
|
if skip_comments and child.node_name == 'comment':
|
||||||
|
continue
|
||||||
|
return_value = child._get_text_nodes_before(node, items)
|
||||||
|
return return_value
|
||||||
|
|
||||||
|
def _get_text_nodes_after(self, node, items, *, skip_comments=True):
|
||||||
|
return_value = True
|
||||||
|
for child in reversed(self.child_nodes):
|
||||||
|
if not return_value:
|
||||||
|
break
|
||||||
|
if child is node:
|
||||||
|
return False
|
||||||
|
if child.node_type == 'text':
|
||||||
|
items.insert(0, child)
|
||||||
|
elif child.node_type == 'element':
|
||||||
|
if skip_comments and child.node_name == 'comment':
|
||||||
|
continue
|
||||||
|
return_value = child._get_text_nodes_after(node, items)
|
||||||
|
return return_value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def previous_sibling(self) -> 'Optional[Node]':
|
||||||
|
if self.parent_node is None:
|
||||||
|
return None
|
||||||
|
assert isinstance(self.parent_index, int)
|
||||||
|
if self.parent_index <= 0:
|
||||||
|
return None
|
||||||
|
return self.parent_node.child_nodes[self.parent_index - 1]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def next_sibling(self) -> 'Optional[Node]':
|
||||||
|
if self.parent_node is None:
|
||||||
|
return None
|
||||||
|
assert isinstance(self.parent_index, int)
|
||||||
|
try:
|
||||||
|
return self.parent_node.child_nodes[self.parent_index + 1]
|
||||||
|
except IndexError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def previous_sibling_element(self) -> 'Optional[Node]':
|
||||||
|
sibling = self.previous_sibling
|
||||||
|
while sibling is not None:
|
||||||
|
if sibling.node_type == 'element':
|
||||||
|
return sibling
|
||||||
|
sibling = sibling.previous_sibling
|
||||||
|
return None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def next_sibling_element(self) -> 'Optional[Node]':
|
||||||
|
sibling = self.next_sibling
|
||||||
|
while sibling is not None:
|
||||||
|
if sibling.node_type == 'element':
|
||||||
|
return sibling
|
||||||
|
sibling = sibling.next_sibling
|
||||||
|
return None
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def root(self) -> 'Optional[Node]':
|
||||||
|
if self.parent_node is None:
|
||||||
|
return self
|
||||||
|
return self.parent_node.root
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def file_path(self) -> str:
|
||||||
|
return f'{self.root.file}:{self.line}:{self.column}'
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def file_url(self) -> str:
|
||||||
|
return f'{self.root.url}:{self.line}:{self.column}'
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
path = '/'.join(self.path)
|
||||||
|
return f'<XMLNode {path} at {self.file_url} object at {hex(id(self))}>'
|
||||||
|
|
||||||
|
|
||||||
|
def parse_xml(document, *, is_file=False) -> Node:
|
||||||
|
root = None
|
||||||
|
parent = None
|
||||||
|
|
||||||
|
filename = document
|
||||||
|
if not is_file:
|
||||||
|
filename = f'document:{hash(document)}'
|
||||||
|
url = filename
|
||||||
|
else:
|
||||||
|
url = Path(document).absolute().as_uri()
|
||||||
|
|
||||||
|
def on_xml_root_start(name, attributes):
|
||||||
|
nonlocal root
|
||||||
|
nonlocal parent
|
||||||
|
nonlocal xml_element_start_parser
|
||||||
|
nonlocal parser
|
||||||
|
root = parent = Node(name, None, 'element', attributes)
|
||||||
|
setattr(root, 'file', filename)
|
||||||
|
setattr(root, 'url', url)
|
||||||
|
setattr(root, 'line', parser.CurrentLineNumber)
|
||||||
|
setattr(root, 'column', parser.CurrentColumnNumber)
|
||||||
|
setattr(root, 'file_offset', parser.CurrentByteIndex)
|
||||||
|
xml_element_start_parser = on_xml_non_root_start
|
||||||
|
|
||||||
|
def on_xml_non_root_start(name, attributes):
|
||||||
|
nonlocal parent
|
||||||
|
nonlocal parser
|
||||||
|
element = Node(name, None, 'element', attributes)
|
||||||
|
setattr(element, 'line', parser.CurrentLineNumber)
|
||||||
|
setattr(element, 'column', parser.CurrentColumnNumber)
|
||||||
|
setattr(element, 'file_offset', parser.CurrentByteIndex)
|
||||||
|
parent.append_child(element)
|
||||||
|
parent = element
|
||||||
|
|
||||||
|
def on_xml_element_end(name):
|
||||||
|
nonlocal parent
|
||||||
|
assert parent is not None and isinstance(parent, Node)
|
||||||
|
assert parent.node_name == name
|
||||||
|
parent = parent.parent_node
|
||||||
|
|
||||||
|
def on_xml_character_data(data):
|
||||||
|
nonlocal parent
|
||||||
|
nonlocal parser
|
||||||
|
node = Node('#text', data, 'text')
|
||||||
|
setattr(node, 'line', parser.CurrentLineNumber)
|
||||||
|
setattr(node, 'column', parser.CurrentColumnNumber)
|
||||||
|
setattr(node, 'file_offset', parser.CurrentByteIndex)
|
||||||
|
parent.append_child(node)
|
||||||
|
|
||||||
|
def on_xml_element_start(*args, **kwargs):
|
||||||
|
nonlocal xml_element_start_parser
|
||||||
|
return xml_element_start_parser(*args, **kwargs)
|
||||||
|
|
||||||
|
xml_element_start_parser = on_xml_root_start
|
||||||
|
parser = expat.ParserCreate(encoding='utf-8')
|
||||||
|
parser.StartElementHandler = on_xml_element_start
|
||||||
|
parser.EndElementHandler = on_xml_element_end
|
||||||
|
parser.CharacterDataHandler = on_xml_character_data
|
||||||
|
|
||||||
|
if is_file:
|
||||||
|
with open(document, 'rb') as file:
|
||||||
|
parser.ParseFile(file)
|
||||||
|
else:
|
||||||
|
parser.Parse(document)
|
||||||
|
|
||||||
|
return root
|
||||||
325
tests/test_node.py
Normal file
325
tests/test_node.py
Normal file
@@ -0,0 +1,325 @@
|
|||||||
|
import unittest
|
||||||
|
|
||||||
|
|
||||||
|
class TestNode(unittest.TestCase):
|
||||||
|
def test_is_class(self):
|
||||||
|
from dragiyski.vulkan.registry.xml import Node
|
||||||
|
assert isinstance(Node, type)
|
||||||
|
|
||||||
|
def test_function_exists_parse_xml(self):
|
||||||
|
from dragiyski.vulkan.registry.xml import parse_xml
|
||||||
|
assert callable(parse_xml)
|
||||||
|
|
||||||
|
def test_node_simple_xml(self):
|
||||||
|
from dragiyski.vulkan.registry.xml import Node, parse_xml
|
||||||
|
xml_content = '''<root attr="value">
|
||||||
|
<child>Text</child>
|
||||||
|
<!-- A comment -->
|
||||||
|
<child2>More Text</child2>
|
||||||
|
<child3>
|
||||||
|
<text>Some Text</text>
|
||||||
|
<text>More Text</text>
|
||||||
|
<text>Even More Text</text>
|
||||||
|
</child3>
|
||||||
|
</root>'''
|
||||||
|
root = parse_xml(xml_content)
|
||||||
|
assert isinstance(root, Node)
|
||||||
|
assert root.node_name == 'root'
|
||||||
|
assert root.has_attribute('attr')
|
||||||
|
assert root.get_attribute('attr') == 'value'
|
||||||
|
assert 'child' in root.children
|
||||||
|
assert 'child2' in root.children
|
||||||
|
assert root.get('child') is root.children['child'][0]
|
||||||
|
assert root.get('child2') is root.children['child2'][0]
|
||||||
|
child_index = root.child_nodes.index(root.get('child'))
|
||||||
|
child2_index = root.child_nodes.index(root.get('child2'))
|
||||||
|
child3_index = root.child_nodes.index(root.get('child3'))
|
||||||
|
assert child_index < child2_index
|
||||||
|
assert child2_index < child3_index
|
||||||
|
for i in range(len(root.child_nodes)):
|
||||||
|
if i not in (child_index, child2_index, child3_index):
|
||||||
|
assert root.child_nodes[i].node_type == 'text'
|
||||||
|
assert root.child_nodes[i].node_name == '#text'
|
||||||
|
|
||||||
|
root.set_attribute('attr', 'foo')
|
||||||
|
assert root.get_attribute('attr') == 'foo'
|
||||||
|
assert root.has_attribute('new_attr') is False
|
||||||
|
root.set_attribute('new_attr', 'new_value')
|
||||||
|
assert root.has_attribute('new_attr') is True
|
||||||
|
assert root.get_attribute('new_attr') == 'new_value'
|
||||||
|
root.set_attribute('new_attr', None)
|
||||||
|
assert root.has_attribute('new_attr') is False
|
||||||
|
assert root.get_attribute('new_attr', 'default') == 'default'
|
||||||
|
assert root.get_attribute('new_attr', 5) == 5
|
||||||
|
assert root.get_attribute('new_attr') is None
|
||||||
|
assert root.has_attribute('not_existing') is False
|
||||||
|
root.set_attribute('not_existing', None)
|
||||||
|
assert root.has_attribute('not_existing') is False
|
||||||
|
assert root.get('not_existing', 'default') == 'default'
|
||||||
|
assert root.get('not_existing', 5) == 5
|
||||||
|
assert root.get('not_existing') is None
|
||||||
|
|
||||||
|
child1_node = root.get('child')
|
||||||
|
assert isinstance(child1_node, Node)
|
||||||
|
assert child1_node.node_name == 'child'
|
||||||
|
child2_node = root.get('child2')
|
||||||
|
assert isinstance(child2_node, Node)
|
||||||
|
assert child2_node.node_name == 'child2'
|
||||||
|
child3_node = root.get('child3')
|
||||||
|
assert isinstance(child3_node, Node)
|
||||||
|
assert child3_node.node_name == 'child3'
|
||||||
|
self.assertRaises(Node.MultipleChildrenError, lambda: child3_node.get('text'))
|
||||||
|
|
||||||
|
assert child1_node.next_sibling_element is child2_node
|
||||||
|
assert child2_node.previous_sibling_element is child1_node
|
||||||
|
assert child2_node.next_sibling_element is child3_node
|
||||||
|
assert child3_node.previous_sibling_element is child2_node
|
||||||
|
assert child1_node.previous_sibling_element is None
|
||||||
|
assert child3_node.next_sibling_element is None
|
||||||
|
|
||||||
|
assert child3_node.root == root
|
||||||
|
assert root.root == root
|
||||||
|
|
||||||
|
child3_node.children['text'].clear()
|
||||||
|
assert child3_node.get('text', 'default') == 'default'
|
||||||
|
assert child3_node.get('text', 5) == 5
|
||||||
|
assert child3_node.get('text') is None
|
||||||
|
|
||||||
|
assert root.previous_sibling is None
|
||||||
|
assert root.next_sibling is None
|
||||||
|
|
||||||
|
assert root.child_nodes[0].previous_sibling is None
|
||||||
|
assert root.child_nodes[0].next_sibling is root.child_nodes[1]
|
||||||
|
|
||||||
|
assert root.child_nodes[1].previous_sibling is root.child_nodes[0]
|
||||||
|
assert root.child_nodes[1].next_sibling is root.child_nodes[2]
|
||||||
|
|
||||||
|
assert root.child_nodes[-1].previous_sibling is root.child_nodes[-2]
|
||||||
|
assert root.child_nodes[-1].next_sibling is None
|
||||||
|
|
||||||
|
assert root.get_all('not_existing') == []
|
||||||
|
|
||||||
|
def test_node_tree_get_all(self):
|
||||||
|
from dragiyski.vulkan.registry.xml import Node, parse_xml
|
||||||
|
xml_content = '''<root>
|
||||||
|
<child>
|
||||||
|
<test>Text0</test>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<other>
|
||||||
|
<subchild>Text1</subchild>
|
||||||
|
<test>Text1</test>
|
||||||
|
</other>
|
||||||
|
</child>
|
||||||
|
<other>
|
||||||
|
<other test="test">
|
||||||
|
<subchild>
|
||||||
|
<nested>With some <test>Text2</test> before and after.</nested>
|
||||||
|
</subchild>
|
||||||
|
</other>
|
||||||
|
</other>
|
||||||
|
</root>'''
|
||||||
|
result = parse_xml(xml_content)
|
||||||
|
assert isinstance(result, Node)
|
||||||
|
i = 0
|
||||||
|
paths = [
|
||||||
|
[
|
||||||
|
'root',
|
||||||
|
'child',
|
||||||
|
'test'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'root',
|
||||||
|
'child',
|
||||||
|
'other',
|
||||||
|
'test'],
|
||||||
|
[
|
||||||
|
'root',
|
||||||
|
'other',
|
||||||
|
'other',
|
||||||
|
'subchild',
|
||||||
|
'nested',
|
||||||
|
'test'
|
||||||
|
],
|
||||||
|
]
|
||||||
|
for node in result.tree_get_all('test'):
|
||||||
|
assert node.get_text() == f'Text{i}'
|
||||||
|
assert node.path == paths[i]
|
||||||
|
i += 1
|
||||||
|
assert i == 3
|
||||||
|
|
||||||
|
def test_node_get_text(self):
|
||||||
|
from dragiyski.vulkan.registry.xml import Node, parse_xml
|
||||||
|
xml_content = '''<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<registry>
|
||||||
|
<comment>
|
||||||
|
Copyright 2015-2025 The Khronos Group Inc.
|
||||||
|
|
||||||
|
SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
|
</comment>
|
||||||
|
<types comment="Vulkan type definitions">
|
||||||
|
<type category="struct" name="VkMemoryDedicatedAllocateInfoTensorARM" structextends="VkMemoryAllocateInfo">
|
||||||
|
<member values="VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_TENSOR_ARM"><type>VkStructureType</type> <name>sType</name></member>
|
||||||
|
<member><comment>const </comment><type>VkTensorARM</type> <name>tensor</name><comment>Tensor that this allocation will be bound to</comment></member>
|
||||||
|
<member optional="true">const <type>void</type>* <name>pNext</name></member>
|
||||||
|
</type>
|
||||||
|
</types>
|
||||||
|
</registry>
|
||||||
|
'''
|
||||||
|
result = parse_xml(xml_content)
|
||||||
|
assert isinstance(result, Node)
|
||||||
|
assert result.get('types').get('type').get_all('member')[0].get_text() == 'VkStructureType sType'
|
||||||
|
assert result.get('types').get('type').get_all('member')[1].get_text() == 'VkTensorARM tensor'
|
||||||
|
assert result.get('types').get('type').get_all('member')[2].get_text() == 'const void* pNext'
|
||||||
|
assert result.get('types').get('type').get_all('member')[0].get_text(skip_comments=True) == 'VkStructureType sType'
|
||||||
|
assert result.get('types').get('type').get_all('member')[1].get_text(skip_comments=True) == 'VkTensorARM tensor'
|
||||||
|
assert result.get('types').get('type').get_all('member')[2].get_text(skip_comments=True) == 'const void* pNext'
|
||||||
|
assert result.get('types').get('type').get_all('member')[0].get_text(skip_comments=False) == 'VkStructureType sType'
|
||||||
|
assert result.get('types').get('type').get_all('member')[1].get_text(skip_comments=False) == 'const VkTensorARM tensorTensor that this allocation will be bound to'
|
||||||
|
assert result.get('types').get('type').get_all('member')[2].get_text(skip_comments=False) == 'const void* pNext'
|
||||||
|
s = result.get('types').get('type').get_text()
|
||||||
|
assert result.get('types').get('type').get_text() == '''
|
||||||
|
VkStructureType sType
|
||||||
|
VkTensorARM tensor
|
||||||
|
const void* pNext
|
||||||
|
'''
|
||||||
|
|
||||||
|
text_list = [
|
||||||
|
[
|
||||||
|
'\n',
|
||||||
|
' ',
|
||||||
|
'VkStructureType',
|
||||||
|
' ',
|
||||||
|
'sType',
|
||||||
|
'\n',
|
||||||
|
' ',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'VkTensorARM',
|
||||||
|
' ',
|
||||||
|
'tensor',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'\n',
|
||||||
|
' ',
|
||||||
|
'const ',
|
||||||
|
'void',
|
||||||
|
'* ',
|
||||||
|
'pNext',
|
||||||
|
'\n',
|
||||||
|
' ',
|
||||||
|
]
|
||||||
|
]
|
||||||
|
text_list_without_comment = [
|
||||||
|
*text_list[0],
|
||||||
|
*text_list[1],
|
||||||
|
*text_list[2],
|
||||||
|
]
|
||||||
|
text_list_with_comment = [
|
||||||
|
*text_list[0],
|
||||||
|
'const ',
|
||||||
|
*text_list[1],
|
||||||
|
'Tensor that this allocation will be bound to',
|
||||||
|
*text_list[2],
|
||||||
|
]
|
||||||
|
type_node = result.get('types').get('type')
|
||||||
|
i = 0
|
||||||
|
for node in type_node.get_text_nodes():
|
||||||
|
assert node.node_type == 'text'
|
||||||
|
assert node.node_name == '#text'
|
||||||
|
assert node.node_value == text_list_without_comment[i], f'''result.get('types').get('type').child_nodes[{i}].get_text() == {text_list_without_comment[i]!r}'''
|
||||||
|
assert node.get_text() == node.node_value
|
||||||
|
i += 1
|
||||||
|
i = 0
|
||||||
|
for node in type_node.get_text_nodes(skip_comments=False):
|
||||||
|
assert node.node_type == 'text'
|
||||||
|
assert node.node_name == '#text'
|
||||||
|
assert node.node_value == text_list_with_comment[i], f'''result.get('types').get('type').child_nodes[{i}].get_text() == {text_list_with_comment[i]!r}'''
|
||||||
|
assert node.get_text() == node.node_value
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
invalid_text_node_before = type_node.get_all('member')[0].get('name').child_nodes[0]
|
||||||
|
invalid_text_node_before.node_type = 'invalid'
|
||||||
|
assert invalid_text_node_before.get_text() == ''
|
||||||
|
text_list_without_comment = text_list_without_comment[0:4] + text_list_without_comment[5:]
|
||||||
|
text_list_with_comment = text_list_with_comment[0:4] + text_list_with_comment[5:]
|
||||||
|
|
||||||
|
invalid_text_node_after = type_node.get_all('member')[2].get('name')
|
||||||
|
invalid_text_node_after.node_type = 'invalid'
|
||||||
|
assert invalid_text_node_after.get_text() == ''
|
||||||
|
text_list_without_comment = text_list_without_comment[:14] + text_list_without_comment[15:]
|
||||||
|
text_list_with_comment = text_list_with_comment[:16] + text_list_with_comment[17:]
|
||||||
|
i = 0
|
||||||
|
for node in type_node.get_text_nodes():
|
||||||
|
assert node.node_type == 'text'
|
||||||
|
assert node.node_name == '#text'
|
||||||
|
assert node.node_value == text_list_without_comment[i], f'''result.get('types').get('type').child_nodes[{i}].get_text() == {text_list_without_comment[i]!r}'''
|
||||||
|
assert node.get_text() == node.node_value
|
||||||
|
i += 1
|
||||||
|
i = 0
|
||||||
|
for node in type_node.get_text_nodes(skip_comments=False):
|
||||||
|
assert node.node_type == 'text'
|
||||||
|
assert node.node_name == '#text'
|
||||||
|
assert node.node_value == text_list_with_comment[i], f'''result.get('types').get('type').child_nodes[{i}].get_text() == {text_list_with_comment[i]!r}'''
|
||||||
|
assert node.get_text() == node.node_value
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
tensor_member_node = type_node.get_all('member')[1]
|
||||||
|
tensor_member_name_node = tensor_member_node.get('name')
|
||||||
|
assert tensor_member_node.get_text_before(tensor_member_name_node) == 'VkTensorARM '
|
||||||
|
assert tensor_member_node.get_text_after(tensor_member_name_node) == ''
|
||||||
|
|
||||||
|
assert tensor_member_node.get_text_before(tensor_member_name_node, skip_comments=False) == 'const VkTensorARM '
|
||||||
|
assert tensor_member_node.get_text_after(tensor_member_name_node, skip_comments=False) == 'Tensor that this allocation will be bound to'
|
||||||
|
|
||||||
|
assert [node.get_text() for node in type_node.get_text_nodes_before(tensor_member_name_node)] == text_list_without_comment[:8]
|
||||||
|
assert [node.get_text() for node in type_node.get_text_nodes_after(tensor_member_name_node)] == text_list_without_comment[9:]
|
||||||
|
|
||||||
|
def test_file_path(self):
|
||||||
|
from dragiyski.vulkan.registry.xml import Node, parse_xml
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
file = Path(__file__).absolute().parent.joinpath('test_node/xml-test-1.xml')
|
||||||
|
root = parse_xml(file, is_file=True)
|
||||||
|
assert isinstance(root, Node)
|
||||||
|
assert root.line == 2
|
||||||
|
assert root.column == 0
|
||||||
|
assert root.file_path == f'{file}:{root.line}:{root.column}'
|
||||||
|
|
||||||
|
child3_node = root.get('child3')
|
||||||
|
assert isinstance(child3_node, Node)
|
||||||
|
assert child3_node.line == 6
|
||||||
|
assert child3_node.column == 4
|
||||||
|
assert child3_node.file_path == f'{file}:{child3_node.line}:{child3_node.column}'
|
||||||
|
|
||||||
|
def test_file_url(self):
|
||||||
|
from dragiyski.vulkan.registry.xml import Node, parse_xml
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
file = Path(__file__).resolve().parent.joinpath('test_node/xml-test-1.xml')
|
||||||
|
root = parse_xml(file, is_file=True)
|
||||||
|
url = file.as_uri()
|
||||||
|
assert isinstance(root, Node)
|
||||||
|
assert root.line == 2
|
||||||
|
assert root.column == 0
|
||||||
|
assert root.file_url == f'{url}:{root.line}:{root.column}'
|
||||||
|
|
||||||
|
child3_node = root.get('child3')
|
||||||
|
assert isinstance(child3_node, Node)
|
||||||
|
assert child3_node.line == 6
|
||||||
|
assert child3_node.column == 4
|
||||||
|
assert child3_node.file_url == f'{url}:{child3_node.line}:{child3_node.column}'
|
||||||
|
|
||||||
|
def test_repr(self):
|
||||||
|
from dragiyski.vulkan.registry.xml import Node, parse_xml
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
file = Path(__file__).resolve().parent.joinpath('test_node/xml-test-1.xml')
|
||||||
|
root = parse_xml(file, is_file=True)
|
||||||
|
url = file.as_uri()
|
||||||
|
path = '/'.join(root.path)
|
||||||
|
assert repr(root) == f'<XMLNode {path} at {root.file_url} object at {hex(id(root))}>'
|
||||||
|
|
||||||
|
child3_node = root.get('child3')
|
||||||
|
path = '/'.join(child3_node.path)
|
||||||
|
assert repr(child3_node) == f'<XMLNode {path} at {child3_node.file_url} object at {hex(id(child3_node))}>'
|
||||||
11
tests/test_node/xml-test-1.xml
Normal file
11
tests/test_node/xml-test-1.xml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<root attr="value">
|
||||||
|
<child>Text</child>
|
||||||
|
<!-- A comment -->
|
||||||
|
<child2>More Text</child2>
|
||||||
|
<child3>
|
||||||
|
<text>Some Text</text>
|
||||||
|
<text>More Text</text>
|
||||||
|
<text>Even More Text</text>
|
||||||
|
</child3>
|
||||||
|
</root>
|
||||||
23
tests/test_taxonomy.py
Normal file
23
tests/test_taxonomy.py
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import unittest
|
||||||
|
import dragiyski.vulkan.registry as registry
|
||||||
|
from collections.abc import Container
|
||||||
|
|
||||||
|
|
||||||
|
class TestTaxonomy(unittest.TestCase):
|
||||||
|
taxonomy = None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
cls.taxonomy = registry.taxonomy
|
||||||
|
|
||||||
|
def test_taxonomy_api(self):
|
||||||
|
self.assertEqual(self.taxonomy.api, 'vulkan')
|
||||||
|
|
||||||
|
def test_taxonomy_tags(self):
|
||||||
|
self.assertHasAttr(self.taxonomy, 'tags')
|
||||||
|
self.assertIsInstance(self.taxonomy.tags, Container)
|
||||||
|
self.assertIn('KHR', self.taxonomy.tags)
|
||||||
|
self.assertIn('EXT', self.taxonomy.tags)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
Reference in New Issue
Block a user