diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 51d74be302..fffa49b721 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -24,4 +24,11 @@ repos: hooks: - id: zizmor stages: [pre-commit] - + - repo: https://github.com/pre-commit/mirrors-mypy + rev: v1.13.0 + hooks: + - id: mypy + name: mypy (type signatures) + files: ^tidy3d/web + args: + - --config-file=pyproject.toml diff --git a/poetry.lock b/poetry.lock index 80a7a08523..87c13d0116 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 2.1.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.1.4 and should not be changed by hand. [[package]] name = "absl-py" @@ -462,7 +462,7 @@ description = "Foreign Function Interface for Python calling C code." optional = true python-versions = ">=3.9" groups = ["main"] -markers = "(extra == \"dev\" or extra == \"docs\") and implementation_name == \"pypy\"" +markers = "extra == \"dev\" or extra == \"docs\"" files = [ {file = "cffi-2.0.0-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:0cf2d91ecc3fcc0625c2c530fe004f82c110405f101548512cce44322fa8ac44"}, {file = "cffi-2.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f73b96c41e3b2adedc34a7356e64c8eb96e03a3782b535e043a986276ce12a49"}, @@ -709,7 +709,7 @@ description = "Chex: Testing made fun, in JAX!" optional = true python-versions = ">=3.9" groups = ["main"] -markers = "python_version < \"3.11\"" +markers = "python_version == \"3.10\"" files = [ {file = "chex-0.1.90-py3-none-any.whl", hash = "sha256:fce3de82588f72d4796e545e574a433aa29229cbdcf792555e41bead24b704ae"}, {file = "chex-0.1.90.tar.gz", hash = "sha256:d3c375aeb6154b08f1cccd2bee4ed83659ee2198a6acf1160d2fe2e4a6c87b5c"}, @@ -831,7 +831,7 @@ description = "Python library for calculating contours of 2D quadrilateral grids optional = false python-versions = ">=3.10" groups = ["main"] -markers = "python_version < \"3.11\"" +markers = "python_version == \"3.10\"" files = [ {file = "contourpy-1.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ba38e3f9f330af820c4b27ceb4b9c7feee5fe0493ea53a8720f4792667465934"}, {file = "contourpy-1.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dc41ba0714aa2968d1f8674ec97504a8f7e334f48eeacebcaa6256213acb0989"}, @@ -1355,7 +1355,7 @@ description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" groups = ["main"] -markers = "python_version < \"3.11\" and (extra == \"dev\" or extra == \"docs\")" +markers = "python_version == \"3.10\" and (extra == \"dev\" or extra == \"docs\")" files = [ {file = "exceptiongroup-1.3.0-py3-none-any.whl", hash = "sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10"}, {file = "exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88"}, @@ -1441,7 +1441,7 @@ description = "A platform independent file lock." optional = true python-versions = ">=3.10" groups = ["main"] -markers = "sys_platform == \"darwin\" and (extra == \"dev\" or extra == \"pytorch\" or extra == \"docs\") or extra == \"dev\" or extra == \"docs\" or extra == \"pytorch\"" +markers = "extra == \"dev\" or extra == \"pytorch\" or extra == \"docs\"" files = [ {file = "filelock-3.20.0-py3-none-any.whl", hash = "sha256:339b4732ffda5cd79b13f4e2711a31b0365ce445d95d243bb996273d072546a2"}, {file = "filelock-3.20.0.tar.gz", hash = "sha256:711e943b4ec6be42e1d4e6690b48dc175c822967466bb31c0c293f34334c13f4"}, @@ -1454,7 +1454,7 @@ description = "Flax: A neural network library for JAX designed for flexibility" optional = true python-versions = ">=3.10" groups = ["main"] -markers = "python_version < \"3.11\"" +markers = "python_version == \"3.10\"" files = [ {file = "flax-0.10.7-py3-none-any.whl", hash = "sha256:4033223a9a9969ba0b252e085e9714d0a1e9124ac300aaf48e92c40769c420f6"}, {file = "flax-0.10.7.tar.gz", hash = "sha256:2930d6671e23076f6db3b96afacf45c5060898f5c189ecab6dda7e05d26c2085"}, @@ -1495,7 +1495,7 @@ jax = ">=0.7.1" msgpack = "*" numpy = [ {version = ">=1.26.0", markers = "python_version >= \"3.12\""}, - {version = ">=1.23.2", markers = "python_version == \"3.11\""}, + {version = ">=1.23.2", markers = "python_version >= \"3.11\""}, ] optax = "*" orbax-checkpoint = "*" @@ -2058,7 +2058,7 @@ description = "IPython: Productive Interactive Computing" optional = true python-versions = ">=3.10" groups = ["main"] -markers = "python_version < \"3.11\" and (extra == \"dev\" or extra == \"docs\")" +markers = "python_version == \"3.10\" and (extra == \"dev\" or extra == \"docs\")" files = [ {file = "ipython-8.37.0-py3-none-any.whl", hash = "sha256:ed87326596b878932dbcb171e3e698845434d8c61b8d8cd474bf663041a9dcf2"}, {file = "ipython-8.37.0.tar.gz", hash = "sha256:ca815841e1a41a1e6b73a0b08f3038af9b2252564d01fc405356d34033012216"}, @@ -2204,7 +2204,7 @@ description = "Differentiate, compile, and transform Numpy code." optional = true python-versions = ">=3.10" groups = ["main"] -markers = "python_version < \"3.11\"" +markers = "python_version == \"3.10\"" files = [ {file = "jax-0.6.2-py3-none-any.whl", hash = "sha256:bb24a82dc60ccf704dcaf6dbd07d04957f68a6c686db19630dd75260d1fb788c"}, {file = "jax-0.6.2.tar.gz", hash = "sha256:a437d29038cbc8300334119692744704ca7941490867b9665406b7f90665cd96"}, @@ -2268,7 +2268,7 @@ description = "XLA library for JAX" optional = true python-versions = ">=3.10" groups = ["main"] -markers = "python_version < \"3.11\"" +markers = "python_version == \"3.10\"" files = [ {file = "jaxlib-0.6.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:da4601b2b5dc8c23d6afb293eacfb9aec4e1d1871cb2f29c5a151d103e73b0f8"}, {file = "jaxlib-0.6.2-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:4205d098ce8efb5f7fe2fe5098bae6036094dc8d8829f5e0e0d7a9b155326336"}, @@ -2382,7 +2382,7 @@ description = "A very fast and expressive template engine." optional = true python-versions = ">=3.7" groups = ["main"] -markers = "sys_platform == \"darwin\" and (extra == \"dev\" or extra == \"pytorch\" or extra == \"docs\") or extra == \"dev\" or extra == \"docs\" or extra == \"pytorch\"" +markers = "extra == \"dev\" or extra == \"pytorch\" or extra == \"docs\"" files = [ {file = "jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67"}, {file = "jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d"}, @@ -3012,7 +3012,7 @@ description = "Safely add untrusted strings to HTML/XML markup." optional = true python-versions = ">=3.9" groups = ["main"] -markers = "sys_platform == \"darwin\" and (extra == \"dev\" or extra == \"pytorch\" or extra == \"docs\") or extra == \"dev\" or extra == \"docs\" or extra == \"pytorch\"" +markers = "extra == \"dev\" or extra == \"pytorch\" or extra == \"docs\"" files = [ {file = "markupsafe-3.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2f981d352f04553a7171b8e44369f2af4055f888dfb147d55e42d29e29e74559"}, {file = "markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e1c1493fb6e50ab01d20a22826e57520f1284df32f2d8601fdd90b6304601419"}, @@ -3328,10 +3328,10 @@ files = [ [package.dependencies] numpy = [ + {version = ">=1.21.2", markers = "python_version >= \"3.10\""}, {version = ">=2.1.0", markers = "python_version >= \"3.13\""}, {version = ">=1.26.0", markers = "python_version == \"3.12\""}, {version = ">=1.23.3", markers = "python_version >= \"3.11\""}, - {version = ">=1.21.2", markers = "python_version >= \"3.10\""}, ] [package.extras] @@ -3428,6 +3428,61 @@ files = [ {file = "msgpack-1.1.2.tar.gz", hash = "sha256:3b60763c1373dd60f398488069bcdc703cd08a711477b5d480eecc9f9626f47e"}, ] +[[package]] +name = "mypy" +version = "1.13.0" +description = "Optional static typing for Python" +optional = true +python-versions = ">=3.8" +groups = ["main"] +markers = "extra == \"dev\"" +files = [ + {file = "mypy-1.13.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6607e0f1dd1fb7f0aca14d936d13fd19eba5e17e1cd2a14f808fa5f8f6d8f60a"}, + {file = "mypy-1.13.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8a21be69bd26fa81b1f80a61ee7ab05b076c674d9b18fb56239d72e21d9f4c80"}, + {file = "mypy-1.13.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7b2353a44d2179846a096e25691d54d59904559f4232519d420d64da6828a3a7"}, + {file = "mypy-1.13.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0730d1c6a2739d4511dc4253f8274cdd140c55c32dfb0a4cf8b7a43f40abfa6f"}, + {file = "mypy-1.13.0-cp310-cp310-win_amd64.whl", hash = "sha256:c5fc54dbb712ff5e5a0fca797e6e0aa25726c7e72c6a5850cfd2adbc1eb0a372"}, + {file = "mypy-1.13.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:581665e6f3a8a9078f28d5502f4c334c0c8d802ef55ea0e7276a6e409bc0d82d"}, + {file = "mypy-1.13.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3ddb5b9bf82e05cc9a627e84707b528e5c7caaa1c55c69e175abb15a761cec2d"}, + {file = "mypy-1.13.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:20c7ee0bc0d5a9595c46f38beb04201f2620065a93755704e141fcac9f59db2b"}, + {file = "mypy-1.13.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3790ded76f0b34bc9c8ba4def8f919dd6a46db0f5a6610fb994fe8efdd447f73"}, + {file = "mypy-1.13.0-cp311-cp311-win_amd64.whl", hash = "sha256:51f869f4b6b538229c1d1bcc1dd7d119817206e2bc54e8e374b3dfa202defcca"}, + {file = "mypy-1.13.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5c7051a3461ae84dfb5dd15eff5094640c61c5f22257c8b766794e6dd85e72d5"}, + {file = "mypy-1.13.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:39bb21c69a5d6342f4ce526e4584bc5c197fd20a60d14a8624d8743fffb9472e"}, + {file = "mypy-1.13.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:164f28cb9d6367439031f4c81e84d3ccaa1e19232d9d05d37cb0bd880d3f93c2"}, + {file = "mypy-1.13.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a4c1bfcdbce96ff5d96fc9b08e3831acb30dc44ab02671eca5953eadad07d6d0"}, + {file = "mypy-1.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:a0affb3a79a256b4183ba09811e3577c5163ed06685e4d4b46429a271ba174d2"}, + {file = "mypy-1.13.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a7b44178c9760ce1a43f544e595d35ed61ac2c3de306599fa59b38a6048e1aa7"}, + {file = "mypy-1.13.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5d5092efb8516d08440e36626f0153b5006d4088c1d663d88bf79625af3d1d62"}, + {file = "mypy-1.13.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:de2904956dac40ced10931ac967ae63c5089bd498542194b436eb097a9f77bc8"}, + {file = "mypy-1.13.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:7bfd8836970d33c2105562650656b6846149374dc8ed77d98424b40b09340ba7"}, + {file = "mypy-1.13.0-cp313-cp313-win_amd64.whl", hash = "sha256:9f73dba9ec77acb86457a8fc04b5239822df0c14a082564737833d2963677dbc"}, + {file = "mypy-1.13.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:100fac22ce82925f676a734af0db922ecfea991e1d7ec0ceb1e115ebe501301a"}, + {file = "mypy-1.13.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7bcb0bb7f42a978bb323a7c88f1081d1b5dee77ca86f4100735a6f541299d8fb"}, + {file = "mypy-1.13.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bde31fc887c213e223bbfc34328070996061b0833b0a4cfec53745ed61f3519b"}, + {file = "mypy-1.13.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:07de989f89786f62b937851295ed62e51774722e5444a27cecca993fc3f9cd74"}, + {file = "mypy-1.13.0-cp38-cp38-win_amd64.whl", hash = "sha256:4bde84334fbe19bad704b3f5b78c4abd35ff1026f8ba72b29de70dda0916beb6"}, + {file = "mypy-1.13.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0246bcb1b5de7f08f2826451abd947bf656945209b140d16ed317f65a17dc7dc"}, + {file = "mypy-1.13.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7f5b7deae912cf8b77e990b9280f170381fdfbddf61b4ef80927edd813163732"}, + {file = "mypy-1.13.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7029881ec6ffb8bc233a4fa364736789582c738217b133f1b55967115288a2bc"}, + {file = "mypy-1.13.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3e38b980e5681f28f033f3be86b099a247b13c491f14bb8b1e1e134d23bb599d"}, + {file = "mypy-1.13.0-cp39-cp39-win_amd64.whl", hash = "sha256:a6789be98a2017c912ae6ccb77ea553bbaf13d27605d2ca20a76dfbced631b24"}, + {file = "mypy-1.13.0-py3-none-any.whl", hash = "sha256:9c250883f9fd81d212e0952c92dbfcc96fc237f4b7c92f56ac81fd48460b3e5a"}, + {file = "mypy-1.13.0.tar.gz", hash = "sha256:0291a61b6fbf3e6673e3405cfcc0e7650bebc7939659fdca2702958038bd835e"}, +] + +[package.dependencies] +mypy-extensions = ">=1.0.0" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +typing-extensions = ">=4.6.0" + +[package.extras] +dmypy = ["psutil (>=4.0)"] +faster-cache = ["orjson"] +install-types = ["pip"] +mypyc = ["setuptools (>=50)"] +reports = ["lxml"] + [[package]] name = "mypy-extensions" version = "1.1.0" @@ -3639,7 +3694,7 @@ description = "Python package for creating and manipulating graphs and networks" optional = true python-versions = ">=3.8" groups = ["main"] -markers = "sys_platform == \"darwin\" and (extra == \"dev\" or extra == \"pytorch\" or extra == \"trimesh\" or extra == \"docs\") or extra == \"dev\" or extra == \"trimesh\" or extra == \"docs\" or extra == \"pytorch\"" +markers = "extra == \"dev\" or extra == \"pytorch\" or extra == \"trimesh\" or extra == \"docs\"" files = [ {file = "networkx-2.8.8-py3-none-any.whl", hash = "sha256:e435dfa75b1d7195c7b8378c3859f0445cd88c6b0375c181ed66823a9ceb7524"}, {file = "networkx-2.8.8.tar.gz", hash = "sha256:230d388117af870fce5647a3c52401fcf753e94720e6ea6b4197a5355648885e"}, @@ -3716,7 +3771,7 @@ description = "Fundamental package for array computing in Python" optional = false python-versions = ">=3.10" groups = ["main"] -markers = "python_version < \"3.11\"" +markers = "python_version == \"3.10\"" files = [ {file = "numpy-2.2.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b412caa66f72040e6d268491a59f2c43bf03eb6c96dd8f0307829feb7fa2b6fb"}, {file = "numpy-2.2.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e41fd67c52b86603a91c1a505ebaef50b3314de0213461c7a6e99c9a3beff90"}, @@ -4265,7 +4320,7 @@ description = "A decorator to automatically detect mismatch when overriding a me optional = true python-versions = ">=3.6" groups = ["main"] -markers = "python_version <= \"3.11\" and (extra == \"dev\" or extra == \"docs\")" +markers = "python_version < \"3.12\" and (extra == \"dev\" or extra == \"docs\")" files = [ {file = "overrides-7.7.0-py3-none-any.whl", hash = "sha256:c7ed9d062f78b8e4c1a7b70bd8796b35ead4d9f510227ef9c5dc7626c60d7e49"}, {file = "overrides-7.7.0.tar.gz", hash = "sha256:55158fa3d93b98cc75299b1e67078ad9003ca27945c76162c1c0766d6f91820a"}, @@ -4350,9 +4405,9 @@ files = [ [package.dependencies] numpy = [ + {version = ">=1.22.4", markers = "python_version < \"3.11\""}, {version = ">=1.26.0", markers = "python_version >= \"3.12\""}, {version = ">=1.23.2", markers = "python_version == \"3.11\""}, - {version = ">=1.22.4", markers = "python_version < \"3.11\""}, ] python-dateutil = ">=2.8.2" pytz = ">=2020.1" @@ -4707,7 +4762,7 @@ description = "Run a subprocess in a pseudo terminal" optional = true python-versions = "*" groups = ["main"] -markers = "(extra == \"dev\" or extra == \"docs\") and (sys_platform != \"win32\" and sys_platform != \"emscripten\" or os_name != \"nt\")" +markers = "(sys_platform != \"win32\" and sys_platform != \"emscripten\" or os_name != \"nt\") and (extra == \"dev\" or extra == \"docs\")" files = [ {file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"}, {file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"}, @@ -4736,7 +4791,7 @@ description = "C parser in Python" optional = true python-versions = ">=3.8" groups = ["main"] -markers = "(extra == \"dev\" or extra == \"docs\") and implementation_name == \"pypy\"" +markers = "(extra == \"dev\" or extra == \"docs\") and implementation_name != \"PyPy\"" files = [ {file = "pycparser-2.23-py3-none-any.whl", hash = "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934"}, {file = "pycparser-2.23.tar.gz", hash = "sha256:78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2"}, @@ -4992,9 +5047,9 @@ files = [ astroid = ">=4.0.1,<=4.1.dev0" colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} dill = [ - {version = ">=0.3.7", markers = "python_version >= \"3.12\""}, - {version = ">=0.3.6", markers = "python_version >= \"3.11\""}, {version = ">=0.2", markers = "python_version < \"3.11\""}, + {version = ">=0.3.7", markers = "python_version >= \"3.12\""}, + {version = ">=0.3.6", markers = "python_version == \"3.11\""}, ] isort = ">=5,<5.13 || >5.13,<8" mccabe = ">=0.6,<0.8" @@ -5270,6 +5325,13 @@ optional = false python-versions = ">=3.8" groups = ["main"] files = [ + {file = "PyYAML-6.0.3-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:c2514fceb77bc5e7a2f7adfaa1feb2fb311607c9cb518dbc378688ec73d8292f"}, + {file = "PyYAML-6.0.3-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c57bb8c96f6d1808c030b1687b9b5fb476abaa47f0db9c0101f5e9f394e97f4"}, + {file = "PyYAML-6.0.3-cp38-cp38-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:efd7b85f94a6f21e4932043973a7ba2613b059c4a000551892ac9f1d11f5baf3"}, + {file = "PyYAML-6.0.3-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:22ba7cfcad58ef3ecddc7ed1db3409af68d023b7f940da23c6c2a1890976eda6"}, + {file = "PyYAML-6.0.3-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:6344df0d5755a2c9a276d4473ae6b90647e216ab4757f8426893b5dd2ac3f369"}, + {file = "PyYAML-6.0.3-cp38-cp38-win32.whl", hash = "sha256:3ff07ec89bae51176c0549bc4c63aa6202991da2d9a6129d7aef7f1407d3f295"}, + {file = "PyYAML-6.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:5cf4e27da7e3fbed4d6c3d8e797387aaad68102272f8f9752883bc32d61cb87b"}, {file = "pyyaml-6.0.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b"}, {file = "pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956"}, {file = "pyyaml-6.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8"}, @@ -5891,7 +5953,7 @@ description = "Fundamental algorithms for scientific computing in Python" optional = false python-versions = ">=3.10" groups = ["main"] -markers = "python_version < \"3.11\"" +markers = "python_version == \"3.10\"" files = [ {file = "scipy-1.15.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:a345928c86d535060c9c2b25e71e87c39ab2f22fc96e9636bd74d1dbf9de448c"}, {file = "scipy-1.15.3-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:ad3432cb0f9ed87477a8d97f03b763fd1d57709f1bbde3c9369b1dff5503b253"}, @@ -6054,7 +6116,7 @@ description = "Easily download, build, install, upgrade, and uninstall Python pa optional = true python-versions = ">=3.9" groups = ["main"] -markers = "python_version >= \"3.12\" and (extra == \"dev\" or extra == \"pytorch\" or extra == \"docs\") or (extra == \"dev\" or extra == \"docs\") and (extra == \"dev\" or extra == \"docs\" or extra == \"pytorch\")" +markers = "(extra == \"dev\" or extra == \"docs\" or python_version >= \"3.12\") and (extra == \"dev\" or extra == \"docs\" or extra == \"pytorch\")" files = [ {file = "setuptools-80.9.0-py3-none-any.whl", hash = "sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922"}, {file = "setuptools-80.9.0.tar.gz", hash = "sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c"}, @@ -6856,7 +6918,7 @@ description = "A lil' TOML parser" optional = false python-versions = ">=3.8" groups = ["main"] -markers = "python_version < \"3.11\" and (extra == \"dev\" or extra == \"docs\")" +markers = "python_version == \"3.10\" and (extra == \"dev\" or extra == \"docs\")" files = [ {file = "tomli-2.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:88bd15eb972f3664f5ed4b57c1634a97153b4bac4479dcb6a495f41921eb7f45"}, {file = "tomli-2.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:883b1c0d6398a6a9d29b508c331fa56adbcdff647f6ace4dfca0f50e90dfd0ba"}, @@ -6933,7 +6995,7 @@ description = "Tensors and Dynamic neural networks in Python with strong GPU acc optional = true python-versions = ">=3.10" groups = ["main"] -markers = "sys_platform == \"darwin\" and (extra == \"dev\" or extra == \"pytorch\")" +markers = "(extra == \"dev\" or extra == \"pytorch\") and sys_platform == \"darwin\"" files = [ {file = "torch-2.9.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:030bbfe367379ae6a4ae4042b6c44da25383343b8b3c68abaa9c7231efbaf2dd"}, {file = "torch-2.9.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:51cb63902182a78e90886e8068befd8ea102af4b00e420263591a3d70c7d3c6c"}, @@ -7002,7 +7064,7 @@ description = "Tensors and Dynamic neural networks in Python with strong GPU acc optional = true python-versions = ">=3.10" groups = ["main"] -markers = "sys_platform != \"darwin\" and (extra == \"dev\" or extra == \"pytorch\")" +markers = "(extra == \"dev\" or extra == \"pytorch\") and sys_platform != \"darwin\"" files = [ {file = "torch-2.9.0+cpu-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:b224792ea567b52c7f1ce1d789567f6920e06fd3b339fa1e1b05948845f783ad"}, {file = "torch-2.9.0+cpu-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:bd2a257e670ede9fc01c6d76dccdc473040913b8e9328169bf177dbdc38e2484"}, @@ -7450,7 +7512,7 @@ description = "N-D labeled arrays and datasets in Python" optional = false python-versions = ">=3.10" groups = ["main"] -markers = "python_version < \"3.11\"" +markers = "python_version == \"3.10\"" files = [ {file = "xarray-2025.6.1-py3-none-any.whl", hash = "sha256:8b988b47f67a383bdc3b04c5db475cd165e580134c1f1943d52aee4a9c97651b"}, {file = "xarray-2025.6.1.tar.gz", hash = "sha256:a84f3f07544634a130d7dc615ae44175419f4c77957a7255161ed99c69c7c8b0"}, @@ -7541,7 +7603,7 @@ files = [ [extras] design = ["bayesian-optimization", "pygad", "pyswarms"] -dev = ["bayesian-optimization", "cma", "coverage", "devsim", "diff-cover", "dill", "gdstk", "grcwa", "ipython", "ipython", "jinja2", "jupyter", "memory_profiler", "myst-parser", "nbconvert", "nbdime", "nbsphinx", "networkx", "openpyxl", "optax", "pre-commit", "psutil", "pydata-sphinx-theme", "pygad", "pylint", "pyswarms", "pytest", "pytest-cov", "pytest-env", "pytest-timeout", "pytest-xdist", "rtree", "ruff", "sax", "scikit-rf", "signac", "sphinx", "sphinx-book-theme", "sphinx-copybutton", "sphinx-design", "sphinx-favicon", "sphinx-notfound-page", "sphinx-sitemap", "sphinx-tabs", "sphinxemoji", "tmm", "torch", "torch", "tox", "trimesh", "vtk", "zizmor"] +dev = ["bayesian-optimization", "cma", "coverage", "devsim", "diff-cover", "dill", "gdstk", "grcwa", "ipython", "ipython", "jinja2", "jupyter", "memory_profiler", "mypy", "myst-parser", "nbconvert", "nbdime", "nbsphinx", "networkx", "openpyxl", "optax", "pre-commit", "psutil", "pydata-sphinx-theme", "pygad", "pylint", "pyswarms", "pytest", "pytest-cov", "pytest-env", "pytest-timeout", "pytest-xdist", "rtree", "ruff", "sax", "scikit-rf", "signac", "sphinx", "sphinx-book-theme", "sphinx-copybutton", "sphinx-design", "sphinx-favicon", "sphinx-notfound-page", "sphinx-sitemap", "sphinx-tabs", "sphinxemoji", "tmm", "torch", "torch", "tox", "trimesh", "vtk", "zizmor"] docs = ["cma", "devsim", "gdstk", "grcwa", "ipython", "jinja2", "jupyter", "myst-parser", "nbconvert", "nbdime", "nbsphinx", "openpyxl", "optax", "pydata-sphinx-theme", "pylint", "sax", "signac", "sphinx", "sphinx-book-theme", "sphinx-copybutton", "sphinx-design", "sphinx-favicon", "sphinx-notfound-page", "sphinx-sitemap", "sphinx-tabs", "sphinxemoji", "tmm"] gdstk = ["gdstk"] heatcharge = ["devsim", "trimesh", "vtk"] @@ -7554,4 +7616,4 @@ vtk = ["vtk"] [metadata] lock-version = "2.1" python-versions = ">=3.10,<3.14" -content-hash = "bd52223956f49ef6e285446605fb41ab53f566282fd04c07a04243e91acda687" +content-hash = "deab3d5c68d8ee1fce2e7c86f2c90d1b601025f5ff2c5465767c0bc479b992be" diff --git a/pyproject.toml b/pyproject.toml index 18b9f01acc..6783ab8382 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -68,6 +68,7 @@ pytest-env = "^1.1.5" tox = { version = "*", optional = true } diff-cover = { version = "*", optional = true } zizmor = { version = "*", optional = true } +mypy = { version = "1.13.0", optional = true } # gdstk gdstk = { version = ">=0.9.49", optional = true } @@ -136,6 +137,7 @@ dev = [ 'jupyter', 'myst-parser', 'memory_profiler', + 'mypy', 'psutil', 'nbconvert', 'nbdime', @@ -312,3 +314,81 @@ norecursedirs = [ filterwarnings = "ignore::DeprecationWarning" testpaths = ["tidy3d", "tests", "docs"] python_files = "*.py" + +[tool.mypy] +python_version = "3.10" +ignore_missing_imports = true +follow_imports = "skip" +disallow_untyped_defs = true +disable_error_code = [ + "abstract", + "annotation-unchecked", + "arg-type", + "assert-type", + "assignment", + "attr-defined", + "await-not-async", + "call-arg", + "call-overload", + "comparison-overlap", + "dict-item", + "empty-body", + "exit-return", + "explicit-override", + "func-returns-value", + "has-type", + "ignore-without-code", + "import", + "import-not-found", + "import-untyped", + "index", + "list-item", + "literal-required", + "method-assign", + "misc", + "mutable-override", + "name-defined", + "name-match", + "narrowed-type-not-subtype", + "no-any-return", + "no-any-unimported", + "no-overload-impl", + "no-redef", + "no-untyped-call", + "operator", + "overload-cannot-match", + "overload-overlap", + "override", + "possibly-undefined", + "prop-decorator", + "redundant-cast", + "redundant-expr", + "redundant-self", + "return", + "return-value", + "safe-super", + "str-bytes-safe", + "str-format", + "syntax", + "top-level-await", + "truthy-bool", + "truthy-function", + "truthy-iterable", + "type-abstract", + "type-arg", + "type-var", + "typeddict-item", + "typeddict-readonly-mutated", + "typeddict-unknown-key", + "unimported-reveal", + "union-attr", + "unreachable", + "unused-awaitable", + "unused-coroutine", + "unused-ignore", + "used-before-def", + "valid-newtype", + "valid-type", + "var-annotated", +] +enable_error_code = ["no-untyped-def"] diff --git a/tidy3d/__main__.py b/tidy3d/__main__.py index 6021d3367f..743a552d02 100644 --- a/tidy3d/__main__.py +++ b/tidy3d/__main__.py @@ -9,7 +9,7 @@ from tidy3d.web import Job -def main(args): +def main(args) -> None: """Parse args and run the corresponding tidy3d simulaton.""" parser = argparse.ArgumentParser(description="Tidy3D") diff --git a/tidy3d/components/autograd/derivative_utils.py b/tidy3d/components/autograd/derivative_utils.py index fba1b54ba4..7c36444687 100644 --- a/tidy3d/components/autograd/derivative_utils.py +++ b/tidy3d/components/autograd/derivative_utils.py @@ -3,7 +3,7 @@ from __future__ import annotations from dataclasses import dataclass, field, replace -from typing import Callable, Optional, Union +from typing import Any, Callable, Optional, Union import numpy as np import xarray as xr @@ -25,12 +25,12 @@ class LazyInterpolator: """Lazy wrapper for interpolators that creates them on first access.""" - def __init__(self, creator_func: Callable): + def __init__(self, creator_func: Callable) -> None: """Initialize with a function that creates the interpolator when called.""" self.creator_func = creator_func self._interpolator = None - def __call__(self, *args, **kwargs): + def __call__(self, *args: Any, **kwargs: Any): """Create interpolator on first call and delegate to it.""" if self._interpolator is None: self._interpolator = self.creator_func() @@ -172,7 +172,7 @@ class DerivativeInfo: # private cache for interpolators _interpolators_cache: dict = field(default_factory=dict, init=False, repr=False) - def updated_copy(self, **kwargs): + def updated_copy(self, **kwargs: Any): """Create a copy with updated fields.""" kwargs.pop("deep", None) kwargs.pop("validate", None) @@ -251,7 +251,7 @@ def create_interpolators(self, dtype: Optional[np.dtype] = None) -> dict: interpolators = {} coord_cache = {} - def _make_lazy_interpolator_group(field_data_dict, group_key, is_field_group=True): + def _make_lazy_interpolator_group(field_data_dict, group_key, is_field_group=True) -> None: """Helper to create a group of lazy interpolators.""" if is_field_group: interpolators[group_key] = {} diff --git a/tidy3d/components/autograd/functions.py b/tidy3d/components/autograd/functions.py index c360ce07e3..6f86b05f4b 100644 --- a/tidy3d/components/autograd/functions.py +++ b/tidy3d/components/autograd/functions.py @@ -1,6 +1,7 @@ from __future__ import annotations import itertools +from typing import Any import autograd.numpy as anp import numpy as np @@ -98,7 +99,7 @@ def interpn( xi: tuple[NDArray[np.float64], ...], *, method: InterpolationType = "linear", - **kwargs, + **kwargs: Any, ) -> NDArray[np.float64]: """Interpolate over a rectilinear grid in arbitrary dimensions. diff --git a/tidy3d/components/base.py b/tidy3d/components/base.py index 6b7f2be82b..a12fc36f3e 100644 --- a/tidy3d/components/base.py +++ b/tidy3d/components/base.py @@ -137,7 +137,7 @@ def skip_if_fields_missing(fields: list[str], root=False): def actual_decorator(validator): @wraps(validator) - def _validator(cls, *args, **kwargs): + def _validator(cls, *args: Any, **kwargs: Any): """New validator function.""" values = kwargs.get("values") if values is None: @@ -180,7 +180,7 @@ def _hash_self(self) -> str: self.to_hdf5(bf) return hashlib.md5(bf.getvalue()).hexdigest() - def __init__(self, **kwargs): + def __init__(self, **kwargs: Any) -> None: """Init method, includes post-init validators.""" log.begin_capture() super().__init__(**kwargs) @@ -274,7 +274,7 @@ def _default(o): return hashlib.sha256(json_str.encode("utf-8")).hexdigest() - def copy(self, deep: bool = True, validate: bool = True, **kwargs) -> Self: + def copy(self, deep: bool = True, validate: bool = True, **kwargs: Any) -> Self: """Copy a Tidy3dBaseModel. With ``deep=True`` and ``validate=True`` as default.""" kwargs.update(deep=deep) new_copy = pydantic.BaseModel.copy(self, **kwargs) @@ -286,7 +286,7 @@ def copy(self, deep: bool = True, validate: bool = True, **kwargs) -> Self: return new_copy def updated_copy( - self, path: Optional[str] = None, deep: bool = True, validate: bool = True, **kwargs + self, path: Optional[str] = None, deep: bool = True, validate: bool = True, **kwargs: Any ) -> Self: """Make copy of a component instance with ``**kwargs`` indicating updated field values. @@ -345,7 +345,7 @@ def updated_copy( return self._updated_copy(deep=deep, validate=validate, **{field_name: new_component}) - def _updated_copy(self, deep: bool = True, validate: bool = True, **kwargs) -> Self: + def _updated_copy(self, deep: bool = True, validate: bool = True, **kwargs: Any) -> Self: """Make copy of a component instance with ``**kwargs`` indicating updated field values.""" return self.copy(update=kwargs, deep=deep, validate=validate) @@ -370,7 +370,7 @@ def from_file( group_path: Optional[str] = None, lazy: bool = False, on_load: Optional[Callable] = None, - **parse_obj_kwargs, + **parse_obj_kwargs: Any, ) -> Self: """Loads a :class:`Tidy3dBaseModel` from .yaml, .json, .hdf5, or .hdf5.gz file. @@ -471,7 +471,7 @@ def to_file(self, fname: PathLike) -> None: return converter(fname=fname) @classmethod - def from_json(cls, fname: PathLike, **parse_obj_kwargs) -> Self: + def from_json(cls, fname: PathLike, **parse_obj_kwargs: Any) -> Self: """Load a :class:`Tidy3dBaseModel` from .json file. Parameters @@ -536,7 +536,7 @@ def to_json(self, fname: PathLike) -> None: file_handle.write(json_string) @classmethod - def from_yaml(cls, fname: PathLike, **parse_obj_kwargs) -> Self: + def from_yaml(cls, fname: PathLike, **parse_obj_kwargs: Any) -> Self: """Loads :class:`Tidy3dBaseModel` from .yaml file. Parameters @@ -759,7 +759,7 @@ def from_hdf5( fname: PathLike, group_path: str = "", custom_decoders: Optional[list[Callable]] = None, - **parse_obj_kwargs, + **parse_obj_kwargs: Any, ) -> Self: """Loads :class:`Tidy3dBaseModel` instance to .hdf5 file. @@ -903,7 +903,7 @@ def from_hdf5_gz( fname: PathLike, group_path: str = "", custom_decoders: Optional[list[Callable]] = None, - **parse_obj_kwargs, + **parse_obj_kwargs: Any, ) -> Self: """Loads :class:`Tidy3dBaseModel` instance to .hdf5.gz file. @@ -1036,7 +1036,7 @@ def _json_string(self) -> str: """ return self._json() - def _json(self, indent=INDENT, exclude_unset=False, **kwargs) -> str: + def _json(self, indent=INDENT, exclude_unset=False, **kwargs: Any) -> str: """Overwrites the model ``json`` representation with some extra customized handling. Parameters @@ -1114,7 +1114,7 @@ def _insert_traced_fields(self, field_mapping: AutogradFieldMap) -> Self: self_dict = self.dict() - def insert_value(x, path: tuple[str, ...], sub_dict: dict): + def insert_value(x, path: tuple[str, ...], sub_dict: dict) -> None: """Insert a value into the path into a dictionary.""" current_dict = sub_dict for key in path[:-1]: @@ -1349,13 +1349,13 @@ def __init__( self, fname: PathLike, group_path: Optional[str], - parse_obj_kwargs: Optional[dict[str, Any]], + parse_obj_kwargs: Any, ): object.__setattr__(self, "_lazy_fname", Path(fname)) object.__setattr__(self, "_lazy_group_path", group_path) object.__setattr__(self, "_lazy_parse_obj_kwargs", dict(parse_obj_kwargs or {})) - def copy(self, **kwargs): + def copy(self, **kwargs: Any): """Return another lazy proxy instead of materializing.""" return _LazyProxy( self._lazy_fname, diff --git a/tidy3d/components/base_sim/simulation.py b/tidy3d/components/base_sim/simulation.py index ea4aee26eb..7f64c9d545 100644 --- a/tidy3d/components/base_sim/simulation.py +++ b/tidy3d/components/base_sim/simulation.py @@ -3,7 +3,7 @@ from __future__ import annotations from abc import ABC, abstractmethod -from typing import Optional +from typing import Any, Optional import autograd.numpy as anp import pydantic.v1 as pd @@ -251,7 +251,7 @@ def plot( hlim: Optional[tuple[float, float]] = None, vlim: Optional[tuple[float, float]] = None, fill_structures: bool = True, - **patch_kwargs, + **patch_kwargs: Any, ) -> Ax: """Plot each of simulation's components on a plane defined by one nonzero x,y,z coordinate. @@ -482,7 +482,7 @@ def plot_boundaries( y: Optional[float] = None, z: Optional[float] = None, ax: Ax = None, - **kwargs, + **kwargs: Any, ) -> Ax: """Plot the simulation boundary conditions as lines on a plane defined by one nonzero x,y,z coordinate. @@ -685,7 +685,7 @@ def plot_structures_heat_conductivity( ) @classmethod - def from_scene(cls, scene: Scene, **kwargs) -> AbstractSimulation: + def from_scene(cls, scene: Scene, **kwargs: Any) -> AbstractSimulation: """Create a simulation from a :class:`.Scene` instance. Must provide additional parameters to define a valid simulation (for example, ``size``, ``run_time``, ``grid_spec``, etc). diff --git a/tidy3d/components/boundary.py b/tidy3d/components/boundary.py index 974f3ba8ec..2a586278a0 100644 --- a/tidy3d/components/boundary.py +++ b/tidy3d/components/boundary.py @@ -3,7 +3,7 @@ from __future__ import annotations from abc import ABC -from typing import Optional, Union +from typing import Any, Optional, Union import numpy as np import pydantic.v1 as pd @@ -416,7 +416,7 @@ def plot( y: Optional[float] = None, z: Optional[float] = None, ax: Ax = None, - **patch_kwargs, + **patch_kwargs: Any, ) -> Ax: """Plot this absorber.""" diff --git a/tidy3d/components/data/data_array.py b/tidy3d/components/data/data_array.py index 08038b2a5c..ea6385a796 100644 --- a/tidy3d/components/data/data_array.py +++ b/tidy3d/components/data/data_array.py @@ -77,7 +77,7 @@ class DataArray(xr.DataArray): # stores a dictionary of attributes corresponding to the data values _data_attrs: dict[str, str] = {} - def __init__(self, data, *args, **kwargs): + def __init__(self, data, *args: Any, **kwargs: Any) -> None: # if data is a vanilla autograd box, convert to our box if isbox(data) and not is_tidy_box(data): data = TidyArrayBox.from_arraybox(data) @@ -155,7 +155,7 @@ def assign_coord_attrs(cls, val): return val @classmethod - def __modify_schema__(cls, field_schema): + def __modify_schema__(cls, field_schema) -> None: """Sets the schema of DataArray object.""" schema = { @@ -435,7 +435,7 @@ def _ag_interp( return self._from_temp_dataset(ds) @staticmethod - def _ag_interp_func(var, indexes_coords, method, **kwargs): + def _ag_interp_func(var, indexes_coords, method, **kwargs: Any): """ Interpolate the variable `var` along the coordinates specified in `indexes_coords` using the given `method`. diff --git a/tidy3d/components/data/dataset.py b/tidy3d/components/data/dataset.py index f36c0c9fe3..fda1c82a7f 100644 --- a/tidy3d/components/data/dataset.py +++ b/tidy3d/components/data/dataset.py @@ -619,7 +619,7 @@ def dispersion(self) -> ModeDispersionDataArray: ) return self.dispersion_raw - def plot_field(self, *args, **kwargs): + def plot_field(self, *args: Any, **kwargs: Any) -> None: """Warn user to use the :class:`.ModeSolver` ``plot_field`` function now.""" raise DeprecationWarning( "The 'plot_field()' method was moved to the 'ModeSolver' object." diff --git a/tidy3d/components/data/monitor_data.py b/tidy3d/components/data/monitor_data.py index 8a8e623a11..d38df13c58 100644 --- a/tidy3d/components/data/monitor_data.py +++ b/tidy3d/components/data/monitor_data.py @@ -1032,7 +1032,7 @@ def time_reversed_copy(self) -> FieldData: new_data[comp] = np.conj(field) return self.copy(update=new_data) - def _check_fields_stored(self, components: list[str]): + def _check_fields_stored(self, components: list[str]) -> None: """Check that all requested field components are stored in the data.""" missing_comps = [comp for comp in components if comp not in self.field_components.keys()] if len(missing_comps) > 0: @@ -1320,7 +1320,7 @@ def normalize(self, source_spectrum_fn: Callable[[float], complex]) -> FieldData return self.copy(update=fields_norm) def to_source( - self, source_time: SourceTimeType, center: Coordinate, size: Size = None, **kwargs + self, source_time: SourceTimeType, center: Coordinate, size: Size = None, **kwargs: Any ) -> CustomFieldSource: """Create a :class:`.CustomFieldSource` from the fields stored in the :class:`.FieldData`. @@ -1786,7 +1786,7 @@ def overlap_sort( return data_reordered.updated_copy(monitor=monitor_updated, deep=False, validate=False) - def _isel(self, **isel_kwargs): + def _isel(self, **isel_kwargs: Any): """Wraps ``xarray.DataArray.isel`` for all data fields that are defined over frequency and mode index. Used in ``overlap_sort`` but not officially supported since for example ``self.monitor.mode_spec`` and ``self.monitor.freqs`` will no longer be matching the @@ -1800,7 +1800,7 @@ def _isel(self, **isel_kwargs): } return self._updated(update=update_dict) - def _assign_coords(self, **assign_coords_kwargs): + def _assign_coords(self, **assign_coords_kwargs: Any): """Wraps ``xarray.DataArray.assign_coords`` for all data fields that are defined over frequency and mode index. Used in ``overlap_sort`` but not officially supported since for example ``self.monitor.mode_spec`` and ``self.monitor.freqs`` will no longer be matching the @@ -2123,7 +2123,7 @@ def to_dataframe(self) -> DataFrame: return dataset.drop_vars(drop).to_dataframe() - def _check_fields_stored(self, components: list[EMField]): + def _check_fields_stored(self, components: list[EMField]) -> None: """Check that all requested field components are stored in the data.""" # ModeData can either have all field components or none @@ -2409,7 +2409,7 @@ def time_reversed_copy(self) -> FieldData: new_data["monitor"] = mnt.updated_copy(direction=new_dir, store_fields_direction=new_dir) return self.copy(update=new_data) - def _check_fields_stored(self, components: list[str]): + def _check_fields_stored(self, components: list[str]) -> None: """Check that all requested field components are stored in the data.""" missing_comps = [comp for comp in components if comp not in self.field_components.keys()] if len(missing_comps) > 0: @@ -2942,13 +2942,13 @@ def tangential_dims(self) -> list[str]: return tangential_dims @staticmethod - def _check_coords_sorted(coord: np.ndarray, name: str): + def _check_coords_sorted(coord: np.ndarray, name: str) -> None: """Helper for checking whether an array is sorted and raises an exception if it is not.""" is_sorted = np.all(np.diff(coord) >= 0) if not is_sorted: raise ValueError(f"{name} was not provided as a sorted array.") - def _check_integration_suitability(self): + def _check_integration_suitability(self) -> None: """Checks whether the sampling of ``theta`` and ``phi`` is suitable for integrating over a spherical surface.""" if ( @@ -3773,7 +3773,7 @@ def normalize(self, source_spectrum_fn: Callable[[float], complex]) -> Directivi return self.copy(update=dict(fields_norm, flux=new_flux)) @staticmethod - def _check_valid_pol_basis(pol_basis: PolarizationBasis, tilt_angle: float): + def _check_valid_pol_basis(pol_basis: PolarizationBasis, tilt_angle: float) -> None: if pol_basis != "linear" and pol_basis != "circular": raise ValueError("'pol_basis' must be either 'linear' or 'circular'") if tilt_angle is not None and pol_basis == "circular": diff --git a/tidy3d/components/data/sim_data.py b/tidy3d/components/data/sim_data.py index 669e69c338..d8a0b853de 100644 --- a/tidy3d/components/data/sim_data.py +++ b/tidy3d/components/data/sim_data.py @@ -8,7 +8,7 @@ from abc import ABC from collections import defaultdict from os import PathLike -from typing import Callable, Optional, Union +from typing import Any, Callable, Optional, Union import h5py import numpy as np @@ -373,7 +373,7 @@ def get_intensity(self, field_monitor_name: str) -> xr.DataArray: @classmethod def mnt_data_from_file( - cls, fname: PathLike, mnt_name: str, **parse_obj_kwargs + cls, fname: PathLike, mnt_name: str, **parse_obj_kwargs: Any ) -> MonitorDataType: """Loads data for a specific monitor from a .hdf5 file with data for a ``SimulationData``. @@ -456,7 +456,7 @@ def plot_field_monitor_data( vmax: Optional[float] = None, ax: Ax = None, shading: str = "flat", - **sel_kwargs, + **sel_kwargs: Any, ) -> Ax: """Plot the field data for a monitor with simulation plot overlaid. @@ -672,7 +672,7 @@ def plot_field( vmax: Optional[float] = None, ax: Ax = None, shading: str = "flat", - **sel_kwargs, + **sel_kwargs: Any, ) -> Ax: """Plot the field data for a monitor with simulation plot overlaid. @@ -753,7 +753,7 @@ def plot_scalar_array( vmax: Optional[float] = None, cmap_type: ColormapType = "divergent", ax: Ax = None, - **kwargs, + **kwargs: Any, ) -> Ax: """Plot the field data for a monitor with simulation plot overlaid. @@ -1320,7 +1320,7 @@ def _get_adjoint_data(self, structure_index: int, data_type: str) -> MonitorData monitor_name = Structure._get_monitor_name(index=structure_index, data_type=data_type) return self[monitor_name] - def to_mat_file(self, fname: PathLike, **kwargs): + def to_mat_file(self, fname: PathLike, **kwargs: Any) -> None: """Output the ``SimulationData`` object as ``.mat`` MATLAB file. Parameters diff --git a/tidy3d/components/data/unstructured/base.py b/tidy3d/components/data/unstructured/base.py index 5ab0581680..44ba534833 100644 --- a/tidy3d/components/data/unstructured/base.py +++ b/tidy3d/components/data/unstructured/base.py @@ -5,7 +5,7 @@ import numbers from abc import ABC, abstractmethod from os import PathLike -from typing import Literal, Optional, Union +from typing import Any, Literal, Optional, Union import numpy as np import pydantic.v1 as pd @@ -281,7 +281,7 @@ def bounds(self) -> Bound: @cached_property @abstractmethod - def _points_3d_array(self): + def _points_3d_array(self) -> None: """3D coordinates of grid points.""" """ Grid cleaning """ @@ -360,7 +360,7 @@ def clean(self, remove_degenerate_cells=True, remove_unused_points=True): """ Arithmetic operations """ - def __array_ufunc__(self, ufunc, method, *inputs, **kwargs): + def __array_ufunc__(self, ufunc, method, *inputs: Any, **kwargs: Any): """Override of numpy functions.""" out = kwargs.get("out", ()) @@ -414,7 +414,7 @@ def abs(self) -> UnstructuredGridDataset: @classmethod @abstractmethod @requires_vtk - def _vtk_cell_type(cls): + def _vtk_cell_type(cls) -> None: """VTK cell type to use in the VTK representation.""" @cached_property @@ -610,7 +610,7 @@ def from_vtk( ) @requires_vtk - def to_vtu(self, fname: PathLike): + def to_vtu(self, fname: PathLike) -> None: """Exports unstructured grid data into a .vtu file. Parameters @@ -713,7 +713,7 @@ def _get_values_from_vtk( return values - def get_cell_values(self, **kwargs): + def get_cell_values(self, **kwargs: Any): """This function returns the cell values for the fields stored in the UnstructuredGridDataset. If multiple fields are stored per point, like in an IndexedVoltageDataArray, cell values will be provided for each of the fields unless a selection argument is provided, e.g., voltage=0.2 @@ -732,7 +732,7 @@ def get_cell_values(self, **kwargs): return values[self.cells].mean(dim="vertex_index").values @abstractmethod - def get_cell_volumes(self): + def get_cell_volumes(self) -> None: """Get the volumes associated to each cell.""" """ Grid operations """ @@ -884,7 +884,7 @@ def interp( max_samples_per_step: int = DEFAULT_MAX_SAMPLES_PER_STEP, max_cells_per_step: int = DEFAULT_MAX_CELLS_PER_STEP, rel_tol: float = DEFAULT_TOLERANCE_CELL_FINDING, - **coords_kwargs, + **coords_kwargs: Any, ) -> XrDataArray: """Interpolate data along spatial dimensions x, y, and z and/or non-spatial dimensions. For spatial sampling points must provide all x, y, and z. @@ -962,7 +962,7 @@ def interp( return result - def _non_spatial_interp(self, method="linear", fill_value=np.nan, **coords_kwargs): + def _non_spatial_interp(self, method="linear", fill_value=np.nan, **coords_kwargs: Any): """Interpolate data at non-spatial dimensions using xarray's interp() function. Parameters @@ -1704,7 +1704,7 @@ def sel( y: Union[float, ArrayLike] = None, z: Union[float, ArrayLike] = None, method: Optional[Literal["None", "nearest", "pad", "ffill", "backfill", "bfill"]] = None, - **sel_kwargs, + **sel_kwargs: Any, ) -> Union[UnstructuredGridDataset, XrDataArray]: """Extract/interpolate data along one or more spatial or non-spatial directions. Must provide at least one argument among 'x', 'y', 'z' or non-spatial dimensions through additional arguments. Along spatial dimensions a suitable slicing of @@ -1733,7 +1733,7 @@ def sel( def _non_spatial_sel( self, method=None, - **sel_kwargs, + **sel_kwargs: Any, ) -> XrDataArray: """Select/interpolate data along one or more non-Cartesian directions. @@ -1760,7 +1760,7 @@ def _non_spatial_sel( def isel( self, - **sel_kwargs, + **sel_kwargs: Any, ) -> XrDataArray: """Select data along one or more non-Cartesian directions by coordinate index. diff --git a/tidy3d/components/data/unstructured/tetrahedral.py b/tidy3d/components/data/unstructured/tetrahedral.py index 42ac4b58b1..9c2cbd582d 100644 --- a/tidy3d/components/data/unstructured/tetrahedral.py +++ b/tidy3d/components/data/unstructured/tetrahedral.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Union +from typing import Any, Union import numpy as np import pydantic.v1 as pd @@ -302,7 +302,7 @@ def sel( y: Union[float, ArrayLike] = None, z: Union[float, ArrayLike] = None, method=None, - **sel_kwargs, + **sel_kwargs: Any, ) -> Union[TriangularGridDataset, XrDataArray]: """Extract/interpolate data along one or more spatial or non-spatial directions. Must provide at least one argument among 'x', 'y', 'z' or non-spatial dimensions through additional arguments. Along spatial dimensions a suitable slicing of diff --git a/tidy3d/components/data/unstructured/triangular.py b/tidy3d/components/data/unstructured/triangular.py index 32d54f259b..b187938049 100644 --- a/tidy3d/components/data/unstructured/triangular.py +++ b/tidy3d/components/data/unstructured/triangular.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Literal, Optional, Union +from typing import Any, Literal, Optional, Union import numpy as np import pydantic.v1 as pd @@ -454,7 +454,7 @@ def sel( y: Union[float, ArrayLike] = None, z: Union[float, ArrayLike] = None, method: Optional[Literal["None", "nearest", "pad", "ffill", "backfill", "bfill"]] = None, - **sel_kwargs, + **sel_kwargs: Any, ) -> XrDataArray: """Extract/interpolate data along one or more spatial or non-spatial directions. Must provide at least one argument among 'x', 'y', 'z' or non-spatial dimensions through additional arguments. Along spatial dimensions a suitable slicing of diff --git a/tidy3d/components/eme/grid.py b/tidy3d/components/eme/grid.py index d197c60677..2ed22e26ca 100644 --- a/tidy3d/components/eme/grid.py +++ b/tidy3d/components/eme/grid.py @@ -3,7 +3,7 @@ from __future__ import annotations from abc import ABC, abstractmethod -from typing import Literal, Optional, Union +from typing import Any, Literal, Optional, Union import numpy as np import pydantic.v1 as pd @@ -320,7 +320,7 @@ def make_grid(self, center: Coordinate, size: Size, axis: Axis) -> EMEGrid: @classmethod def from_structures( - cls, structures: list[Structure], axis: Axis, mode_spec: EMEModeSpec, **kwargs + cls, structures: list[Structure], axis: Axis, mode_spec: EMEModeSpec, **kwargs: Any ) -> EMEExplicitGrid: """Create an explicit EME grid with boundaries aligned with structure bounding boxes. Every cell in the resulting grid diff --git a/tidy3d/components/eme/simulation.py b/tidy3d/components/eme/simulation.py index b01b928e4f..263a2cf434 100644 --- a/tidy3d/components/eme/simulation.py +++ b/tidy3d/components/eme/simulation.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Literal, Optional, Union +from typing import Any, Literal, Optional, Union try: import matplotlib as mpl @@ -314,7 +314,7 @@ def plot_eme_ports( ax: Ax = None, hlim: Optional[tuple[float, float]] = None, vlim: Optional[tuple[float, float]] = None, - **kwargs, + **kwargs: Any, ) -> Ax: """Plot the EME ports.""" kwargs.setdefault("linewidth", 0.4) @@ -358,7 +358,7 @@ def plot_eme_subgrid_boundaries( ax: Ax = None, hlim: Optional[tuple[float, float]] = None, vlim: Optional[tuple[float, float]] = None, - **kwargs, + **kwargs: Any, ) -> Ax: """Plot the EME subgrid boundaries. Does nothing if ``eme_grid_spec`` is not :class:`.EMECompositeGrid`. @@ -410,7 +410,7 @@ def plot_eme_grid( ax: Ax = None, hlim: Optional[tuple[float, float]] = None, vlim: Optional[tuple[float, float]] = None, - **kwargs, + **kwargs: Any, ) -> Ax: """Plot the EME grid.""" kwargs.setdefault("linewidth", 0.2) @@ -453,7 +453,7 @@ def plot( monitor_alpha: Optional[float] = None, hlim: Optional[tuple[float, float]] = None, vlim: Optional[tuple[float, float]] = None, - **patch_kwargs, + **patch_kwargs: Any, ) -> Ax: """Plot each of simulation's components on a plane defined by one nonzero x,y,z coordinate. @@ -526,7 +526,7 @@ def eme_grid(self) -> EMEGrid: return self.eme_grid_spec.make_grid(center=center, size=size, axis=self.axis) @classmethod - def from_scene(cls, scene: Scene, **kwargs) -> EMESimulation: + def from_scene(cls, scene: Scene, **kwargs: Any) -> EMESimulation: """Create an EME simulation from a :`.Scene` instance. Must provide additional parameters to define a valid EME simulation (for example, ``size``, ``grid_spec``, etc). @@ -605,7 +605,7 @@ def validate_pre_upload(self) -> None: # self._warn_monitor_interval() log.end_capture(self) - def _validate_too_close_to_edges(self): + def _validate_too_close_to_edges(self) -> None: """Can't have mode planes closer to boundary than extreme Yee grid center.""" cell_centers = self.eme_grid.centers yee_centers = list(self.grid.centers.to_dict.values())[self.axis] @@ -632,7 +632,7 @@ def _validate_too_close_to_edges(self): "Please move the monitor further from the boundary." ) - def _validate_constraint(self): + def _validate_constraint(self) -> None: """Constraint can be slow with too many modes. Warn in this case.""" constraint = self.constraint max_num_modes = self.max_num_modes @@ -645,7 +645,7 @@ def _validate_constraint(self): "reducing the number of modes or setting 'constraint=None'." ) - def _validate_port_offsets(self): + def _validate_port_offsets(self) -> None: """Port offsets cannot jointly exceed simulation length.""" total_offset = self.port_offsets[0] + self.port_offsets[1] size = self.size @@ -656,7 +656,7 @@ def _validate_port_offsets(self): "cannot exceed the simulation 'size' in the 'axis' direction." ) - def _validate_symmetry(self): + def _validate_symmetry(self) -> None: """Symmetry in propagation direction is not supported.""" if self.symmetry[self.axis] != 0: raise SetupError("Symmetry in the propagation diretion is not currently supported.") @@ -673,7 +673,7 @@ def _validate_symmetry(self): # "it always monitors every EME cell." # ) - def _validate_sweep_spec_size(self): + def _validate_sweep_spec_size(self) -> None: """Make sure sweep spec is not too large.""" if self.sweep_spec is None: return @@ -684,7 +684,7 @@ def _validate_sweep_spec_size(self): f"which exceeds the maximum allowed '{MAX_NUM_SWEEP}'." ) - def _validate_sweep_spec(self): + def _validate_sweep_spec(self) -> None: """Validate sweep spec.""" if self.sweep_spec is None: return @@ -743,7 +743,7 @@ def _validate_sweep_spec(self): "which is not compatible with 'EMEPeriodicitySweep'." ) - def _validate_monitor_setup(self): + def _validate_monitor_setup(self) -> None: """Check monitor setup.""" for i, monitor in enumerate(self.monitors): if isinstance(monitor, EMEMonitor): @@ -873,7 +873,7 @@ def _validate_monitor_size(self) -> None: def _validate_modes_size(self) -> None: """Warn if mode sources or monitors have a large number of points.""" - def warn_mode_size(monitor: AbstractModeMonitor, msg_header: str, custom_loc: list): + def warn_mode_size(monitor: AbstractModeMonitor, msg_header: str, custom_loc: list) -> None: """Warn if a mode component has a large number of points.""" num_cells = np.prod(self.discretize_monitor(monitor).num_cells) if num_cells > WARN_MODE_NUM_CELLS: @@ -1116,7 +1116,7 @@ def subsection( monitors: Optional[tuple[MonitorType, ...]] = None, remove_outside_structures: bool = True, remove_outside_custom_mediums: bool = False, - **kwargs, + **kwargs: Any, ) -> EMESimulation: """Generate a simulation instance containing only the ``region``. Same as in :class:`.AbstractYeeGridSimulation`, except also restricting EME grid. diff --git a/tidy3d/components/frequencies.py b/tidy3d/components/frequencies.py index f6f37b0499..125d94b4f4 100644 --- a/tidy3d/components/frequencies.py +++ b/tidy3d/components/frequencies.py @@ -2,6 +2,8 @@ from __future__ import annotations +from typing import Any + import numpy as np import pydantic as pd import pydantic.v1 as pydantic @@ -526,7 +528,7 @@ def wvls(self, num_points: int, spacing: str = "uniform_wvl") -> NDArray[np.floa f"Received: {spacing!r}. Please provide a valid spacing type." ) - def to_gaussian_pulse(self, **kwargs) -> GaussianPulse: + def to_gaussian_pulse(self, **kwargs: Any) -> GaussianPulse: """ to_gaussian_pulse(): Return a ``GaussianPulse`` instance based on this frequency range. diff --git a/tidy3d/components/geometry/base.py b/tidy3d/components/geometry/base.py index 59b1241e47..aa71653b58 100644 --- a/tidy3d/components/geometry/base.py +++ b/tidy3d/components/geometry/base.py @@ -139,7 +139,7 @@ def point_inside(x: float, y: float, z: float): return inside.reshape(arrays[0].shape) @staticmethod - def _ensure_equal_shape(*arrays): + def _ensure_equal_shape(*arrays: Any) -> None: """Ensure all input arrays have the same shape.""" shapes = {np.array(arr).shape for arr in arrays} if len(shapes) > 1: @@ -510,7 +510,7 @@ def plot( ax: Ax = None, plot_length_units: LengthUnit = None, viz_spec: VisualizationSpec = None, - **patch_kwargs, + **patch_kwargs: Any, ) -> Ax: """Plot geometry cross section at single (x,y,z) coordinate. @@ -780,7 +780,7 @@ def unpop_axis(ax_coord: Any, plane_coords: tuple[Any, Any], axis: int) -> tuple return tuple(coords) @staticmethod - def parse_xyz_kwargs(**xyz) -> tuple[Axis, float]: + def parse_xyz_kwargs(**xyz: Any) -> tuple[Axis, float]: """Turns x,y,z kwargs into index of the normal axis and position along that axis. Parameters @@ -805,7 +805,7 @@ def parse_xyz_kwargs(**xyz) -> tuple[Axis, float]: return axis, position @staticmethod - def parse_two_xyz_kwargs(**xyz) -> list[tuple[Axis, float]]: + def parse_two_xyz_kwargs(**xyz: Any) -> list[tuple[Axis, float]]: """Turns x,y,z kwargs into indices of axes and the position along each axis. Parameters @@ -1867,7 +1867,7 @@ class Box(SimplePlaneIntersection, Centered): ) @classmethod - def from_bounds(cls, rmin: Coordinate, rmax: Coordinate, **kwargs): + def from_bounds(cls, rmin: Coordinate, rmax: Coordinate, **kwargs: Any): """Constructs a :class:`Box` from minimum and maximum coordinate bounds Parameters @@ -1896,7 +1896,7 @@ def _normal_axis(self) -> Axis: return self.size.index(0.0) @classmethod - def surfaces(cls, size: Size, center: Coordinate, **kwargs): + def surfaces(cls, size: Size, center: Coordinate, **kwargs: Any): """Returns a list of 6 :class:`Box` instances corresponding to each surface of a 3D volume. The output surfaces are stored in the order [x-, x+, y-, y+, z-, z+], where x, y, and z denote which axis is perpendicular to that surface, while "-" and "+" denote the direction @@ -1984,7 +1984,7 @@ def del_items(items, indices): return surfaces @classmethod - def surfaces_with_exclusion(cls, size: Size, center: Coordinate, **kwargs): + def surfaces_with_exclusion(cls, size: Size, center: Coordinate, **kwargs: Any): """Returns a list of 6 :class:`Box` instances corresponding to each surface of a 3D volume. The output surfaces are stored in the order [x-, x+, y-, y+, z-, z+], where x, y, and z denote which axis is perpendicular to that surface, while "-" and "+" denote the direction @@ -2319,7 +2319,7 @@ def _plot_arrow( @staticmethod def _arrow_shape_cb(arrow, pos, direction, sign, bend_radius): - def _cb(event): + def _cb(event) -> None: # We only want to set the shape once, so we disconnect ourselves event.canvas.mpl_disconnect(arrow.set_shape_cb[0]) diff --git a/tidy3d/components/geometry/mesh.py b/tidy3d/components/geometry/mesh.py index ccf6305c8f..434a527412 100644 --- a/tidy3d/components/geometry/mesh.py +++ b/tidy3d/components/geometry/mesh.py @@ -3,7 +3,7 @@ from __future__ import annotations from abc import ABC -from typing import Callable, Literal, Optional, Union +from typing import Any, Callable, Literal, Optional, Union import numpy as np import pydantic.v1 as pydantic @@ -153,7 +153,7 @@ def from_stl( scale: float = 1.0, origin: tuple[float, float, float] = (0, 0, 0), solid_index: Optional[int] = None, - **kwargs, + **kwargs: Any, ) -> Union[TriangleMesh, base.GeometryGroup]: """Load a :class:`.TriangleMesh` directly from an STL file. The ``solid_index`` parameter can be used to select a single solid from the file. @@ -660,7 +660,7 @@ def plot( y: Optional[float] = None, z: Optional[float] = None, ax: Ax = None, - **patch_kwargs, + **patch_kwargs: Any, ) -> Ax: """Plot geometry cross section at single (x,y,z) coordinate. diff --git a/tidy3d/components/geometry/primitives.py b/tidy3d/components/geometry/primitives.py index b75304c2ab..ec07562ee3 100644 --- a/tidy3d/components/geometry/primitives.py +++ b/tidy3d/components/geometry/primitives.py @@ -3,7 +3,7 @@ from __future__ import annotations from math import isclose -from typing import Optional +from typing import Any, Optional import autograd.numpy as anp import numpy as np @@ -228,7 +228,7 @@ def _only_middle_for_infinite_length_slanted_cylinder(cls, val, values): return val def to_polyslab( - self, num_pts_circumference: int = _N_PTS_CYLINDER_POLYSLAB, **kwargs + self, num_pts_circumference: int = _N_PTS_CYLINDER_POLYSLAB, **kwargs: Any ) -> PolySlab: """Convert instance of ``Cylinder`` into a discretized version using ``PolySlab``. diff --git a/tidy3d/components/geometry/utils.py b/tidy3d/components/geometry/utils.py index 8f4c556cf0..56109ddaa1 100644 --- a/tidy3d/components/geometry/utils.py +++ b/tidy3d/components/geometry/utils.py @@ -366,7 +366,9 @@ def vertices_from_shapely(shape: Shapely) -> ArrayFloat2D: raise Tidy3dError(f"Shape {shape} cannot be converted to Geometry.") -def validate_no_transformed_polyslabs(geometry: GeometryType, transform: MatrixReal4x4 = None): +def validate_no_transformed_polyslabs( + geometry: GeometryType, transform: MatrixReal4x4 = None +) -> None: """Prevents the creation of slanted polyslabs rotated out of plane.""" if transform is None: transform = np.eye(4) diff --git a/tidy3d/components/grid/grid_spec.py b/tidy3d/components/grid/grid_spec.py index 93a945eac8..6ad1013af9 100644 --- a/tidy3d/components/grid/grid_spec.py +++ b/tidy3d/components/grid/grid_spec.py @@ -118,7 +118,7 @@ def _make_coords_initial( self, axis: Axis, structures: list[StructureType], - **kwargs, + **kwargs: Any, ) -> Coords1D: """Generate 1D coords to be used as grid boundaries, based on simulation parameters. Symmetry, PML etc. are not considered in this method. @@ -303,7 +303,7 @@ def _make_coords_initial( self, axis: Axis, structures: list[StructureType], - **kwargs, + **kwargs: Any, ) -> Coords1D: """Uniform 1D coords to be used as grid boundaries. @@ -375,7 +375,7 @@ def _make_coords_initial( self, axis: Axis, structures: list[StructureType], - **kwargs, + **kwargs: Any, ) -> Coords1D: """Customized 1D coords to be used as grid boundaries. @@ -471,7 +471,7 @@ def _make_coords_initial( self, axis: Axis, structures: list[StructureType], - **kwargs, + **kwargs: Any, ) -> Coords1D: """Customized 1D coords to be used as grid boundaries. @@ -1109,7 +1109,7 @@ def from_layer_bounds( refinement_inside_sim_only: bool = True, gap_meshing_iters: pd.NonNegativeInt = 1, dl_min_from_gap_width: bool = True, - **kwargs, + **kwargs: Any, ): """Constructs a :class:`LayerRefinementSpec` that is unbounded in inplane dimensions from bounds along layer thickness dimension. @@ -1185,7 +1185,7 @@ def from_bounds( refinement_inside_sim_only: bool = True, gap_meshing_iters: pd.NonNegativeInt = 1, dl_min_from_gap_width: bool = True, - **kwargs, + **kwargs: Any, ): """Constructs a :class:`LayerRefinementSpec` from minimum and maximum coordinate bounds. @@ -1262,7 +1262,7 @@ def from_structures( refinement_inside_sim_only: bool = True, gap_meshing_iters: pd.NonNegativeInt = 1, dl_min_from_gap_width: bool = True, - **kwargs, + **kwargs: Any, ): """Constructs a :class:`LayerRefinementSpec` from the bounding box of a list of structures. diff --git a/tidy3d/components/material/tcad/charge.py b/tidy3d/components/material/tcad/charge.py index aee8d1a5e6..94d8cdb778 100644 --- a/tidy3d/components/material/tcad/charge.py +++ b/tidy3d/components/material/tcad/charge.py @@ -41,7 +41,7 @@ def charge(self): def eps_model(self, frequency: float) -> complex: return self.permittivity - def n_cfl(self): + def n_cfl(self) -> None: return None diff --git a/tidy3d/components/material/tcad/heat.py b/tidy3d/components/material/tcad/heat.py index 47014cbdfd..8e800177de 100644 --- a/tidy3d/components/material/tcad/heat.py +++ b/tidy3d/components/material/tcad/heat.py @@ -33,15 +33,15 @@ def heat(self): return self @property - def charge(self): + def charge(self) -> None: raise ValueError(f"A `charge` medium does not exist in this Medium definition: {self}") @property - def electrical(self): + def electrical(self) -> None: raise ValueError(f"An `electrical` medium does not exist in this Medium definition: {self}") @property - def optical(self): + def optical(self) -> None: raise ValueError(f"An `optical` medium does not exist in this Medium definition: {self}") diff --git a/tidy3d/components/medium.py b/tidy3d/components/medium.py index e733df186c..def1efd5a8 100644 --- a/tidy3d/components/medium.py +++ b/tidy3d/components/medium.py @@ -5,7 +5,7 @@ import functools from abc import ABC, abstractmethod from math import isclose -from typing import Callable, Literal, Optional, Union +from typing import Any, Callable, Literal, Optional, Union import autograd.numpy as np @@ -160,7 +160,7 @@ class NonlinearModel(ABC, Tidy3dBaseModel): """Abstract model for a nonlinear material response. Used as part of a :class:`.NonlinearSpec`.""" - def _validate_medium_type(self, medium: AbstractMedium): + def _validate_medium_type(self, medium: AbstractMedium) -> None: """Check that the model is compatible with the medium.""" if isinstance(medium, AbstractCustomMedium): raise ValidationError( @@ -178,7 +178,7 @@ def _validate_medium_type(self, medium: AbstractMedium): f"for medium class '{type(medium).__name__}'." ) - def _validate_medium(self, medium: AbstractMedium): + def _validate_medium(self, medium: AbstractMedium) -> None: """Any additional validation that depends on the medium""" def _validate_medium_freqs(self, medium: AbstractMedium, freqs: list[pd.PositiveFloat]) -> None: @@ -502,7 +502,7 @@ def _hardcode_medium_freqs( freq0 = self._get_freq0(freq0=self.freq0, freqs=freqs) return self.updated_copy(n0=n0, freq0=freq0) - def _validate_medium(self, medium: AbstractMedium): + def _validate_medium(self, medium: AbstractMedium) -> None: """Check that the model is compatible with the medium.""" # if n0 is specified, we can go ahead and validate passivity if self.n0 is not None: @@ -628,7 +628,7 @@ def _validate_medium_freqs(self, medium: AbstractMedium, freqs: list[pd.Positive "gain medium are unstable, and are likely to diverge." ) - def _validate_medium(self, medium: AbstractMedium): + def _validate_medium(self, medium: AbstractMedium) -> None: """Check that the model is compatible with the medium.""" # if n0 is specified, we can go ahead and validate passivity if self.n0 is not None: @@ -813,7 +813,7 @@ def _post_init_validators(self) -> None: self._validate_nonlinear_spec() self._validate_modulation_spec_post_init() - def _validate_nonlinear_spec(self): + def _validate_nonlinear_spec(self) -> None: """Check compatibility with nonlinear_spec.""" if self.__class__.__name__ == "AnisotropicMedium" and any( comp.nonlinear_spec is not None for comp in [self.xx, self.yy, self.zz] @@ -851,7 +851,7 @@ def _validate_nonlinear_spec(self): "Please use 'NonlinearSpec.num_iters' instead." ) - def _validate_modulation_spec_post_init(self): + def _validate_modulation_spec_post_init(self) -> None: """Check compatibility with nonlinear_spec.""" if self.__class__.__name__ == "Medium2D" and any( comp.modulation_spec is not None for comp in [self.ss, self.tt] @@ -875,11 +875,11 @@ def _validate_modulation_spec_post_init(self): ) @property - def charge(self): + def charge(self) -> None: return None @property - def electrical(self): + def electrical(self) -> None: return None @property @@ -887,7 +887,7 @@ def heat(self): return self.heat_spec @property - def optical(self): + def optical(self) -> None: return None @pd.validator("modulation_spec", always=True) @@ -1104,7 +1104,7 @@ def _eps_plot( @cached_property @abstractmethod - def n_cfl(self): + def n_cfl(self) -> None: # TODO this should be moved out of here into FDTD Simulation Mediums? """To ensure a stable FDTD simulation, it is essential to select an appropriate time step size in accordance with the CFL condition. The maximal time step @@ -1638,7 +1638,7 @@ def _validate_isreal_dataarray_tuple( return np.all([AbstractCustomMedium._validate_isreal_dataarray(f) for f in dataarray_tuple]) @abstractmethod - def _sel_custom_data_inside(self, bounds: Bound): + def _sel_custom_data_inside(self, bounds: Bound) -> None: """Return a new medium that contains the minimal amount custom data necessary to cover a spatial region defined by ``bounds``.""" @@ -1954,7 +1954,7 @@ def eps_model(self, frequency: float) -> complex: return self._eps_model(self.permittivity, self.conductivity, frequency) @classmethod - def from_nk(cls, n: float, k: float, freq: float, **kwargs): + def from_nk(cls, n: float, k: float, freq: float, **kwargs: Any): """Convert ``n`` and ``k`` values at frequency ``freq`` to :class:`.Medium`. Parameters @@ -2646,7 +2646,7 @@ def from_eps_raw( eps: Union[ScalarFieldDataArray, CustomSpatialDataType], freq: Optional[float] = None, interp_method: InterpMethod = "nearest", - **kwargs, + **kwargs: Any, ) -> CustomMedium: """Construct a :class:`.CustomMedium` from datasets containing raw permittivity values. @@ -2716,7 +2716,7 @@ def from_nk( k: Optional[Union[ScalarFieldDataArray, CustomSpatialDataType]] = None, freq: Optional[float] = None, interp_method: InterpMethod = "nearest", - **kwargs, + **kwargs: Any, ) -> CustomMedium: """Construct a :class:`.CustomMedium` from datasets containing n and k values. @@ -4302,7 +4302,7 @@ def _from_dispersion_to_coeffs(n: float, freq: float, dn_dwvl: float): return [(b_coeff, c_coeff)] @classmethod - def from_dispersion(cls, n: float, freq: float, dn_dwvl: float = 0, **kwargs): + def from_dispersion(cls, n: float, freq: float, dn_dwvl: float = 0, **kwargs: Any): """Convert ``n`` and wavelength dispersion ``dn_dwvl`` values at frequency ``freq`` to a single-pole :class:`Sellmeier` medium. @@ -4530,7 +4530,7 @@ def from_dispersion( freq: float, dn_dwvl: CustomSpatialDataType, interp_method="nearest", - **kwargs, + **kwargs: Any, ): """Convert ``n`` and wavelength dispersion ``dn_dwvl`` values at frequency ``freq`` to a single-pole :class:`CustomSellmeier` medium. @@ -4770,7 +4770,7 @@ def _all_larger(coeff_a, coeff_b) -> bool: return coeff_a > coeff_b @classmethod - def from_nk(cls, n: float, k: float, freq: float, **kwargs): + def from_nk(cls, n: float, k: float, freq: float, **kwargs: Any): """Convert ``n`` and ``k`` values at frequency ``freq`` to a single-pole Lorentz medium. @@ -7187,7 +7187,7 @@ def from_unperturbed( medium: Union[Medium, DispersiveMedium], subpixel: bool = True, perturbation_spec: Union[PermittivityPerturbation, IndexPerturbation] = None, - **kwargs, + **kwargs: Any, ) -> AbstractPerturbationMedium: """Construct a medium with pertubation models from an unpertubed one. @@ -8079,7 +8079,7 @@ def is_comp_pec_2d(self, comp: Axis, axis: Axis): # Utility function -def medium_from_nk(n: float, k: float, freq: float, **kwargs) -> Union[Medium, Lorentz]: +def medium_from_nk(n: float, k: float, freq: float, **kwargs: Any) -> Union[Medium, Lorentz]: """Convert ``n`` and ``k`` values at frequency ``freq`` to :class:`.Medium` if ``Re[epsilon]>=1``, or :class:`Lorentz` if if ``Re[epsilon]<1``. diff --git a/tidy3d/components/microwave/path_integrals/integrals/base.py b/tidy3d/components/microwave/path_integrals/integrals/base.py index 04fa762596..34527cce14 100644 --- a/tidy3d/components/microwave/path_integrals/integrals/base.py +++ b/tidy3d/components/microwave/path_integrals/integrals/base.py @@ -116,7 +116,7 @@ def _get_field_along_path(self, scalar_field: EMScalarFieldType) -> EMScalarFiel return scalar_field @staticmethod - def _check_monitor_data_supported(em_field: IntegrableMonitorDataType): + def _check_monitor_data_supported(em_field: IntegrableMonitorDataType) -> None: """Helper for validating that monitor data is supported.""" if not isinstance(em_field, (FieldData, FieldTimeData, ModeData, ModeSolverData)): supported_types = list(IntegrableMonitorDataType.__args__) diff --git a/tidy3d/components/microwave/path_integrals/specs/current.py b/tidy3d/components/microwave/path_integrals/specs/current.py index 8447902e47..f2e7c0063a 100644 --- a/tidy3d/components/microwave/path_integrals/specs/current.py +++ b/tidy3d/components/microwave/path_integrals/specs/current.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Literal, Optional, Union +from typing import Any, Literal, Optional, Union import numpy as np import pydantic.v1 as pd @@ -151,7 +151,7 @@ def plot( y: Optional[float] = None, z: Optional[float] = None, ax: Ax = None, - **path_kwargs, + **path_kwargs: Any, ) -> Ax: """Plot path integral at single (x,y,z) coordinate. @@ -246,7 +246,7 @@ def plot( y: Optional[float] = None, z: Optional[float] = None, ax: Ax = None, - **path_kwargs, + **path_kwargs: Any, ) -> Ax: """Plot path integral at single (x,y,z) coordinate. @@ -335,7 +335,7 @@ def plot( y: Optional[float] = None, z: Optional[float] = None, ax: Ax = None, - **path_kwargs, + **path_kwargs: Any, ) -> Ax: """Plot path integral at single (x,y,z) coordinate. diff --git a/tidy3d/components/microwave/path_integrals/specs/voltage.py b/tidy3d/components/microwave/path_integrals/specs/voltage.py index 340940f20b..e564502d85 100644 --- a/tidy3d/components/microwave/path_integrals/specs/voltage.py +++ b/tidy3d/components/microwave/path_integrals/specs/voltage.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Optional +from typing import Any, Optional import numpy as np import pydantic.v1 as pd @@ -98,7 +98,7 @@ def plot( y: Optional[float] = None, z: Optional[float] = None, ax: Ax = None, - **path_kwargs, + **path_kwargs: Any, ) -> Ax: """Plot path integral at single (x,y,z) coordinate. @@ -163,7 +163,7 @@ def plot( y: Optional[float] = None, z: Optional[float] = None, ax: Ax = None, - **path_kwargs, + **path_kwargs: Any, ) -> Ax: """Plot path integral at single (x,y,z) coordinate. diff --git a/tidy3d/components/mode/data/sim_data.py b/tidy3d/components/mode/data/sim_data.py index 7647d220e7..9ba247161a 100644 --- a/tidy3d/components/mode/data/sim_data.py +++ b/tidy3d/components/mode/data/sim_data.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Literal, Optional, Union +from typing import Any, Literal, Optional, Union import pydantic.v1 as pd @@ -53,7 +53,7 @@ def plot_field( vmin: Optional[float] = None, vmax: Optional[float] = None, ax: Ax = None, - **sel_kwargs, + **sel_kwargs: Any, ) -> Ax: """Plot the field for a :class:`.ModeSolverData` with :class:`.Simulation` plot overlaid. diff --git a/tidy3d/components/mode/mode_solver.py b/tidy3d/components/mode/mode_solver.py index f703ca812e..3f9be545d0 100644 --- a/tidy3d/components/mode/mode_solver.py +++ b/tidy3d/components/mode/mode_solver.py @@ -6,7 +6,7 @@ from functools import wraps from math import isclose -from typing import Literal, Optional, Union, get_args +from typing import Any, Literal, Optional, Union, get_args import numpy as np import pydantic.v1 as pydantic @@ -116,7 +116,7 @@ def require_fdtd_simulation(fn): """Decorate a function to check that ``simulation`` is an FDTD ``Simulation``.""" @wraps(fn) - def _fn(self, **kwargs): + def _fn(self, **kwargs: Any): """New decorated function.""" if not isinstance(self.simulation, Simulation): raise SetupError( @@ -274,7 +274,7 @@ def _warn_thick_pml( plane: Box, mode_spec: ModeSpec, msg_prefix: str = "'ModeSolver'", - ): + ) -> None: """Warn if the pml covers a significant portion of the mode plane.""" coord_0, coord_1 = cls._plane_grid( simulation=simulation, @@ -302,7 +302,7 @@ def _mode_plane(plane: Box, sim_geom: Box) -> Box: return Box.from_bounds(*mode_plane_bnds) @classmethod - def _validate_mode_plane_radius(cls, mode_spec: ModeSpec, plane: Box, sim_geom: Box): + def _validate_mode_plane_radius(cls, mode_spec: ModeSpec, plane: Box, sim_geom: Box) -> None: """Validate that the radius of a mode spec with a bend is not smaller than half the size of the plane along the radial direction.""" @@ -1338,7 +1338,7 @@ def _colocate_data(self, mode_solver_data: ModeSolverData) -> ModeSolverData: return mode_solver_data - def _normalize_modes(self, mode_solver_data: ModeSolverData): + def _normalize_modes(self, mode_solver_data: ModeSolverData) -> None: """Normalize modes. Note: this modifies ``mode_solver_data`` in-place.""" scaling = np.sqrt(np.abs(mode_solver_data.flux)) for field in mode_solver_data.field_components.values(): @@ -1809,7 +1809,7 @@ def _process_fields( return ((Ex, Ey, Ez), (Hx, Hy, Hz)) - def _field_decay_warning(self, field_data: ModeSolverData): + def _field_decay_warning(self, field_data: ModeSolverData) -> None: """Warn if any of the modes do not decay at the edges.""" _, plane_dims = self.plane.pop_axis(["x", "y", "z"], axis=self.normal_axis) field_sizes = field_data.Ex.sizes @@ -1968,7 +1968,7 @@ def to_source( direction: Direction = None, mode_index: pydantic.NonNegativeInt = 0, num_freqs: pydantic.PositiveInt = 1, - **kwargs, + **kwargs: Any, ) -> ModeSource: """Creates :class:`.ModeSource` from a :class:`.ModeSolver` instance plus additional specifications. @@ -2184,7 +2184,7 @@ def plot_field( vmin: Optional[float] = None, vmax: Optional[float] = None, ax: Ax = None, - **sel_kwargs, + **sel_kwargs: Any, ) -> Ax: """Plot the field for a :class:`.ModeSolverData` with :class:`.Simulation` plot overlaid. @@ -2244,7 +2244,7 @@ def plot( hlim: Optional[tuple[float, float]] = None, vlim: Optional[tuple[float, float]] = None, fill_structures: bool = True, - **patch_kwargs, + **patch_kwargs: Any, ) -> Ax: """Plot the mode plane simulation's components. @@ -2414,7 +2414,7 @@ def plot_structures_eps( def plot_grid( self, ax: Ax = None, - **kwargs, + **kwargs: Any, ) -> Ax: """Plot the mode plane cell boundaries as lines. @@ -2635,7 +2635,7 @@ def _center_and_lims(simulation: Simulation, plane: Box) -> tuple[list, list, li return a_center, h_lim, v_lim, t_axes - def _validate_modes_size(self): + def _validate_modes_size(self) -> None: """Make sure that the total size of the modes fields is not too large.""" monitor = self.to_mode_solver_monitor(name=MODE_MONITOR_NAME) num_cells = self.simulation._monitor_num_cells(monitor) @@ -2649,7 +2649,7 @@ def _validate_modes_size(self): "frequencies or modes." ) - def validate_pre_upload(self, source_required: bool = True): + def validate_pre_upload(self, source_required: bool = True) -> None: """Validate the fully initialized mode solver is ok for upload to our servers.""" self._validate_modes_size() @@ -2747,7 +2747,7 @@ def as_fdtd_mode_solver(self) -> ModeSolver: :class:`.ModeSolver` webapi.""" return self.to_fdtd_mode_solver() - def _patch_data(self, data: ModeSolverData): + def _patch_data(self, data: ModeSolverData) -> None: """ Patch the :class:`.ModeSolver` with the provided data so that it will be used everywhere instead of locally-computed data. diff --git a/tidy3d/components/mode/simulation.py b/tidy3d/components/mode/simulation.py index d0190747af..2e836c55ec 100644 --- a/tidy3d/components/mode/simulation.py +++ b/tidy3d/components/mode/simulation.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Optional, Union +from typing import Any, Optional, Union import numpy as np import pydantic.v1 as pd @@ -320,7 +320,7 @@ def from_simulation( cls, simulation: AbstractYeeGridSimulation, wavelength: Optional[pd.PositiveFloat] = None, - **kwargs, + **kwargs: Any, ) -> ModeSimulation: """Creates :class:`.ModeSimulation` from a :class:`.AbstractYeeGridSimulation`. @@ -413,7 +413,7 @@ def plot( hlim: Optional[tuple[float, float]] = None, vlim: Optional[tuple[float, float]] = None, fill_structures: bool = True, - **patch_kwargs, + **patch_kwargs: Any, ) -> Ax: """Plot the mode simulation. If any of ``x``, ``y``, or ``z`` is provided, the potentially larger FDTD simulation containing the mode plane is plotted at the desired location. @@ -473,7 +473,7 @@ def plot( def plot_mode_plane( self, ax: Ax = None, - **patch_kwargs, + **patch_kwargs: Any, ) -> Ax: """Plot the mode plane simulation's components. @@ -574,7 +574,7 @@ def plot_structures_eps_mode_plane( def plot_grid_mode_plane( self, ax: Ax = None, - **kwargs, + **kwargs: Any, ) -> Ax: """Plot the mode plane cell boundaries as lines. @@ -612,7 +612,7 @@ def plot_pml_mode_plane( """ return self._mode_solver.plot_pml(ax=ax) - def validate_pre_upload(self, source_required: bool = False): + def validate_pre_upload(self, source_required: bool = False) -> None: super().validate_pre_upload() self._mode_solver.validate_pre_upload(source_required=source_required) diff --git a/tidy3d/components/mode/solver.py b/tidy3d/components/mode/solver.py index afb4fc9671..bb107d9d16 100644 --- a/tidy3d/components/mode/solver.py +++ b/tidy3d/components/mode/solver.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Optional +from typing import TYPE_CHECKING, Any, Optional import numpy as np @@ -855,7 +855,7 @@ def solver_eigs( vec_init, guess_value=1.0, M=None, - **kwargs, + **kwargs: Any, ): """Find ``num_modes`` eigenmodes of ``mat`` cloest to ``guess_value``. @@ -894,7 +894,7 @@ def solver_eigs_relative( guess_value=1.0, M=None, basis_vecs=None, - **kwargs, + **kwargs: Any, ): """Find ``num_modes`` eigenmodes of ``mat`` cloest to ``guess_value``. @@ -1076,7 +1076,7 @@ def make_pml_invariant(Nxy, tensor, num_pml): return new_ten.reshape((3, 3, -1)) @staticmethod - def split_curl_field_postprocess_inverse(split_curl, E): + def split_curl_field_postprocess_inverse(split_curl, E) -> None: """E has the shape (3, N, num_modes)""" raise RuntimeError("Split curl not yet implemented for relative mode solver.") @@ -1090,6 +1090,6 @@ def mode_plane_contain_good_conductor(material_response) -> bool: return np.any(np.abs(material_response) > GOOD_CONDUCTOR_THRESHOLD * np.abs(pec_val)) -def compute_modes(*args, **kwargs) -> tuple[Numpy, Numpy, str]: +def compute_modes(*args: Any, **kwargs: Any) -> tuple[Numpy, Numpy, str]: """A wrapper around ``EigSolver.compute_modes``, which is used in :class:`.ModeSolver`.""" return EigSolver.compute_modes(*args, **kwargs) diff --git a/tidy3d/components/monitor.py b/tidy3d/components/monitor.py index 2e594168a2..ba0c37e916 100644 --- a/tidy3d/components/monitor.py +++ b/tidy3d/components/monitor.py @@ -3,7 +3,7 @@ from __future__ import annotations from abc import ABC, abstractmethod -from typing import Literal, Optional +from typing import Any, Literal, Optional import numpy as np import pydantic.v1 as pydantic @@ -364,7 +364,7 @@ def plot( y: Optional[float] = None, z: Optional[float] = None, ax: Ax = None, - **patch_kwargs, + **patch_kwargs: Any, ) -> Ax: """Plot this monitor.""" # call the monitor.plot() function first diff --git a/tidy3d/components/scene.py b/tidy3d/components/scene.py index 85b643188c..c502b4ceec 100644 --- a/tidy3d/components/scene.py +++ b/tidy3d/components/scene.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Literal, Optional, Union +from typing import Any, Literal, Optional, Union import autograd.numpy as np @@ -463,7 +463,7 @@ def plot( hlim: Optional[tuple[float, float]] = None, vlim: Optional[tuple[float, float]] = None, fill_structures: bool = True, - **patch_kwargs, + **patch_kwargs: Any, ) -> Ax: """Plot each of scene's components on a plane defined by one nonzero x,y,z coordinate. @@ -1269,7 +1269,7 @@ def _pcolormesh_shape_custom_medium_structure_eps( grid: Grid, eps_component: Optional[PermittivityComponent] = None, norm: mpl.colors.Normalize = None, - ): + ) -> None: """ Plot shape made of custom medium with ``pcolormesh``. """ @@ -2096,7 +2096,7 @@ def _pcolormesh_shape_doping_box( ax: Ax, plt_type: str = "doping", norm: mpl.colors.Normalize = None, - ): + ) -> None: """ Plot shape made of structure defined with doping. plt_type accepts ["doping", "N_a", "N_d"] diff --git a/tidy3d/components/simulation.py b/tidy3d/components/simulation.py index 0b127d8bb5..05ffbff6b6 100644 --- a/tidy3d/components/simulation.py +++ b/tidy3d/components/simulation.py @@ -7,7 +7,7 @@ from abc import ABC, abstractmethod from collections import defaultdict from os import PathLike -from typing import Literal, Optional, Union, get_args +from typing import Any, Literal, Optional, Union, get_args import autograd.numpy as np @@ -418,7 +418,7 @@ def _check_3d_simulation_with_lumped_elements(cls, val, values): @pydantic.validator("grid_spec", always=True) @abstractmethod - def _validate_auto_grid_wavelength(cls, val, values): + def _validate_auto_grid_wavelength(cls, val, values) -> None: """Check that wavelength can be defined if there is auto grid spec.""" def _monitor_num_cells(self, monitor: Monitor) -> int: @@ -554,7 +554,7 @@ def plot( hlim: Optional[tuple[float, float]] = None, vlim: Optional[tuple[float, float]] = None, fill_structures: bool = True, - **patch_kwargs, + **patch_kwargs: Any, ) -> Ax: """Plot each of simulation's components on a plane defined by one nonzero x,y,z coordinate. @@ -1080,7 +1080,7 @@ def plot_grid( vlim: Optional[tuple[float, float]] = None, override_structures_alpha: float = 1, snapping_points_alpha: float = 1, - **kwargs, + **kwargs: Any, ) -> Ax: """Plot the cell boundaries as lines on a plane defined by one nonzero x,y,z coordinate. @@ -1224,7 +1224,7 @@ def plot_boundaries( y: Optional[float] = None, z: Optional[float] = None, ax: Ax = None, - **kwargs, + **kwargs: Any, ) -> Ax: """Plot the simulation boundary conditions as lines on a plane defined by one nonzero x,y,z coordinate. @@ -1841,7 +1841,7 @@ def volumetric_structures(self) -> tuple[Structure]: volumetric equivalents.""" return self._volumetric_structures_grid(self.grid) - def suggest_mesh_overrides(self, **kwargs) -> list[MeshOverrideStructure]: + def suggest_mesh_overrides(self, **kwargs: Any) -> list[MeshOverrideStructure]: """Generate a :class:`.MeshOverrideStructure` `List` which is automatically generated from structures in the simulation. """ @@ -1868,7 +1868,7 @@ def subsection( validate_geometries: bool = True, deep_copy: bool = True, internal_absorbers: Optional[tuple[InternalAbsorber, ...]] = None, - **kwargs, + **kwargs: Any, ) -> AbstractYeeGridSimulation: """Generate a simulation instance containing only the ``region``. @@ -2239,7 +2239,7 @@ def _finalized(self) -> Simulation: return self.updated_copy(grid_spec=GridSpec.from_grid(self.grid), structures=structures) - def _validate_finalized(self): + def _validate_finalized(self) -> None: """Validate that after adding pec frames simulation setup is still valid.""" try: @@ -3391,7 +3391,7 @@ def _structures_not_close_pml(cls, val, values): with log as consolidated_logger: - def warn(structure, istruct, side): + def warn(structure, istruct, side) -> None: """Warning message for a structure too close to PML.""" obj_descr = named_obj_descr(structure, "structures", istruct) consolidated_logger.warning( @@ -4203,7 +4203,7 @@ def _post_init_validators(self) -> None: self._warn_rf_license() self._validate_internal_abc_no_fully_anisotropic() - def _warn_rf_license(self): + def _warn_rf_license(self) -> None: """ Warn about new licensing requirements for RF simulations. This function details all the conditions in which a simulation is categorised as RF simulation at the backend. @@ -4241,7 +4241,9 @@ def _validate_mode_objects(self) -> None: """Create a ModeSolver for each mode object in order to validate.""" from .mode.mode_solver import ModeSolver - def validate_mode_object(mode_obj: Union[ModeSource, AbstractModeMonitor], msg_prefix: str): + def validate_mode_object( + mode_obj: Union[ModeSource, AbstractModeMonitor], msg_prefix: str + ) -> None: # Warn if pml is too thick ModeSolver._warn_thick_pml( simulation=self, @@ -4281,7 +4283,7 @@ def validate_mode_object(mode_obj: Union[ModeSource, AbstractModeMonitor], msg_p except Exception as e: raise SetupError(f"Source at 'sources[{isrc}]' failed validation: {e!s}") from e - def _validate_custom_source_time(self): + def _validate_custom_source_time(self) -> None: """Warn if all simulation times are outside CustomSourceTime definition range.""" run_time = self._run_time for idx, source in enumerate(self.sources): @@ -4415,7 +4417,7 @@ def _aux_tfsf_source(self, source: TFSF) -> PlaneWave: num_freqs=source.num_freqs, ) - def _validate_tfsf_aux_sources(self): + def _validate_tfsf_aux_sources(self) -> None: """Validate that PlaneWave sources auxiliary to TFSF sources can be successfully created.""" for source in self.sources: if isinstance(source, TFSF): @@ -4459,7 +4461,7 @@ def aux_fields(self) -> list[str]: fields += medium.nonlinear_spec.aux_fields return fields - def _validate_internal_abc_no_fully_anisotropic(self): + def _validate_internal_abc_no_fully_anisotropic(self) -> None: """Error if internal absorber intersect fully anisotropic mediums.""" total_structures = [self.scene.background_structure, *list(self.structures)] @@ -4568,7 +4570,7 @@ def _validate_monitor_size(self) -> None: def _validate_modes_size(self) -> None: """Warn if mode sources or monitors have a large number of points.""" - def warn_mode_size(monitor: AbstractModeMonitor, msg_header: str, custom_loc: list): + def warn_mode_size(monitor: AbstractModeMonitor, msg_header: str, custom_loc: list) -> None: """Warn if a mode component has a large number of points.""" num_cells = np.prod(self.discretize_monitor(monitor).num_cells) if num_cells > WARN_MODE_NUM_CELLS: @@ -4608,7 +4610,7 @@ def _validate_num_cells_in_mode_objects(self) -> None: def check_num_cells( mode_object: tuple[ModeSource, ModeMonitor], normal_axis: Axis, msg_header: str - ): + ) -> None: disc_grid = self.discretize(mode_object) _, check_axes = Box.pop_axis([0, 1, 2], axis=normal_axis) for axis in check_axes: @@ -5050,7 +5052,7 @@ def _check_bloch_vec( medium: MediumType, domain_size: float, has_diff_mnt: bool = False, - ): + ) -> None: """Helper to check if a given Bloch vector is consistent with a given source.""" # make a dummy Bloch boundary to check for correctness @@ -5795,7 +5797,7 @@ def perturbed_mediums_copy( return Simulation.parse_obj(sim_dict) @classmethod - def from_scene(cls, scene: Scene, **kwargs) -> Simulation: + def from_scene(cls, scene: Scene, **kwargs: Any) -> Simulation: """Create a simulation from a :class:`.Scene` instance. Must provide additional parameters to define a valid simulation (for example, ``run_time``, ``grid_spec``, etc). diff --git a/tidy3d/components/source/base.py b/tidy3d/components/source/base.py index c94366ed3e..0b76239d08 100644 --- a/tidy3d/components/source/base.py +++ b/tidy3d/components/source/base.py @@ -3,7 +3,7 @@ from __future__ import annotations from abc import ABC -from typing import Optional +from typing import Any, Optional import pydantic.v1 as pydantic @@ -45,7 +45,7 @@ def geometry(self) -> Box: return Box(center=self.center, size=self.size) @cached_property - def _injection_axis(self): + def _injection_axis(self) -> None: """Injection axis of the source.""" return @@ -74,7 +74,7 @@ def plot( y: Optional[float] = None, z: Optional[float] = None, ax: Ax = None, - **patch_kwargs, + **patch_kwargs: Any, ) -> Ax: """Plot this source.""" diff --git a/tidy3d/components/source/current.py b/tidy3d/components/source/current.py index a768a94e59..994ef1eff3 100644 --- a/tidy3d/components/source/current.py +++ b/tidy3d/components/source/current.py @@ -4,7 +4,7 @@ from abc import ABC from math import cos, isclose, sin -from typing import Optional +from typing import Any, Optional import pydantic.v1 as pydantic from typing_extensions import Literal @@ -116,7 +116,7 @@ def sources_from_angles( angle_theta: float, angle_phi: float, component: Literal["electric", "magnetic"] = "electric", - **kwargs, + **kwargs: Any, ) -> list[PointDipole]: """Returns a list of `PointDipole` objects used to emulate a single dipole polarized in an arbitrary direction. The direction is specificed using a polar and azimuthal angle. diff --git a/tidy3d/components/source/field.py b/tidy3d/components/source/field.py index 1632edcaa8..55ce9e6537 100644 --- a/tidy3d/components/source/field.py +++ b/tidy3d/components/source/field.py @@ -3,7 +3,7 @@ from __future__ import annotations from abc import ABC -from typing import Optional, Union +from typing import Any, Optional, Union import numpy as np import pydantic.v1 as pydantic @@ -725,7 +725,7 @@ def plot( y: Optional[float] = None, z: Optional[float] = None, ax: Ax = None, - **patch_kwargs, + **patch_kwargs: Any, ) -> Ax: # call Source.plot but with the base of the arrow centered on the injection plane patch_kwargs["arrow_base"] = self.injection_plane_center diff --git a/tidy3d/components/source/time.py b/tidy3d/components/source/time.py index f2532ea3d7..a3b2f0f95b 100644 --- a/tidy3d/components/source/time.py +++ b/tidy3d/components/source/time.py @@ -4,7 +4,7 @@ import logging from abc import ABC, abstractmethod -from typing import Optional, Union +from typing import Any, Optional, Union import numpy as np import pydantic.v1 as pydantic @@ -303,7 +303,7 @@ def amp_complex(self) -> complex: return self.amplitude * phase @classmethod - def from_amp_complex(cls, amp: complex, **kwargs) -> GaussianPulse: + def from_amp_complex(cls, amp: complex, **kwargs: Any) -> GaussianPulse: """Set the complex amplitude of a ``GaussianPulse``. Parameters @@ -344,7 +344,7 @@ def from_frequency_range( fmin: pydantic.PositiveFloat, fmax: pydantic.PositiveFloat, minimum_source_bandwidth: pydantic.PositiveFloat = None, - **kwargs, + **kwargs: Any, ) -> GaussianPulse: """Create a ``GaussianPulse`` that maximizes its amplitude in the frequency range [fmin, fmax]. diff --git a/tidy3d/components/structure.py b/tidy3d/components/structure.py index d4d10aca5d..07f19a3e06 100644 --- a/tidy3d/components/structure.py +++ b/tidy3d/components/structure.py @@ -6,7 +6,7 @@ from collections import defaultdict from functools import cmp_to_key from os import PathLike -from typing import Optional, Union +from typing import Any, Optional, Union import autograd.numpy as anp import numpy as np @@ -139,7 +139,7 @@ def structure_comparator(struct1, struct2): return sorted(structures, key=cmp_to_key(structure_comparator)) @property - def viz_spec(self): + def viz_spec(self) -> None: return None @equal_aspect @@ -150,7 +150,7 @@ def plot( y: Optional[float] = None, z: Optional[float] = None, ax: Ax = None, - **patch_kwargs, + **patch_kwargs: Any, ) -> Ax: """Plot structure's geometric cross section at single (x,y,z) coordinate. @@ -586,7 +586,7 @@ def to_gds_file( @classmethod def from_permittivity_array( - cls, geometry: GeometryType, eps_data: np.ndarray, **kwargs + cls, geometry: GeometryType, eps_data: np.ndarray, **kwargs: Any ) -> Structure: """Create ``Structure`` with ``geometry`` and ``CustomMedium`` containing ``eps_data`` for The ``permittivity`` field. Extra keyword arguments are passed to ``td.Structure()``. diff --git a/tidy3d/components/tcad/data/monitor_data/abstract.py b/tidy3d/components/tcad/data/monitor_data/abstract.py index 147141974d..629c97ac74 100644 --- a/tidy3d/components/tcad/data/monitor_data/abstract.py +++ b/tidy3d/components/tcad/data/monitor_data/abstract.py @@ -138,7 +138,7 @@ def _symmetry_expanded_copy_base(self, property: FieldDataset) -> FieldDataset: return new_property - def _post_init_validators(self): + def _post_init_validators(self) -> None: """Call validators taking ``self`` that get run after init.""" # validate that data exists for all fields for field_name, field in self.field_components.items(): diff --git a/tidy3d/components/tcad/data/monitor_data/charge.py b/tidy3d/components/tcad/data/monitor_data/charge.py index 9e056696f1..f185934421 100644 --- a/tidy3d/components/tcad/data/monitor_data/charge.py +++ b/tidy3d/components/tcad/data/monitor_data/charge.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Union +from typing import Any, Union import numpy as np import pydantic.v1 as pd @@ -212,7 +212,7 @@ def check_correct_data_type(cls, values): return values @add_ax_if_none - def plot(self, ax: Ax = None, **sel_kwargs) -> Ax: + def plot(self, ax: Ax = None, **sel_kwargs: Any) -> Ax: """Plot the 1D cross-section of the energy bandgap diagram. Parameters diff --git a/tidy3d/components/tcad/data/sim_data.py b/tidy3d/components/tcad/data/sim_data.py index 1c6c86fb9d..fb62043507 100644 --- a/tidy3d/components/tcad/data/sim_data.py +++ b/tidy3d/components/tcad/data/sim_data.py @@ -3,7 +3,7 @@ from __future__ import annotations from abc import ABC -from typing import Literal, Optional +from typing import Any, Literal, Optional import numpy as np import pydantic.v1 as pd @@ -130,7 +130,7 @@ def plot_mesh( field_name: Optional[str] = None, structures_fill: bool = True, ax: Ax = None, - **sel_kwargs, + **sel_kwargs: Any, ) -> Ax: """Plot the simulation mesh in a monitor region with structures overlaid. @@ -281,7 +281,7 @@ def plot_field( vmin: Optional[float] = None, vmax: Optional[float] = None, ax: Ax = None, - **sel_kwargs, + **sel_kwargs: Any, ) -> Ax: """Plot the data for a monitor with simulation structures overlaid. diff --git a/tidy3d/components/tcad/doping.py b/tidy3d/components/tcad/doping.py index 3925b0440f..88bf353449 100644 --- a/tidy3d/components/tcad/doping.py +++ b/tidy3d/components/tcad/doping.py @@ -59,7 +59,7 @@ def _get_indices_in_box(self, coords: dict, meshgrid: bool = True): return indices_in_box, X, Y, Z - def _post_init_validators(self): + def _post_init_validators(self) -> None: # check the doping box is 3D if len(self.zero_dims) > 0: raise SetupError( diff --git a/tidy3d/components/tcad/effective_DOS.py b/tidy3d/components/tcad/effective_DOS.py index 56d26a99ee..15c8356a4a 100644 --- a/tidy3d/components/tcad/effective_DOS.py +++ b/tidy3d/components/tcad/effective_DOS.py @@ -17,7 +17,7 @@ class EffectiveDOS(Tidy3dBaseModel, ABC): """Abstract class for the effective density of states""" @abstractmethod - def calc_eff_dos(self, T: float): + def calc_eff_dos(self, T: float) -> None: """Abstract method to calculate the effective density of states.""" def get_effective_DOS(self, T: float): diff --git a/tidy3d/components/tcad/simulation/heat_charge.py b/tidy3d/components/tcad/simulation/heat_charge.py index 5598cfa48a..73dd7c130f 100644 --- a/tidy3d/components/tcad/simulation/heat_charge.py +++ b/tidy3d/components/tcad/simulation/heat_charge.py @@ -4,7 +4,7 @@ from __future__ import annotations from enum import Enum -from typing import Optional, Union +from typing import Any, Optional, Union import numpy as np import pydantic.v1 as pd @@ -334,7 +334,7 @@ class HeatChargeSimulation(AbstractSimulation): "specify Charge simulations or transient Heat simulations.", ) - def _post_init_validators(self): + def _post_init_validators(self) -> None: """Call validators taking ``self`` that get run after init.""" # Charge mesh size validator @@ -513,7 +513,7 @@ def check_natural_convection_bc(cls, values): media[bg_medium.name] = bg_medium structures_map = {s.name: s for s in structures if s.name} - def check_fluid_medium_attr(fluid_medium): + def check_fluid_medium_attr(fluid_medium) -> None: if ( (fluid_medium.thermal_conductivity is None) or (fluid_medium.viscosity is None) @@ -990,7 +990,7 @@ def check_conduction_sim(cls, values): return values - def _estimate_charge_mesh_size(self): + def _estimate_charge_mesh_size(self) -> None: """Make an estimate of the mesh size and raise a warning if too big. NOTE: this is a very rough estimate. The back-end will actually stop execution based on actual node-count.""" @@ -1264,7 +1264,7 @@ def plot_heat_conductivity( colorbar: str = "conductivity", hlim: Optional[tuple[float, float]] = None, vlim: Optional[tuple[float, float]] = None, - **kwargs, + **kwargs: Any, ) -> Ax: """ DEPRECATED: Method added for backwards compatibility with :class:`HeatSimulation.plot_heat_conductivity`. @@ -1804,7 +1804,7 @@ def plot_sources( ) return ax - def _add_source_cbar(self, ax: Ax, property: str = "heat_conductivity"): + def _add_source_cbar(self, ax: Ax, property: str = "heat_conductivity") -> None: """Add colorbar for heat sources.""" source_min, source_max = self.source_bounds(property=property) self.scene._add_cbar( @@ -1877,7 +1877,7 @@ def _plot_shape_structure_source( return ax @classmethod - def from_scene(cls, scene: Scene, **kwargs) -> HeatChargeSimulation: + def from_scene(cls, scene: Scene, **kwargs: Any) -> HeatChargeSimulation: """Create a simulation from a :class:`.Scene` instance. Must provide additional parameters to define a valid simulation (for example, ``size``, ``grid_spec``, etc). diff --git a/tidy3d/components/types/base.py b/tidy3d/components/types/base.py index 60c8c8ea03..cfe1f03615 100644 --- a/tidy3d/components/types/base.py +++ b/tidy3d/components/types/base.py @@ -94,7 +94,7 @@ def assert_non_null(cls, val): return val @classmethod - def __modify_schema__(cls, field_schema): + def __modify_schema__(cls, field_schema) -> None: """Sets the schema of DataArray object.""" schema = { @@ -174,7 +174,7 @@ def validate(cls, value): return cls(value) @classmethod - def __modify_schema__(cls, field_schema): + def __modify_schema__(cls, field_schema) -> None: """Sets the schema of ComplexNumber.""" field_schema.update(ComplexNumber.schema()) diff --git a/tidy3d/components/validators.py b/tidy3d/components/validators.py index 4116a7e2ca..c6a9d9c640 100644 --- a/tidy3d/components/validators.py +++ b/tidy3d/components/validators.py @@ -341,7 +341,7 @@ def _warn_potential_error( val_change_range: tuple[float, float], allowed_real_range: tuple[float, float], allowed_imag_range: tuple[float, float], -): +) -> None: """Basic validation that perturbations do not drive a parameter out of physical bounds.""" min_val = val_change_range[0] + base_value @@ -431,7 +431,7 @@ def _warn_perturbed_val_range(cls, val, values): return _warn_perturbed_val_range -def _assert_min_freq(freqs, msg_start: str): +def _assert_min_freq(freqs, msg_start: str) -> None: """Check if all ``freqs`` are above the minimum frequency.""" if np.min(freqs) < MIN_FREQUENCY: raise ValidationError( diff --git a/tidy3d/components/viz/axes_utils.py b/tidy3d/components/viz/axes_utils.py index 85007e773c..8fb78f699c 100644 --- a/tidy3d/components/viz/axes_utils.py +++ b/tidy3d/components/viz/axes_utils.py @@ -1,7 +1,7 @@ from __future__ import annotations from functools import wraps -from typing import Optional +from typing import Any, Optional from tidy3d.components.types import Ax, Axis, LengthUnit from tidy3d.constants import UnitScaling @@ -15,7 +15,7 @@ def _create_unit_aware_locator(): class UnitAwareLocator(ticker.Locator): """Custom tick locator that places ticks at nice positions in the target unit.""" - def __init__(self, scale_factor: float): + def __init__(self, scale_factor: float) -> None: """ Parameters ---------- @@ -111,7 +111,7 @@ def add_ax_if_none(plot): """ @wraps(plot) - def _plot(*args, **kwargs) -> Ax: + def _plot(*args: Any, **kwargs: Any) -> Ax: """New plot function using a generated ax if None.""" if kwargs.get("ax") is None: ax = make_ax() @@ -128,7 +128,7 @@ def equal_aspect(plot): """ @wraps(plot) - def _plot(*args, **kwargs) -> Ax: + def _plot(*args: Any, **kwargs: Any) -> Ax: """New plot function with equal aspect ratio axes returned.""" ax = plot(*args, **kwargs) ax.set_aspect("equal") diff --git a/tidy3d/components/viz/descartes.py b/tidy3d/components/viz/descartes.py index f8bd32668a..b743839585 100644 --- a/tidy3d/components/viz/descartes.py +++ b/tidy3d/components/viz/descartes.py @@ -15,6 +15,8 @@ from __future__ import annotations +from typing import Any + try: from matplotlib.patches import PathPatch from matplotlib.path import Path @@ -26,7 +28,7 @@ class Polygon: """Adapt Shapely polygons to a common interface""" - def __init__(self, context): + def __init__(self, context) -> None: if isinstance(context, dict): self.context = context["coordinates"] else: @@ -86,7 +88,7 @@ def coding(obj): return Path(vertices, codes) -def polygon_patch(polygon, **kwargs): +def polygon_patch(polygon, **kwargs: Any): """Constructs a matplotlib patch from a geometric object The ``polygon`` may be a Shapely or GeoJSON-like object with or without holes. diff --git a/tidy3d/components/viz/flex_style.py b/tidy3d/components/viz/flex_style.py index f2ced3a407..0706826fca 100644 --- a/tidy3d/components/viz/flex_style.py +++ b/tidy3d/components/viz/flex_style.py @@ -5,7 +5,7 @@ _ORIGINAL_PARAMS = None -def apply_tidy3d_params(): +def apply_tidy3d_params() -> None: """ Applies a set of defaults to the matplotlib params that are following the tidy3d color palettes and design. """ @@ -25,7 +25,7 @@ def apply_tidy3d_params(): pass -def restore_matplotlib_rcparams(): +def restore_matplotlib_rcparams() -> None: """ Resets matplotlib rcParams to the values they had before the Tidy3D style was automatically applied on import. diff --git a/tidy3d/components/viz/plot_params.py b/tidy3d/components/viz/plot_params.py index 48c393a419..f01920667e 100644 --- a/tidy3d/components/viz/plot_params.py +++ b/tidy3d/components/viz/plot_params.py @@ -16,7 +16,7 @@ class AbstractPlotParams(Tidy3dBaseModel): alpha: Any = pd.Field(1.0, title="Opacity") zorder: float = pd.Field(None, title="Display Order") - def include_kwargs(self, **kwargs) -> AbstractPlotParams: + def include_kwargs(self, **kwargs: Any) -> AbstractPlotParams: """Update the plot params with supplied kwargs.""" update_dict = { key: value diff --git a/tidy3d/components/viz/plot_sim_3d.py b/tidy3d/components/viz/plot_sim_3d.py index 75e51327af..7111309446 100644 --- a/tidy3d/components/viz/plot_sim_3d.py +++ b/tidy3d/components/viz/plot_sim_3d.py @@ -23,7 +23,7 @@ def plot_scene_3d(scene, width=800, height=800) -> None: buffer2 = BytesIO() with h5py.File(buffer2, "w") as dst: - def copy_item(name, obj): + def copy_item(name, obj) -> None: if isinstance(obj, h5py.Group): dst.create_group(name) for k, v in obj.attrs.items(): diff --git a/tidy3d/exceptions.py b/tidy3d/exceptions.py index 96b137d749..237d592450 100644 --- a/tidy3d/exceptions.py +++ b/tidy3d/exceptions.py @@ -10,7 +10,7 @@ class Tidy3dError(ValueError): """Any error in tidy3d""" - def __init__(self, message: Optional[str] = None): + def __init__(self, message: Optional[str] = None) -> None: """Log just the error message and then raise the Exception.""" super().__init__(message) log.error(message) diff --git a/tidy3d/log.py b/tidy3d/log.py index 36eeb957e5..b2e98b9fa7 100644 --- a/tidy3d/log.py +++ b/tidy3d/log.py @@ -6,7 +6,7 @@ from contextlib import contextmanager from datetime import datetime from os import PathLike -from typing import Callable, Optional, Union +from typing import Any, Callable, Optional, Union from rich.console import Console from rich.text import Text @@ -74,13 +74,13 @@ def __init__( level: LogValue, log_level_format: Callable = _default_log_level_format, prefix_every_line: bool = False, - ): + ) -> None: self.level = _get_level_int(level) self.console = console self.log_level_format = log_level_format self.prefix_every_line = prefix_every_line - def handle(self, level, level_name, message): + def handle(self, level, level_name, message) -> None: """Output log messages depending on log level""" if level >= self.level: stack = inspect.stack() @@ -120,7 +120,7 @@ class Logger: _static_cache = set() - def __init__(self): + def __init__(self) -> None: self.handlers = {} self.suppression = True self._counts = None @@ -128,7 +128,7 @@ def __init__(self): self._capture = False self._captured_warnings = [] - def set_capture(self, capture: bool): + def set_capture(self, capture: bool) -> None: """Turn on/off tree-like capturing of log messages.""" self._capture = capture @@ -162,7 +162,7 @@ def __exit__(self, exc_type, exc_value, traceback): self._stack = stack return False - def begin_capture(self): + def begin_capture(self) -> None: """Start capturing log stack for consolidated validation log. This method is used before any model validation starts and is included in the initialization @@ -177,7 +177,7 @@ def begin_capture(self): else: self._stack = [stack_item] - def end_capture(self, model): + def end_capture(self, model) -> None: """End capturing log stack for consolidated validation log. This method is used after all model validations and is included in the initialization of @@ -208,7 +208,7 @@ def end_capture(self, model): hash_ = hash(model) self._stack[-1]["children"][hash_] = stack_item - def _parse_warning_capture(self, current_loc, stack_item): + def _parse_warning_capture(self, current_loc, stack_item) -> None: """Process capture tree to compile formatted captured warnings.""" if "parent_fields" in stack_item: @@ -244,7 +244,7 @@ def _log( level: int, level_name: str, message: str, - *args, + *args: Any, log_once: bool = False, custom_loc: Optional[list] = None, capture: bool = True, @@ -285,7 +285,7 @@ def _log( for handler in self.handlers.values(): handler.handle(level, level_name, composed_message) - def log(self, level: LogValue, message: str, *args, log_once: bool = False) -> None: + def log(self, level: LogValue, message: str, *args: Any, log_once: bool = False) -> None: """Log (message) % (args) with given level""" if isinstance(level, str): level_name = level @@ -294,26 +294,26 @@ def log(self, level: LogValue, message: str, *args, log_once: bool = False) -> N level_name = _level_name.get(level, "unknown") self._log(level, level_name, message, *args, log_once=log_once) - def debug(self, message: str, *args, log_once: bool = False) -> None: + def debug(self, message: str, *args: Any, log_once: bool = False) -> None: """Log (message) % (args) at debug level""" self._log(_level_value["DEBUG"], "DEBUG", message, *args, log_once=log_once) - def support(self, message: str, *args, log_once: bool = False) -> None: + def support(self, message: str, *args: Any, log_once: bool = False) -> None: """Log (message) % (args) at support level""" self._log(_level_value["SUPPORT"], "SUPPORT", message, *args, log_once=log_once) - def user(self, message: str, *args, log_once: bool = False) -> None: + def user(self, message: str, *args: Any, log_once: bool = False) -> None: """Log (message) % (args) at user level""" self._log(_level_value["USER"], "USER", message, *args, log_once=log_once) - def info(self, message: str, *args, log_once: bool = False) -> None: + def info(self, message: str, *args: Any, log_once: bool = False) -> None: """Log (message) % (args) at info level""" self._log(_level_value["INFO"], "INFO", message, *args, log_once=log_once) def warning( self, message: str, - *args, + *args: Any, log_once: bool = False, custom_loc: Optional[list] = None, capture: bool = True, @@ -329,11 +329,11 @@ def warning( capture=capture, ) - def error(self, message: str, *args, log_once: bool = False) -> None: + def error(self, message: str, *args: Any, log_once: bool = False) -> None: """Log (message) % (args) at error level""" self._log(_level_value["ERROR"], "ERROR", message, *args, log_once=log_once) - def critical(self, message: str, *args, log_once: bool = False) -> None: + def critical(self, message: str, *args: Any, log_once: bool = False) -> None: """Log (message) % (args) at critical level""" self._log(_level_value["CRITICAL"], "CRITICAL", message, *args, log_once=log_once) @@ -454,13 +454,13 @@ class NoOpProgress: def __enter__(self): return self - def __exit__(self, *args, **kwargs): + def __exit__(self, *args: Any, **kwargs: Any) -> None: pass - def add_task(self, *args, **kwargs): + def add_task(self, *args: Any, **kwargs: Any) -> None: pass - def update(self, *args, **kwargs): + def update(self, *args: Any, **kwargs: Any) -> None: pass diff --git a/tidy3d/material_library/util.py b/tidy3d/material_library/util.py index 206cbdf4a7..b7e202ae79 100644 --- a/tidy3d/material_library/util.py +++ b/tidy3d/material_library/util.py @@ -109,7 +109,7 @@ def summarize_variant_item(v) -> str: return "\n".join(lines) -def repr_pretty_with_rich(obj, p, cycle): +def repr_pretty_with_rich(obj, p, cycle) -> None: """Enable _repr_pretty_ for jupyter notebooks to use the rich printing output.""" if cycle: p.text("MaterialLibrary(...)") @@ -121,7 +121,7 @@ def repr_pretty_with_rich(obj, p, cycle): p.text(sio.getvalue()) -def add_medium_details_to_tree(medium, medium_node: Tree): +def add_medium_details_to_tree(medium, medium_node: Tree) -> None: """Adds details of a medium dictionary to a Rich Tree node.""" if hasattr(medium, "eps_inf"): diff --git a/tidy3d/packaging.py b/tidy3d/packaging.py index 2ea0c15551..81014c1885 100644 --- a/tidy3d/packaging.py +++ b/tidy3d/packaging.py @@ -8,7 +8,7 @@ import functools from importlib import import_module -from typing import Literal +from typing import Any, Literal import numpy as np @@ -74,7 +74,7 @@ def decorator(func): """ @functools.wraps(func) - def checks_modules_import(*args, **kwargs): + def checks_modules_import(*args: Any, **kwargs: Any): """ Checks if the modules are available. If they are not available, it will raise an error depending on the value. """ @@ -127,7 +127,7 @@ def requires_vtk(fn): """When decorating a method, requires that vtk is available.""" @functools.wraps(fn) - def _fn(*args, **kwargs): + def _fn(*args: Any, **kwargs: Any): if vtk["mod"] is None: try: import vtk as vtk_mod @@ -188,7 +188,7 @@ def supports_local_subpixel(fn): conditioned on 'config.use_local_subpixel'.""" @functools.wraps(fn) - def _fn(*args, **kwargs): + def _fn(*args: Any, **kwargs: Any): preference = config.simulation.use_local_subpixel if preference is False: @@ -247,7 +247,7 @@ def disable_local_subpixel(fn): """When decorating a method, temporarily disables local subpixel.""" @functools.wraps(fn) - def _fn(*args, **kwargs): + def _fn(*args: Any, **kwargs: Any): simulation = config.simulation previous = simulation.use_local_subpixel diff --git a/tidy3d/plugins/autograd/invdes/filters.py b/tidy3d/plugins/autograd/invdes/filters.py index b8bb019563..8314b78726 100644 --- a/tidy3d/plugins/autograd/invdes/filters.py +++ b/tidy3d/plugins/autograd/invdes/filters.py @@ -3,7 +3,7 @@ import abc from collections.abc import Iterable from functools import lru_cache, partial -from typing import Annotated, Callable, Optional, Union +from typing import Annotated, Any, Callable, Optional, Union import numpy as np import pydantic.v1 as pd @@ -32,7 +32,10 @@ class AbstractFilter(Tidy3dBaseModel, abc.ABC): @classmethod def from_radius_dl( - cls, radius: Union[float, tuple[float, ...]], dl: Union[float, tuple[float, ...]], **kwargs + cls, + radius: Union[float, tuple[float, ...]], + dl: Union[float, tuple[float, ...]], + **kwargs: Any, ) -> AbstractFilter: """Create a filter from radius and grid spacing. diff --git a/tidy3d/plugins/autograd/invdes/parametrizations.py b/tidy3d/plugins/autograd/invdes/parametrizations.py index a21e22c1d0..c6435f25a9 100644 --- a/tidy3d/plugins/autograd/invdes/parametrizations.py +++ b/tidy3d/plugins/autograd/invdes/parametrizations.py @@ -1,7 +1,7 @@ from __future__ import annotations from collections import deque -from typing import Callable, Literal, Optional, Union +from typing import Any, Callable, Literal, Optional, Union import autograd.numpy as np import pydantic.v1 as pd @@ -115,7 +115,7 @@ def initialize_params_from_simulation( bounds: tuple[Optional[float], Optional[float]] = (0.0, 1.0), rel_improve_tol: float = 1e-3, verbose: bool = False, - **param_kwargs, + **param_kwargs: Any, ) -> np.ndarray: """Initialize design parameters to match base simulation permittivity in a region. @@ -279,7 +279,7 @@ def loss_fn(params_vec: np.ndarray) -> float: "best_x": params0.ravel().copy(), } - def callback(xk: np.ndarray): + def callback(xk: np.ndarray) -> None: val = loss_fn(xk) if val < state["best_val"]: state["best_val"] = val diff --git a/tidy3d/plugins/design/design.py b/tidy3d/plugins/design/design.py index cee82953e9..b68fa1d5d3 100644 --- a/tidy3d/plugins/design/design.py +++ b/tidy3d/plugins/design/design.py @@ -281,7 +281,7 @@ def _get_evaluate_fn_pre_post( """Get function that tries to use batch processing on a set of arguments.""" class Pre_Post_Handler: - def __init__(self, console): + def __init__(self, console) -> None: self.sim_counter = 0 self.sim_names = [] self.sim_paths = [] @@ -335,7 +335,7 @@ def _find_and_map( output_dict: dict, naming_dict: dict, previous_key: str = "", - ): + ) -> None: """Recursively search for search_type objects within a dictionary.""" current_key = previous_key for key, value in search_dict.items(): @@ -461,7 +461,7 @@ def run_batch( Union[SimulationData, list[SimulationData], dict[str, SimulationData]], Any ], path_dir: str = ".", - **batch_kwargs, + **batch_kwargs: Any, ) -> Result: """ This function has been superceded by `run`, please use `run` for batched simulations. diff --git a/tidy3d/plugins/design/method.py b/tidy3d/plugins/design/method.py index 22b0745bce..777995079d 100644 --- a/tidy3d/plugins/design/method.py +++ b/tidy3d/plugins/design/method.py @@ -96,7 +96,7 @@ class MethodSample(Method, ABC): """A sweep method where all points are independently computed in one iteration.""" @abstractmethod - def sample(self, parameters: tuple[ParameterType, ...], **kwargs) -> dict[str, Any]: + def sample(self, parameters: tuple[ParameterType, ...], **kwargs: Any) -> dict[str, Any]: """Defines how the design parameters are sampled.""" def _assemble_args( @@ -793,7 +793,7 @@ def _get_run_count(self, parameters: Optional[list] = None) -> int: """Return the maximum number of runs for the method based on current method arguments.""" return self.num_points - def sample(self, parameters: tuple[ParameterType, ...], **kwargs) -> list[dict[str, Any]]: + def sample(self, parameters: tuple[ParameterType, ...], **kwargs: Any) -> list[dict[str, Any]]: """Defines how the design parameters are sampled on grid.""" sampler = self._get_sampler(parameters) diff --git a/tidy3d/plugins/design/result.py b/tidy3d/plugins/design/result.py index abf843183d..1d69022627 100644 --- a/tidy3d/plugins/design/result.py +++ b/tidy3d/plugins/design/result.py @@ -177,7 +177,7 @@ def get_value(self, coords: tuple) -> Any: """Get a data element indexing by function arg tuple.""" return self.data[coords] - def sel(self, **kwargs) -> Any: + def sel(self, **kwargs: Any) -> Any: """Get a data element by function kwargs..""" coords_tuple = tuple(kwargs[dim] for dim in self.dims) return self.get_value(coords_tuple) diff --git a/tidy3d/plugins/dispersion/fit.py b/tidy3d/plugins/dispersion/fit.py index e9c0051015..57e9643e46 100644 --- a/tidy3d/plugins/dispersion/fit.py +++ b/tidy3d/plugins/dispersion/fit.py @@ -5,7 +5,7 @@ import codecs import csv from os import PathLike -from typing import Optional +from typing import Any, Optional import numpy as np import requests @@ -557,7 +557,7 @@ def plot( return ax @staticmethod - def _validate_url_load(data_load: list): + def _validate_url_load(data_load: list) -> None: """Validate if the loaded data from URL is valid The data list should be in this format: [["wl", "n"], @@ -610,7 +610,7 @@ def _validate_url_load(data_load: list): @classmethod def from_url( - cls, url_file: str, delimiter: str = ",", ignore_k: bool = False, **kwargs + cls, url_file: str, delimiter: str = ",", ignore_k: bool = False, **kwargs: Any ) -> DispersionFitter: """loads :class:`DispersionFitter` from url linked to a csv/txt file that contains wavelength (micron), n, and optionally k data. Preferred from @@ -699,7 +699,7 @@ def from_url( return cls(wvl_um=n_lam[:, 0], n_data=n_lam[:, 1], **kwargs) @classmethod - def from_file(cls, fname: PathLike, **loadtxt_kwargs) -> DispersionFitter: + def from_file(cls, fname: PathLike, **loadtxt_kwargs: Any) -> DispersionFitter: """Loads :class:`DispersionFitter` from file containing wavelength, n, k data. Parameters diff --git a/tidy3d/plugins/invdes/design.py b/tidy3d/plugins/invdes/design.py index 737698b9b6..22c8a88c68 100644 --- a/tidy3d/plugins/invdes/design.py +++ b/tidy3d/plugins/invdes/design.py @@ -4,6 +4,7 @@ import abc import typing +from typing import Any import autograd.numpy as anp import numpy as np @@ -99,7 +100,7 @@ def initial_simulation(self) -> td.Simulation: initial_params = self.design_region.initial_parameters return self.to_simulation(initial_params) - def run(self, simulation, **kwargs) -> td.SimulationData: + def run(self, simulation, **kwargs: Any) -> td.SimulationData: """Run a single tidy3d simulation.""" from tidy3d.web import run @@ -107,7 +108,7 @@ def run(self, simulation, **kwargs) -> td.SimulationData: kwargs.setdefault("task_name", self.task_name) return run(simulation, **kwargs) - def run_async(self, simulations, **kwargs) -> web.BatchData: # noqa: F821 + def run_async(self, simulations, **kwargs: Any) -> web.BatchData: # noqa: F821 """Run a batch of tidy3d simulations.""" from tidy3d.web import run_async @@ -250,7 +251,7 @@ def to_simulation(self, params: anp.ndarray) -> td.Simulation: grid_spec=grid_spec, ) - def to_simulation_data(self, params: anp.ndarray, **kwargs) -> td.SimulationData: + def to_simulation_data(self, params: anp.ndarray, **kwargs: Any) -> td.SimulationData: """Convert the ``InverseDesign`` to a ``td.Simulation`` and run it.""" simulation = self.to_simulation(params=params) return self.run(simulation, **kwargs) @@ -322,7 +323,7 @@ def to_simulation(self, params: anp.ndarray) -> dict[str, td.Simulation]: simulation_list = [design.to_simulation(params) for design in self.designs] return dict(zip(self.task_names, simulation_list)) - def to_simulation_data(self, params: anp.ndarray, **kwargs) -> web.BatchData: # noqa: F821 + def to_simulation_data(self, params: anp.ndarray, **kwargs: Any) -> web.BatchData: # noqa: F821 """Convert the ``InverseDesignMulti`` to a set of ``td.Simulation``s and run async.""" simulations = self.to_simulation(params) return self.run_async(simulations, **kwargs) diff --git a/tidy3d/plugins/invdes/penalty.py b/tidy3d/plugins/invdes/penalty.py index 1683f577fd..37d31b4978 100644 --- a/tidy3d/plugins/invdes/penalty.py +++ b/tidy3d/plugins/invdes/penalty.py @@ -3,6 +3,7 @@ import abc import typing +from typing import Any import autograd.numpy as anp import pydantic.v1 as pd @@ -28,7 +29,7 @@ class AbstractPenalty(InvdesBaseModel, abc.ABC): def evaluate(self) -> float: """Evaluate the penalty on supplied values.""" - def __call__(self, *args, **kwargs) -> float: + def __call__(self, *args: Any, **kwargs: Any) -> float: return self.evaluate(*args, **kwargs) diff --git a/tidy3d/plugins/invdes/region.py b/tidy3d/plugins/invdes/region.py index 17fa5009c4..640bafc2ab 100644 --- a/tidy3d/plugins/invdes/region.py +++ b/tidy3d/plugins/invdes/region.py @@ -4,6 +4,7 @@ import abc import typing import warnings +from typing import Any import autograd.numpy as anp import numpy as np @@ -71,13 +72,13 @@ class DesignRegion(InvdesBaseModel, abc.ABC): discriminator=TYPE_TAG_STR, ) - def _post_init_validators(self): + def _post_init_validators(self) -> None: """Automatically call any `_validate_XXX` method.""" for attr_name in dir(self): if attr_name.startswith("_validate") and callable(getattr(self, attr_name)): getattr(self, attr_name)() - def _validate_eps_bounds(self): + def _validate_eps_bounds(self) -> None: if self.eps_bounds[1] < self.eps_bounds[0]: raise ValidationError( f"Maximum relative permittivity ({self.eps_bounds[1]}) must be " @@ -118,7 +119,7 @@ def evaluate_penalty(self, penalty: None) -> float: """How this design region evaluates a penalty given some passed information.""" @abc.abstractmethod - def to_structure(self, *args, **kwargs) -> td.Structure: + def to_structure(self, *args: Any, **kwargs: Any) -> td.Structure: """Convert this ``DesignRegion`` into a ``Structure`` with tracers. Implement in subs.""" @property @@ -178,7 +179,7 @@ class TopologyDesignRegion(DesignRegion): "Supplying ``False`` will completely leave out the override structure.", ) - def _validate_eps_values(self): + def _validate_eps_values(self) -> None: """Validate the epsilon values by evaluating the transformations.""" try: x = self.initial_parameters @@ -186,7 +187,7 @@ def _validate_eps_values(self): except Exception as e: raise ValidationError(f"Could not evaluate transformations: {e!s}") from e - def _validate_penalty_value(self): + def _validate_penalty_value(self) -> None: """Validate the penalty values by evaluating the penalties.""" try: x = self.initial_parameters @@ -194,7 +195,7 @@ def _validate_penalty_value(self): except Exception as e: raise ValidationError(f"Could not evaluate penalties: {e!s}") from e - def _validate_gradients(self): + def _validate_gradients(self) -> None: """Validate the gradients of the penalties and transformations.""" x = self.initial_parameters @@ -234,7 +235,7 @@ def _validate_gradients(self): ) @staticmethod - def _check_params(params: anp.ndarray = None): + def _check_params(params: anp.ndarray = None) -> None: """Ensure ``params`` are between 0 and 1.""" if params is None: return @@ -253,7 +254,7 @@ def params_shape(self) -> tuple[int, int, int]: num_pixels[np.logical_or(np.isinf(num_pixels), self.uniform)] = 1 return tuple(int(n) for n in num_pixels) - def _warn_deprecate_params(self): + def _warn_deprecate_params(self) -> None: td.log.warning( "Parameter initialization via design region methods is deprecated and will be " "removed in the future. Please specify this through the design region's " diff --git a/tidy3d/plugins/invdes/result.py b/tidy3d/plugins/invdes/result.py index 3a000ab80c..ae844fb5ad 100644 --- a/tidy3d/plugins/invdes/result.py +++ b/tidy3d/plugins/invdes/result.py @@ -2,6 +2,7 @@ from __future__ import annotations import typing +from typing import Any import matplotlib.pyplot as plt import numpy as np @@ -143,7 +144,7 @@ def get_sim(self, index: int = -1) -> typing.Union[td.Simulation, list[td.Simula return self.design.to_simulation(params=params) def get_sim_data( - self, index: int = -1, **kwargs + self, index: int = -1, **kwargs: Any ) -> typing.Union[td.SimulationData, list[td.SimulationData]]: """Get the simulation data at a specific index in the history (list of simdata if multi).""" params = np.array(self.get(key="params", index=index)) @@ -154,11 +155,11 @@ def sim_last(self) -> typing.Union[td.Simulation, list[td.Simulation]]: """The last simulation.""" return self.get_sim(index=-1) - def sim_data_last(self, **kwargs) -> td.SimulationData: + def sim_data_last(self, **kwargs: Any) -> td.SimulationData: """Run the last simulation and return its data.""" return self.get_sim_data(index=-1, **kwargs) - def plot_optimization(self): + def plot_optimization(self) -> None: """Plot the optimization progress from the history.""" plt.plot(self.objective_fn_val, label="objective function") plt.plot(self.post_process_val, label="post process function") diff --git a/tidy3d/plugins/invdes/transformation.py b/tidy3d/plugins/invdes/transformation.py index c5060209cf..233531dc0a 100644 --- a/tidy3d/plugins/invdes/transformation.py +++ b/tidy3d/plugins/invdes/transformation.py @@ -3,6 +3,7 @@ import abc import typing +from typing import Any import autograd.numpy as anp import pydantic.v1 as pd @@ -21,7 +22,7 @@ class AbstractTransformation(InvdesBaseModel, abc.ABC): def evaluate(self) -> float: """Evaluate the penalty on supplied values.""" - def __call__(self, *args, **kwargs) -> float: + def __call__(self, *args: Any, **kwargs: Any) -> float: return self.evaluate(*args, **kwargs) diff --git a/tidy3d/plugins/invdes/utils.py b/tidy3d/plugins/invdes/utils.py index eeb3fff79f..b29f4e703d 100644 --- a/tidy3d/plugins/invdes/utils.py +++ b/tidy3d/plugins/invdes/utils.py @@ -4,6 +4,7 @@ from __future__ import annotations import typing +from typing import Any import autograd.numpy as anp import xarray as xr @@ -18,7 +19,7 @@ def make_array(arr: typing.Any) -> anp.ndarray: return anp.array(arr) -def get_amps(sim_data: td.SimulationData, monitor_name: str, **sel_kwargs) -> anp.ndarray: +def get_amps(sim_data: td.SimulationData, monitor_name: str, **sel_kwargs: Any) -> anp.ndarray: """Grab amplitudes from a ``ModeMonitorData`` and select out values.""" monitor_data = sim_data[monitor_name] @@ -35,7 +36,7 @@ def get_field_component( sim_data: td.SimulationData, monitor_name: str, field_component: td.components.types.EMField, - **sel_kwargs, + **sel_kwargs: Any, ) -> anp.ndarray: """Grab field component from a ``FieldMonitorData`` and select out values.""" @@ -49,7 +50,7 @@ def get_field_component( return field_component_sel -def get_intensity(sim_data: td.SimulationData, monitor_name: str, **sel_kwargs) -> anp.ndarray: +def get_intensity(sim_data: td.SimulationData, monitor_name: str, **sel_kwargs: Any) -> anp.ndarray: """Grab field intensity from a ``FieldMonitorData`` and select out values.""" intensity = sim_data.get_intensity(monitor_name) intensity_sel = intensity.sel(**sel_kwargs) diff --git a/tidy3d/plugins/invdes/validators.py b/tidy3d/plugins/invdes/validators.py index 07a522b42e..559ed14471 100644 --- a/tidy3d/plugins/invdes/validators.py +++ b/tidy3d/plugins/invdes/validators.py @@ -16,7 +16,7 @@ def ignore_inherited_field(field_name: str) -> typing.Callable: """Create validator that ignores a field inherited but not set by user.""" @pd.validator(field_name, always=True) - def _ignore_field(cls, val): + def _ignore_field(cls, val) -> None: """Ignore supplied field value and warn.""" if val is not None: td.log.warning( diff --git a/tidy3d/plugins/klayout/drc/drc.py b/tidy3d/plugins/klayout/drc/drc.py index c219cff4ca..a174323e93 100644 --- a/tidy3d/plugins/klayout/drc/drc.py +++ b/tidy3d/plugins/klayout/drc/drc.py @@ -5,7 +5,7 @@ import re from pathlib import Path from subprocess import run -from typing import Union +from typing import Any, Union import pydantic.v1 as pd from pydantic.v1 import validator @@ -121,7 +121,7 @@ def run( source: Union[Geometry, Structure, Simulation, Path], td_object_gds_savefile: Path = DEFAULT_GDSFILE, resultsfile: Path = DEFAULT_RESULTSFILE, - **to_gds_file_kwargs, + **to_gds_file_kwargs: Any, ) -> None: """Runs KLayout's DRC on a GDS file or a Tidy3D object. The Tidy3D object can be a :class:`.Geometry`, :class:`.Structure`, or :class:`.Simulation`. diff --git a/tidy3d/plugins/microwave/array_factor.py b/tidy3d/plugins/microwave/array_factor.py index b312649bb8..446c8fa292 100644 --- a/tidy3d/plugins/microwave/array_factor.py +++ b/tidy3d/plugins/microwave/array_factor.py @@ -57,7 +57,7 @@ def _antenna_phases(self) -> ArrayLike: @property @abstractmethod - def _extend_dims(self): + def _extend_dims(self) -> None: """Dimensions along which antennas will be duplicated.""" @property diff --git a/tidy3d/plugins/pytorch/wrapper.py b/tidy3d/plugins/pytorch/wrapper.py index e5d0597337..d6716dca3a 100644 --- a/tidy3d/plugins/pytorch/wrapper.py +++ b/tidy3d/plugins/pytorch/wrapper.py @@ -1,6 +1,7 @@ from __future__ import annotations import inspect +from typing import Any import torch from autograd import make_vjp @@ -48,7 +49,7 @@ class _Wrapper(torch.autograd.Function): """ @staticmethod - def forward(ctx, *args): + def forward(ctx, *args: Any): numpy_args = [] grad_argnums = [] @@ -85,7 +86,7 @@ def backward(ctx, grad_output): grads[idx] = torch.as_tensor(grad, device=ctx.device) return tuple(grads) - def apply(*args, **kwargs): + def apply(*args: Any, **kwargs: Any): # we bind the full function signature including defaults so that we can pass # all values as positional since torch.autograd.Function.apply only accepts # positional arguments diff --git a/tidy3d/plugins/smatrix/component_modelers/modal.py b/tidy3d/plugins/smatrix/component_modelers/modal.py index 699d7e09f2..591ad4c624 100644 --- a/tidy3d/plugins/smatrix/component_modelers/modal.py +++ b/tidy3d/plugins/smatrix/component_modelers/modal.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Optional +from typing import Any, Optional import autograd.numpy as np import pydantic.v1 as pd @@ -180,7 +180,7 @@ def to_monitor(self, port: Port) -> ModeMonitor: ) def to_source( - self, port: Port, mode_index: int, num_freqs: int = 1, **kwargs + self, port: Port, mode_index: int, num_freqs: int = 1, **kwargs: Any ) -> list[ModeSource]: """Creates a mode source from a given port. @@ -287,7 +287,7 @@ def plot_sim_eps( y: Optional[float] = None, z: Optional[float] = None, ax: Ax = None, - **kwargs, + **kwargs: Any, ) -> Ax: """Plots the permittivity of the simulation with all sources. diff --git a/tidy3d/plugins/smatrix/component_modelers/terminal.py b/tidy3d/plugins/smatrix/component_modelers/terminal.py index ac7f16ffe3..48705e1b5a 100644 --- a/tidy3d/plugins/smatrix/component_modelers/terminal.py +++ b/tidy3d/plugins/smatrix/component_modelers/terminal.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Optional, Union +from typing import Any, Optional, Union import numpy as np import pydantic.v1 as pd @@ -241,7 +241,7 @@ def plot_sim( y: Optional[float] = None, z: Optional[float] = None, ax: Ax = None, - **kwargs, + **kwargs: Any, ) -> Ax: """Plot a :class:`.Simulation` with all sources and absorbers. @@ -276,7 +276,7 @@ def plot_sim_eps( y: Optional[float] = None, z: Optional[float] = None, ax: Ax = None, - **kwargs, + **kwargs: Any, ) -> Ax: """Plot permittivity of the :class:`.Simulation`. @@ -769,14 +769,14 @@ def _validate_radiation_monitors(cls, val, values): @staticmethod def _check_grid_size_at_ports( simulation: Simulation, ports: list[Union[LumpedPort, CoaxialLumpedPort]] - ): + ) -> None: """Raises :class:`.SetupError` if the grid is too coarse at port locations""" yee_grid = simulation.grid.yee for port in ports: port._check_grid_size(yee_grid) @staticmethod - def _check_grid_size_at_wave_ports(simulation: Simulation, ports: list[WavePort]): + def _check_grid_size_at_wave_ports(simulation: Simulation, ports: list[WavePort]) -> None: """Raises :class:`.SetupError` if the grid is too coarse at port locations""" for port in ports: disc_grid = simulation.discretize(port) diff --git a/tidy3d/plugins/smatrix/ports/base_lumped.py b/tidy3d/plugins/smatrix/ports/base_lumped.py index 2871da304a..0e4516aa69 100644 --- a/tidy3d/plugins/smatrix/ports/base_lumped.py +++ b/tidy3d/plugins/smatrix/ports/base_lumped.py @@ -92,5 +92,5 @@ def to_monitors( ] @abstractmethod - def _check_grid_size(self, yee_grid: YeeGrid): + def _check_grid_size(self, yee_grid: YeeGrid) -> None: """Raises :class:`SetupError` if the grid is too coarse at port locations.""" diff --git a/tidy3d/plugins/smatrix/ports/base_terminal.py b/tidy3d/plugins/smatrix/ports/base_terminal.py index 086ac36b91..7d77310407 100644 --- a/tidy3d/plugins/smatrix/ports/base_terminal.py +++ b/tidy3d/plugins/smatrix/ports/base_terminal.py @@ -34,7 +34,7 @@ class AbstractTerminalPort(MicrowaveBaseModel, ABC): @cached_property @abstractmethod - def injection_axis(self): + def injection_axis(self) -> None: """Injection axis of the port.""" @abstractmethod diff --git a/tidy3d/plugins/smatrix/ports/coaxial_lumped.py b/tidy3d/plugins/smatrix/ports/coaxial_lumped.py index ed93899fe3..6ceb518c87 100644 --- a/tidy3d/plugins/smatrix/ports/coaxial_lumped.py +++ b/tidy3d/plugins/smatrix/ports/coaxial_lumped.py @@ -381,7 +381,7 @@ def _voltage_path_size(self) -> Size: size = Geometry.unpop_axis(axis_size, (0, 0), self._voltage_axis) return size - def _check_grid_size(self, yee_grid: YeeGrid): + def _check_grid_size(self, yee_grid: YeeGrid) -> None: """Raises :class:``SetupError`` if the grid is too coarse at port locations""" trans_axes = self.remaining_axes for axis in trans_axes: diff --git a/tidy3d/plugins/smatrix/ports/rectangular_lumped.py b/tidy3d/plugins/smatrix/ports/rectangular_lumped.py index b81974dbd8..db076b04b1 100644 --- a/tidy3d/plugins/smatrix/ports/rectangular_lumped.py +++ b/tidy3d/plugins/smatrix/ports/rectangular_lumped.py @@ -248,7 +248,7 @@ def compute_current(self, sim_data: SimulationData) -> FreqDataArray: ) return I_integral.compute_current(field_data) - def _check_grid_size(self, yee_grid: YeeGrid): + def _check_grid_size(self, yee_grid: YeeGrid) -> None: """Raises :class:`SetupError` if the grid is too coarse at port locations""" e_component = "xyz"[self.voltage_axis] e_yee_grid = yee_grid.grid_dict[f"E{e_component}"] diff --git a/tidy3d/plugins/smatrix/run.py b/tidy3d/plugins/smatrix/run.py index 8035e91229..97f9393338 100644 --- a/tidy3d/plugins/smatrix/run.py +++ b/tidy3d/plugins/smatrix/run.py @@ -2,6 +2,7 @@ import json from os import PathLike +from typing import Any from tidy3d.components.base import Tidy3dBaseModel from tidy3d.components.data.index import SimulationDataMap @@ -126,7 +127,7 @@ def compose_modeler_data_from_batch_data( def create_batch( modeler: ComponentModelerType, - **kwargs, + **kwargs: Any, ) -> Batch: """Create a simulation Batch from a component modeler. @@ -153,7 +154,7 @@ def create_batch( def _run_local( modeler: ComponentModelerType, path_dir: str = DEFAULT_DATA_DIR, - **kwargs, + **kwargs: Any, ) -> ComponentModelerDataType: """Execute the full simulation workflow for a given component modeler. diff --git a/tidy3d/plugins/smatrix/utils.py b/tidy3d/plugins/smatrix/utils.py index e53f469508..43c822dc00 100644 --- a/tidy3d/plugins/smatrix/utils.py +++ b/tidy3d/plugins/smatrix/utils.py @@ -76,7 +76,7 @@ def ab_to_s( return s_matrix -def check_port_impedance_sign(Z_numpy: np.ndarray): +def check_port_impedance_sign(Z_numpy: np.ndarray) -> None: """Sanity check for consistent sign of real part of Z for each port. This check iterates through each port and ensures that the sign of the real diff --git a/tidy3d/plugins/waveguide/rectangular_dielectric.py b/tidy3d/plugins/waveguide/rectangular_dielectric.py index 73c4f9b88e..647022f3c0 100644 --- a/tidy3d/plugins/waveguide/rectangular_dielectric.py +++ b/tidy3d/plugins/waveguide/rectangular_dielectric.py @@ -822,7 +822,7 @@ def plot( ax: Ax = None, source_alpha: Optional[float] = None, monitor_alpha: Optional[float] = None, - **patch_kwargs, + **patch_kwargs: Any, ) -> Ax: """Plot each of simulation's components on a plane defined by one nonzero x,y,z coordinate. @@ -997,7 +997,7 @@ def plot_grid( y: Optional[float] = None, z: Optional[float] = None, ax: Ax = None, - **kwargs, + **kwargs: Any, ) -> Ax: """Plot the cell boundaries as lines on a plane defined by one nonzero x,y,z coordinate. @@ -1099,7 +1099,7 @@ def plot_field( vmax: Optional[float] = None, ax: Ax = None, geometry_edges: Optional[str] = None, - **sel_kwargs, + **sel_kwargs: Any, ) -> Ax: """Plot the field for a :class:`.ModeSolverData` with :class:`.Simulation` plot overlaid. diff --git a/tidy3d/updater.py b/tidy3d/updater.py index 5d4a9c8752..867dd14cc5 100644 --- a/tidy3d/updater.py +++ b/tidy3d/updater.py @@ -182,7 +182,7 @@ def new_update_function(sim_dict: dict) -> dict: return decorator -def iterate_update_dict(update_dict: dict, update_types: dict[str, Callable]): +def iterate_update_dict(update_dict: dict, update_types: dict[str, Callable]) -> None: """Recursively iterate nested ``update_dict``. For any nested ``nested_dict`` found, apply an update function if its ``nested_dict["type"]`` is in the keys of the ``update_types`` dictionary. Also iterates lists and tuples. @@ -296,12 +296,12 @@ def fix_mode_field_mnt(mnt_dict: dict) -> dict: def update_1_4(sim_dict: dict) -> dict: """Updates version 1.4.""" - def fix_polyslab(geo_dict): + def fix_polyslab(geo_dict) -> None: """Fix a PolySlab dictionary.""" geo_dict.pop("length", None) geo_dict.pop("center", None) - def fix_modespec(ms_dict): + def fix_modespec(ms_dict) -> None: """Fix a ModeSpec dictionary.""" sort_by = ms_dict.pop("sort_by", None) if sort_by and sort_by != "largest_neff": @@ -310,7 +310,7 @@ def fix_modespec(ms_dict): "largest effective index. Use ModeSpec.filter_pol to select polarization instead." ) - def fix_geometry_group(geo_dict): + def fix_geometry_group(geo_dict) -> None: """Fix a GeometryGroup dictionary.""" geo_dict.pop("center", None) diff --git a/tidy3d/web/api/autograd/autograd.py b/tidy3d/web/api/autograd/autograd.py index 1b5592f27b..47bb1c7d8d 100644 --- a/tidy3d/web/api/autograd/autograd.py +++ b/tidy3d/web/api/autograd/autograd.py @@ -4,6 +4,7 @@ import typing from os import PathLike from pathlib import Path +from typing import Any from autograd.builtins import dict as dict_ag from autograd.extend import defvjp, primitive @@ -421,7 +422,7 @@ def _run( task_name: str, local_gradient: bool = False, max_num_adjoint_per_fwd: typing.Optional[int] = None, - **run_kwargs, + **run_kwargs: Any, ) -> td.SimulationData: """User-facing ``web.run`` function, compatible with ``autograd`` differentiation.""" @@ -464,7 +465,7 @@ def _run_async( simulations: dict[str, td.Simulation], local_gradient: bool = False, max_num_adjoint_per_fwd: typing.Optional[int] = None, - **run_async_kwargs, + **run_async_kwargs: Any, ) -> dict[str, td.SimulationData]: """User-facing ``web.run_async`` function, compatible with ``autograd`` differentiation.""" @@ -535,7 +536,7 @@ def _run_primitive( aux_data: dict, local_gradient: bool, max_num_adjoint_per_fwd: int, - **run_kwargs, + **run_kwargs: Any, ) -> AutogradFieldMap: """Autograd-traced 'run()' function: runs simulation, strips tracer data, caches fwd data.""" @@ -588,7 +589,7 @@ def _run_async_primitive( aux_data_dict: dict[dict[str, typing.Any]], local_gradient: bool, max_num_adjoint_per_fwd: int, - **run_async_kwargs, + **run_async_kwargs: Any, ) -> dict[str, AutogradFieldMap]: task_names = sim_fields_dict.keys() @@ -668,7 +669,9 @@ def postprocess_fwd( ) -def upload_sim_fields_keys(sim_fields_keys: list[tuple], task_id: str, verbose: bool = False): +def upload_sim_fields_keys( + sim_fields_keys: list[tuple], task_id: str, verbose: bool = False +) -> None: """Upload traced simulation field keys for adjoint runs (delegated).""" return _upload_sim_fields_keys_impl( sim_fields_keys=sim_fields_keys, task_id=task_id, verbose=verbose @@ -691,7 +694,7 @@ def _run_bwd( aux_data: dict, local_gradient: bool, max_num_adjoint_per_fwd: int, - **run_kwargs, + **run_kwargs: Any, ) -> typing.Callable[[AutogradFieldMap], AutogradFieldMap]: """VJP-maker for ``_run_primitive()``. Constructs and runs adjoint simulations, computes grad.""" @@ -816,7 +819,7 @@ def _run_async_bwd( aux_data_dict: dict[str, dict[str, typing.Any]], local_gradient: bool, max_num_adjoint_per_fwd: int, - **run_async_kwargs, + **run_async_kwargs: Any, ) -> typing.Callable[[dict[str, AutogradFieldMap]], dict[str, AutogradFieldMap]]: """VJP-maker for ``_run_primitive()``. Constructs and runs adjoint simulation, computes grad.""" @@ -990,20 +993,20 @@ def postprocess_adj( """ The fundamental Tidy3D run and run_async functions used above. """ -def parse_run_kwargs(**run_kwargs): +def parse_run_kwargs(**run_kwargs: Any) -> dict[str, Any]: """Parse run kwargs for low-level engine (delegated).""" return _parse_run_kwargs_impl(**run_kwargs) def _run_tidy3d( - simulation: td.Simulation, task_name: str, **run_kwargs + simulation: td.Simulation, task_name: str, **run_kwargs: Any ) -> tuple[td.SimulationData, str]: """Run a simulation via engine wrapper (delegated).""" return _run_tidy3d_engine(simulation=simulation, task_name=task_name, **run_kwargs) def _run_async_tidy3d( - simulations: dict[str, td.Simulation], **run_kwargs + simulations: dict[str, td.Simulation], **run_kwargs: Any ) -> tuple[BatchData, dict[str, str]]: """Run a batch of simulations via engine wrapper (delegated).""" return _run_async_tidy3d_engine(simulations=simulations, **run_kwargs) @@ -1011,13 +1014,13 @@ def _run_async_tidy3d( def _run_async_tidy3d_bwd( simulations: dict[str, td.Simulation], - **run_kwargs, + **run_kwargs: Any, ) -> dict[str, AutogradFieldMap]: """Run a batch of adjoint simulations via engine wrapper (delegated).""" return _run_async_tidy3d_bwd_engine(simulations=simulations, **run_kwargs) -def __getattr__(name: str): +def __getattr__(name: str) -> Any: if name == "MAX_NUM_TRACED_STRUCTURES": return config.adjoint.max_traced_structures if name == "MAX_NUM_ADJOINT_PER_FWD": diff --git a/tidy3d/web/api/autograd/backward.py b/tidy3d/web/api/autograd/backward.py index 98de1febca..0c596f61dd 100644 --- a/tidy3d/web/api/autograd/backward.py +++ b/tidy3d/web/api/autograd/backward.py @@ -6,8 +6,10 @@ import xarray as xr import tidy3d as td +from tidy3d import Medium from tidy3d.components.autograd import AutogradFieldMap, get_static from tidy3d.components.autograd.derivative_utils import DerivativeInfo +from tidy3d.components.data.data_array import DataArray from tidy3d.config import config from tidy3d.exceptions import AdjointError from tidy3d.packaging import disable_local_subpixel @@ -81,12 +83,10 @@ def setup_adj( return sims_adj -def _compute_eps_array(medium, frequencies): +def _compute_eps_array(medium: Medium, frequencies: list[float]) -> DataArray: """Compute permittivity array for all frequencies.""" eps_data = [np.mean(medium.eps_model(f)) for f in frequencies] - return td.components.data.data_array.DataArray( - data=np.array(eps_data), dims=("f",), coords={"f": frequencies} - ) + return DataArray(data=np.array(eps_data), dims=("f",), coords={"f": frequencies}) def _slice_field_data( diff --git a/tidy3d/web/api/autograd/engine.py b/tidy3d/web/api/autograd/engine.py index 4838312d85..c9f36e0a42 100644 --- a/tidy3d/web/api/autograd/engine.py +++ b/tidy3d/web/api/autograd/engine.py @@ -1,6 +1,7 @@ from __future__ import annotations from pathlib import Path +from typing import Any import tidy3d as td from tidy3d.web.api.container import DEFAULT_DATA_PATH, Batch, Job @@ -8,15 +9,15 @@ from .io_utils import get_vjp_traced_fields, upload_sim_fields_keys -def parse_run_kwargs(**run_kwargs): +def parse_run_kwargs(**run_kwargs: Any) -> dict[str, Any]: """Parse the ``run_kwargs`` to extract what should be passed to the ``Job``/``Batch`` init.""" - job_fields = [*list(Job._upload_fields), "solver_version", "pay_type", "lazy", "use_cache"] + job_fields = [*list(Job._upload_fields), "solver_version", "pay_type", "lazy"] job_init_kwargs = {k: v for k, v in run_kwargs.items() if k in job_fields} return job_init_kwargs def _run_tidy3d( - simulation: td.Simulation, task_name: str, **run_kwargs + simulation: td.Simulation, task_name: str, **run_kwargs: Any ) -> tuple[td.SimulationData, str]: """Run a simulation without any tracers using regular web.run().""" @@ -38,7 +39,7 @@ def _run_tidy3d( def _run_async_tidy3d( - simulations: dict[str, td.Simulation], **run_kwargs + simulations: dict[str, td.Simulation], **run_kwargs: Any ) -> tuple[td.web.api.container.BatchData, dict[str, str]]: """Run a batch of simulations using regular web.run().""" @@ -74,7 +75,7 @@ def _run_async_tidy3d( def _run_async_tidy3d_bwd( simulations: dict[str, td.Simulation], - **run_kwargs, + **run_kwargs: Any, ) -> dict[str, dict]: """Run a batch of adjoint simulations using regular web.run().""" diff --git a/tidy3d/web/api/autograd/io_utils.py b/tidy3d/web/api/autograd/io_utils.py index afd9f01410..e5b1f71c67 100644 --- a/tidy3d/web/api/autograd/io_utils.py +++ b/tidy3d/web/api/autograd/io_utils.py @@ -4,13 +4,16 @@ import tempfile import tidy3d as td +from tidy3d.components.autograd import AutogradFieldMap from tidy3d.components.autograd.field_map import FieldMap, TracerKeys from tidy3d.web.core.s3utils import download_file, upload_file # type: ignore from .constants import SIM_FIELDS_KEYS_FILE, SIM_VJP_FILE -def upload_sim_fields_keys(sim_fields_keys: list[tuple], task_id: str, verbose: bool = False): +def upload_sim_fields_keys( + sim_fields_keys: list[tuple], task_id: str, verbose: bool = False +) -> None: """Function to upload the traced simulation field keys to the server for adjoint runs.""" handle, fname = tempfile.mkstemp(suffix=".hdf5") os.close(handle) @@ -29,7 +32,7 @@ def upload_sim_fields_keys(sim_fields_keys: list[tuple], task_id: str, verbose: os.unlink(fname) -def get_vjp_traced_fields(task_id_adj: str, verbose: bool): +def get_vjp_traced_fields(task_id_adj: str, verbose: bool) -> AutogradFieldMap: """Download and deserialize VJP traced fields for a completed adjoint job.""" handle, fname = tempfile.mkstemp(suffix=".hdf5") os.close(handle) diff --git a/tidy3d/web/api/connect_util.py b/tidy3d/web/api/connect_util.py index 5f10d3af3e..6148c67154 100644 --- a/tidy3d/web/api/connect_util.py +++ b/tidy3d/web/api/connect_util.py @@ -4,7 +4,7 @@ import time from functools import wraps -from typing import Optional +from typing import Any, Callable, Optional from requests import ReadTimeout from requests.exceptions import ConnectionError as ConnErr @@ -17,14 +17,20 @@ from tidy3d.web.common import REFRESH_TIME -def wait_for_connection(decorated_fn=None, wait_time_sec: Optional[float] = None): +def wait_for_connection( + decorated_fn: Optional[Callable[..., Any]] = None, + wait_time_sec: Optional[float] = None, +) -> Callable[[Callable[..., Any]], Callable[..., Any]] | Callable[..., Any]: """Causes function to ignore connection errors and retry for ``wait_time_sec`` secs.""" - def decorator(web_fn, wait_time_sec=wait_time_sec): + def decorator( + web_fn: Callable[..., Any], + wait_time_sec: Optional[float] = wait_time_sec, + ) -> Callable[..., Any]: """Decorator returned by @wait_for_connection()""" @wraps(web_fn) - def web_fn_wrapped(*args, **kwargs): + def web_fn_wrapped(*args: Any, **kwargs: Any) -> Any: """Function to return including connection waiting.""" time_start = time.time() warned_previously = False @@ -50,7 +56,7 @@ def web_fn_wrapped(*args, **kwargs): return decorator -def get_time_steps_str(time_steps) -> str: +def get_time_steps_str(time_steps: int) -> str: """get_time_steps_str""" if time_steps < 1000: time_steps_str = f"{time_steps}" @@ -61,7 +67,7 @@ def get_time_steps_str(time_steps) -> str: return time_steps_str -def get_grid_points_str(grid_points) -> str: +def get_grid_points_str(grid_points: int) -> str: """get_grid_points_str""" if grid_points < 1000: grid_points_str = f"{grid_points}" diff --git a/tidy3d/web/api/container.py b/tidy3d/web/api/container.py index e9c27c6fd9..3cd8dfe407 100644 --- a/tidy3d/web/api/container.py +++ b/tidy3d/web/api/container.py @@ -10,11 +10,11 @@ import time import uuid from abc import ABC -from collections.abc import Mapping +from collections.abc import Iterator, Mapping from concurrent.futures import ThreadPoolExecutor from os import PathLike from pathlib import Path -from typing import Literal, Optional, Union +from typing import Any, Literal, Optional, Union import pydantic.v1 as pd from pydantic.v1 import PrivateAttr @@ -379,7 +379,7 @@ def get_info(self) -> TaskInfo: return web.get_info(task_id=self.task_id) @property - def status(self): + def status(self) -> str: """Return current status of :class:`Job`.""" if self.load_if_cached: return "success" @@ -391,7 +391,7 @@ def status(self): return self.get_info().status @property - def postprocess_status(self): + def postprocess_status(self) -> Optional[str]: """Return current postprocess status of :class:`Job` if it is a Component Modeler.""" if web._is_modeler_batch(self.task_id): detail = self.get_info() @@ -580,7 +580,7 @@ def _check_path_dir(path: PathLike) -> None: parent_dir.mkdir(parents=True, exist_ok=True) @pd.root_validator(pre=True) - def set_task_name_if_none(cls, values): + def set_task_name_if_none(cls, values: dict[str, Any]) -> dict[str, Any]: """ Auto-assign a task_name if user did not provide one. """ @@ -667,11 +667,11 @@ def __getitem__(self, task_name: TaskName) -> WorkflowDataType: """Get the simulation data object for a given ``task_name``.""" return self.load_sim_data(task_name) - def __iter__(self): + def __iter__(self) -> Iterator[TaskName]: """Iterate over the task names.""" return iter(self.task_paths) - def __len__(self): + def __len__(self) -> int: """Return the number of tasks in the batch.""" return len(self.task_paths) @@ -1065,7 +1065,7 @@ def monitor( self._check_path_dir(path_dir=path_dir) download_executor = ThreadPoolExecutor(max_workers=self.num_workers) - def _should_download(job) -> bool: + def _should_download(job: Job) -> bool: status = job.status if not web._is_modeler_batch(job.task_id): return status == "success" @@ -1073,7 +1073,7 @@ def _should_download(job) -> bool: return True return status == "run_success" and getattr(job, "postprocess_status", None) == "success" - def schedule_download(job) -> None: + def schedule_download(job: Job) -> None: if download_executor is None or not _should_download(job): return task_id = job.task_id @@ -1095,7 +1095,7 @@ def schedule_download(job) -> None: download_futures[task_id] = download_executor.submit(job.download, job_path) # ----- continue condition & status formatting ------------------------------- - def check_continue_condition(job) -> bool: + def check_continue_condition(job: Job) -> bool: status = job.status if not web._is_modeler_batch(job.task_id): return status not in END_STATES @@ -1333,7 +1333,7 @@ def download( job._materialize_from_stash(job_path) continue - def fn(job=job, job_path=job_path) -> None: + def fn(job: Job = job, job_path: PathLike = job_path) -> None: job.download(path=job_path) fns.append(fn) diff --git a/tidy3d/web/api/material_libray.py b/tidy3d/web/api/material_libray.py index 98bfeaa0b2..2bc05cb419 100644 --- a/tidy3d/web/api/material_libray.py +++ b/tidy3d/web/api/material_libray.py @@ -4,12 +4,12 @@ import builtins import json -from typing import Optional +from typing import Any, Optional from pydantic.v1 import Field, parse_obj_as, validator from tidy3d.components.medium import MediumType -from tidy3d.web.core.http_util import http +from tidy3d.web.core.http_util import JSONType, http from tidy3d.web.core.types import Queryable @@ -27,7 +27,7 @@ class MaterialLibray(Queryable, smart_union=True): ) @validator("medium", "json_input", pre=True) - def parse_result(cls, values): + def parse_result(cls, values: dict[str, Any]) -> JSONType: """Automatically parsing medium and json_input from string to object.""" return json.loads(values) diff --git a/tidy3d/web/api/mode.py b/tidy3d/web/api/mode.py index b09f1bfd20..bd50876fc2 100644 --- a/tidy3d/web/api/mode.py +++ b/tidy3d/web/api/mode.py @@ -11,9 +11,10 @@ from typing import Callable, Literal, Optional, Union import pydantic.v1 as pydantic +import requests from botocore.exceptions import ClientError from joblib import Parallel, delayed -from rich.progress import Progress +from rich.progress import Progress, TaskID from tidy3d.components.data.monitor_data import ModeSolverData from tidy3d.components.eme.simulation import EMESimulation @@ -203,7 +204,9 @@ def run_batch( if results_files is None: results_files = [f"mode_solver_batch_results_{i}.hdf5" for i in range(num_mode_solvers)] - def handle_mode_solver(index, progress, pbar): + def handle_mode_solver( + index: int, progress: Progress, pbar: Optional[TaskID] + ) -> Optional[Parallel]: retries = 0 while retries <= max_retries: try: @@ -466,7 +469,7 @@ def upload( def submit( self, pay_type: Union[PayType, str] = PayType.AUTO, - ): + ) -> None: """Start the execution of this task. The mode solver must be uploaded to the server with the :meth:`ModeSolverTask.upload` method @@ -483,14 +486,14 @@ def submit( }, ) - def delete(self): + def delete(self) -> None: """Delete the mode solver and its corresponding task from the server.""" # Delete mode solver http.delete(f"{MODESOLVER_API}/{self.task_id}/{self.solver_id}") # Delete parent task http.delete(f"tidy3d/tasks/{self.task_id}") - def abort(self): + def abort(self) -> requests.Response: """Abort the mode solver and its corresponding task from the server.""" return http.put( "tidy3d/tasks/abort", json={"taskType": "MODE_SOLVER", "taskId": self.solver_id} diff --git a/tidy3d/web/api/tidy3d_stub.py b/tidy3d/web/api/tidy3d_stub.py index 20fddb5bab..fc979a1e2d 100644 --- a/tidy3d/web/api/tidy3d_stub.py +++ b/tidy3d/web/api/tidy3d_stub.py @@ -133,7 +133,7 @@ def from_file(cls, file_path: PathLike) -> WorkflowType: def to_file( self, file_path: PathLike, - ): + ) -> None: """Exports Union[:class:`.Simulation`, :class:`.HeatSimulation`, :class:`.EMESimulation`] instance to .yaml, .json, or .hdf5 file @@ -177,7 +177,7 @@ def get_type(self) -> str: """ return task_type_name_of(self.simulation) - def validate_pre_upload(self, source_required) -> None: + def validate_pre_upload(self, source_required: bool) -> None: """Perform some pre-checks on instances of component""" if isinstance(self.simulation, Simulation): self.simulation.validate_pre_upload(source_required) @@ -274,7 +274,7 @@ def from_file( return sim_data - def to_file(self, file_path: PathLike): + def to_file(self, file_path: PathLike) -> None: """Exports Union[:class:`.SimulationData`, :class:`.HeatSimulationData`, :class:`.EMESimulationData`] instance to .yaml, .json, or .hdf5 file diff --git a/tidy3d/web/api/webapi.py b/tidy3d/web/api/webapi.py index 021f4ed806..5d47c5ec18 100644 --- a/tidy3d/web/api/webapi.py +++ b/tidy3d/web/api/webapi.py @@ -93,7 +93,7 @@ def _is_modeler_batch(resource_id: str) -> bool: return BatchTask.is_batch(resource_id, batch_type="RF_SWEEP") -def _batch_detail(resource_id: str): +def _batch_detail(resource_id: str) -> BatchDetail: return BatchTask(resource_id).detail(batch_type="RF_SWEEP") @@ -159,7 +159,7 @@ def _batch_detail_error(resource_id: str) -> Optional[WebError]: def _upload_component_modeler_subtasks( resource_id: str, verbose: bool = True, solver_version: Optional[str] = None -): +) -> Optional[WebError]: """Kicks off and monitors the split and validation of component modeler tasks. This function orchestrates a two-phase process. First, it initiates a @@ -752,7 +752,9 @@ def upload( return resource_id -def get_reduced_simulation(simulation, reduce_simulation): +def get_reduced_simulation( + simulation: WorkflowType, reduce_simulation: Literal["auto", True, False] +) -> WorkflowType: """ Adjust the given simulation object based on the reduce_simulation parameter. Currently only implemented for the mode solver. @@ -924,7 +926,7 @@ def get_run_info(task_id: TaskId) -> tuple[Optional[float], Optional[float]]: return task.get_running_info() -def get_status(task_id) -> str: +def get_status(task_id: TaskId) -> str: """Get the status of a task. Raises an error if status is "error". Parameters @@ -1143,7 +1145,7 @@ def monitor_preprocess() -> None: @wait_for_connection -def abort(task_id: TaskId): +def abort(task_id: TaskId) -> Optional[TaskInfo]: """Abort server-side data associated with task. Parameters @@ -1800,7 +1802,7 @@ def estimate_cost( @wait_for_connection -def real_cost(task_id: str, verbose=True) -> float | None: +def real_cost(task_id: str, verbose: bool = True) -> float | None: """Get the billed cost for given task after it has been run. Parameters @@ -1891,7 +1893,7 @@ def real_cost(task_id: str, verbose=True) -> float | None: @wait_for_connection -def account(verbose=True) -> Account: +def account(verbose: bool = True) -> Account: """Get account information including FlexCredit balance and usage limits. Parameters diff --git a/tidy3d/web/cache.py b/tidy3d/web/cache.py index 20e9a0a712..8c9669bcc8 100644 --- a/tidy3d/web/cache.py +++ b/tidy3d/web/cache.py @@ -100,7 +100,7 @@ def list(self) -> list[dict[str, Any]]: with self._lock: return [entry.metadata for entry in self._iter_entries()] - def clear(self, hard=False) -> None: + def clear(self, hard: bool = False) -> None: """Remove all cache contents.""" with self._lock: if self._root.exists(): @@ -285,11 +285,6 @@ def try_fetch( """ Attempt to resolve and fetch a cached result entry for the given simulation context. On miss or any cache error, returns None (the caller should proceed with upload/run). - - Notes - ----- - - Mirrors the exact cache key/context computation from `run`. - - Safe to call regardless of `use_cache` value; will no-op if cache is disabled. """ try: simulation_hash = simulation._hash_self() @@ -412,7 +407,7 @@ def _timestamp_suffix() -> str: class _Hasher: - def __init__(self): + def __init__(self) -> None: self._hasher = hashlib.sha256() def update(self, data: bytes) -> None: diff --git a/tidy3d/web/cli/app.py b/tidy3d/web/cli/app.py index 00911c1f1b..8a2d60eb17 100644 --- a/tidy3d/web/cli/app.py +++ b/tidy3d/web/cli/app.py @@ -7,6 +7,7 @@ import os import shutil import ssl +from typing import Any import click import requests @@ -27,7 +28,7 @@ os.makedirs(TIDY3D_DIR, exist_ok=True) -def get_description(): +def get_description() -> str: """Get the description for the config command. Returns ------- @@ -47,7 +48,7 @@ def get_description(): @click.group() -def tidy3d_cli(): +def tidy3d_cli() -> None: """ Tidy3d command line tool. """ @@ -55,7 +56,7 @@ def tidy3d_cli(): @click.command() @click.option("--apikey", prompt=False) -def configure(apikey): +def configure(apikey: str) -> None: """Click command to configure the api key. Parameters @@ -75,7 +76,7 @@ def configure_fn(apikey: str) -> None: User input api key. """ - def auth(req): + def auth(req: requests.Request) -> requests.Request: """Enrich auth information to request. Parameters ---------- @@ -112,7 +113,7 @@ def auth(req): @click.command() @click.argument("lsf_file") @click.argument("new_file") -def convert(lsf_file, new_file): +def convert(lsf_file: Any, new_file: Any) -> None: """Click command to convert .lsf project into Tidy3D .py file""" raise ValueError( "The converter feature is deprecated. " @@ -206,7 +207,7 @@ def config_migrate(overwrite: bool, delete_legacy: bool) -> None: @click.group() -def config_group(): +def config_group() -> None: """Configuration utilities.""" diff --git a/tidy3d/web/cli/develop/documentation.py b/tidy3d/web/cli/develop/documentation.py index 9da6926577..ab86cc5509 100644 --- a/tidy3d/web/cli/develop/documentation.py +++ b/tidy3d/web/cli/develop/documentation.py @@ -17,7 +17,7 @@ import json import os -from typing import Optional +from typing import Any, Optional import click @@ -38,8 +38,8 @@ def replace_in_files( directory: str, json_file_path: str, selected_version: str, - dry_run=False, -): + dry_run: bool = False, +) -> None: """ Recursively finds and replaces strings in files within a directory based on a given dictionary loaded from a JSON file. The JSON file also includes a version selector. The function will print the file line and prompt for @@ -126,7 +126,7 @@ def replace_in_files( help="Path to the submodule.", type=str, # Specify the type as str for the 'submodule-path' option ) -def commit(message: str, submodule_path: str): +def commit(message: str, submodule_path: str) -> int: """ Add and commit changes in both the Git repository and its submodule. @@ -141,7 +141,7 @@ def commit(message: str, submodule_path: str): The relative path to the submodule. """ - def commit_repository(repository_path, commit_message): + def commit_repository(repository_path: str, commit_message: str) -> None: """ Commit changes in the specified Git repository. @@ -164,7 +164,7 @@ def commit_repository(repository_path, commit_message): @develop.command(name="build-docs", help="Builds the sphinx documentation.") -def build_documentation(args=None): +def build_documentation(args: Any = None) -> None: """ Build the Sphinx documentation. @@ -211,7 +211,7 @@ def build_documentation(args=None): default="./docs/notebooks", help="The remote branch from tidy3d-notebooks.", ) -def build_documentation_from_remote_notebooks(args=None): +def build_documentation_from_remote_notebooks(args: Any = None) -> int: """ Update the notebooks submodule and build documentation. @@ -300,7 +300,7 @@ def build_documentation_from_remote_notebooks(args=None): ) def replace_in_files_command( directory: str, json_dictionary: Optional[str], selected_version: Optional[str], dry_run: bool -): +) -> int: """ Recursively finds and replaces strings in files within a directory based on a given dictionary loaded from a JSON file. The JSON file also includes a version selector. The function will print the file line and prompt for diff --git a/tidy3d/web/cli/develop/index.py b/tidy3d/web/cli/develop/index.py index bbb63fef78..9d6f7d096b 100644 --- a/tidy3d/web/cli/develop/index.py +++ b/tidy3d/web/cli/develop/index.py @@ -10,7 +10,7 @@ @click.group(name="develop") -def develop(): +def develop() -> None: """ Development related command group in the CLI. diff --git a/tidy3d/web/cli/develop/install.py b/tidy3d/web/cli/develop/install.py index 302cc4ac55..a80a5c9849 100644 --- a/tidy3d/web/cli/develop/install.py +++ b/tidy3d/web/cli/develop/install.py @@ -9,6 +9,7 @@ import platform import re import subprocess +from typing import Any, Optional import click @@ -31,7 +32,7 @@ ] -def activate_correct_poetry_python(): +def activate_correct_poetry_python() -> None: """ Activate the correct Python environment for Poetry based on the operating system. """ @@ -46,7 +47,7 @@ def activate_correct_poetry_python(): print("Do you have a python available in your terminal?") -def configure_submodules(args=None): +def configure_submodules(args: Any = None) -> None: """ Initialize and update the notebook submodule. @@ -63,7 +64,7 @@ def configure_submodules(args=None): return 0 -def verify_pandoc_is_installed_and_version_less_than_3(): +def verify_pandoc_is_installed_and_version_less_than_3() -> bool: """ Check if Pandoc is installed and its version is less than 3. @@ -98,7 +99,7 @@ def verify_pandoc_is_installed_and_version_less_than_3(): return False -def verify_pipx_is_installed(): +def verify_pipx_is_installed() -> Optional[bool]: """ Verify if pipx is installed on the system. @@ -123,7 +124,7 @@ def verify_pipx_is_installed(): return False -def verify_poetry_is_installed(): +def verify_poetry_is_installed() -> Optional[bool]: """ Check if Poetry is installed on the system. @@ -151,7 +152,7 @@ def verify_poetry_is_installed(): raise OSError("Poetry is not installed or not found in the system PATH.") from exc -def verify_sphinx_is_installed(): +def verify_sphinx_is_installed() -> None: """ Verify if Sphinx is installed in the poetry environment. @@ -174,7 +175,7 @@ def verify_sphinx_is_installed(): @develop.command(name="get-install-directory", help="Gets the TIDY3D base directory.") -def get_install_directory_command(): +def get_install_directory_command() -> int: """ Get the tidy3d installation directory. @@ -188,7 +189,7 @@ def get_install_directory_command(): name="install-dev-environment", help="Installs and configures the full required development environment.", ) -def install_development_environment(args=None): +def install_development_environment(args: Any = None) -> None: """Install and configure the full required development environment. This command automates the installation of development tools like pipx, poetry, and pandoc, and sets up @@ -267,7 +268,7 @@ def install_development_environment(args=None): @develop.command( name="install-in-poetry", help="Just installs the tidy3d development package in poetry." ) -def install_in_poetry(env: str = "dev"): +def install_in_poetry(env: str = "dev") -> int: """ Install the tidy3d development package in the poetry environment with the specified extra option, by default 'dev'. @@ -288,7 +289,7 @@ def install_in_poetry(env: str = "dev"): @develop.command( name="uninstall-dev-environment", help="Uninstalls the tools installed by this CLI helper." ) -def uninstall_development_environment(args=None): +def uninstall_development_environment(args: Any = None) -> int: """ Uninstall the development environment and the tools installed by this CLI. @@ -359,7 +360,7 @@ def uninstall_development_environment(args=None): @develop.command(name="update-submodules", help="Updates notebooks and FAQ submodule from remote") -def update_submodules_remote(args=None): +def update_submodules_remote(args: Any = None) -> int: """ Update the notebooks submodule from the remote repository. @@ -376,7 +377,7 @@ def update_submodules_remote(args=None): @develop.command(name="verify-dev-environment", help="Verifies the development environment.") -def verify_development_environment(args=None): +def verify_development_environment(args: Any = None) -> int: """ Verify that the current development environment conforms to the specified requirements. diff --git a/tidy3d/web/cli/develop/packaging.py b/tidy3d/web/cli/develop/packaging.py index 0b92790dfb..a98fc17332 100644 --- a/tidy3d/web/cli/develop/packaging.py +++ b/tidy3d/web/cli/develop/packaging.py @@ -38,7 +38,7 @@ def benchmark_timing_operations( timing_command: str, in_poetry_environment: bool = True, output_file: str = "import.log" -): +) -> None: """ This function is used to time and benchmark the timing performance of various operations in the codebase. The idea of this functionality is to be able to track the performance of various operations over time and normalise @@ -106,7 +106,7 @@ def benchmark_timing_operations( ) def benchmark_timing_operations_command( timing_command: str, in_poetry_environment: bool = True, output_file: str = "import.log" -): +) -> None: # If timing_command is inputted without a value, raise a warning and print out the existing key options from the # timing command dictionary. if timing_command is None: diff --git a/tidy3d/web/cli/develop/tests.py b/tidy3d/web/cli/develop/tests.py index 3a75a07389..41d9c48e65 100644 --- a/tidy3d/web/cli/develop/tests.py +++ b/tidy3d/web/cli/develop/tests.py @@ -17,7 +17,7 @@ ] -def test_options(options: list): +def test_options(options: list) -> None: """ Inclusive rather than exclusive tests in a given set of environments. @@ -47,7 +47,7 @@ def test_options(options: list): @develop.command( name="test-in-envrionment", help="Installs the specified poetry environment and tests" ) -def test_in_environment_command(types: list, env: str = "dev"): +def test_in_environment_command(types: list, env: str = "dev") -> None: """ Installs a poetry environment specified by the extra definition in pyproject.toml and runs tests with pytest and any additional arguments. Requires a poetry installation so make sure to verify the installation previously. diff --git a/tidy3d/web/cli/develop/utils.py b/tidy3d/web/cli/develop/utils.py index 8faaf5d6e1..f359aa39a6 100644 --- a/tidy3d/web/cli/develop/utils.py +++ b/tidy3d/web/cli/develop/utils.py @@ -6,6 +6,7 @@ import pathlib import subprocess +from typing import Any import tidy3d @@ -16,7 +17,7 @@ ] -def get_install_directory(): +def get_install_directory() -> pathlib.Path: """ Retrieve the installation directory of the tidy3d module. @@ -28,7 +29,7 @@ def get_install_directory(): return pathlib.Path(tidy3d.__file__).parent.parent.absolute() -def echo_and_run_subprocess(command: list, **kwargs): +def echo_and_run_subprocess(command: list, **kwargs: Any) -> subprocess.CompletedProcess[Any]: """ Print and execute a subprocess command. @@ -49,7 +50,7 @@ def echo_and_run_subprocess(command: list, **kwargs): return subprocess.run(command, cwd=get_install_directory(), **kwargs) -def echo_and_check_subprocess(command: list, *args, **kwargs): +def echo_and_check_subprocess(command: list, *args: Any, **kwargs: Any) -> int: """ Print and execute a subprocess command, ensuring it completes successfully. diff --git a/tidy3d/web/core/account.py b/tidy3d/web/core/account.py index 07cef4caaa..0eda27928f 100644 --- a/tidy3d/web/core/account.py +++ b/tidy3d/web/core/account.py @@ -49,7 +49,7 @@ class Account(Tidy3DResource, extra=Extra.allow): ) @classmethod - def get(cls): + def get(cls) -> Optional[Account]: """Get user account information. Parameters diff --git a/tidy3d/web/core/core_config.py b/tidy3d/web/core/core_config.py index 77f0fb5c33..72d2853c3a 100644 --- a/tidy3d/web/core/core_config.py +++ b/tidy3d/web/core/core_config.py @@ -4,6 +4,10 @@ import logging as log +from rich.console import Console + +from tidy3d.log import Logger + # default setting config_setting = { "logger": log, @@ -12,7 +16,7 @@ } -def set_config(logger, logger_console, version: str): +def set_config(logger: Logger, logger_console: Console, version: str) -> None: """Init tidy3d core logger and logger console. Parameters @@ -29,16 +33,16 @@ def set_config(logger, logger_console, version: str): config_setting["version"] = version -def get_logger(): +def get_logger() -> Logger: """Get logging handlers.""" return config_setting["logger"] -def get_logger_console(): +def get_logger_console() -> Console: """Get console from logging handlers.""" return config_setting["logger_console"] -def get_version(): +def get_version() -> str: """Get version from cache.""" return config_setting["version"] diff --git a/tidy3d/web/core/exceptions.py b/tidy3d/web/core/exceptions.py index 4061a8c6f8..3dd6f15a35 100644 --- a/tidy3d/web/core/exceptions.py +++ b/tidy3d/web/core/exceptions.py @@ -10,7 +10,7 @@ class WebError(Exception): """Any error in tidy3d""" - def __init__(self, message: Optional[str] = None): + def __init__(self, message: Optional[str] = None) -> None: """Log just the error message and then raise the Exception.""" log = get_logger() super().__init__(message) diff --git a/tidy3d/web/core/http_util.py b/tidy3d/web/core/http_util.py index ba5bdf05d9..611b66c29a 100644 --- a/tidy3d/web/core/http_util.py +++ b/tidy3d/web/core/http_util.py @@ -6,8 +6,10 @@ import os from enum import Enum from functools import wraps +from typing import Any, Optional, TypeAlias import requests +from jedi.inference.gradual.typing import Callable from requests.adapters import HTTPAdapter from urllib3.util.ssl_ import create_urllib3_context @@ -28,6 +30,8 @@ from .environment import Env from .exceptions import WebError, WebNotFoundError +JSONType: TypeAlias = dict[str, Any] | list[Any] | str | int + class ResponseCodes(Enum): """HTTP response codes to handle individually.""" @@ -42,7 +46,7 @@ def get_version() -> str: return core_config.get_version() -def get_user_agent(): +def get_user_agent() -> str: """Get the user agent the current environment.""" return os.environ.get("TIDY3D_AGENT", f"Python-Client/{get_version()}") @@ -115,11 +119,11 @@ def get_headers() -> dict[str, str]: } -def http_interceptor(func): +def http_interceptor(func: Callable[..., Any]) -> Callable[..., JSONType]: """Intercept the response and raise an exception if the status code is not 200.""" @wraps(func) - def wrapper(*args, **kwargs): + def wrapper(*args: Any, **kwargs: Any) -> JSONType: """The wrapper function.""" suppress_404 = kwargs.pop("suppress_404", False) @@ -196,7 +200,7 @@ def wrapper(*args, **kwargs): class TLSAdapter(HTTPAdapter): - def init_poolmanager(self, *args, **kwargs): + def init_poolmanager(self, *args: Any, **kwargs: Any) -> None: context = create_urllib3_context(ssl_version=Env.current.ssl_version) kwargs["ssl_context"] = context return super().init_poolmanager(*args, **kwargs) @@ -205,20 +209,20 @@ def init_poolmanager(self, *args, **kwargs): class HttpSessionManager: """Http util class.""" - def __init__(self, session: requests.Session): + def __init__(self, session: requests.Session) -> None: """Initialize the session.""" self.session = session self._mounted_ssl_version = None self._ensure_tls_adapter(Env.current.ssl_version) self.session.verify = Env.current.ssl_verify - def reinit(self): + def reinit(self) -> None: """Reinitialize the session.""" ssl_version = Env.current.ssl_version self._ensure_tls_adapter(ssl_version) self.session.verify = Env.current.ssl_verify - def _ensure_tls_adapter(self, ssl_version): + def _ensure_tls_adapter(self, ssl_version: str) -> None: if not ssl_version: self._mounted_ssl_version = None return @@ -227,7 +231,9 @@ def _ensure_tls_adapter(self, ssl_version): self._mounted_ssl_version = ssl_version @http_interceptor - def get(self, path: str, json=None, params=None): + def get( + self, path: str, json: JSONType = None, params: Optional[dict[str, Any]] = None + ) -> requests.Response: """Get the resource.""" self.reinit() return self.session.get( @@ -235,13 +241,15 @@ def get(self, path: str, json=None, params=None): ) @http_interceptor - def post(self, path: str, json=None): + def post(self, path: str, json: JSONType = None) -> requests.Response: """Create the resource.""" self.reinit() return self.session.post(Env.current.get_real_url(path), json=json, auth=api_key_auth) @http_interceptor - def put(self, path: str, json=None, files=None): + def put( + self, path: str, json: JSONType = None, files: Optional[dict[str, Any]] = None + ) -> requests.Response: """Update the resource.""" self.reinit() return self.session.put( @@ -249,7 +257,9 @@ def put(self, path: str, json=None, files=None): ) @http_interceptor - def delete(self, path: str, json=None, params=None): + def delete( + self, path: str, json: JSONType = None, params: Optional[dict[str, Any]] = None + ) -> requests.Response: """Delete the resource.""" self.reinit() return self.session.delete( diff --git a/tidy3d/web/core/s3utils.py b/tidy3d/web/core/s3utils.py index 2965e8ca61..0ba2fee9da 100644 --- a/tidy3d/web/core/s3utils.py +++ b/tidy3d/web/core/s3utils.py @@ -10,9 +10,10 @@ from enum import Enum from os import PathLike from pathlib import Path -from typing import Callable, Optional +from typing import Any, Callable, Optional import boto3 +import rich from boto3.s3.transfer import TransferConfig from pydantic import BaseModel, Field from rich.progress import ( @@ -92,12 +93,12 @@ class UploadProgress: Progressbar task instance. """ - def __init__(self, size_bytes, progress): + def __init__(self, size_bytes: int, progress: rich.progress.Progress) -> None: """initialize with the size of file and rich.progress.Progress() instance. Parameters ---------- - size_bytes: float + size_bytes: int Number of total bytes to upload. progress : rich.progress.Progress() Progressbar instance from rich @@ -105,12 +106,12 @@ def __init__(self, size_bytes, progress): self.progress = progress self.ul_task = self.progress.add_task("[red]Uploading...", total=size_bytes) - def report(self, bytes_in_chunk): + def report(self, bytes_in_chunk: Any) -> None: """Update the progressbar with the most recent chunk. Parameters ---------- - bytes_in_chunk : float + bytes_in_chunk : int Description """ self.progress.update(self.ul_task, advance=bytes_in_chunk) @@ -127,7 +128,7 @@ class DownloadProgress: Progressbar task instance. """ - def __init__(self, size_bytes, progress): + def __init__(self, size_bytes: int, progress: rich.progress.Progress) -> None: """initialize with the size of file and rich.progress.Progress() instance Parameters @@ -140,7 +141,7 @@ def __init__(self, size_bytes, progress): self.progress = progress self.dl_task = self.progress.add_task("[red]Downloading...", total=size_bytes) - def report(self, bytes_in_chunk): + def report(self, bytes_in_chunk: int) -> None: """Update the progressbar with the most recent chunk. Parameters @@ -156,7 +157,7 @@ class _S3Action(Enum): DOWNLOADING = "↓" -def _get_progress(action: _S3Action): +def _get_progress(action: _S3Action) -> Progress: """Get the progress of an action.""" col = ( @@ -181,7 +182,7 @@ def _get_progress(action: _S3Action): _s3_config = TransferConfig() -_s3_sts_tokens: [str, _S3STSToken] = {} +_s3_sts_tokens: dict[str, _S3STSToken] = {} def get_s3_sts_token( @@ -222,7 +223,7 @@ def upload_file( verbose: bool = True, progress_callback: Optional[Callable[[float], None]] = None, extra_arguments: Optional[Mapping[str, str]] = None, -): +) -> None: """Upload a file to S3. Parameters @@ -275,7 +276,7 @@ def _upload(_callback: Callable) -> None: "upload", filename=str(remote_filename), total=total_size ) - def _callback(bytes_in_chunk): + def _callback(bytes_in_chunk: int) -> None: progress.update(task_id, advance=bytes_in_chunk) _upload(_callback) @@ -363,7 +364,7 @@ def _download(_callback: Callable) -> None: progress.start() task_id = progress.add_task("download", filename=remote_basename, total=total_size) - def _callback(bytes_in_chunk): + def _callback(bytes_in_chunk: int) -> None: progress.update(task_id, advance=bytes_in_chunk) _download(_callback) diff --git a/tidy3d/web/core/stub.py b/tidy3d/web/core/stub.py index 53ec961462..c351551f63 100644 --- a/tidy3d/web/core/stub.py +++ b/tidy3d/web/core/stub.py @@ -24,7 +24,7 @@ def from_file(self, file_path: PathLike) -> TaskStubData: """ @abstractmethod - def to_file(self, file_path: PathLike): + def to_file(self, file_path: PathLike) -> None: """Loads a :class:`Stub` from .yaml, .json, or .hdf5 file. Parameters @@ -56,7 +56,7 @@ def from_file(self, file_path: PathLike) -> TaskStub: """ @abstractmethod - def to_file(self, file_path: PathLike): + def to_file(self, file_path: PathLike) -> None: """Loads a :class:`TaskStub` from .yaml, .json, .hdf5 or .hdf5.gz file. Parameters diff --git a/tidy3d/web/core/task_core.py b/tidy3d/web/core/task_core.py index 696e7edab0..d23f45ffc7 100644 --- a/tidy3d/web/core/task_core.py +++ b/tidy3d/web/core/task_core.py @@ -10,6 +10,7 @@ from os import PathLike from typing import Callable, Optional, Union +import requests from botocore.exceptions import ClientError from pydantic.v1 import Extra, Field, parse_obj_as @@ -71,7 +72,7 @@ def get( create: bool = False, projects_endpoint: str = "tidy3d/projects", project_endpoint: str = "tidy3d/project", - ): + ) -> Folder: """Get folder by name. Parameters @@ -98,7 +99,7 @@ def get( return folder @classmethod - def create(cls, folder_name: str): + def create(cls, folder_name: str) -> Folder: """Create a folder, return existing folder if there is one has the same name. Parameters @@ -112,7 +113,7 @@ def create(cls, folder_name: str): """ return Folder.get(folder_name, True) - def delete(self, projects_endpoint: str = "tidy3d/projects"): + def delete(self, projects_endpoint: str = "tidy3d/projects") -> None: """Remove this folder.""" http.delete(f"{projects_endpoint}/{self.folder_id}") @@ -312,7 +313,7 @@ def get_running_tasks(cls) -> list[SimulationTask]: return [] return parse_obj_as(list[SimulationTask], resp) - def delete(self, versions: bool = False): + def delete(self, versions: bool = False) -> None: """Delete current task from server. Parameters @@ -335,7 +336,7 @@ def delete(self, versions: bool = False): else: # Fallback to old method if we can't get the groupId and version http.delete(f"tidy3d/tasks/{self.task_id}") - def get_simulation_json(self, to_file: PathLike, verbose: bool = True): + def get_simulation_json(self, to_file: PathLike, verbose: bool = True) -> None: """Get json file for a :class:`.Simulation` from server. Parameters @@ -344,11 +345,6 @@ def get_simulation_json(self, to_file: PathLike, verbose: bool = True): Save file to path. verbose: bool = True Whether to display progress bars. - - Returns - ------- - path: pathlib.Path - Path to saved file. """ if not self.task_id: raise WebError("Expected field 'task_id' is unset.") @@ -450,7 +446,7 @@ def submit( worker_group: Optional[str] = None, pay_type: Union[PayType, str] = PayType.AUTO, priority: Optional[int] = None, - ): + ) -> None: """Kick off this task. It will be uploaded to server before @@ -488,7 +484,7 @@ def submit( }, ) - def estimate_cost(self, solver_version=None) -> float: + def estimate_cost(self, solver_version: Optional[str] = None) -> float: """Compute the maximum flex unit charge for a given task, assuming the simulation runs for the full ``run_time``. If early shut-off is triggered, the cost is adjusted proportionately. @@ -697,7 +693,7 @@ def get_error_json(self, to_file: PathLike, verbose: bool = True) -> pathlib.Pat verbose=verbose, ) - def abort(self): + def abort(self) -> requests.Response: """Aborting current task from server.""" if not self.task_id: raise ValueError("Task id not found.") @@ -705,7 +701,7 @@ def abort(self): "tidy3d/tasks/abort", json={"taskType": self.task_type, "taskId": self.task_id} ) - def validate_post_upload(self, parent_tasks: Optional[list[str]] = None): + def validate_post_upload(self, parent_tasks: Optional[list[str]] = None) -> None: """Perform checks after task is uploaded and metadata is processed.""" if self.task_type == "HEAT_CHARGE" and parent_tasks: try: @@ -747,7 +743,7 @@ class BatchTask: most methods, as it dictates which backend service handles the request. """ - def __init__(self, batch_id: str): + def __init__(self, batch_id: str) -> None: self.batch_id = batch_id @staticmethod @@ -810,7 +806,7 @@ def check( solver_version: Optional[str] = None, protocol_version: Optional[str] = None, batch_type: str = "", - ): + ) -> requests.Response: """Submits a request to validate the batch configuration on the server. Parameters @@ -844,7 +840,7 @@ def submit( protocol_version: Optional[str] = None, worker_group: Optional[str] = None, batch_type: str = "", - ): + ) -> requests.Response: """Submits the batch for execution on the server. Parameters @@ -881,7 +877,7 @@ def postprocess( protocol_version: Optional[str] = None, worker_group: Optional[str] = None, batch_type: str = "", - ): + ) -> requests.Response: """Initiates post-processing for a completed batch run. Parameters diff --git a/tidy3d/web/core/task_info.py b/tidy3d/web/core/task_info.py index 93a68fb4ce..64cf00ea0f 100644 --- a/tidy3d/web/core/task_info.py +++ b/tidy3d/web/core/task_info.py @@ -163,7 +163,7 @@ class RunInfo(TaskBase): field_decay: pydantic.confloat(ge=0.0, le=1.0) """Field decay from the maximum value (0 to 1).""" - def display(self): + def display(self) -> None: """Print some info about the task's progress.""" print(f" - {self.perc_done:.2f} (%) done") print(f" - {self.field_decay:.2e} field decay from max") diff --git a/tidy3d/web/core/types.py b/tidy3d/web/core/types.py index a3f7bb9519..39ab0bc926 100644 --- a/tidy3d/web/core/types.py +++ b/tidy3d/web/core/types.py @@ -4,6 +4,7 @@ from abc import ABC, abstractmethod from enum import Enum +from typing import Any from pydantic.v1 import BaseModel @@ -13,7 +14,7 @@ class Tidy3DResource(BaseModel, ABC): @classmethod @abstractmethod - def get(cls, *args, **kwargs) -> Tidy3DResource: + def get(cls, *args: Any, **kwargs: Any) -> Tidy3DResource: """Get a resource from the server.""" @@ -22,11 +23,11 @@ class ResourceLifecycle(Tidy3DResource, ABC): @classmethod @abstractmethod - def create(cls, *args, **kwargs) -> Tidy3DResource: + def create(cls, *args: Any, **kwargs: Any) -> Tidy3DResource: """Create a new resource and return it.""" @abstractmethod - def delete(self, *args, **kwargs) -> None: + def delete(self, *args: Any, **kwargs: Any) -> None: """Delete the resource.""" @@ -34,7 +35,7 @@ class Submittable(BaseModel, ABC): """Abstract base class / template for a webservice that implements a submit method.""" @abstractmethod - def submit(self, *args, **kwargs) -> None: + def submit(self, *args: Any, **kwargs: Any) -> None: """Submit the task to the webservice.""" @@ -43,7 +44,7 @@ class Queryable(BaseModel, ABC): @classmethod @abstractmethod - def list(cls, *args, **kwargs) -> [Queryable]: + def list(cls, *args: Any, **kwargs: Any) -> [Queryable]: """List all resources of this type."""